Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / sparc / sparc32 / sem_waitcommon.c
blob08fd12ce50a0d5c2ef3358e107e59243996f96b1
1 /* sem_waitcommon -- wait on a semaphore, shared code.
2 Copyright (C) 2003-2017 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
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.
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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
20 #include <errno.h>
21 #include <sysdep.h>
22 #include <futex-internal.h>
23 #include <internaltypes.h>
24 #include <semaphore.h>
25 #include <sys/time.h>
27 #include <pthreadP.h>
28 #include <shlib-compat.h>
29 #include <atomic.h>
32 static void
33 __sem_wait_32_finish (struct new_sem *sem);
35 static void
36 __sem_wait_cleanup (void *arg)
38 struct new_sem *sem = (struct new_sem *) arg;
40 __sem_wait_32_finish (sem);
43 /* Wait until at least one token is available, possibly with a timeout.
44 This is in a separate function in order to make sure gcc
45 puts the call site into an exception region, and thus the
46 cleanups get properly run. TODO still necessary? Other futex_wait
47 users don't seem to need it. */
48 static int
49 __attribute__ ((noinline))
50 do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
52 int err;
54 err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
55 abstime, sem->private);
57 return err;
60 /* Fast path: Try to grab a token without blocking. */
61 static int
62 __new_sem_wait_fast (struct new_sem *sem, int definitive_result)
64 unsigned int v;
65 int ret = 0;
67 __sparc32_atomic_do_lock24(&sem->pad);
69 v = sem->value;
70 if ((v >> SEM_VALUE_SHIFT) == 0)
71 ret = -1;
72 else
73 sem->value = v - (1 << SEM_VALUE_SHIFT);
75 __sparc32_atomic_do_unlock24(&sem->pad);
77 return ret;
80 /* Slow path that blocks. */
81 static int
82 __attribute__ ((noinline))
83 __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
85 unsigned int v;
86 int err = 0;
88 __sparc32_atomic_do_lock24(&sem->pad);
90 sem->nwaiters++;
92 pthread_cleanup_push (__sem_wait_cleanup, sem);
94 /* Wait for a token to be available. Retry until we can grab one. */
95 v = sem->value;
98 if (!(v & SEM_NWAITERS_MASK))
99 sem->value = v | SEM_NWAITERS_MASK;
101 /* If there is no token, wait. */
102 if ((v >> SEM_VALUE_SHIFT) == 0)
104 __sparc32_atomic_do_unlock24(&sem->pad);
106 err = do_futex_wait(sem, abstime);
107 if (err == ETIMEDOUT || err == EINTR)
109 __set_errno (err);
110 err = -1;
111 goto error;
113 err = 0;
115 __sparc32_atomic_do_lock24(&sem->pad);
117 /* We blocked, so there might be a token now. */
118 v = sem->value;
121 /* If there is no token, we must not try to grab one. */
122 while ((v >> SEM_VALUE_SHIFT) == 0);
124 sem->value = v - (1 << SEM_VALUE_SHIFT);
126 __sparc32_atomic_do_unlock24(&sem->pad);
128 error:
129 pthread_cleanup_pop (0);
131 __sem_wait_32_finish (sem);
133 return err;
136 /* Stop being a registered waiter (non-64b-atomics code only). */
137 static void
138 __sem_wait_32_finish (struct new_sem *sem)
140 __sparc32_atomic_do_lock24(&sem->pad);
142 if (--sem->nwaiters == 0)
143 sem->value &= ~SEM_NWAITERS_MASK;
145 __sparc32_atomic_do_unlock24(&sem->pad);