You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Justin Erenkrantz <je...@ebuilt.com> on 2001/07/31 00:06:10 UTC

[PATCH] Worker fdqueue patch...

In the course of Aaron showing me how condition variables are supposed
to work, Aaron and I came up with this patch for the fdqueue code in 
the new worker MPM.

We think this makes the code thread-safe (tail == head, push starts, pop
comes - you are screwed, so the push should acquire one_big_mutex), 
but I'll let you guys be the judge of that.  Based on what I know about 
condition variables (which until this morning was nothing), this looks 
to be closer to what we want.

HTH.  -- justin

Index: fdqueue.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/worker/fdqueue.c,v
retrieving revision 1.1
diff -u -r1.1 fdqueue.c
--- fdqueue.c	2001/07/30 05:02:53	1.1
+++ fdqueue.c	2001/07/30 21:51:39
@@ -87,11 +87,6 @@
     return FD_QUEUE_SUCCESS;
 }
 
-static int increase_blanks(FDQueue *queue) {
-    queue->blanks++;
-    return FD_QUEUE_SUCCESS;
-}
-
 static apr_status_t ap_queue_destroy(void *data) {
     FDQueue *queue = data;
     /* Ignore errors here, we can't do anything about them anyway */
@@ -117,45 +112,40 @@
     return FD_QUEUE_SUCCESS;
 }
 
+/* Producer */
 int ap_queue_push(FDQueue *queue, apr_socket_t *sd, apr_pool_t *p) {
+    pthread_mutex_lock(&queue->one_big_mutex);
+    while (ap_queue_full(queue))
+        pthread_cond_wait(&queue->not_full, &queue->one_big_mutex);
     queue->data[queue->tail].sd = sd;
     queue->data[queue->tail].p  = p;
     queue->tail = (queue->tail + 1) % queue->bounds;
     queue->blanks--;
+    /* According to POSIX, cond_signal doesn't need the mutex.  This avoids 
+     * lock contention and unnecessary delays. */
+    pthread_mutex_unlock(&queue->one_big_mutex);
     pthread_cond_signal(&queue->not_empty);
-#if 0
-    if (queue->head == (queue->tail + 1) % queue->bounds) {
-#endif
-    if (ap_queue_full(queue)) {
-        pthread_cond_wait(&queue->not_full, &queue->one_big_mutex);
-    }
     return FD_QUEUE_SUCCESS;
 }
-
-apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p, int block_if_empty) {
-    increase_blanks(queue);
-    /* We have just removed one from the queue.  By definition, it is
-     * no longer full.  We can ALWAYS signal the listener thread at
-     * this point.  However, the original code didn't do it this way,
-     * so I am leaving the original code in, just commented out.  BTW,
-     * originally, the increase_blanks wasn't in this function either.
-     *
-     if (queue->blanks > 0) {
-     */
-    pthread_cond_signal(&queue->not_full);
 
-    /*    }    */
-    if (queue->head == queue->tail) {
-        if (block_if_empty) {
-            pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
-        }
-    } 
-    
+/* Consumer */
+apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p) {
+    pthread_mutex_lock(&queue->one_big_mutex);
+    /* Wait until we have one to consume */
+    while (!ap_queue_size(queue))
+        pthread_cond_wait(&queue->not_empty, &queue->one_big_mutex);
+    /* Do the pop. */
     *sd = queue->data[queue->head].sd;
     *p  = queue->data[queue->head].p;
     queue->data[queue->head].sd = NULL;
+    queue->blanks++;
+    /* Advance the head. */
     if (*sd != NULL) {
         queue->head = (queue->head + 1) % queue->bounds;
     }
+    /* According to POSIX, cond_signal doesn't need the mutex.  This avoids 
+     * lock contention and unnecessary delays. */
+    pthread_mutex_unlock(&queue->one_big_mutex);
+    pthread_cond_signal(&queue->not_full);
     return APR_SUCCESS;
 }
Index: fdqueue.h
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/worker/fdqueue.h,v
retrieving revision 1.1
diff -u -r1.1 fdqueue.h
--- fdqueue.h	2001/07/30 05:02:53	1.1
+++ fdqueue.h	2001/07/30 21:51:39
@@ -87,7 +87,7 @@
 
 int ap_queue_init(FDQueue *queue, int queue_size, apr_pool_t *a);
 int ap_queue_push(FDQueue *queue, apr_socket_t *sd, apr_pool_t *p);
-apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p, int block_if_empty);
+apr_status_t ap_queue_pop(FDQueue *queue, apr_socket_t **sd, apr_pool_t **p);
 int ap_queue_size(FDQueue *queue);
 int ap_queue_full(FDQueue *queue);
 int ap_block_on_queue(FDQueue *queue);
Index: worker.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.1
diff -u -r1.1 worker.c
--- worker.c	2001/07/30 05:02:53	1.1
+++ worker.c	2001/07/30 21:51:39
@@ -632,7 +632,6 @@
             }
             if (csd != NULL) {
                 ap_queue_push(worker_queue, csd, ptrans);
-                ap_block_on_queue(worker_queue);
             }
         }
         else {
@@ -680,7 +679,7 @@
     free(ti);
 
     while (!workers_may_exit) {
-        ap_queue_pop(worker_queue, &csd, &ptrans, 1);
+        ap_queue_pop(worker_queue, &csd, &ptrans);
         process_socket(ptrans, csd, process_slot, thread_slot);
         requests_this_child--;
         apr_pool_clear(ptrans);