]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fs/aufs/aiops.cc
date: 2002/10/24 18:49:56; author: wessels; state: Exp; lines: +20 -4
[thirdparty/squid.git] / src / fs / aufs / aiops.cc
CommitLineData
cd748f27 1/*
40173038 2 * $Id: aiops.cc,v 1.16 2002/10/22 07:02:00 hno Exp $
cd748f27 3 *
4 * DEBUG: section 43 AIOPS
5 * AUTHOR: Stewart Forster <slf@connect.com.au>
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
cd748f27 8 * ----------------------------------------------------------
9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
cd748f27 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35#include "squid.h"
36#include "store_asyncufs.h"
37
38#include <stdio.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <fcntl.h>
42#include <pthread.h>
43#include <errno.h>
44#include <dirent.h>
45#include <signal.h>
46#if HAVE_SCHED_H
47#include <sched.h>
48#endif
49
50#define RIDICULOUS_LENGTH 4096
51
c04d4f40 52enum _squidaio_thread_status {
cd748f27 53 _THREAD_STARTING = 0,
54 _THREAD_WAITING,
55 _THREAD_BUSY,
56 _THREAD_FAILED,
57 _THREAD_DONE
58};
c04d4f40 59typedef enum _squidaio_thread_status squidaio_thread_status;
cd748f27 60
c04d4f40 61typedef struct squidaio_request_t {
62 struct squidaio_request_t *next;
63 squidaio_request_type request_type;
cd748f27 64 int cancelled;
65 char *path;
66 int oflag;
67 mode_t mode;
68 int fd;
69 char *bufferp;
70 char *tmpbufp;
71 int buflen;
72 off_t offset;
73 int whence;
74 int ret;
75 int err;
76 struct stat *tmpstatp;
77 struct stat *statp;
c04d4f40 78 squidaio_result_t *resultp;
79} squidaio_request_t;
cd748f27 80
c04d4f40 81typedef struct squidaio_request_queue_t {
55f0e6f7 82 pthread_mutex_t mutex;
83 pthread_cond_t cond;
c04d4f40 84 squidaio_request_t *volatile head;
85 squidaio_request_t *volatile *volatile tailp;
55f0e6f7 86 unsigned long requests;
f0debecb 87 unsigned long blocked; /* main failed to lock the queue */
c04d4f40 88} squidaio_request_queue_t;
55f0e6f7 89
c04d4f40 90typedef struct squidaio_thread_t squidaio_thread_t;
91struct squidaio_thread_t {
92 squidaio_thread_t *next;
cd748f27 93 pthread_t thread;
c04d4f40 94 squidaio_thread_status status;
95 struct squidaio_request_t *current_req;
55f0e6f7 96 unsigned long requests;
97};
cd748f27 98
c04d4f40 99static void squidaio_init(void);
100static void squidaio_queue_request(squidaio_request_t *);
101static void squidaio_cleanup_request(squidaio_request_t *);
102static void *squidaio_thread_loop(void *);
103static void squidaio_do_open(squidaio_request_t *);
104static void squidaio_do_read(squidaio_request_t *);
105static void squidaio_do_write(squidaio_request_t *);
106static void squidaio_do_close(squidaio_request_t *);
107static void squidaio_do_stat(squidaio_request_t *);
108static void squidaio_do_unlink(squidaio_request_t *);
109static void squidaio_do_truncate(squidaio_request_t *);
cd748f27 110#if AIO_OPENDIR
c04d4f40 111static void *squidaio_do_opendir(squidaio_request_t *);
cd748f27 112#endif
c04d4f40 113static void squidaio_debug(squidaio_request_t *);
114static void squidaio_poll_queues(void);
cd748f27 115
c04d4f40 116static squidaio_thread_t *threads = NULL;
117static int squidaio_initialised = 0;
cd748f27 118
55f0e6f7 119
58cd5bbd 120#define AIO_LARGE_BUFS 16384
121#define AIO_MEDIUM_BUFS AIO_LARGE_BUFS >> 1
122#define AIO_SMALL_BUFS AIO_LARGE_BUFS >> 2
123#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3
55f0e6f7 124#define AIO_MICRO_BUFS 128
58cd5bbd 125
c04d4f40 126static MemPool *squidaio_large_bufs = NULL; /* 16K */
9bea1d5b 127static MemPool *squidaio_medium_bufs = NULL; /* 8K */
c04d4f40 128static MemPool *squidaio_small_bufs = NULL; /* 4K */
129static MemPool *squidaio_tiny_bufs = NULL; /* 2K */
130static MemPool *squidaio_micro_bufs = NULL; /* 128K */
58cd5bbd 131
cd748f27 132static int request_queue_len = 0;
c04d4f40 133static MemPool *squidaio_request_pool = NULL;
134static MemPool *squidaio_thread_pool = NULL;
135static squidaio_request_queue_t request_queue;
f0debecb 136static struct {
c04d4f40 137 squidaio_request_t *head, **tailp;
f0debecb 138} request_queue2 = {
139
140 NULL, &request_queue2.head
141};
c04d4f40 142static squidaio_request_queue_t done_queue;
f0debecb 143static struct {
c04d4f40 144 squidaio_request_t *head, **tailp;
f0debecb 145} done_requests = {
146
147 NULL, &done_requests.head
148};
cd748f27 149static pthread_attr_t globattr;
5e5c622b 150#if HAVE_SCHED_H
cd748f27 151static struct sched_param globsched;
5e5c622b 152#endif
cd748f27 153static pthread_t main_thread;
154
58cd5bbd 155static MemPool *
c04d4f40 156squidaio_get_pool(int size)
58cd5bbd 157{
158 MemPool *p;
159 if (size <= AIO_LARGE_BUFS) {
f0debecb 160 if (size <= AIO_MICRO_BUFS)
c04d4f40 161 p = squidaio_micro_bufs;
55f0e6f7 162 else if (size <= AIO_TINY_BUFS)
c04d4f40 163 p = squidaio_tiny_bufs;
f0debecb 164 else if (size <= AIO_SMALL_BUFS)
c04d4f40 165 p = squidaio_small_bufs;
f0debecb 166 else if (size <= AIO_MEDIUM_BUFS)
c04d4f40 167 p = squidaio_medium_bufs;
f0debecb 168 else
c04d4f40 169 p = squidaio_large_bufs;
58cd5bbd 170 } else
171 p = NULL;
172 return p;
173}
174
175static void *
c04d4f40 176squidaio_xmalloc(int size)
58cd5bbd 177{
178 void *p;
179 MemPool *pool;
180
c04d4f40 181 if ((pool = squidaio_get_pool(size)) != NULL) {
58cd5bbd 182 p = memPoolAlloc(pool);
183 } else
184 p = xmalloc(size);
185
186 return p;
187}
188
55f0e6f7 189static char *
c04d4f40 190squidaio_xstrdup(const char *str)
55f0e6f7 191{
192 char *p;
f0debecb 193 int len = strlen(str) + 1;
55f0e6f7 194
e6ccf245 195 p = (char *)squidaio_xmalloc(len);
55f0e6f7 196 strncpy(p, str, len);
197
198 return p;
199}
200
58cd5bbd 201static void
c04d4f40 202squidaio_xfree(void *p, int size)
58cd5bbd 203{
204 MemPool *pool;
205
c04d4f40 206 if ((pool = squidaio_get_pool(size)) != NULL) {
f0debecb 207 memPoolFree(pool, p);
58cd5bbd 208 } else
f0debecb 209 xfree(p);
58cd5bbd 210}
211
55f0e6f7 212static void
c04d4f40 213squidaio_xstrfree(char *str)
55f0e6f7 214{
215 MemPool *pool;
f0debecb 216 int len = strlen(str) + 1;
55f0e6f7 217
c04d4f40 218 if ((pool = squidaio_get_pool(len)) != NULL) {
f0debecb 219 memPoolFree(pool, str);
55f0e6f7 220 } else
f0debecb 221 xfree(str);
55f0e6f7 222}
223
cd748f27 224static void
c04d4f40 225squidaio_init(void)
cd748f27 226{
227 int i;
c04d4f40 228 squidaio_thread_t *threadp;
cd748f27 229
c04d4f40 230 if (squidaio_initialised)
cd748f27 231 return;
232
233 pthread_attr_init(&globattr);
234#if HAVE_PTHREAD_ATTR_SETSCOPE
235 pthread_attr_setscope(&globattr, PTHREAD_SCOPE_SYSTEM);
236#endif
5e5c622b 237#if HAVE_SCHED_H
cd748f27 238 globsched.sched_priority = 1;
5e5c622b 239#endif
cd748f27 240 main_thread = pthread_self();
5e5c622b 241#if HAVE_SCHED_H && HAVE_PTHREAD_SETSCHEDPARAM
cd748f27 242 pthread_setschedparam(main_thread, SCHED_OTHER, &globsched);
243#endif
5e5c622b 244#if HAVE_SCHED_H
cd748f27 245 globsched.sched_priority = 2;
5e5c622b 246#endif
247#if HAVE_SCHED_H && HAVE_PTHREAD_ATTR_SETSCHEDPARAM
cd748f27 248 pthread_attr_setschedparam(&globattr, &globsched);
249#endif
250
55f0e6f7 251 /* Initialize request queue */
252 if (pthread_mutex_init(&(request_queue.mutex), NULL))
253 fatal("Failed to create mutex");
254 if (pthread_cond_init(&(request_queue.cond), NULL))
255 fatal("Failed to create condition variable");
256 request_queue.head = NULL;
257 request_queue.tailp = &request_queue.head;
258 request_queue.requests = 0;
259 request_queue.blocked = 0;
260
261 /* Initialize done queue */
262 if (pthread_mutex_init(&(done_queue.mutex), NULL))
263 fatal("Failed to create mutex");
264 if (pthread_cond_init(&(done_queue.cond), NULL))
265 fatal("Failed to create condition variable");
266 done_queue.head = NULL;
267 done_queue.tailp = &done_queue.head;
268 done_queue.requests = 0;
269 done_queue.blocked = 0;
cd748f27 270
55f0e6f7 271 /* Create threads and get them to sit in their wait loop */
c04d4f40 272 squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t));
12e137b0 273 assert (NUMTHREADS);
cd748f27 274 for (i = 0; i < NUMTHREADS; i++) {
e6ccf245 275 threadp = (squidaio_thread_t *)memPoolAlloc(squidaio_thread_pool);
cd748f27 276 threadp->status = _THREAD_STARTING;
55f0e6f7 277 threadp->current_req = NULL;
278 threadp->requests = 0;
279 threadp->next = threads;
280 threads = threadp;
c04d4f40 281 if (pthread_create(&threadp->thread, &globattr, squidaio_thread_loop, threadp)) {
cd748f27 282 fprintf(stderr, "Thread creation failed\n");
283 threadp->status = _THREAD_FAILED;
284 continue;
285 }
cd748f27 286 }
287
288 /* Create request pool */
c04d4f40 289 squidaio_request_pool = memPoolCreate("aio_request", sizeof(squidaio_request_t));
290 squidaio_large_bufs = memPoolCreate("squidaio_large_bufs", AIO_LARGE_BUFS);
291 squidaio_medium_bufs = memPoolCreate("squidaio_medium_bufs", AIO_MEDIUM_BUFS);
292 squidaio_small_bufs = memPoolCreate("squidaio_small_bufs", AIO_SMALL_BUFS);
293 squidaio_tiny_bufs = memPoolCreate("squidaio_tiny_bufs", AIO_TINY_BUFS);
294 squidaio_micro_bufs = memPoolCreate("squidaio_micro_bufs", AIO_MICRO_BUFS);
295
296 squidaio_initialised = 1;
cd748f27 297}
298
299
300static void *
c04d4f40 301squidaio_thread_loop(void *ptr)
cd748f27 302{
e6ccf245 303 squidaio_thread_t *threadp = (squidaio_thread_t *)ptr;
c04d4f40 304 squidaio_request_t *request;
e6ccf245 305 sigset_t newSig;
cd748f27 306
307 /*
308 * Make sure to ignore signals which may possibly get sent to
309 * the parent squid thread. Causes havoc with mutex's and
310 * condition waits otherwise
311 */
312
e6ccf245 313 sigemptyset(&newSig);
314 sigaddset(&newSig, SIGPIPE);
315 sigaddset(&newSig, SIGCHLD);
cd748f27 316#ifdef _SQUID_LINUX_THREADS_
e6ccf245 317 sigaddset(&newSig, SIGQUIT);
318 sigaddset(&newSig, SIGTRAP);
cd748f27 319#else
e6ccf245 320 sigaddset(&newSig, SIGUSR1);
321 sigaddset(&newSig, SIGUSR2);
cd748f27 322#endif
e6ccf245 323 sigaddset(&newSig, SIGHUP);
324 sigaddset(&newSig, SIGTERM);
325 sigaddset(&newSig, SIGINT);
326 sigaddset(&newSig, SIGALRM);
327 pthread_sigmask(SIG_BLOCK, &newSig, NULL);
cd748f27 328
cd748f27 329 while (1) {
55f0e6f7 330 threadp->current_req = request = NULL;
331 request = NULL;
332 /* Get a request to process */
f0debecb 333 threadp->status = _THREAD_WAITING;
55f0e6f7 334 pthread_mutex_lock(&request_queue.mutex);
f0debecb 335 while (!request_queue.head) {
55f0e6f7 336 pthread_cond_wait(&request_queue.cond, &request_queue.mutex);
cd748f27 337 }
55f0e6f7 338 request = request_queue.head;
339 if (request)
340 request_queue.head = request->next;
f0debecb 341 if (!request_queue.head)
342 request_queue.tailp = &request_queue.head;
55f0e6f7 343 pthread_mutex_unlock(&request_queue.mutex);
344 /* process the request */
345 threadp->status = _THREAD_BUSY;
346 request->next = NULL;
347 threadp->current_req = request;
cd748f27 348 errno = 0;
349 if (!request->cancelled) {
350 switch (request->request_type) {
351 case _AIO_OP_OPEN:
c04d4f40 352 squidaio_do_open(request);
cd748f27 353 break;
354 case _AIO_OP_READ:
c04d4f40 355 squidaio_do_read(request);
cd748f27 356 break;
357 case _AIO_OP_WRITE:
c04d4f40 358 squidaio_do_write(request);
cd748f27 359 break;
360 case _AIO_OP_CLOSE:
c04d4f40 361 squidaio_do_close(request);
cd748f27 362 break;
363 case _AIO_OP_UNLINK:
c04d4f40 364 squidaio_do_unlink(request);
cd748f27 365 break;
15a47d1d 366 case _AIO_OP_TRUNCATE:
c04d4f40 367 squidaio_do_truncate(request);
15a47d1d 368 break;
cd748f27 369#if AIO_OPENDIR /* Opendir not implemented yet */
370 case _AIO_OP_OPENDIR:
c04d4f40 371 squidaio_do_opendir(request);
cd748f27 372 break;
373#endif
374 case _AIO_OP_STAT:
c04d4f40 375 squidaio_do_stat(request);
cd748f27 376 break;
377 default:
378 request->ret = -1;
379 request->err = EINVAL;
380 break;
381 }
382 } else { /* cancelled */
383 request->ret = -1;
384 request->err = EINTR;
385 }
55f0e6f7 386 threadp->status = _THREAD_DONE;
387 /* put the request in the done queue */
388 pthread_mutex_lock(&done_queue.mutex);
389 *done_queue.tailp = request;
390 done_queue.tailp = &request->next;
391 pthread_mutex_unlock(&done_queue.mutex);
392 threadp->requests++;
393 } /* while forever */
cd748f27 394 return NULL;
c04d4f40 395} /* squidaio_thread_loop */
cd748f27 396
397static void
c04d4f40 398squidaio_queue_request(squidaio_request_t * request)
cd748f27 399{
cd748f27 400 static int high_start = 0;
99cce4cb 401 debug(43, 9) ("squidaio_queue_request: %p type=%d result=%p\n",
f0debecb 402 request, request->request_type, request->resultp);
cd748f27 403 /* Mark it as not executed (failing result, no error) */
55f0e6f7 404 request->ret = -1;
405 request->err = 0;
406 /* Internal housekeeping */
407 request_queue_len += 1;
408 request->resultp->_data = request;
409 /* Play some tricks with the request_queue2 queue */
410 request->next = NULL;
40173038 411 if (pthread_mutex_trylock(&request_queue.mutex) == 0) {
412 if (request_queue2.head) {
413 /* Grab blocked requests */
55f0e6f7 414 *request_queue.tailp = request_queue2.head;
40173038 415 request_queue.tailp = request_queue2.tailp;
416 }
417 /* Enqueue request */
418 *request_queue.tailp = request;
419 request_queue.tailp = &request->next;
420 pthread_cond_signal(&request_queue.cond);
421 pthread_mutex_unlock(&request_queue.mutex);
422 if (request_queue2.head) {
423 /* Clear queue of blocked requests */
55f0e6f7 424 request_queue2.head = NULL;
425 request_queue2.tailp = &request_queue2.head;
55f0e6f7 426 }
40173038 427 } else {
428 /* Oops, the request queue is blocked, use request_queue2 */
429 *request_queue2.tailp = request;
430 request_queue2.tailp = &request->next;
55f0e6f7 431 }
432 if (request_queue2.head) {
433 static int filter = 0;
434 static int filter_limit = 8;
435 if (++filter >= filter_limit) {
436 filter_limit += filter;
437 filter = 0;
c04d4f40 438 debug(43, 1) ("squidaio_queue_request: WARNING - Queue congestion\n");
55f0e6f7 439 }
cd748f27 440 }
cd748f27 441 /* Warn if out of threads */
55f0e6f7 442 if (request_queue_len > MAGIC1) {
443 static int last_warn = 0;
444 static int queue_high, queue_low;
cd748f27 445 if (high_start == 0) {
446 high_start = squid_curtime;
447 queue_high = request_queue_len;
448 queue_low = request_queue_len;
449 }
450 if (request_queue_len > queue_high)
451 queue_high = request_queue_len;
452 if (request_queue_len < queue_low)
453 queue_low = request_queue_len;
454 if (squid_curtime >= (last_warn + 15) &&
55f0e6f7 455 squid_curtime >= (high_start + 5)) {
c04d4f40 456 debug(43, 1) ("squidaio_queue_request: WARNING - Disk I/O overloading\n");
55f0e6f7 457 if (squid_curtime >= (high_start + 15))
33272404 458 debug(43, 1) ("squidaio_queue_request: Queue Length: current=%d, high=%d, low=%d, duration=%ld\n",
459 request_queue_len, queue_high, queue_low, (long int) (squid_curtime - high_start));
cd748f27 460 last_warn = squid_curtime;
461 }
462 } else {
463 high_start = 0;
464 }
55f0e6f7 465 /* Warn if seriously overloaded */
cd748f27 466 if (request_queue_len > RIDICULOUS_LENGTH) {
c04d4f40 467 debug(43, 0) ("squidaio_queue_request: Async request queue growing uncontrollably!\n");
468 debug(43, 0) ("squidaio_queue_request: Syncing pending I/O operations.. (blocking)\n");
469 squidaio_sync();
470 debug(43, 0) ("squidaio_queue_request: Synced\n");
cd748f27 471 }
c04d4f40 472} /* squidaio_queue_request */
cd748f27 473
cd748f27 474static void
c04d4f40 475squidaio_cleanup_request(squidaio_request_t * requestp)
cd748f27 476{
c04d4f40 477 squidaio_result_t *resultp = requestp->resultp;
cd748f27 478 int cancelled = requestp->cancelled;
479
480 /* Free allocated structures and copy data back to user space if the */
481 /* request hasn't been cancelled */
482 switch (requestp->request_type) {
483 case _AIO_OP_STAT:
484 if (!cancelled && requestp->ret == 0)
485 xmemcpy(requestp->statp, requestp->tmpstatp, sizeof(struct stat));
c04d4f40 486 squidaio_xfree(requestp->tmpstatp, sizeof(struct stat));
487 squidaio_xstrfree(requestp->path);
55f0e6f7 488 break;
cd748f27 489 case _AIO_OP_OPEN:
490 if (cancelled && requestp->ret >= 0)
491 /* The open() was cancelled but completed */
492 close(requestp->ret);
c04d4f40 493 squidaio_xstrfree(requestp->path);
cd748f27 494 break;
495 case _AIO_OP_CLOSE:
496 if (cancelled && requestp->ret < 0)
497 /* The close() was cancelled and never got executed */
498 close(requestp->fd);
499 break;
500 case _AIO_OP_UNLINK:
15a47d1d 501 case _AIO_OP_TRUNCATE:
cd748f27 502 case _AIO_OP_OPENDIR:
c04d4f40 503 squidaio_xstrfree(requestp->path);
cd748f27 504 break;
505 case _AIO_OP_READ:
506 if (!cancelled && requestp->ret > 0)
507 xmemcpy(requestp->bufferp, requestp->tmpbufp, requestp->ret);
c04d4f40 508 squidaio_xfree(requestp->tmpbufp, requestp->buflen);
55f0e6f7 509 break;
cd748f27 510 case _AIO_OP_WRITE:
c04d4f40 511 squidaio_xfree(requestp->tmpbufp, requestp->buflen);
cd748f27 512 break;
513 default:
514 break;
515 }
516 if (resultp != NULL && !cancelled) {
517 resultp->aio_return = requestp->ret;
518 resultp->aio_errno = requestp->err;
519 }
c04d4f40 520 memPoolFree(squidaio_request_pool, requestp);
521} /* squidaio_cleanup_request */
cd748f27 522
523
524int
c04d4f40 525squidaio_cancel(squidaio_result_t * resultp)
cd748f27 526{
e6ccf245 527 squidaio_request_t *request = (squidaio_request_t *)resultp->_data;
cd748f27 528
55f0e6f7 529 if (request && request->resultp == resultp) {
99cce4cb 530 debug(43, 9) ("squidaio_cancel: %p type=%d result=%p\n",
f0debecb 531 request, request->request_type, request->resultp);
55f0e6f7 532 request->cancelled = 1;
533 request->resultp = NULL;
534 resultp->_data = NULL;
12e137b0 535 resultp->result_type = _AIO_OP_NONE;
55f0e6f7 536 return 0;
537 }
cd748f27 538 return 1;
c04d4f40 539} /* squidaio_cancel */
cd748f27 540
541
542int
c04d4f40 543squidaio_open(const char *path, int oflag, mode_t mode, squidaio_result_t * resultp)
cd748f27 544{
c04d4f40 545 squidaio_request_t *requestp;
cd748f27 546
c04d4f40 547 if (!squidaio_initialised)
548 squidaio_init();
e6ccf245 549 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
c04d4f40 550 requestp->path = (char *) squidaio_xstrdup(path);
cd748f27 551 requestp->oflag = oflag;
552 requestp->mode = mode;
553 requestp->resultp = resultp;
554 requestp->request_type = _AIO_OP_OPEN;
555 requestp->cancelled = 0;
12e137b0 556 resultp->result_type = _AIO_OP_OPEN;
cd748f27 557
c04d4f40 558 squidaio_queue_request(requestp);
cd748f27 559 return 0;
560}
561
562
563static void
c04d4f40 564squidaio_do_open(squidaio_request_t * requestp)
cd748f27 565{
566 requestp->ret = open(requestp->path, requestp->oflag, requestp->mode);
567 requestp->err = errno;
568}
569
570
571int
c04d4f40 572squidaio_read(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp)
cd748f27 573{
c04d4f40 574 squidaio_request_t *requestp;
cd748f27 575
c04d4f40 576 if (!squidaio_initialised)
577 squidaio_init();
e6ccf245 578 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
cd748f27 579 requestp->fd = fd;
580 requestp->bufferp = bufp;
c04d4f40 581 requestp->tmpbufp = (char *) squidaio_xmalloc(bufs);
cd748f27 582 requestp->buflen = bufs;
583 requestp->offset = offset;
584 requestp->whence = whence;
585 requestp->resultp = resultp;
586 requestp->request_type = _AIO_OP_READ;
587 requestp->cancelled = 0;
12e137b0 588 resultp->result_type = _AIO_OP_READ;
cd748f27 589
c04d4f40 590 squidaio_queue_request(requestp);
cd748f27 591 return 0;
592}
593
594
595static void
c04d4f40 596squidaio_do_read(squidaio_request_t * requestp)
cd748f27 597{
598 lseek(requestp->fd, requestp->offset, requestp->whence);
599 requestp->ret = read(requestp->fd, requestp->tmpbufp, requestp->buflen);
600 requestp->err = errno;
601}
602
603
604int
c04d4f40 605squidaio_write(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp)
cd748f27 606{
c04d4f40 607 squidaio_request_t *requestp;
cd748f27 608
c04d4f40 609 if (!squidaio_initialised)
610 squidaio_init();
e6ccf245 611 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
cd748f27 612 requestp->fd = fd;
c04d4f40 613 requestp->tmpbufp = (char *) squidaio_xmalloc(bufs);
cd748f27 614 xmemcpy(requestp->tmpbufp, bufp, bufs);
615 requestp->buflen = bufs;
616 requestp->offset = offset;
617 requestp->whence = whence;
618 requestp->resultp = resultp;
619 requestp->request_type = _AIO_OP_WRITE;
620 requestp->cancelled = 0;
12e137b0 621 resultp->result_type = _AIO_OP_WRITE;
cd748f27 622
c04d4f40 623 squidaio_queue_request(requestp);
cd748f27 624 return 0;
625}
626
627
628static void
c04d4f40 629squidaio_do_write(squidaio_request_t * requestp)
cd748f27 630{
631 requestp->ret = write(requestp->fd, requestp->tmpbufp, requestp->buflen);
632 requestp->err = errno;
633}
634
635
636int
c04d4f40 637squidaio_close(int fd, squidaio_result_t * resultp)
cd748f27 638{
c04d4f40 639 squidaio_request_t *requestp;
cd748f27 640
c04d4f40 641 if (!squidaio_initialised)
642 squidaio_init();
e6ccf245 643 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
cd748f27 644 requestp->fd = fd;
645 requestp->resultp = resultp;
646 requestp->request_type = _AIO_OP_CLOSE;
647 requestp->cancelled = 0;
12e137b0 648 resultp->result_type = _AIO_OP_CLOSE;
cd748f27 649
c04d4f40 650 squidaio_queue_request(requestp);
cd748f27 651 return 0;
652}
653
654
655static void
c04d4f40 656squidaio_do_close(squidaio_request_t * requestp)
cd748f27 657{
658 requestp->ret = close(requestp->fd);
659 requestp->err = errno;
660}
661
662
663int
c04d4f40 664squidaio_stat(const char *path, struct stat *sb, squidaio_result_t * resultp)
cd748f27 665{
c04d4f40 666 squidaio_request_t *requestp;
cd748f27 667
c04d4f40 668 if (!squidaio_initialised)
669 squidaio_init();
e6ccf245 670 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
c04d4f40 671 requestp->path = (char *) squidaio_xstrdup(path);
cd748f27 672 requestp->statp = sb;
c04d4f40 673 requestp->tmpstatp = (struct stat *) squidaio_xmalloc(sizeof(struct stat));
cd748f27 674 requestp->resultp = resultp;
675 requestp->request_type = _AIO_OP_STAT;
676 requestp->cancelled = 0;
12e137b0 677 resultp->result_type = _AIO_OP_STAT;
cd748f27 678
c04d4f40 679 squidaio_queue_request(requestp);
cd748f27 680 return 0;
681}
682
683
684static void
c04d4f40 685squidaio_do_stat(squidaio_request_t * requestp)
cd748f27 686{
687 requestp->ret = stat(requestp->path, requestp->tmpstatp);
688 requestp->err = errno;
689}
690
691
692int
c04d4f40 693squidaio_unlink(const char *path, squidaio_result_t * resultp)
cd748f27 694{
c04d4f40 695 squidaio_request_t *requestp;
cd748f27 696
c04d4f40 697 if (!squidaio_initialised)
698 squidaio_init();
e6ccf245 699 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
c04d4f40 700 requestp->path = squidaio_xstrdup(path);
cd748f27 701 requestp->resultp = resultp;
702 requestp->request_type = _AIO_OP_UNLINK;
703 requestp->cancelled = 0;
12e137b0 704 resultp->result_type = _AIO_OP_UNLINK;
cd748f27 705
c04d4f40 706 squidaio_queue_request(requestp);
cd748f27 707 return 0;
708}
709
710
711static void
c04d4f40 712squidaio_do_unlink(squidaio_request_t * requestp)
cd748f27 713{
714 requestp->ret = unlink(requestp->path);
715 requestp->err = errno;
716}
717
15a47d1d 718int
c04d4f40 719squidaio_truncate(const char *path, off_t length, squidaio_result_t * resultp)
15a47d1d 720{
c04d4f40 721 squidaio_request_t *requestp;
15a47d1d 722
c04d4f40 723 if (!squidaio_initialised)
724 squidaio_init();
e6ccf245 725 requestp = (squidaio_request_t *)memPoolAlloc(squidaio_request_pool);
c04d4f40 726 requestp->path = (char *) squidaio_xstrdup(path);
15a47d1d 727 requestp->offset = length;
15a47d1d 728 requestp->resultp = resultp;
729 requestp->request_type = _AIO_OP_TRUNCATE;
730 requestp->cancelled = 0;
12e137b0 731 resultp->result_type = _AIO_OP_TRUNCATE;
15a47d1d 732
c04d4f40 733 squidaio_queue_request(requestp);
15a47d1d 734 return 0;
735}
736
737
738static void
c04d4f40 739squidaio_do_truncate(squidaio_request_t * requestp)
15a47d1d 740{
741 requestp->ret = truncate(requestp->path, requestp->offset);
742 requestp->err = errno;
743}
744
cd748f27 745
746#if AIO_OPENDIR
c04d4f40 747/* XXX squidaio_opendir NOT implemented yet.. */
cd748f27 748
749int
c04d4f40 750squidaio_opendir(const char *path, squidaio_result_t * resultp)
cd748f27 751{
c04d4f40 752 squidaio_request_t *requestp;
cd748f27 753 int len;
754
c04d4f40 755 if (!squidaio_initialised)
756 squidaio_init();
757 requestp = memPoolAlloc(squidaio_request_pool);
12e137b0 758 resultp->result_type = _AIO_OP_OPENDIR;
cd748f27 759 return -1;
760}
761
762static void
c04d4f40 763squidaio_do_opendir(squidaio_request_t * requestp)
cd748f27 764{
765 /* NOT IMPLEMENTED */
766}
767
768#endif
769
55f0e6f7 770static void
c04d4f40 771squidaio_poll_queues(void)
55f0e6f7 772{
773 /* kick "overflow" request queue */
774 if (request_queue2.head &&
4672d0cd 775 pthread_mutex_trylock(&request_queue.mutex) == 0) {
55f0e6f7 776 *request_queue.tailp = request_queue2.head;
777 request_queue.tailp = request_queue2.tailp;
778 pthread_cond_signal(&request_queue.cond);
779 pthread_mutex_unlock(&request_queue.mutex);
780 request_queue2.head = NULL;
781 request_queue2.tailp = &request_queue2.head;
782 }
783 /* poll done queue */
784 if (done_queue.head && pthread_mutex_trylock(&done_queue.mutex) == 0) {
c04d4f40 785 struct squidaio_request_t *requests = done_queue.head;
55f0e6f7 786 done_queue.head = NULL;
787 done_queue.tailp = &done_queue.head;
788 pthread_mutex_unlock(&done_queue.mutex);
789 *done_requests.tailp = requests;
790 request_queue_len -= 1;
4672d0cd 791 while (requests->next) {
55f0e6f7 792 requests = requests->next;
793 request_queue_len -= 1;
cd748f27 794 }
55f0e6f7 795 done_requests.tailp = &requests->next;
796 }
5e5c622b 797#if HAVE_SCHED_H
55f0e6f7 798 /* Give up the CPU to allow the threads to do their work */
4672d0cd 799 /*
800 * For Andres thoughts about yield(), see
801 * http://www.squid-cache.org/mail-archive/squid-dev/200012/0001.html
802 */
55f0e6f7 803 if (done_queue.head || request_queue.head)
4672d0cd 804#ifndef _SQUID_SOLARIS_
55f0e6f7 805 sched_yield();
4672d0cd 806#else
807 yield();
808#endif
5e5c622b 809#endif
55f0e6f7 810}
cd748f27 811
c04d4f40 812squidaio_result_t *
813squidaio_poll_done(void)
cd748f27 814{
c04d4f40 815 squidaio_request_t *request;
816 squidaio_result_t *resultp;
cd748f27 817 int cancelled;
55f0e6f7 818 int polled = 0;
cd748f27 819
820 AIO_REPOLL:
55f0e6f7 821 request = done_requests.head;
822 if (request == NULL && !polled) {
c04d4f40 823 squidaio_poll_queues();
55f0e6f7 824 polled = 1;
825 request = done_requests.head;
826 }
827 if (!request) {
cd748f27 828 return NULL;
829 }
99cce4cb 830 debug(43, 9) ("squidaio_poll_done: %p type=%d result=%p\n",
f0debecb 831 request, request->request_type, request->resultp);
55f0e6f7 832 done_requests.head = request->next;
833 if (!done_requests.head)
834 done_requests.tailp = &done_requests.head;
835 resultp = request->resultp;
836 cancelled = request->cancelled;
c04d4f40 837 squidaio_debug(request);
55f0e6f7 838 debug(43, 5) ("DONE: %d -> %d\n", request->ret, request->err);
c04d4f40 839 squidaio_cleanup_request(request);
cd748f27 840 if (cancelled)
841 goto AIO_REPOLL;
842 return resultp;
c04d4f40 843} /* squidaio_poll_done */
cd748f27 844
845int
c04d4f40 846squidaio_operations_pending(void)
cd748f27 847{
55f0e6f7 848 return request_queue_len + (done_requests.head ? 1 : 0);
cd748f27 849}
850
851int
c04d4f40 852squidaio_sync(void)
cd748f27 853{
55f0e6f7 854 /* XXX This might take a while if the queue is large.. */
cd748f27 855 do {
c04d4f40 856 squidaio_poll_queues();
cd748f27 857 } while (request_queue_len > 0);
c04d4f40 858 return squidaio_operations_pending();
cd748f27 859}
860
861int
c04d4f40 862squidaio_get_queue_len(void)
cd748f27 863{
864 return request_queue_len;
865}
866
867static void
c04d4f40 868squidaio_debug(squidaio_request_t * request)
cd748f27 869{
55f0e6f7 870 switch (request->request_type) {
cd748f27 871 case _AIO_OP_OPEN:
55f0e6f7 872 debug(43, 5) ("OPEN of %s to FD %d\n", request->path, request->ret);
cd748f27 873 break;
874 case _AIO_OP_READ:
55f0e6f7 875 debug(43, 5) ("READ on fd: %d\n", request->fd);
cd748f27 876 break;
877 case _AIO_OP_WRITE:
55f0e6f7 878 debug(43, 5) ("WRITE on fd: %d\n", request->fd);
cd748f27 879 break;
880 case _AIO_OP_CLOSE:
55f0e6f7 881 debug(43, 5) ("CLOSE of fd: %d\n", request->fd);
cd748f27 882 break;
883 case _AIO_OP_UNLINK:
55f0e6f7 884 debug(43, 5) ("UNLINK of %s\n", request->path);
cd748f27 885 break;
15a47d1d 886 case _AIO_OP_TRUNCATE:
55f0e6f7 887 debug(43, 5) ("UNLINK of %s\n", request->path);
15a47d1d 888 break;
cd748f27 889 default:
890 break;
891 }
892}