Deleted Added
full compact
thr_sem.c (144518) thr_sem.c (149691)
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:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice(s), this list of conditions and the following disclaimer as
11 * the first lines of this file unmodified other than the possible
12 * addition of one or more copyright notices.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice(s), this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
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:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice(s), this list of conditions and the following disclaimer as
11 * the first lines of this file unmodified other than the possible
12 * addition of one or more copyright notices.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice(s), this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
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 144518 2005-04-02 01:20:00Z davidxu $
30 * $FreeBSD: head/lib/libthr/thread/thr_sem.c 149691 2005-09-01 15:21:23Z stefanf $
31 */
32
33#include "namespace.h"
31 */
32
33#include "namespace.h"
34#include <sys/types.h>
34#include <sys/queue.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <pthread.h>
38#include <semaphore.h>
39#include <stdlib.h>
40#include <time.h>
41#include <_semaphore.h>
42#include "un-namespace.h"
43
44#include "thr_private.h"
45
46
47__weak_reference(_sem_init, sem_init);
48__weak_reference(_sem_destroy, sem_destroy);
49__weak_reference(_sem_getvalue, sem_getvalue);
50__weak_reference(_sem_trywait, sem_trywait);
51__weak_reference(_sem_wait, sem_wait);
52__weak_reference(_sem_timedwait, sem_timedwait);
53__weak_reference(_sem_post, sem_post);
54
55
56static inline int
57sem_check_validity(sem_t *sem)
58{
59
60 if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC))
61 return (0);
62 else {
63 errno = EINVAL;
64 return (-1);
65 }
66}
67
68static sem_t
69sem_alloc(unsigned int value, semid_t semid, int system_sem)
70{
71 sem_t sem;
72
73 if (value > SEM_VALUE_MAX) {
74 errno = EINVAL;
75 return (NULL);
76 }
77
78 sem = (sem_t)malloc(sizeof(struct sem));
79 if (sem == NULL) {
80 errno = ENOSPC;
81 return (NULL);
82 }
83 _thr_umtx_init((umtx_t *)&sem->lock);
84 /*
85 * Fortunatly count and nwaiters are adjacency, so we can
86 * use umtx_wait to wait on it, umtx_wait needs an address
87 * can be accessed as a long interger.
88 */
89 sem->count = (u_int32_t)value;
90 sem->nwaiters = 0;
91 sem->magic = SEM_MAGIC;
92 sem->semid = semid;
93 sem->syssem = system_sem;
94 return (sem);
95}
96
97int
98_sem_init(sem_t *sem, int pshared, unsigned int value)
99{
100 semid_t semid;
101
102 semid = (semid_t)SEM_USER;
103 if ((pshared != 0) && (ksem_init(&semid, value) != 0))
104 return (-1);
105
106 (*sem) = sem_alloc(value, semid, pshared);
107 if ((*sem) == NULL) {
108 if (pshared != 0)
109 ksem_destroy(semid);
110 return (-1);
111 }
112 return (0);
113}
114
115int
116_sem_destroy(sem_t *sem)
117{
118 int retval;
119
120 if (sem_check_validity(sem) != 0)
121 return (-1);
122
123 /*
124 * If this is a system semaphore let the kernel track it otherwise
125 * make sure there are no waiters.
126 */
127 if ((*sem)->syssem != 0)
128 retval = ksem_destroy((*sem)->semid);
129 else {
130 retval = 0;
131 (*sem)->magic = 0;
132 }
133 if (retval == 0)
134 free(*sem);
135 return (retval);
136}
137
138int
139_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
140{
141 int retval;
142
143 if (sem_check_validity(sem) != 0)
144 return (-1);
145
146 if ((*sem)->syssem != 0)
147 retval = ksem_getvalue((*sem)->semid, sval);
148 else {
149 *sval = (int)(*sem)->count;
150 retval = 0;
151 }
152 return (retval);
153}
154
155int
156_sem_trywait(sem_t *sem)
157{
158 int val;
159
160 if (sem_check_validity(sem) != 0)
161 return (-1);
162
163 if ((*sem)->syssem != 0)
164 return (ksem_trywait((*sem)->semid));
165
166 while ((val = (*sem)->count) > 0) {
167 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
168 return (0);
169 }
170 errno = EAGAIN;
171 return (-1);
172}
173
174int
175_sem_wait(sem_t *sem)
176{
177 struct pthread *curthread;
178 int val, oldcancel, retval;
179
180 if (sem_check_validity(sem) != 0)
181 return (-1);
182
183 curthread = _get_curthread();
184 if ((*sem)->syssem != 0) {
185 oldcancel = _thr_cancel_enter(curthread);
186 retval = ksem_wait((*sem)->semid);
187 _thr_cancel_leave(curthread, oldcancel);
188 return (retval);
189 }
190
191 _pthread_testcancel();
192 do {
193 while ((val = (*sem)->count) > 0) {
194 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
195 return (0);
196 }
197 oldcancel = _thr_cancel_enter(curthread);
198 retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, NULL);
199 _thr_cancel_leave(curthread, oldcancel);
200 } while (retval == 0);
201 errno = retval;
202 return (-1);
203}
204
205int
206_sem_timedwait(sem_t * __restrict sem, struct timespec * __restrict abstime)
207{
208 struct timespec ts, ts2;
209 struct pthread *curthread;
210 int val, oldcancel, retval;
211
212 if (sem_check_validity(sem) != 0)
213 return (-1);
214
215 curthread = _get_curthread();
216 if ((*sem)->syssem != 0) {
217 oldcancel = _thr_cancel_enter(curthread);
218 retval = ksem_timedwait((*sem)->semid, abstime);
219 _thr_cancel_leave(curthread, oldcancel);
220 return (retval);
221 }
222
223 /*
224 * The timeout argument is only supposed to
225 * be checked if the thread would have blocked.
226 */
227 _pthread_testcancel();
228 do {
229 while ((val = (*sem)->count) > 0) {
230 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
231 return (0);
232 }
233 if (abstime == NULL) {
234 errno = EINVAL;
235 return (-1);
236 }
237 clock_gettime(CLOCK_REALTIME, &ts);
238 TIMESPEC_SUB(&ts2, abstime, &ts);
239 oldcancel = _thr_cancel_enter(curthread);
240 retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, &ts2);
241 _thr_cancel_leave(curthread, oldcancel);
242 } while (retval == 0);
243 errno = retval;
244 return (-1);
245}
246
247int
248_sem_post(sem_t *sem)
249{
250 int val, retval;
251
252 if (sem_check_validity(sem) != 0)
253 return (-1);
254
255 if ((*sem)->syssem != 0)
256 return (ksem_post((*sem)->semid));
257
258 /*
259 * sem_post() is required to be safe to call from within
260 * signal handlers, these code should work as that.
261 */
262 do {
263 val = (*sem)->count;
264 } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1));
265 retval = _thr_umtx_wake((umtx_t *)&(*sem)->count, val + 1);
266 if (retval > 0)
267 retval = 0;
268 return (retval);
269}
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
47
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);
55
56
57static inline int
58sem_check_validity(sem_t *sem)
59{
60
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 _thr_umtx_init((umtx_t *)&sem->lock);
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
99_sem_init(sem_t *sem, int pshared, unsigned int value)
100{
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);
114}
115
116int
117_sem_destroy(sem_t *sem)
118{
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);
137}
138
139int
140_sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
141{
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);
154}
155
156int
157_sem_trywait(sem_t *sem)
158{
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);
173}
174
175int
176_sem_wait(sem_t *sem)
177{
178 struct pthread *curthread;
179 int val, oldcancel, retval;
180
181 if (sem_check_validity(sem) != 0)
182 return (-1);
183
184 curthread = _get_curthread();
185 if ((*sem)->syssem != 0) {
186 oldcancel = _thr_cancel_enter(curthread);
187 retval = ksem_wait((*sem)->semid);
188 _thr_cancel_leave(curthread, oldcancel);
189 return (retval);
190 }
191
192 _pthread_testcancel();
193 do {
194 while ((val = (*sem)->count) > 0) {
195 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
196 return (0);
197 }
198 oldcancel = _thr_cancel_enter(curthread);
199 retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, NULL);
200 _thr_cancel_leave(curthread, oldcancel);
201 } while (retval == 0);
202 errno = retval;
203 return (-1);
204}
205
206int
207_sem_timedwait(sem_t * __restrict sem, struct timespec * __restrict abstime)
208{
209 struct timespec ts, ts2;
210 struct pthread *curthread;
211 int val, oldcancel, retval;
212
213 if (sem_check_validity(sem) != 0)
214 return (-1);
215
216 curthread = _get_curthread();
217 if ((*sem)->syssem != 0) {
218 oldcancel = _thr_cancel_enter(curthread);
219 retval = ksem_timedwait((*sem)->semid, abstime);
220 _thr_cancel_leave(curthread, oldcancel);
221 return (retval);
222 }
223
224 /*
225 * The timeout argument is only supposed to
226 * be checked if the thread would have blocked.
227 */
228 _pthread_testcancel();
229 do {
230 while ((val = (*sem)->count) > 0) {
231 if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
232 return (0);
233 }
234 if (abstime == NULL) {
235 errno = EINVAL;
236 return (-1);
237 }
238 clock_gettime(CLOCK_REALTIME, &ts);
239 TIMESPEC_SUB(&ts2, abstime, &ts);
240 oldcancel = _thr_cancel_enter(curthread);
241 retval = _thr_umtx_wait((umtx_t *)&(*sem)->count, 0, &ts2);
242 _thr_cancel_leave(curthread, oldcancel);
243 } while (retval == 0);
244 errno = retval;
245 return (-1);
246}
247
248int
249_sem_post(sem_t *sem)
250{
251 int val, retval;
252
253 if (sem_check_validity(sem) != 0)
254 return (-1);
255
256 if ((*sem)->syssem != 0)
257 return (ksem_post((*sem)->semid));
258
259 /*
260 * sem_post() is required to be safe to call from within
261 * signal handlers, these code should work as that.
262 */
263 do {
264 val = (*sem)->count;
265 } while (!atomic_cmpset_acq_int(&(*sem)->count, val, val + 1));
266 retval = _thr_umtx_wake((umtx_t *)&(*sem)->count, val + 1);
267 if (retval > 0)
268 retval = 0;
269 return (retval);
270}