]>
Commit | Line | Data |
---|---|---|
d4abeca5 | 1 | /* sem_waitcommon -- wait on a semaphore, shared code. |
688903eb | 2 | Copyright (C) 2003-2018 Free Software Foundation, Inc. |
d4abeca5 DM |
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, see | |
18 | <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include <errno.h> | |
21 | #include <sysdep.h> | |
a2f0363f | 22 | #include <futex-internal.h> |
d4abeca5 DM |
23 | #include <internaltypes.h> |
24 | #include <semaphore.h> | |
25 | #include <sys/time.h> | |
26 | ||
27 | #include <pthreadP.h> | |
28 | #include <shlib-compat.h> | |
29 | #include <atomic.h> | |
30 | ||
d4abeca5 DM |
31 | |
32 | static void | |
33 | __sem_wait_32_finish (struct new_sem *sem); | |
34 | ||
35 | static void | |
36 | __sem_wait_cleanup (void *arg) | |
37 | { | |
38 | struct new_sem *sem = (struct new_sem *) arg; | |
39 | ||
40 | __sem_wait_32_finish (sem); | |
41 | } | |
42 | ||
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) | |
51 | { | |
52 | int err; | |
53 | ||
a2f0363f | 54 | err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK, |
be3c0fe8 | 55 | abstime, FUTEX_CLOCK_REALTIME, sem->private); |
d4abeca5 DM |
56 | |
57 | return err; | |
58 | } | |
59 | ||
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) | |
63 | { | |
64 | unsigned int v; | |
65 | int ret = 0; | |
66 | ||
67 | __sparc32_atomic_do_lock24(&sem->pad); | |
68 | ||
69 | v = sem->value; | |
70 | if ((v >> SEM_VALUE_SHIFT) == 0) | |
71 | ret = -1; | |
72 | else | |
73 | sem->value = v - (1 << SEM_VALUE_SHIFT); | |
74 | ||
75 | __sparc32_atomic_do_unlock24(&sem->pad); | |
76 | ||
77 | return ret; | |
78 | } | |
79 | ||
80 | /* Slow path that blocks. */ | |
81 | static int | |
82 | __attribute__ ((noinline)) | |
83 | __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime) | |
84 | { | |
85 | unsigned int v; | |
86 | int err = 0; | |
87 | ||
88 | __sparc32_atomic_do_lock24(&sem->pad); | |
89 | ||
90 | sem->nwaiters++; | |
91 | ||
92 | pthread_cleanup_push (__sem_wait_cleanup, sem); | |
93 | ||
94 | /* Wait for a token to be available. Retry until we can grab one. */ | |
95 | v = sem->value; | |
96 | do | |
97 | { | |
98 | if (!(v & SEM_NWAITERS_MASK)) | |
99 | sem->value = v | SEM_NWAITERS_MASK; | |
100 | ||
101 | /* If there is no token, wait. */ | |
102 | if ((v >> SEM_VALUE_SHIFT) == 0) | |
103 | { | |
104 | __sparc32_atomic_do_unlock24(&sem->pad); | |
105 | ||
106 | err = do_futex_wait(sem, abstime); | |
a2f0363f | 107 | if (err == ETIMEDOUT || err == EINTR) |
d4abeca5 DM |
108 | { |
109 | __set_errno (err); | |
110 | err = -1; | |
111 | goto error; | |
112 | } | |
113 | err = 0; | |
114 | ||
115 | __sparc32_atomic_do_lock24(&sem->pad); | |
116 | ||
117 | /* We blocked, so there might be a token now. */ | |
118 | v = sem->value; | |
119 | } | |
120 | } | |
121 | /* If there is no token, we must not try to grab one. */ | |
122 | while ((v >> SEM_VALUE_SHIFT) == 0); | |
123 | ||
124 | sem->value = v - (1 << SEM_VALUE_SHIFT); | |
125 | ||
126 | __sparc32_atomic_do_unlock24(&sem->pad); | |
127 | ||
128 | error: | |
129 | pthread_cleanup_pop (0); | |
130 | ||
131 | __sem_wait_32_finish (sem); | |
132 | ||
133 | return err; | |
134 | } | |
135 | ||
136 | /* Stop being a registered waiter (non-64b-atomics code only). */ | |
137 | static void | |
138 | __sem_wait_32_finish (struct new_sem *sem) | |
139 | { | |
140 | __sparc32_atomic_do_lock24(&sem->pad); | |
141 | ||
142 | if (--sem->nwaiters == 0) | |
143 | sem->value &= ~SEM_NWAITERS_MASK; | |
144 | ||
145 | __sparc32_atomic_do_unlock24(&sem->pad); | |
146 | } |