]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libpthread / nptl / sysdeps / unix / sysv / linux / sem_timedwait.c
1 /* sem_timedwait -- wait on a semaphore.  Generic futex-using version.
2    Copyright (C) 2003, 2007 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <errno.h>
22 #include <sysdep.h>
23 #include <lowlevellock.h>
24 #include <internaltypes.h>
25 #include <semaphore.h>
26
27 #include <pthreadP.h>
28
29
30 extern void __sem_wait_cleanup (void *arg) attribute_hidden;
31
32
33 int
34 sem_timedwait (sem_t *sem, const struct timespec *abstime)
35 {
36   struct new_sem *isem = (struct new_sem *) sem;
37   int err;
38
39   if (atomic_decrement_if_positive (&isem->value) > 0)
40     return 0;
41
42   if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
43     {
44       __set_errno (EINVAL);
45       return -1;
46     }
47
48   atomic_increment (&isem->nwaiters);
49
50   pthread_cleanup_push (__sem_wait_cleanup, isem);
51
52   while (1)
53     {
54       struct timeval tv;
55       struct timespec rt;
56       int sec, nsec;
57
58       /* Get the current time.  */
59       __gettimeofday (&tv, NULL);
60
61       /* Compute relative timeout.  */
62       sec = abstime->tv_sec - tv.tv_sec;
63       nsec = abstime->tv_nsec - tv.tv_usec * 1000;
64       if (nsec < 0)
65         {
66           nsec += 1000000000;
67           --sec;
68         }
69
70       /* Already timed out?  */
71       err = -ETIMEDOUT;
72       if (sec < 0)
73         {
74           __set_errno (ETIMEDOUT);
75           err = -1;
76           break;
77         }
78
79       /* Do wait.  */
80       rt.tv_sec = sec;
81       rt.tv_nsec = nsec;
82
83       /* Enable asynchronous cancellation.  Required by the standard.  */
84       int oldtype = __pthread_enable_asynccancel ();
85
86       err = lll_futex_timed_wait (&isem->value, 0, &rt,
87                                   isem->private ^ FUTEX_PRIVATE_FLAG);
88
89       /* Disable asynchronous cancellation.  */
90       __pthread_disable_asynccancel (oldtype);
91
92       if (err != 0 && err != -EWOULDBLOCK)
93         {
94           __set_errno (-err);
95           err = -1;
96           break;
97         }
98
99       if (atomic_decrement_if_positive (&isem->value) > 0)
100         {
101           err = 0;
102           break;
103         }
104     }
105
106   pthread_cleanup_pop (0);
107
108   atomic_decrement (&isem->nwaiters);
109
110   return err;
111 }