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