(pthread_barrier_wait): Don't save, load, and restore %esi for last thread.
[kopensolaris-gnu/glibc.git] / nptl / sysdeps / unix / sysv / linux / s390 / sem_timedwait.c
1 /* Copyright (C) 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <errno.h>
21 #include <sysdep.h>
22 #include <lowlevelsem.h>
23 #include <internaltypes.h>
24
25 #include <shlib-compat.h>
26
27
28 int
29 sem_timedwait (sem, abstime)
30      sem_t *sem;
31      const struct timespec *abstime;
32 {
33   int oldval, newval;
34
35   while (1)
36     {
37       /* Atomically decrement semaphore counter if it is > 0.  */
38       lll_compare_and_swap ((int *) sem, oldval, newval,
39                             "ltr %2,%1; jnp 1f; ahi %2,-1");
40       /* oldval != newval if the semaphore count has been decremented.  */
41       if (oldval != newval)
42         return 0;
43
44       /* Check for invalid timeout values.  */
45       if (abstime->tv_nsec >= 1000000000)
46         {
47           __set_errno(EINVAL);
48           return -1;
49         }
50
51       /* Get the current time.  */
52       struct timeval tv;
53       gettimeofday(&tv, NULL);
54
55       /* Compute the relative timeout.  */
56       struct timespec rt;
57       rt.tv_sec = abstime->tv_sec - tv.tv_sec;
58       rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
59       if (rt.tv_nsec < 0)
60         {
61           rt.tv_nsec += 1000000000;
62           rt.tv_sec--;
63         }
64       /* Already timed out.  */
65       if (rt.tv_sec < 0)
66         {
67           __set_errno(ETIMEDOUT);
68           return -1;
69         }
70
71       /* Do wait.  */
72       int err = lll_futex_timed_wait ((int *) sem, 0, &rt);
73
74       /* Returned after timing out?  */
75       if (err == -ETIMEDOUT)
76         {
77           __set_errno (ETIMEDOUT);
78           return -1;
79         }
80
81       /* Handle EINTR.  */
82       if (err != 0 && err != -EWOULDBLOCK)
83         {
84           __set_errno (-err);
85           return -1;
86         }
87     }
88 }