]> git.ipfire.org Git - thirdparty/squid.git/blame - src/DiskIO/DiskThreads/aiops.cc
Adding a comment that tests/testUfs will fail when 'heap' is the only
[thirdparty/squid.git] / src / DiskIO / DiskThreads / aiops.cc
CommitLineData
cd748f27 1/*
b3fb9070 2 * $Id: aiops.cc,v 1.13 2007/04/12 23:51:57 wessels 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
e4116bdb 35#ifndef _REENTRANT
36#error "_REENTRANT MUST be defined to build squid async io support."
37#endif
38
cd748f27 39#include "squid.h"
b9ae18aa 40#include "DiskThreads.h"
cd748f27 41
42#include <stdio.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <pthread.h>
47#include <errno.h>
48#include <dirent.h>
49#include <signal.h>
50#if HAVE_SCHED_H
51#include <sched.h>
52#endif
56410c89 53#include "CommIO.h"
985c86bc 54#include "SquidTime.h"
a553a5a3 55#include "Store.h"
cd748f27 56
57#define RIDICULOUS_LENGTH 4096
58
c04d4f40 59enum _squidaio_thread_status {
cd748f27 60 _THREAD_STARTING = 0,
61 _THREAD_WAITING,
62 _THREAD_BUSY,
63 _THREAD_FAILED,
64 _THREAD_DONE
65};
c04d4f40 66typedef enum _squidaio_thread_status squidaio_thread_status;
cd748f27 67
62e76326 68typedef struct squidaio_request_t
69{
70
c04d4f40 71 struct squidaio_request_t *next;
72 squidaio_request_type request_type;
cd748f27 73 int cancelled;
74 char *path;
75 int oflag;
76 mode_t mode;
77 int fd;
78 char *bufferp;
cd748f27 79 int buflen;
80 off_t offset;
81 int whence;
82 int ret;
83 int err;
62e76326 84
cd748f27 85 struct stat *tmpstatp;
62e76326 86
cd748f27 87 struct stat *statp;
c04d4f40 88 squidaio_result_t *resultp;
62e76326 89}
90
91squidaio_request_t;
cd748f27 92
62e76326 93typedef struct squidaio_request_queue_t
94{
55f0e6f7 95 pthread_mutex_t mutex;
96 pthread_cond_t cond;
c04d4f40 97 squidaio_request_t *volatile head;
98 squidaio_request_t *volatile *volatile tailp;
55f0e6f7 99 unsigned long requests;
f0debecb 100 unsigned long blocked; /* main failed to lock the queue */
62e76326 101}
102
103squidaio_request_queue_t;
55f0e6f7 104
c04d4f40 105typedef struct squidaio_thread_t squidaio_thread_t;
62e76326 106
107struct squidaio_thread_t
108{
c04d4f40 109 squidaio_thread_t *next;
cd748f27 110 pthread_t thread;
c04d4f40 111 squidaio_thread_status status;
62e76326 112
c04d4f40 113 struct squidaio_request_t *current_req;
55f0e6f7 114 unsigned long requests;
115};
cd748f27 116
c04d4f40 117static void squidaio_queue_request(squidaio_request_t *);
118static void squidaio_cleanup_request(squidaio_request_t *);
119static void *squidaio_thread_loop(void *);
120static void squidaio_do_open(squidaio_request_t *);
121static void squidaio_do_read(squidaio_request_t *);
122static void squidaio_do_write(squidaio_request_t *);
123static void squidaio_do_close(squidaio_request_t *);
124static void squidaio_do_stat(squidaio_request_t *);
efa3acd1 125static void squidaio_do_unlink(squidaio_request_t *);
cd748f27 126#if AIO_OPENDIR
c04d4f40 127static void *squidaio_do_opendir(squidaio_request_t *);
cd748f27 128#endif
c04d4f40 129static void squidaio_debug(squidaio_request_t *);
130static void squidaio_poll_queues(void);
cd748f27 131
c04d4f40 132static squidaio_thread_t *threads = NULL;
133static int squidaio_initialised = 0;
cd748f27 134
55f0e6f7 135
58cd5bbd 136#define AIO_LARGE_BUFS 16384
137#define AIO_MEDIUM_BUFS AIO_LARGE_BUFS >> 1
138#define AIO_SMALL_BUFS AIO_LARGE_BUFS >> 2
139#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3
55f0e6f7 140#define AIO_MICRO_BUFS 128
58cd5bbd 141
a3efa961 142static MemAllocator *squidaio_large_bufs = NULL; /* 16K */
143static MemAllocator *squidaio_medium_bufs = NULL; /* 8K */
144static MemAllocator *squidaio_small_bufs = NULL; /* 4K */
145static MemAllocator *squidaio_tiny_bufs = NULL; /* 2K */
146static MemAllocator *squidaio_micro_bufs = NULL; /* 128K */
58cd5bbd 147
cd748f27 148static int request_queue_len = 0;
a3efa961 149static MemAllocator *squidaio_request_pool = NULL;
150static MemAllocator *squidaio_thread_pool = NULL;
c04d4f40 151static squidaio_request_queue_t request_queue;
62e76326 152
153static struct
154{
c04d4f40 155 squidaio_request_t *head, **tailp;
62e76326 156}
f0debecb 157
62e76326 158request_queue2 = {
159
160 NULL, &request_queue2.head
161 };
c04d4f40 162static squidaio_request_queue_t done_queue;
62e76326 163
164static struct
165{
c04d4f40 166 squidaio_request_t *head, **tailp;
62e76326 167}
f0debecb 168
62e76326 169done_requests = {
170
171 NULL, &done_requests.head
172 };
cd748f27 173static pthread_attr_t globattr;
5e5c622b 174#if HAVE_SCHED_H
62e76326 175
cd748f27 176static struct sched_param globsched;
5e5c622b 177#endif
cd748f27 178static pthread_t main_thread;
179
a3efa961 180static MemAllocator *
c04d4f40 181squidaio_get_pool(int size)
58cd5bbd 182{
58cd5bbd 183 if (size <= AIO_LARGE_BUFS) {
62e76326 184 if (size <= AIO_MICRO_BUFS)
a3efa961 185 return squidaio_micro_bufs;
62e76326 186 else if (size <= AIO_TINY_BUFS)
a3efa961 187 return squidaio_tiny_bufs;
62e76326 188 else if (size <= AIO_SMALL_BUFS)
a3efa961 189 return squidaio_small_bufs;
62e76326 190 else if (size <= AIO_MEDIUM_BUFS)
a3efa961 191 return squidaio_medium_bufs;
62e76326 192 else
a3efa961 193 return squidaio_large_bufs;
194 }
62e76326 195
a3efa961 196 return NULL;
58cd5bbd 197}
198
211f1d0b 199void *
c04d4f40 200squidaio_xmalloc(int size)
58cd5bbd 201{
202 void *p;
a3efa961 203 MemAllocator *pool;
58cd5bbd 204
c04d4f40 205 if ((pool = squidaio_get_pool(size)) != NULL) {
b001e822 206 p = pool->alloc();
58cd5bbd 207 } else
62e76326 208 p = xmalloc(size);
58cd5bbd 209
210 return p;
211}
212
55f0e6f7 213static char *
c04d4f40 214squidaio_xstrdup(const char *str)
55f0e6f7 215{
216 char *p;
f0debecb 217 int len = strlen(str) + 1;
55f0e6f7 218
e6ccf245 219 p = (char *)squidaio_xmalloc(len);
55f0e6f7 220 strncpy(p, str, len);
221
222 return p;
223}
224
211f1d0b 225void
c04d4f40 226squidaio_xfree(void *p, int size)
58cd5bbd 227{
a3efa961 228 MemAllocator *pool;
58cd5bbd 229
c04d4f40 230 if ((pool = squidaio_get_pool(size)) != NULL) {
b001e822 231 pool->free(p);
58cd5bbd 232 } else
62e76326 233 xfree(p);
58cd5bbd 234}
235
55f0e6f7 236static void
c04d4f40 237squidaio_xstrfree(char *str)
55f0e6f7 238{
a3efa961 239 MemAllocator *pool;
f0debecb 240 int len = strlen(str) + 1;
55f0e6f7 241
c04d4f40 242 if ((pool = squidaio_get_pool(len)) != NULL) {
b001e822 243 pool->free(str);
55f0e6f7 244 } else
62e76326 245 xfree(str);
55f0e6f7 246}
247
d06925a4 248void
c04d4f40 249squidaio_init(void)
cd748f27 250{
251 int i;
c04d4f40 252 squidaio_thread_t *threadp;
cd748f27 253
c04d4f40 254 if (squidaio_initialised)
62e76326 255 return;
cd748f27 256
257 pthread_attr_init(&globattr);
62e76326 258
cd748f27 259#if HAVE_PTHREAD_ATTR_SETSCOPE
62e76326 260
cd748f27 261 pthread_attr_setscope(&globattr, PTHREAD_SCOPE_SYSTEM);
62e76326 262
cd748f27 263#endif
5e5c622b 264#if HAVE_SCHED_H
62e76326 265
cd748f27 266 globsched.sched_priority = 1;
62e76326 267
5e5c622b 268#endif
62e76326 269
cd748f27 270 main_thread = pthread_self();
62e76326 271
5e5c622b 272#if HAVE_SCHED_H && HAVE_PTHREAD_SETSCHEDPARAM
62e76326 273
cd748f27 274 pthread_setschedparam(main_thread, SCHED_OTHER, &globsched);
62e76326 275
cd748f27 276#endif
5e5c622b 277#if HAVE_SCHED_H
62e76326 278
cd748f27 279 globsched.sched_priority = 2;
62e76326 280
5e5c622b 281#endif
282#if HAVE_SCHED_H && HAVE_PTHREAD_ATTR_SETSCHEDPARAM
62e76326 283
cd748f27 284 pthread_attr_setschedparam(&globattr, &globsched);
62e76326 285
cd748f27 286#endif
287
5a3501d2 288 /* Give each thread a smaller 256KB stack, should be more than sufficient */
289 pthread_attr_setstacksize(&globattr, 256 * 1024);
290
55f0e6f7 291 /* Initialize request queue */
292 if (pthread_mutex_init(&(request_queue.mutex), NULL))
62e76326 293 fatal("Failed to create mutex");
294
55f0e6f7 295 if (pthread_cond_init(&(request_queue.cond), NULL))
62e76326 296 fatal("Failed to create condition variable");
297
55f0e6f7 298 request_queue.head = NULL;
62e76326 299
55f0e6f7 300 request_queue.tailp = &request_queue.head;
62e76326 301
55f0e6f7 302 request_queue.requests = 0;
62e76326 303
55f0e6f7 304 request_queue.blocked = 0;
305
306 /* Initialize done queue */
307 if (pthread_mutex_init(&(done_queue.mutex), NULL))
62e76326 308 fatal("Failed to create mutex");
309
55f0e6f7 310 if (pthread_cond_init(&(done_queue.cond), NULL))
62e76326 311 fatal("Failed to create condition variable");
312
55f0e6f7 313 done_queue.head = NULL;
62e76326 314
55f0e6f7 315 done_queue.tailp = &done_queue.head;
62e76326 316
55f0e6f7 317 done_queue.requests = 0;
62e76326 318
55f0e6f7 319 done_queue.blocked = 0;
cd748f27 320
55f0e6f7 321 /* Create threads and get them to sit in their wait loop */
04eb0689 322 squidaio_thread_pool = memPoolCreate("aio_thread", sizeof(squidaio_thread_t));
62e76326 323
9fbbe256 324 assert(NUMTHREADS);
62e76326 325
cd748f27 326 for (i = 0; i < NUMTHREADS; i++) {
b001e822 327 threadp = (squidaio_thread_t *)squidaio_thread_pool->alloc();
62e76326 328 threadp->status = _THREAD_STARTING;
329 threadp->current_req = NULL;
330 threadp->requests = 0;
331 threadp->next = threads;
332 threads = threadp;
333
334 if (pthread_create(&threadp->thread, &globattr, squidaio_thread_loop, threadp)) {
335 fprintf(stderr, "Thread creation failed\n");
336 threadp->status = _THREAD_FAILED;
337 continue;
338 }
cd748f27 339 }
340
341 /* Create request pool */
04eb0689 342 squidaio_request_pool = memPoolCreate("aio_request", sizeof(squidaio_request_t));
62e76326 343
04eb0689 344 squidaio_large_bufs = memPoolCreate("squidaio_large_bufs", AIO_LARGE_BUFS);
62e76326 345
04eb0689 346 squidaio_medium_bufs = memPoolCreate("squidaio_medium_bufs", AIO_MEDIUM_BUFS);
62e76326 347
04eb0689 348 squidaio_small_bufs = memPoolCreate("squidaio_small_bufs", AIO_SMALL_BUFS);
62e76326 349
04eb0689 350 squidaio_tiny_bufs = memPoolCreate("squidaio_tiny_bufs", AIO_TINY_BUFS);
62e76326 351
04eb0689 352 squidaio_micro_bufs = memPoolCreate("squidaio_micro_bufs", AIO_MICRO_BUFS);
c04d4f40 353
354 squidaio_initialised = 1;
cd748f27 355}
356
d06925a4 357void
358squidaio_shutdown(void)
359{
360 if (!squidaio_initialised)
361 return;
362
363 /* This is the same as in squidaio_sync */
364 do {
365 squidaio_poll_queues();
366 } while (request_queue_len > 0);
367
368 CommIO::NotifyIOClose();
369
370 squidaio_initialised = 0;
371}
cd748f27 372
373static void *
c04d4f40 374squidaio_thread_loop(void *ptr)
cd748f27 375{
e6ccf245 376 squidaio_thread_t *threadp = (squidaio_thread_t *)ptr;
c04d4f40 377 squidaio_request_t *request;
e6ccf245 378 sigset_t newSig;
cd748f27 379
380 /*
381 * Make sure to ignore signals which may possibly get sent to
382 * the parent squid thread. Causes havoc with mutex's and
383 * condition waits otherwise
384 */
385
e6ccf245 386 sigemptyset(&newSig);
387 sigaddset(&newSig, SIGPIPE);
388 sigaddset(&newSig, SIGCHLD);
cd748f27 389#ifdef _SQUID_LINUX_THREADS_
62e76326 390
e6ccf245 391 sigaddset(&newSig, SIGQUIT);
392 sigaddset(&newSig, SIGTRAP);
cd748f27 393#else
62e76326 394
e6ccf245 395 sigaddset(&newSig, SIGUSR1);
396 sigaddset(&newSig, SIGUSR2);
cd748f27 397#endif
62e76326 398
e6ccf245 399 sigaddset(&newSig, SIGHUP);
400 sigaddset(&newSig, SIGTERM);
401 sigaddset(&newSig, SIGINT);
402 sigaddset(&newSig, SIGALRM);
403 pthread_sigmask(SIG_BLOCK, &newSig, NULL);
cd748f27 404
cd748f27 405 while (1) {
62e76326 406 threadp->current_req = request = NULL;
407 request = NULL;
408 /* Get a request to process */
409 threadp->status = _THREAD_WAITING;
410 pthread_mutex_lock(&request_queue.mutex);
411
412 while (!request_queue.head) {
413 pthread_cond_wait(&request_queue.cond, &request_queue.mutex);
414 }
415
416 request = request_queue.head;
417
418 if (request)
419 request_queue.head = request->next;
420
421 if (!request_queue.head)
422 request_queue.tailp = &request_queue.head;
423
424 pthread_mutex_unlock(&request_queue.mutex);
425
426 /* process the request */
427 threadp->status = _THREAD_BUSY;
428
429 request->next = NULL;
430
431 threadp->current_req = request;
432
433 errno = 0;
434
435 if (!request->cancelled) {
436 switch (request->request_type) {
437
438 case _AIO_OP_OPEN:
439 squidaio_do_open(request);
440 break;
441
442 case _AIO_OP_READ:
443 squidaio_do_read(request);
444 break;
445
446 case _AIO_OP_WRITE:
447 squidaio_do_write(request);
448 break;
449
450 case _AIO_OP_CLOSE:
451 squidaio_do_close(request);
452 break;
453
efa3acd1 454 case _AIO_OP_UNLINK:
455 squidaio_do_unlink(request);
456 break;
457
cd748f27 458#if AIO_OPENDIR /* Opendir not implemented yet */
62e76326 459
460 case _AIO_OP_OPENDIR:
461 squidaio_do_opendir(request);
462 break;
cd748f27 463#endif
62e76326 464
465 case _AIO_OP_STAT:
466 squidaio_do_stat(request);
467 break;
468
469 default:
470 request->ret = -1;
471 request->err = EINVAL;
472 break;
473 }
474 } else { /* cancelled */
475 request->ret = -1;
476 request->err = EINTR;
477 }
478
479 threadp->status = _THREAD_DONE;
480 /* put the request in the done queue */
481 pthread_mutex_lock(&done_queue.mutex);
482 *done_queue.tailp = request;
483 done_queue.tailp = &request->next;
484 pthread_mutex_unlock(&done_queue.mutex);
485 CommIO::NotifyIOCompleted();
486 threadp->requests++;
55f0e6f7 487 } /* while forever */
62e76326 488
cd748f27 489 return NULL;
c04d4f40 490} /* squidaio_thread_loop */
cd748f27 491
492static void
c04d4f40 493squidaio_queue_request(squidaio_request_t * request)
cd748f27 494{
cd748f27 495 static int high_start = 0;
99cce4cb 496 debug(43, 9) ("squidaio_queue_request: %p type=%d result=%p\n",
62e76326 497 request, request->request_type, request->resultp);
cd748f27 498 /* Mark it as not executed (failing result, no error) */
55f0e6f7 499 request->ret = -1;
500 request->err = 0;
501 /* Internal housekeeping */
502 request_queue_len += 1;
503 request->resultp->_data = request;
504 /* Play some tricks with the request_queue2 queue */
505 request->next = NULL;
62e76326 506
40173038 507 if (pthread_mutex_trylock(&request_queue.mutex) == 0) {
62e76326 508 if (request_queue2.head) {
509 /* Grab blocked requests */
510 *request_queue.tailp = request_queue2.head;
511 request_queue.tailp = request_queue2.tailp;
512 }
513
514 /* Enqueue request */
515 *request_queue.tailp = request;
516
517 request_queue.tailp = &request->next;
518
519 pthread_cond_signal(&request_queue.cond);
520
521 pthread_mutex_unlock(&request_queue.mutex);
522
523 if (request_queue2.head) {
524 /* Clear queue of blocked requests */
525 request_queue2.head = NULL;
526 request_queue2.tailp = &request_queue2.head;
527 }
40173038 528 } else {
62e76326 529 /* Oops, the request queue is blocked, use request_queue2 */
530 *request_queue2.tailp = request;
531 request_queue2.tailp = &request->next;
55f0e6f7 532 }
62e76326 533
55f0e6f7 534 if (request_queue2.head) {
62e76326 535 static int filter = 0;
536 static int filter_limit = 8;
537
538 if (++filter >= filter_limit) {
539 filter_limit += filter;
540 filter = 0;
541 debug(43, 1) ("squidaio_queue_request: WARNING - Queue congestion\n");
542 }
cd748f27 543 }
62e76326 544
cd748f27 545 /* Warn if out of threads */
55f0e6f7 546 if (request_queue_len > MAGIC1) {
62e76326 547 static int last_warn = 0;
548 static int queue_high, queue_low;
549
550 if (high_start == 0) {
551 high_start = squid_curtime;
552 queue_high = request_queue_len;
553 queue_low = request_queue_len;
554 }
555
556 if (request_queue_len > queue_high)
557 queue_high = request_queue_len;
558
559 if (request_queue_len < queue_low)
560 queue_low = request_queue_len;
561
562 if (squid_curtime >= (last_warn + 15) &&
563 squid_curtime >= (high_start + 5)) {
564 debug(43, 1) ("squidaio_queue_request: WARNING - Disk I/O overloading\n");
565
566 if (squid_curtime >= (high_start + 15))
567 debug(43, 1) ("squidaio_queue_request: Queue Length: current=%d, high=%d, low=%d, duration=%ld\n",
568 request_queue_len, queue_high, queue_low, (long int) (squid_curtime - high_start));
569
570 last_warn = squid_curtime;
571 }
cd748f27 572 } else {
62e76326 573 high_start = 0;
cd748f27 574 }
62e76326 575
55f0e6f7 576 /* Warn if seriously overloaded */
cd748f27 577 if (request_queue_len > RIDICULOUS_LENGTH) {
62e76326 578 debug(43, 0) ("squidaio_queue_request: Async request queue growing uncontrollably!\n");
579 debug(43, 0) ("squidaio_queue_request: Syncing pending I/O operations.. (blocking)\n");
580 squidaio_sync();
581 debug(43, 0) ("squidaio_queue_request: Synced\n");
cd748f27 582 }
c04d4f40 583} /* squidaio_queue_request */
cd748f27 584
cd748f27 585static void
c04d4f40 586squidaio_cleanup_request(squidaio_request_t * requestp)
cd748f27 587{
c04d4f40 588 squidaio_result_t *resultp = requestp->resultp;
cd748f27 589 int cancelled = requestp->cancelled;
590
591 /* Free allocated structures and copy data back to user space if the */
592 /* request hasn't been cancelled */
62e76326 593
cd748f27 594 switch (requestp->request_type) {
62e76326 595
cd748f27 596 case _AIO_OP_STAT:
62e76326 597
598 if (!cancelled && requestp->ret == 0)
599
600 xmemcpy(requestp->statp, requestp->tmpstatp, sizeof(struct stat));
601
602 squidaio_xfree(requestp->tmpstatp, sizeof(struct stat));
603
604 squidaio_xstrfree(requestp->path);
605
606 break;
607
cd748f27 608 case _AIO_OP_OPEN:
62e76326 609 if (cancelled && requestp->ret >= 0)
610 /* The open() was cancelled but completed */
611 close(requestp->ret);
612
613 squidaio_xstrfree(requestp->path);
614
615 break;
616
cd748f27 617 case _AIO_OP_CLOSE:
62e76326 618 if (cancelled && requestp->ret < 0)
619 /* The close() was cancelled and never got executed */
620 close(requestp->fd);
621
622 break;
623
cd748f27 624 case _AIO_OP_UNLINK:
62e76326 625
cd748f27 626 case _AIO_OP_OPENDIR:
62e76326 627 squidaio_xstrfree(requestp->path);
628
629 break;
630
cd748f27 631 case _AIO_OP_READ:
62e76326 632 break;
633
cd748f27 634 case _AIO_OP_WRITE:
62e76326 635 break;
636
cd748f27 637 default:
62e76326 638 break;
cd748f27 639 }
62e76326 640
cd748f27 641 if (resultp != NULL && !cancelled) {
62e76326 642 resultp->aio_return = requestp->ret;
643 resultp->aio_errno = requestp->err;
cd748f27 644 }
62e76326 645
b001e822 646 squidaio_request_pool->free(requestp);
c04d4f40 647} /* squidaio_cleanup_request */
cd748f27 648
649
650int
c04d4f40 651squidaio_cancel(squidaio_result_t * resultp)
cd748f27 652{
e6ccf245 653 squidaio_request_t *request = (squidaio_request_t *)resultp->_data;
cd748f27 654
55f0e6f7 655 if (request && request->resultp == resultp) {
62e76326 656 debug(43, 9) ("squidaio_cancel: %p type=%d result=%p\n",
657 request, request->request_type, request->resultp);
658 request->cancelled = 1;
659 request->resultp = NULL;
660 resultp->_data = NULL;
661 resultp->result_type = _AIO_OP_NONE;
662 return 0;
55f0e6f7 663 }
62e76326 664
cd748f27 665 return 1;
c04d4f40 666} /* squidaio_cancel */
cd748f27 667
668
669int
c04d4f40 670squidaio_open(const char *path, int oflag, mode_t mode, squidaio_result_t * resultp)
cd748f27 671{
e65c313f 672 squidaio_init();
c04d4f40 673 squidaio_request_t *requestp;
cd748f27 674
b001e822 675 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 676
c04d4f40 677 requestp->path = (char *) squidaio_xstrdup(path);
62e76326 678
cd748f27 679 requestp->oflag = oflag;
62e76326 680
cd748f27 681 requestp->mode = mode;
62e76326 682
cd748f27 683 requestp->resultp = resultp;
62e76326 684
cd748f27 685 requestp->request_type = _AIO_OP_OPEN;
62e76326 686
cd748f27 687 requestp->cancelled = 0;
62e76326 688
12e137b0 689 resultp->result_type = _AIO_OP_OPEN;
cd748f27 690
c04d4f40 691 squidaio_queue_request(requestp);
62e76326 692
cd748f27 693 return 0;
694}
695
696
697static void
c04d4f40 698squidaio_do_open(squidaio_request_t * requestp)
cd748f27 699{
700 requestp->ret = open(requestp->path, requestp->oflag, requestp->mode);
701 requestp->err = errno;
702}
703
704
705int
c04d4f40 706squidaio_read(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp)
cd748f27 707{
c04d4f40 708 squidaio_request_t *requestp;
cd748f27 709
b001e822 710 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 711
cd748f27 712 requestp->fd = fd;
62e76326 713
cd748f27 714 requestp->bufferp = bufp;
62e76326 715
cd748f27 716 requestp->buflen = bufs;
62e76326 717
cd748f27 718 requestp->offset = offset;
62e76326 719
cd748f27 720 requestp->whence = whence;
62e76326 721
cd748f27 722 requestp->resultp = resultp;
62e76326 723
cd748f27 724 requestp->request_type = _AIO_OP_READ;
62e76326 725
cd748f27 726 requestp->cancelled = 0;
62e76326 727
12e137b0 728 resultp->result_type = _AIO_OP_READ;
cd748f27 729
c04d4f40 730 squidaio_queue_request(requestp);
62e76326 731
cd748f27 732 return 0;
733}
734
735
736static void
c04d4f40 737squidaio_do_read(squidaio_request_t * requestp)
cd748f27 738{
739 lseek(requestp->fd, requestp->offset, requestp->whence);
211f1d0b 740 requestp->ret = read(requestp->fd, requestp->bufferp, requestp->buflen);
cd748f27 741 requestp->err = errno;
742}
743
744
745int
c04d4f40 746squidaio_write(int fd, char *bufp, int bufs, off_t offset, int whence, squidaio_result_t * resultp)
cd748f27 747{
c04d4f40 748 squidaio_request_t *requestp;
cd748f27 749
b001e822 750 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 751
cd748f27 752 requestp->fd = fd;
62e76326 753
d06925a4 754 requestp->bufferp = bufp;
62e76326 755
cd748f27 756 requestp->buflen = bufs;
62e76326 757
cd748f27 758 requestp->offset = offset;
62e76326 759
cd748f27 760 requestp->whence = whence;
62e76326 761
cd748f27 762 requestp->resultp = resultp;
62e76326 763
cd748f27 764 requestp->request_type = _AIO_OP_WRITE;
62e76326 765
cd748f27 766 requestp->cancelled = 0;
62e76326 767
12e137b0 768 resultp->result_type = _AIO_OP_WRITE;
cd748f27 769
c04d4f40 770 squidaio_queue_request(requestp);
62e76326 771
cd748f27 772 return 0;
773}
774
775
776static void
c04d4f40 777squidaio_do_write(squidaio_request_t * requestp)
cd748f27 778{
d06925a4 779 requestp->ret = write(requestp->fd, requestp->bufferp, requestp->buflen);
cd748f27 780 requestp->err = errno;
781}
782
783
784int
c04d4f40 785squidaio_close(int fd, squidaio_result_t * resultp)
cd748f27 786{
c04d4f40 787 squidaio_request_t *requestp;
cd748f27 788
b001e822 789 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 790
cd748f27 791 requestp->fd = fd;
62e76326 792
cd748f27 793 requestp->resultp = resultp;
62e76326 794
cd748f27 795 requestp->request_type = _AIO_OP_CLOSE;
62e76326 796
cd748f27 797 requestp->cancelled = 0;
62e76326 798
12e137b0 799 resultp->result_type = _AIO_OP_CLOSE;
cd748f27 800
c04d4f40 801 squidaio_queue_request(requestp);
62e76326 802
cd748f27 803 return 0;
804}
805
806
807static void
c04d4f40 808squidaio_do_close(squidaio_request_t * requestp)
cd748f27 809{
810 requestp->ret = close(requestp->fd);
811 requestp->err = errno;
812}
813
814
815int
62e76326 816
c04d4f40 817squidaio_stat(const char *path, struct stat *sb, squidaio_result_t * resultp)
cd748f27 818{
e65c313f 819 squidaio_init();
c04d4f40 820 squidaio_request_t *requestp;
cd748f27 821
b001e822 822 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 823
c04d4f40 824 requestp->path = (char *) squidaio_xstrdup(path);
62e76326 825
cd748f27 826 requestp->statp = sb;
62e76326 827
c04d4f40 828 requestp->tmpstatp = (struct stat *) squidaio_xmalloc(sizeof(struct stat));
62e76326 829
cd748f27 830 requestp->resultp = resultp;
62e76326 831
cd748f27 832 requestp->request_type = _AIO_OP_STAT;
62e76326 833
cd748f27 834 requestp->cancelled = 0;
62e76326 835
12e137b0 836 resultp->result_type = _AIO_OP_STAT;
cd748f27 837
c04d4f40 838 squidaio_queue_request(requestp);
62e76326 839
cd748f27 840 return 0;
841}
842
843
844static void
c04d4f40 845squidaio_do_stat(squidaio_request_t * requestp)
cd748f27 846{
847 requestp->ret = stat(requestp->path, requestp->tmpstatp);
848 requestp->err = errno;
849}
850
851
15a47d1d 852int
efa3acd1 853squidaio_unlink(const char *path, squidaio_result_t * resultp)
15a47d1d 854{
e65c313f 855 squidaio_init();
c04d4f40 856 squidaio_request_t *requestp;
15a47d1d 857
b001e822 858 requestp = (squidaio_request_t *)squidaio_request_pool->alloc();
62e76326 859
efa3acd1 860 requestp->path = squidaio_xstrdup(path);
62e76326 861
15a47d1d 862 requestp->resultp = resultp;
62e76326 863
efa3acd1 864 requestp->request_type = _AIO_OP_UNLINK;
62e76326 865
15a47d1d 866 requestp->cancelled = 0;
62e76326 867
efa3acd1 868 resultp->result_type = _AIO_OP_UNLINK;
15a47d1d 869
c04d4f40 870 squidaio_queue_request(requestp);
62e76326 871
15a47d1d 872 return 0;
873}
874
875
876static void
efa3acd1 877squidaio_do_unlink(squidaio_request_t * requestp)
15a47d1d 878{
efa3acd1 879 requestp->ret = unlink(requestp->path);
15a47d1d 880 requestp->err = errno;
881}
882
cd748f27 883#if AIO_OPENDIR
c04d4f40 884/* XXX squidaio_opendir NOT implemented yet.. */
cd748f27 885
886int
c04d4f40 887squidaio_opendir(const char *path, squidaio_result_t * resultp)
cd748f27 888{
c04d4f40 889 squidaio_request_t *requestp;
cd748f27 890 int len;
891
b001e822 892 requestp = squidaio_request_pool->alloc();
62e76326 893
12e137b0 894 resultp->result_type = _AIO_OP_OPENDIR;
62e76326 895
cd748f27 896 return -1;
897}
898
899static void
c04d4f40 900squidaio_do_opendir(squidaio_request_t * requestp)
cd748f27 901{
902 /* NOT IMPLEMENTED */
903}
904
905#endif
906
55f0e6f7 907static void
c04d4f40 908squidaio_poll_queues(void)
55f0e6f7 909{
910 /* kick "overflow" request queue */
62e76326 911
55f0e6f7 912 if (request_queue2.head &&
62e76326 913 pthread_mutex_trylock(&request_queue.mutex) == 0) {
914 *request_queue.tailp = request_queue2.head;
915 request_queue.tailp = request_queue2.tailp;
916 pthread_cond_signal(&request_queue.cond);
917 pthread_mutex_unlock(&request_queue.mutex);
918 request_queue2.head = NULL;
919 request_queue2.tailp = &request_queue2.head;
55f0e6f7 920 }
62e76326 921
55f0e6f7 922 /* poll done queue */
923 if (done_queue.head && pthread_mutex_trylock(&done_queue.mutex) == 0) {
62e76326 924
925 struct squidaio_request_t *requests = done_queue.head;
926 done_queue.head = NULL;
927 done_queue.tailp = &done_queue.head;
928 pthread_mutex_unlock(&done_queue.mutex);
929 *done_requests.tailp = requests;
930 request_queue_len -= 1;
931
932 while (requests->next) {
933 requests = requests->next;
934 request_queue_len -= 1;
935 }
936
937 done_requests.tailp = &requests->next;
55f0e6f7 938 }
55f0e6f7 939}
cd748f27 940
c04d4f40 941squidaio_result_t *
942squidaio_poll_done(void)
cd748f27 943{
c04d4f40 944 squidaio_request_t *request;
945 squidaio_result_t *resultp;
cd748f27 946 int cancelled;
55f0e6f7 947 int polled = 0;
cd748f27 948
62e76326 949AIO_REPOLL:
55f0e6f7 950 request = done_requests.head;
62e76326 951
55f0e6f7 952 if (request == NULL && !polled) {
62e76326 953 CommIO::ResetNotifications();
954 squidaio_poll_queues();
955 polled = 1;
956 request = done_requests.head;
55f0e6f7 957 }
62e76326 958
55f0e6f7 959 if (!request) {
62e76326 960 return NULL;
cd748f27 961 }
62e76326 962
99cce4cb 963 debug(43, 9) ("squidaio_poll_done: %p type=%d result=%p\n",
62e76326 964 request, request->request_type, request->resultp);
55f0e6f7 965 done_requests.head = request->next;
62e76326 966
55f0e6f7 967 if (!done_requests.head)
62e76326 968 done_requests.tailp = &done_requests.head;
969
55f0e6f7 970 resultp = request->resultp;
62e76326 971
55f0e6f7 972 cancelled = request->cancelled;
62e76326 973
c04d4f40 974 squidaio_debug(request);
62e76326 975
55f0e6f7 976 debug(43, 5) ("DONE: %d -> %d\n", request->ret, request->err);
62e76326 977
c04d4f40 978 squidaio_cleanup_request(request);
62e76326 979
cd748f27 980 if (cancelled)
62e76326 981 goto AIO_REPOLL;
982
cd748f27 983 return resultp;
c04d4f40 984} /* squidaio_poll_done */
cd748f27 985
986int
c04d4f40 987squidaio_operations_pending(void)
cd748f27 988{
55f0e6f7 989 return request_queue_len + (done_requests.head ? 1 : 0);
cd748f27 990}
991
992int
c04d4f40 993squidaio_sync(void)
cd748f27 994{
55f0e6f7 995 /* XXX This might take a while if the queue is large.. */
62e76326 996
cd748f27 997 do {
62e76326 998 squidaio_poll_queues();
cd748f27 999 } while (request_queue_len > 0);
62e76326 1000
c04d4f40 1001 return squidaio_operations_pending();
cd748f27 1002}
1003
1004int
c04d4f40 1005squidaio_get_queue_len(void)
cd748f27 1006{
1007 return request_queue_len;
1008}
1009
1010static void
c04d4f40 1011squidaio_debug(squidaio_request_t * request)
cd748f27 1012{
55f0e6f7 1013 switch (request->request_type) {
62e76326 1014
cd748f27 1015 case _AIO_OP_OPEN:
62e76326 1016 debug(43, 5) ("OPEN of %s to FD %d\n", request->path, request->ret);
1017 break;
1018
cd748f27 1019 case _AIO_OP_READ:
62e76326 1020 debug(43, 5) ("READ on fd: %d\n", request->fd);
1021 break;
1022
cd748f27 1023 case _AIO_OP_WRITE:
62e76326 1024 debug(43, 5) ("WRITE on fd: %d\n", request->fd);
1025 break;
1026
cd748f27 1027 case _AIO_OP_CLOSE:
62e76326 1028 debug(43, 5) ("CLOSE of fd: %d\n", request->fd);
1029 break;
1030
cd748f27 1031 case _AIO_OP_UNLINK:
62e76326 1032 debug(43, 5) ("UNLINK of %s\n", request->path);
1033 break;
1034
cd748f27 1035 default:
62e76326 1036 break;
cd748f27 1037 }
1038}
b0465494 1039
1040void
1041squidaio_stats(StoreEntry * sentry)
1042{
1043 squidaio_thread_t *threadp;
1044 int i;
1045
1046 if (!squidaio_initialised)
1047 return;
1048
1049 storeAppendPrintf(sentry, "\n\nThreads Status:\n");
1050
1051 storeAppendPrintf(sentry, "#\tID\t# Requests\n");
1052
1053 threadp = threads;
1054
1055 for (i = 0; i < NUMTHREADS; i++) {
691aef5a 1056 storeAppendPrintf(sentry, "%i\t0x%lx\t%ld\n", i + 1, (unsigned long)threadp->thread, threadp->requests);
b0465494 1057 threadp = threadp->next;
1058 }
1059}