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