]>
Commit | Line | Data |
---|---|---|
e4720b0e | 1 | /* sem_wait -- wait on a semaphore. Generic futex-using version. |
b168057a | 2 | Copyright (C) 2003-2015 Free Software Foundation, Inc. |
b01fe5f7 UD |
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 | |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
b01fe5f7 UD |
19 | |
20 | #include <errno.h> | |
21 | #include <sysdep.h> | |
22 | #include <lowlevellock.h> | |
23 | #include <internaltypes.h> | |
24 | #include <semaphore.h> | |
25 | ||
26 | #include <pthreadP.h> | |
27 | #include <shlib-compat.h> | |
7000d82e | 28 | #include <sparc-nptl.h> |
b01fe5f7 | 29 | |
e4720b0e JJ |
30 | void |
31 | attribute_hidden | |
32 | __sem_wait_cleanup (void *arg) | |
33 | { | |
34 | struct sparc_new_sem *isem = (struct sparc_new_sem *) arg; | |
35 | ||
36 | if (__atomic_is_v9) | |
37 | atomic_decrement (&isem->nwaiters); | |
38 | else | |
39 | { | |
40 | __sparc32_atomic_do_lock24 (&isem->lock); | |
41 | isem->nwaiters--; | |
42 | __sparc32_atomic_do_unlock24 (&isem->lock); | |
43 | } | |
44 | } | |
45 | ||
39c4451c DM |
46 | /* This is in a seperate function in order to make sure gcc |
47 | puts the call site into an exception region, and thus the | |
48 | cleanups get properly run. */ | |
49 | static int | |
50 | __attribute__ ((noinline)) | |
51 | do_futex_wait (struct sparc_new_sem *isem) | |
52 | { | |
53 | int err, oldtype = __pthread_enable_asynccancel (); | |
54 | ||
55 | err = lll_futex_wait (&isem->value, 0, isem->private ^ FUTEX_PRIVATE_FLAG); | |
56 | ||
57 | __pthread_disable_asynccancel (oldtype); | |
58 | return err; | |
59 | } | |
e4720b0e | 60 | |
b01fe5f7 UD |
61 | int |
62 | __new_sem_wait (sem_t *sem) | |
63 | { | |
e4720b0e JJ |
64 | struct sparc_new_sem *isem = (struct sparc_new_sem *) sem; |
65 | int err; | |
66 | int val; | |
67 | ||
68 | if (__atomic_is_v9) | |
69 | val = atomic_decrement_if_positive (&isem->value); | |
70 | else | |
71 | { | |
72 | __sparc32_atomic_do_lock24 (&isem->lock); | |
73 | val = isem->value; | |
74 | if (val > 0) | |
75 | isem->value = val - 1; | |
76 | else | |
77 | isem->nwaiters++; | |
78 | __sparc32_atomic_do_unlock24 (&isem->lock); | |
79 | } | |
80 | ||
81 | if (val > 0) | |
82 | return 0; | |
83 | ||
84 | if (__atomic_is_v9) | |
85 | atomic_increment (&isem->nwaiters); | |
86 | else | |
87 | /* Already done above while still holding isem->lock. */; | |
88 | ||
89 | pthread_cleanup_push (__sem_wait_cleanup, isem); | |
90 | ||
91 | while (1) | |
92 | { | |
39c4451c | 93 | err = do_futex_wait(isem); |
e4720b0e JJ |
94 | if (err != 0 && err != -EWOULDBLOCK) |
95 | { | |
96 | __set_errno (-err); | |
97 | err = -1; | |
98 | break; | |
99 | } | |
100 | ||
101 | if (__atomic_is_v9) | |
102 | val = atomic_decrement_if_positive (&isem->value); | |
103 | else | |
104 | { | |
105 | __sparc32_atomic_do_lock24 (&isem->lock); | |
106 | val = isem->value; | |
107 | if (val > 0) | |
108 | isem->value = val - 1; | |
109 | __sparc32_atomic_do_unlock24 (&isem->lock); | |
110 | } | |
111 | ||
112 | if (val > 0) | |
113 | { | |
114 | err = 0; | |
115 | break; | |
116 | } | |
117 | } | |
118 | ||
119 | pthread_cleanup_pop (0); | |
b01fe5f7 | 120 | |
e4720b0e JJ |
121 | if (__atomic_is_v9) |
122 | atomic_decrement (&isem->nwaiters); | |
123 | else | |
124 | { | |
125 | __sparc32_atomic_do_lock24 (&isem->lock); | |
126 | isem->nwaiters--; | |
127 | __sparc32_atomic_do_unlock24 (&isem->lock); | |
128 | } | |
129 | ||
130 | return err; | |
131 | } | |
132 | versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1); | |
133 | ||
134 | ||
135 | #if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1) | |
136 | int | |
137 | attribute_compat_text_section | |
138 | __old_sem_wait (sem_t *sem) | |
139 | { | |
140 | struct sparc_old_sem *isem = (struct sparc_old_sem *) sem; | |
b01fe5f7 | 141 | int err; |
e4720b0e | 142 | int val; |
b01fe5f7 UD |
143 | |
144 | do | |
145 | { | |
b01fe5f7 | 146 | if (__atomic_is_v9) |
e4720b0e | 147 | val = atomic_decrement_if_positive (&isem->value); |
b01fe5f7 UD |
148 | else |
149 | { | |
e4720b0e JJ |
150 | __sparc32_atomic_do_lock24 (&isem->lock); |
151 | val = isem->value; | |
b01fe5f7 | 152 | if (val > 0) |
e4720b0e JJ |
153 | isem->value = val - 1; |
154 | __sparc32_atomic_do_unlock24 (&isem->lock); | |
b01fe5f7 | 155 | } |
e4720b0e | 156 | |
b01fe5f7 UD |
157 | if (val > 0) |
158 | return 0; | |
159 | ||
160 | /* Enable asynchronous cancellation. Required by the standard. */ | |
161 | int oldtype = __pthread_enable_asynccancel (); | |
162 | ||
2313c48f | 163 | err = lll_futex_wait (&isem->value, 0, |
e4720b0e | 164 | isem->private ^ FUTEX_PRIVATE_FLAG); |
b01fe5f7 UD |
165 | |
166 | /* Disable asynchronous cancellation. */ | |
167 | __pthread_disable_asynccancel (oldtype); | |
168 | } | |
169 | while (err == 0 || err == -EWOULDBLOCK); | |
170 | ||
171 | __set_errno (-err); | |
172 | return -1; | |
173 | } | |
174 | ||
b01fe5f7 UD |
175 | compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0); |
176 | #endif |