Back to index

glibc  2.9
pthread_rwlock_timedrdlock.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <sysdep.h>
00022 #include <lowlevellock.h>
00023 #include <pthread.h>
00024 #include <pthreadP.h>
00025 
00026 
00027 /* Try to acquire read lock for RWLOCK or return after specfied time.  */
00028 int
00029 pthread_rwlock_timedrdlock (rwlock, abstime)
00030      pthread_rwlock_t *rwlock;
00031      const struct timespec *abstime;
00032 {
00033   int result = 0;
00034 
00035   /* Make sure we are along.  */
00036   lll_lock(rwlock->__data.__lock, rwlock->__data.__shared);
00037 
00038   while (1)
00039     {
00040       int err;
00041 
00042       /* Get the rwlock if there is no writer...  */
00043       if (rwlock->__data.__writer == 0
00044          /* ...and if either no writer is waiting or we prefer readers.  */
00045          && (!rwlock->__data.__nr_writers_queued
00046              || PTHREAD_RWLOCK_PREFER_READER_P (rwlock)))
00047        {
00048          /* Increment the reader counter.  Avoid overflow.  */
00049          if (++rwlock->__data.__nr_readers == 0)
00050            {
00051              /* Overflow on number of readers.    */
00052              --rwlock->__data.__nr_readers;
00053              result = EAGAIN;
00054            }
00055 
00056          break;
00057        }
00058 
00059       /* Make sure we are not holding the rwlock as a writer.  This is
00060         a deadlock situation we recognize and report.  */
00061       if (__builtin_expect (rwlock->__data.__writer
00062                          == THREAD_GETMEM (THREAD_SELF, tid), 0))
00063        {
00064          result = EDEADLK;
00065          break;
00066        }
00067 
00068       /* Make sure the passed in timeout value is valid.  Ideally this
00069         test would be executed once.  But since it must not be
00070         performed if we would not block at all simply moving the test
00071         to the front is no option.  Replicating all the code is
00072         costly while this test is not.  */
00073       if (__builtin_expect (abstime->tv_nsec >= 1000000000
00074                             || abstime->tv_nsec < 0, 0))
00075        {
00076          result = EINVAL;
00077          break;
00078        }
00079 
00080       /* Get the current time.  So far we support only one clock.  */
00081       struct timeval tv;
00082       (void) gettimeofday (&tv, NULL);
00083 
00084       /* Convert the absolute timeout value to a relative timeout.  */
00085       struct timespec rt;
00086       rt.tv_sec = abstime->tv_sec - tv.tv_sec;
00087       rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
00088       if (rt.tv_nsec < 0)
00089        {
00090          rt.tv_nsec += 1000000000;
00091          --rt.tv_sec;
00092        }
00093       /* Did we already time out?  */
00094       if (rt.tv_sec < 0)
00095        {
00096          /* Yep, return with an appropriate error.  */
00097          result = ETIMEDOUT;
00098          break;
00099        }
00100 
00101       /* Remember that we are a reader.  */
00102       if (++rwlock->__data.__nr_readers_queued == 0)
00103        {
00104          /* Overflow on number of queued readers.  */
00105          --rwlock->__data.__nr_readers_queued;
00106          result = EAGAIN;
00107          break;
00108        }
00109 
00110       int waitval = rwlock->__data.__readers_wakeup;
00111 
00112       /* Free the lock.  */
00113       lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
00114 
00115       /* Wait for the writer to finish.  */
00116       err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup,
00117                               waitval, &rt, rwlock->__data.__shared);
00118 
00119       /* Get the lock.  */
00120       lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
00121 
00122       --rwlock->__data.__nr_readers_queued;
00123 
00124       /* Did the futex call time out?  */
00125       if (err == -ETIMEDOUT)
00126        {
00127          /* Yep, report it.  */
00128          result = ETIMEDOUT;
00129          break;
00130        }
00131     }
00132 
00133   /* We are done, free the lock.  */
00134   lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
00135 
00136   return result;
00137 }