apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From i...@apache.org
Subject cvs commit: apr-util/test testqueue.c
Date Fri, 14 Feb 2003 04:39:09 GMT
ianh        2003/02/13 20:39:07

  Modified:    .        CHANGES
               misc     apr_queue.c
               test     testqueue.c
  Log:
  Fix race condition in apr_queue.
  
  "When calling apr_queue_pop to retrieve an item from the queue the call may
     block indefinately despite items having been pushed in. Same things goes
     for calls to apr_queue_push that are blocking until there is room in the
     queue (they may stay blocked even though items have been popped from the
     queue). The problem lies in the logic that manages the two conditions that
     help operate the queue - NOT_EMPTY, and NOT_FULL. In apr_queue_push, the
     NOT_EMPTY condition is only signaled if the queue was empty prior to
     adding the new item. This can cause problems if there are multiple threads
     blocked in calls to apr_queue_pop and then two or more successive calls to
     apr_queue_push are handled prior to one of the apr_queue_pop awakening..."
  
  Thanks Jacob!
  
  Submitted by:	Jacob Lewallen <jlwalle@cs.ucr.edu>
  Reviewed by:	Ian Holsman
  
  Revision  Changes    Path
  1.100     +3 -0      apr-util/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apr-util/CHANGES,v
  retrieving revision 1.99
  retrieving revision 1.100
  diff -u -r1.99 -r1.100
  --- CHANGES	4 Feb 2003 14:22:56 -0000	1.99
  +++ CHANGES	14 Feb 2003 04:39:07 -0000	1.100
  @@ -1,5 +1,8 @@
   Changes with APR-util 0.9.2
     
  +  *) Fix race conditions in apr_queue
  +     [Jacob Lewallen <jlwalle@cs.ucr.edu>]
  +
     *) Stop buildconf copying rules.mk, copy it at configure time. 
        [Thom May]
   
  
  
  
  1.11      +13 -24    apr-util/misc/apr_queue.c
  
  Index: apr_queue.c
  ===================================================================
  RCS file: /home/cvs/apr-util/misc/apr_queue.c,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- apr_queue.c	13 Jan 2003 20:15:50 -0000	1.10
  +++ apr_queue.c	14 Feb 2003 04:39:07 -0000	1.11
  @@ -85,6 +85,8 @@
       unsigned int        in;    /**< next empty location */
       unsigned int        out;   /**< next filled location */
       unsigned int        bounds;/**< max size of queue */
  +    unsigned int        full_waiters;
  +    unsigned int        empty_waiters;
       apr_thread_mutex_t *one_big_mutex;
       apr_thread_cond_t  *not_empty;
       apr_thread_cond_t  *not_full;
  @@ -169,6 +171,8 @@
       queue->in = 0;
       queue->out = 0;
       queue->terminated = 0;
  +    queue->full_waiters = 0;
  +    queue->empty_waiters = 0;
   
       apr_pool_cleanup_register(a, queue, queue_destroy, apr_pool_cleanup_null);
   
  @@ -183,7 +187,6 @@
   APU_DECLARE(apr_status_t) apr_queue_push(apr_queue_t *queue, void *data)
   {
       apr_status_t rv;
  -    int need_signal = 0;
   
       if (queue->terminated) {
           return APR_EOF; /* no more elements ever again */
  @@ -196,7 +199,9 @@
   
       if (apr_queue_full(queue)) {
           if (!queue->terminated) {
  +            queue->full_waiters++;
               rv = apr_thread_cond_wait(queue->not_full, queue->one_big_mutex);
  +            queue->full_waiters--;
               if (rv != APR_SUCCESS) {
                   apr_thread_mutex_unlock(queue->one_big_mutex);
                   return rv;
  @@ -218,16 +223,11 @@
           }
       }
   
  -    /* if we were empty then signal that we aren't */
  -    if (apr_queue_empty(queue)) {
  -        need_signal = 1;
  -    }
  -
       queue->data[queue->in] = data;
       queue->in = (queue->in + 1) % queue->bounds;
       queue->nelts++;
   
  -    if (need_signal == 1) {
  +    if (queue->empty_waiters) {
           Q_DBG("sig !empty", queue);
           rv = apr_thread_cond_signal(queue->not_empty);
           if (rv != APR_SUCCESS) {
  @@ -248,7 +248,7 @@
   APU_DECLARE(apr_status_t) apr_queue_trypush(apr_queue_t *queue, void *data)
   {
       apr_status_t rv;
  -    int need_signal = 0;
  +
       if (queue->terminated) {
           return APR_EOF; /* no more elements ever again */
       }
  @@ -262,17 +262,12 @@
           rv = apr_thread_mutex_unlock(queue->one_big_mutex);
           return APR_EAGAIN;
       }
  -
  -    /* if we were empty then signal that we aren't */
  -    if (apr_queue_empty(queue)) {
  -        need_signal = 1;
  -    }
       
       queue->data[queue->in] = data;
       queue->in = (queue->in + 1) % queue->bounds;
       queue->nelts++;
   
  -    if (need_signal == 1) {
  +    if (queue->empty_waiters) {
           Q_DBG("sig !empty", queue);
           rv  = apr_thread_cond_signal(queue->not_empty);
           if (rv != APR_SUCCESS) {
  @@ -301,7 +296,6 @@
   APU_DECLARE(apr_status_t) apr_queue_pop(apr_queue_t *queue, void **data)
   {
       apr_status_t rv;
  -    int need_signal = 0;
   
       if (queue->terminated) {
           return APR_EOF; /* no more elements ever again */
  @@ -315,7 +309,9 @@
       /* Keep waiting until we wake up and find that the queue is not empty. */
       if (apr_queue_empty(queue)) {
           if (!queue->terminated) {
  +            queue->empty_waiters++;
               rv = apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
  +            queue->empty_waiters--;
               if (rv != APR_SUCCESS) {
                   apr_thread_mutex_unlock(queue->one_big_mutex);
                   return rv;
  @@ -336,15 +332,12 @@
               }
           }
       } 
  -    if (apr_queue_full(queue)) {
  -        need_signal = 1;
  -    }
   
       *data = &queue->data[queue->out];
       queue->nelts--;
   
       queue->out = (queue->out + 1) % queue->bounds;
  -    if (need_signal == 1) {
  +    if (queue->full_waiters) {
           Q_DBG("signal !full", queue);
           rv = apr_thread_cond_signal(queue->not_full);
           if (rv != APR_SUCCESS) {
  @@ -366,7 +359,6 @@
   APU_DECLARE(apr_status_t) apr_queue_trypop(apr_queue_t *queue, void **data)
   {
       apr_status_t rv;
  -    int need_signal = 0;
   
       if (queue->terminated) {
           return APR_EOF; /* no more elements ever again */
  @@ -382,15 +374,12 @@
           rv = apr_thread_mutex_unlock(queue->one_big_mutex);
           return APR_EAGAIN;
       } 
  -    if (apr_queue_full(queue)) {
  -        need_signal = 1;
  -    }
   
       *data = &queue->data[queue->out];
       queue->nelts--;
   
       queue->out = (queue->out + 1) % queue->bounds;
  -    if (need_signal == 1) {
  +    if (queue->full_waiters) {
           Q_DBG("signal !full", queue);
           rv = apr_thread_cond_signal(queue->not_full);
           if (rv != APR_SUCCESS) {
  
  
  
  1.4       +2 -2      apr-util/test/testqueue.c
  
  Index: testqueue.c
  ===================================================================
  RCS file: /home/cvs/apr-util/test/testqueue.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- testqueue.c	1 Jan 2003 00:02:22 -0000	1.3
  +++ testqueue.c	14 Feb 2003 04:39:07 -0000	1.4
  @@ -82,7 +82,7 @@
   int verbose=0;
   static void * APR_THREAD_FUNC consumer(apr_thread_t *thd, void *data);
   static void * APR_THREAD_FUNC producer(apr_thread_t *thd, void *data);
  -static void usage();
  +static void usage(void);
   
   static void * APR_THREAD_FUNC consumer(apr_thread_t *thd, void *data)
   {
  @@ -159,7 +159,7 @@
       return NULL;
   } 
   
  -static void usage()
  +static void usage(void)
   {
       fprintf(stderr,"usage: testqueue -p n -P n -c n -C n -q n -s n ");
       fprintf(stderr,"-c # of consumer\n");
  
  
  

Mime
View raw message