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