Deleted Added
full compact
thr_sem.c (178647) thr_sem.c (201546)
1/*
2 * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
3 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 13 unchanged lines hidden (view full) ---

22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
1/*
2 * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
3 * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 13 unchanged lines hidden (view full) ---

22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: head/lib/libthr/thread/thr_sem.c 178647 2008-04-29 03:58:18Z davidxu $
30 * $FreeBSD: head/lib/libthr/thread/thr_sem.c 201546 2010-01-05 02:37:59Z davidxu $
31 */
32
33#include "namespace.h"
34#include <sys/types.h>
35#include <sys/queue.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <pthread.h>
31 */
32
33#include "namespace.h"
34#include <sys/types.h>
35#include <sys/queue.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <pthread.h>
39#include <semaphore.h>
40#include <stdlib.h>
41#include <time.h>
42#include <_semaphore.h>
43#include "un-namespace.h"
44
45#include "thr_private.h"
46
39#include <stdlib.h>
40#include <time.h>
41#include <_semaphore.h>
42#include "un-namespace.h"
43
44#include "thr_private.h"
45
46FB10_COMPAT(_sem_init_compat, sem_init);
47FB10_COMPAT(_sem_destroy_compat, sem_destroy);
48FB10_COMPAT(_sem_getvalue_compat, sem_getvalue);
49FB10_COMPAT(_sem_trywait_compat, sem_trywait);
50FB10_COMPAT(_sem_wait_compat, sem_wait);
51FB10_COMPAT(_sem_timedwait_compat, sem_timedwait);
52FB10_COMPAT(_sem_post_compat, sem_post);
47
53
48__weak_reference(_sem_init, sem_init);
49__weak_reference(_sem_destroy, sem_destroy);
50__weak_reference(_sem_getvalue, sem_getvalue);
51__weak_reference(_sem_trywait, sem_trywait);
52__weak_reference(_sem_wait, sem_wait);
53__weak_reference(_sem_timedwait, sem_timedwait);
54__weak_reference(_sem_post, sem_post);
54typedef struct sem *sem_t;
55
55
56extern int _libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value);
57extern int _libc_sem_destroy_compat(sem_t *sem);
58extern int _libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval);
59extern int _libc_sem_trywait_compat(sem_t *sem);
60extern int _libc_sem_wait_compat(sem_t *sem);
61extern int _libc_sem_timedwait_compat(sem_t * __restrict sem,
62 const struct timespec * __restrict abstime);
63extern int _libc_sem_post_compat(sem_t *sem);
56
64
57static inline int
58sem_check_validity(sem_t *sem)
59{
65int _sem_init_compat(sem_t *sem, int pshared, unsigned int value);
66int _sem_destroy_compat(sem_t *sem);
67int _sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval);
68int _sem_trywait_compat(sem_t *sem);
69int _sem_wait_compat(sem_t *sem);
70int _sem_timedwait_compat(sem_t * __restrict sem,
71 const struct timespec * __restrict abstime);
72int _sem_post_compat(sem_t *sem);
60
73
61 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
62 return (0);
63 else {
64 errno = EINVAL;
65 return (-1);
66 }
67}
68
69static sem_t
70sem_alloc(unsigned int value, semid_t semid, int system_sem)
71{
72 sem_t sem;
73
74 if (value > SEM_VALUE_MAX) {
75 errno = EINVAL;
76 return (NULL);
77 }
78
79 sem = (sem_t)malloc(sizeof(struct sem));
80 if (sem == NULL) {
81 errno = ENOSPC;
82 return (NULL);
83 }
84 bzero(sem, sizeof(*sem));
85 /*
86 * Fortunatly count and nwaiters are adjacency, so we can
87 * use umtx_wait to wait on it, umtx_wait needs an address
88 * can be accessed as a long interger.
89 */
90 sem->count = (u_int32_t)value;
91 sem->nwaiters = 0;
92 sem->magic = SEM_MAGIC;
93 sem->semid = semid;
94 sem->syssem = system_sem;
95 return (sem);
96}
97
98int
74int
99_sem_init(sem_t *sem, int pshared, unsigned int value)
75_sem_init_compat(sem_t *sem, int pshared, unsigned int value)
100{
76{
101 semid_t semid;
102
103 semid = (semid_t)SEM_USER;
104 if ((pshared != 0) && (ksem_init(&semid, value) != 0))
105 return (-1);
106
107 (*sem) = sem_alloc(value, semid, pshared);
108 if ((*sem) == NULL) {
109 if (pshared != 0)
110 ksem_destroy(semid);
111 return (-1);
112 }
113 return (0);
77 return _libc_sem_init_compat(sem, pshared, value);
114}
115
116int
78}
79
80int
117_sem_destroy(sem_t *sem)
81_sem_destroy_compat(sem_t *sem)
118{
82{
119 int retval;
120
121 if (sem_check_validity(sem) != 0)
122 return (-1);
123
124 /*
125 * If this is a system semaphore let the kernel track it otherwise
126 * make sure there are no waiters.
127 */
128 if ((*sem)->syssem != 0)
129 retval = ksem_destroy((*sem)->semid);
130 else {
131 retval = 0;
132 (*sem)->magic = 0;
133 }
134 if (retval == 0)
135 free(*sem);
136 return (retval);
83 return _libc_sem_destroy_compat(sem);
137}
138
139int
84}
85
86int
140_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
87_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval)
141{
88{
142 int retval;
143
144 if (sem_check_validity(sem) != 0)
145 return (-1);
146
147 if ((*sem)->syssem != 0)
148 retval = ksem_getvalue((*sem)->semid, sval);
149 else {
150 *sval = (int)(*sem)->count;
151 retval = 0;
152 }
153 return (retval);
89 return _libc_sem_getvalue_compat(sem, sval);
154}
155
156int
90}
91
92int
157_sem_trywait(sem_t *sem)
93_sem_trywait_compat(sem_t *sem)
158{
94{
159 int val;
160
161 if (sem_check_validity(sem) != 0)
162 return (-1);
163
164 if ((*sem)->syssem != 0)
165 return (ksem_trywait((*sem)->semid));
166
167 while ((val = (*sem)->count) > 0) {
168 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
169 return (0);
170 }
171 errno = EAGAIN;
172 return (-1);
95 return _libc_sem_trywait_compat(sem);
173}
174
96}
97
175static void
176sem_cancel_handler(void *arg)
177{
178 sem_t *sem = arg;
179
180 atomic_add_int(&(*sem)->nwaiters, -1);
181 if ((*sem)->nwaiters && (*sem)->count)
182 _thr_umtx_wake(&(*sem)->count, 1, 0);
183}
184
185int
98int
186_sem_wait(sem_t *sem)
99_sem_wait_compat(sem_t *sem)
187{
100{
188 struct pthread *curthread;
189 int val, retval;
190
191 if (sem_check_validity(sem) != 0)
192 return (-1);
193
194 curthread = _get_curthread();
195 if ((*sem)->syssem != 0) {
196 _thr_cancel_enter(curthread);
197 retval = ksem_wait((*sem)->semid);
198 _thr_cancel_leave(curthread);
199 return (retval);
200 }
201
202 _pthread_testcancel();
203 do {
204 while ((val = (*sem)->count) > 0) {
205 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
206 return (0);
207 }
208 atomic_add_int(&(*sem)->nwaiters, 1);
209 THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem);
210 _thr_cancel_enter(curthread);
211 retval = _thr_umtx_wait_uint(&(*sem)->count, 0, NULL, 0);
212 _thr_cancel_leave(curthread);
213 THR_CLEANUP_POP(curthread, 0);
214 atomic_add_int(&(*sem)->nwaiters, -1);
215 } while (retval == 0);
216 errno = retval;
217 return (-1);
101 return _libc_sem_wait_compat(sem);
218}
219
220int
102}
103
104int
221_sem_timedwait(sem_t * __restrict sem,
105_sem_timedwait_compat(sem_t * __restrict sem,
222 const struct timespec * __restrict abstime)
223{
106 const struct timespec * __restrict abstime)
107{
224 struct timespec ts, ts2;
225 struct pthread *curthread;
226 int val, retval;
227
228 if (sem_check_validity(sem) != 0)
229 return (-1);
230
231 curthread = _get_curthread();
232 if ((*sem)->syssem != 0) {
233 _thr_cancel_enter(curthread);
234 retval = ksem_timedwait((*sem)->semid, abstime);
235 _thr_cancel_leave(curthread);
236 return (retval);
237 }
238
239 /*
240 * The timeout argument is only supposed to
241 * be checked if the thread would have blocked.
242 */
243 _pthread_testcancel();
244 do {
245 while ((val = (*sem)->count) > 0) {
246 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
247 return (0);
248 }
249 if (abstime == NULL) {
250 errno = EINVAL;
251 return (-1);
252 }
253 clock_gettime(CLOCK_REALTIME, &ts);
254 TIMESPEC_SUB(&ts2, abstime, &ts);
255 atomic_add_int(&(*sem)->nwaiters, 1);
256 THR_CLEANUP_PUSH(curthread, sem_cancel_handler, sem);
257 _thr_cancel_enter(curthread);
258 retval = _thr_umtx_wait_uint((uint32_t*)&(*sem)->count, 0, &ts2, 0);
259 _thr_cancel_leave(curthread);
260 THR_CLEANUP_POP(curthread, 0);
261 atomic_add_int(&(*sem)->nwaiters, -1);
262 } while (retval == 0);
263 errno = retval;
264 return (-1);
108 return _libc_sem_timedwait_compat(sem, abstime);
265}
266
109}
110
267/*
268 * sem_post() is required to be safe to call from within
269 * signal handlers, these code should work as that.
270 */
271
272int
111int
273_sem_post(sem_t *sem)
112_sem_post_compat(sem_t *sem)
274{
113{
275 int retval = 0;
276
277 if (sem_check_validity(sem) != 0)
278 return (-1);
279
280 if ((*sem)->syssem != 0)
281 return (ksem_post((*sem)->semid));
282
283 atomic_add_rel_int(&(*sem)->count, 1);
284
285 if ((*sem)->nwaiters) {
286 retval = _thr_umtx_wake(&(*sem)->count, 1, 0);
287 if (retval != 0)
288 retval = -1;
289 }
290 return (retval);
114 return _libc_sem_post_compat(sem);
291}
115}