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