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