// Initialize AIO. Create an AIO disk Io thread Based on the configuration file
Void
Squidaio_init (void)
{
Int I;
Int done_pipe [2];
Squidaio_thread_t * threadp;
If (squidaio_initialised)
Return;
Pthread_attr_init (& globattr );
# If have_pthread_attr_setscope
Pthread_attr_setscope (& globattr, pthread_scope_system );
# Endif
# If have_sched_h
Globsched. sched_priority = 1;
# Endif
Main_thread = pthread_self ();
# If have_sched_h & have_pthread_setschedparam
Pthread_setschedparam (main_thread, sched_other, & globsched );
# Endif
# If have_sched_h
Globsched. sched_priority = 2;
# Endif
# If have_sched_h & have_pthread_attr_setschedparam
Pthread_attr_setschedparam (& globattr, & globsched );
# Endif
/* Give each thread a smaller 256kb stack, shocould be more than sufficient */
Pthread_attr_setstacksize (& globattr, 256*1024 );
/* Initialize Request queue */
If (pthread_mutex_init (& (request_queue.mutex), null ))
Libcore_fatalf ("failed to create mutex ");
If (pthread_cond_init (& (request_queue.cond), null ))
Libcore_fatalf ("failed to create condition variable ");
Request_queue.head = NULL;
Request_queue.tailp = & request_queue.head;
Request_queue.requests = 0;
Request_queue.blocked = 0;
/* Initialize done queue */
If (pthread_mutex_init (& (done_queue.mutex), null ))
Libcore_fatalf ("failed to create mutex ");
If (pthread_cond_init (& (done_queue.cond), null ))
Libcore_fatalf ("failed to create condition variable ");
Done_queue.head = NULL;
Done_queue.tailp = & done_queue.head;
Done_queue.requests = 0;
Done_queue.blocked = 0;
/* Initialize done pipe signal */
Pipe (done_pipe );
Done_fd = done_pipe [1];
Done_fd_read = done_pipe [0];
Fd_open (done_fd_read, fd_pipe, "async-io completion event: Main ");
Fd_open (done_fd, fd_pipe, "async-io completion event: Threads ");
Commsetnonblocking (done_pipe [0]);
Commsetnonblocking (done_pipe [1]);
Commsetcloseonexec (done_pipe [0]);
Commsetcloseonexec (done_pipe [1]);
Commsetselect (done_pipe [0], comm_select_read, squidaio_fdhandler, null, 0 );
/* Create threads and get them to sit in their wait loop */
Squidaio_thread_pool = mempoolcreate ("aio_thread", sizeof (squidaio_thread_t ));
/* Default to basing the thread count on thread_factor and aiops_default_ndirs */
If (squidaio_nthreads = 0 ){
Int J = thread_factor;
For (I = 0; I <aiops_default_ndirs; I ++ ){
Squidaio_nthreads + = J;
J = J * 2/3;
If (j <4)
J = 4;
}
}
If (squidaio_nthreads = 0)
Squidaio_nthreads = thread_factor;
Squidaio_magic1 = squidaio_nthreads * magic1_factor;
Squidaio_magic2 = squidaio_nthreads * magic2_factor;
For (I = 0; I <squidaio_nthreads; I ++ ){
Threadp = mempoolalloc (squidaio_thread_pool );
Threadp-> Status = _ thread_starting;
Threadp-> current_req = NULL;
Threadp-> requests = 0;
Threadp-> next = threads;
Threads = threadp;
If (pthread_create (& threadp-> thread, & globattr, squidaio_thread_loop, threadp )){
Fprintf (stderr, "thread creation failed \ n ");
Threadp-> Status = _ thread_failed;
Continue;
}
}
/* CREATE request pool */
Squidaio_request_pool = mempoolcreate ("aio_request", sizeof (squidaio_request_t ));
Squidaio_initialised = 1;
}
// Thread processing function
Static void *
Squidaio_thread_loop (void * PTR)
{
Squidaio_thread_t * threadp = PTR;
Squidaio_request_t * request;
Sigset_t new;
/*
* Make sure to ignore signals which may possibly get sent
* The parent squid thread. causes havoc with mutex's and
* Condition waits otherwise
*/
// Clear the signal space
Sigemptyset (& New );
// Add a new signal to the signal space
Sigaddset (& New, sigpipe );
Sigaddset (& New, sigchld );
# Ifdef _ squid_linux_threads _
Sigaddset (& New, sigquit );
Sigaddset (& New, sigtrap );
# Else
Sigaddset (& New, SIGUSR1 );
Sigaddset (& New, sigusr2 );
# Endif
Sigaddset (& New, sighup );
Sigaddset (& New, sigterm );
Sigaddset (& New, SIGINT );
Sigaddset (& New, sigalrm );
// Block the signal mask
Pthread_sigmask (sig_block, & New, null );
While (1 ){
Threadp-> current_req = request = NULL;
Request = NULL;
/* Get a request to process */
Threadp-> Status = _ thread_waiting;
Pthread_mutex_lock (& request_queue.mutex );
// View the Request queue cyclically, if not null. Unlock and check whether there is a signal request. If not, enter the sleep status and wait for the signal.
While (! Request_queue.head ){
Pthread_cond_wait (& request_queue.cond, & request_queue.mutex );
}
// The request just processed
Request = request_queue.head;
If (request)
Request_queue.head = request-> next;
// Process. If request_queue is empty, set the end of request_queue to the header after reinitialization.
If (! Request_queue.head)
Request_queue.tailp = & request_queue.head;
// Unlock to process the request. Sets the status of the current thread. Different AIO processes are called based on different types of requests.
Pthread_mutex_unlock (& request_queue.mutex );
/* Process the request */
Threadp-> Status = _ thread_busy;
Request-> next = NULL;
Threadp-> current_req = request;
Errno = 0;
If (! Request-> canceled ){
Switch (request-> REQUEST_TYPE ){
Case _ aio_op_open:
Squidaio_do_open (request );
Break;
Case _ aio_op_read:
Squidaio_do_read (request );
Break;
Case _ aio_op_write:
Squidaio_do_write (request );
Break;
Case _ aio_op_close:
Squidaio_do_close (request );
Break;
Case _ aio_op_unlink:
Squidaio_do_unlink (request );
Break;
Case _ aio_op_truncate:
Squidaio_do_truncate (request );
Break;
# If aio_opendir/* opendir not implemented yet */
Case _ aio_op_opendir:
Squidaio_do_opendir (request );
Break;
# Endif
Case _ aio_op_stat:
Squidaio_do_stat (request );
Break;
Default:
Request-> ret =-1;
Request-> err = einval;
Break;
}
} Else {/* canceled */
Request-> ret =-1;
Request-> err = eintr;
}
Threadp-> Status = _ thread_done;
/* Put the request in the done queue */
// Lock the request and put it in the Completion queue to unlock
Pthread_mutex_lock (& done_queue.mutex );
* Done_queue.tailp = request;
Done_queue.tailp = & request-> next;
Pthread_mutex_unlock (& done_queue.mutex );
If (! Done_signalled ){
Done_signalled = 1;
Fd_write_method (done_fd ,"! ", 1 );
}
Threadp-> requests ++;
}/* While forever */
Return NULL;
}/* Squidaio_thread_loop */
// Squid AIO Request queue
Static void
Squidaio_queue_request (squidaio_request_t * request)
{
Static int high_start = 0;
Debug (43, 9) ("squidaio_queue_request: % P type = % d result = % P \ n ",
Request, request-> REQUEST_TYPE, request-> resultp );
/* Mark it as not executed (failing result, no error )*/
Request-> ret =-1;
Request-> err = 0;
/* Internal housekeeping */
Request_queue_len + = 1;
Request-> resultp-> _ DATA = request;
/* Play some tricks with the request_queue2 queue */
Request-> next = NULL;
// If the request queue is null (request_queue2 blocks the queue)
If (! Request_queue2.head ){
// If the request queue is successfully locked (normal)
If (pthread_mutex_trylock (& request_queue.mutex) = 0 ){
/* Normal path */
// Assign a value to the next of the last request in the queue
// Assign the value of tail to the next request
* Request_queue.tailp = request;
Request_queue.tailp = & request-> next;
// Send a signal to the blocked wait state and unlock it
Pthread_cond_signal (& request_queue.cond );
Pthread_mutex_unlock (& request_queue.mutex );
} Else {
/* Oops, the request queue is blocked, use request_queue2 */
// If the lock fails, add the request to the queue 2
* Request_queue2.tailp = request;
Request_queue2.tailp = & request-> next;
}
} Else {
/* Secondary path. We have blocked requests to deal */
/* Add the request to the chain */
// If request_queue2 is not empty, add the request to the Request queue 2.
* Request_queue2.tailp = request;
If (pthread_mutex_trylock (& request_queue.mutex) = 0 ){
/* OK, the queue is no longer blocked */
* Request_queue.tailp = request_queue2.head;
Request_queue.tailp = & request-> next;
Pthread_cond_signal (& request_queue.cond );
Pthread_mutex_unlock (& request_queue.mutex );
Request_queue2.head = NULL;
Request_queue2.tailp = & request_queue2.head;
} Else {
/* Still blocked, bump the blocked request chain */
Request_queue2.tailp = & request-> next;
}
}
If (request_queue2.head ){
Static int filter = 0;
Static int filter_limit = 8;
If (++ filter> = filter_limit ){
Filter_limit + = filter;
Filter = 0;
Debug (43, 1) ("squidaio_queue_request: Warning-queue congestion \ n ");
}
}
/* Warn if out of threads */
// If the thread warning is exceeded
If (request_queue_len> magic1 ){
Static int last_warn = 0;
Static int queue_high, queue_low;
If (high_start = 0 ){
High_start = squid_curtime;
Queue_high = request_queue_len;
Queue_low = request_queue_len;
}
If (request_queue_len> queue_high)
Queue_high = request_queue_len;
If (request_queue_len <queue_low)
Queue_low = request_queue_len;
If (squid_curtime >=( last_warn + 15 )&&
Squid_curtime> = (high_start + 5 )){
Debug (43, 1) ("squidaio_queue_request: Warning-disk I/O overloading \ n ");
If (squid_curtime> = (high_start + 15 ))
Debug (43, 1) ("squidaio_queue_request: queue length: Current = % d, high = % d, low = % d, duration = % LD \ n ",
Request_queue_len, queue_high, queue_low, (long INT) (squid_curtime-high_start ));
Last_warn = squid_curtime;
}
} Else {
High_start = 0;
}
/* Warn if seriously overloaded */
If (request_queue_len> ridiculous_length ){
Debug (43, 0) ("squidaio_queue_request: async Request queue growing uncontrollably! \ N ");
Debug (43, 0) ("squidaio_queue_request: syncing pending I/O operations... (blocking) \ n ");
Squidaio_sync ();
Debug (43, 0) ("squidaio_queue_request: synced \ n ");
}
}/* Squidaio_queue_request */