Back to index

glibc  2.9
pthread_rwlock_timedwrlock.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 write lock for RWLOCK or return after specfied time.       */
00028 int
00029 pthread_rwlock_timedwrlock (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 and no reader.  */
00043       if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
00044        {
00045          /* Mark self as writer.  */
00046          rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid);
00047          break;
00048        }
00049 
00050       /* Make sure we are not holding the rwlock as a writer.  This is
00051         a deadlock situation we recognize and report.  */
00052       if (__builtin_expect (rwlock->__data.__writer
00053                          == THREAD_GETMEM (THREAD_SELF, tid), 0))
00054        {
00055          result = EDEADLK;
00056          break;
00057        }
00058 
00059       /* Make sure the passed in timeout value is valid.  Ideally this
00060         test would be executed once.  But since it must not be
00061         performed if we would not block at all simply moving the test
00062         to the front is no option.  Replicating all the code is
00063         costly while this test is not.  */
00064       if (__builtin_expect (abstime->tv_nsec >= 1000000000
00065                             || abstime->tv_nsec < 0, 0))
00066        {
00067          result = EINVAL;
00068          break;
00069        }
00070 
00071       /* Get the current time.  So far we support only one clock.  */
00072       struct timeval tv;
00073       (void) gettimeofday (&tv, NULL);
00074 
00075       /* Convert the absolute timeout value to a relative timeout.  */
00076       struct timespec rt;
00077       rt.tv_sec = abstime->tv_sec - tv.tv_sec;
00078       rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
00079       if (rt.tv_nsec < 0)
00080        {
00081          rt.tv_nsec += 1000000000;
00082          --rt.tv_sec;
00083        }
00084       /* Did we already time out?  */
00085       if (rt.tv_sec < 0)
00086        {
00087          result = ETIMEDOUT;
00088          break;
00089        }
00090 
00091       /* Remember that we are a writer.  */
00092       if (++rwlock->__data.__nr_writers_queued == 0)
00093        {
00094          /* Overflow on number of queued writers.  */
00095          --rwlock->__data.__nr_writers_queued;
00096          result = EAGAIN;
00097          break;
00098        }
00099 
00100       int waitval = rwlock->__data.__writer_wakeup;
00101 
00102       /* Free the lock.  */
00103       lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
00104 
00105       /* Wait for the writer or reader(s) to finish.  */
00106       err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup,
00107                               waitval, &rt, rwlock->__data.__shared);
00108 
00109       /* Get the lock.  */
00110       lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
00111 
00112       /* To start over again, remove the thread from the writer list.  */
00113       --rwlock->__data.__nr_writers_queued;
00114 
00115       /* Did the futex call time out?  */
00116       if (err == -ETIMEDOUT)
00117        {
00118          result = ETIMEDOUT;
00119          break;
00120        }
00121     }
00122 
00123   /* We are done, free the lock.  */
00124   lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
00125 
00126   return result;
00127 }