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