uipc_sem.c revision 1.2 1 1.2 christos /* $NetBSD: uipc_sem.c,v 1.2 2003/01/20 20:24:22 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Copyright (c) 2002 Alfred Perlstein <alfred (at) FreeBSD.org>
5 1.1 christos * All rights reserved.
6 1.1 christos *
7 1.1 christos * Redistribution and use in source and binary forms, with or without
8 1.1 christos * modification, are permitted provided that the following conditions
9 1.1 christos * are met:
10 1.1 christos * 1. Redistributions of source code must retain the above copyright
11 1.1 christos * notice, this list of conditions and the following disclaimer.
12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 christos * notice, this list of conditions and the following disclaimer in the
14 1.1 christos * documentation and/or other materials provided with the distribution.
15 1.1 christos *
16 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 christos * SUCH DAMAGE.
27 1.1 christos *
28 1.1 christos * $FreeBSD: src/sys/kern/uipc_sem.c,v 1.4 2003/01/10 23:13:16 alfred Exp $
29 1.1 christos */
30 1.1 christos
31 1.1 christos #include "opt_posix.h"
32 1.1 christos
33 1.1 christos #include <sys/param.h>
34 1.1 christos #include <sys/systm.h>
35 1.1 christos #include <sys/kernel.h>
36 1.1 christos #include <sys/proc.h>
37 1.1 christos #include <sys/lock.h>
38 1.1 christos #include <sys/ksem.h>
39 1.1 christos #include <sys/syscall.h>
40 1.1 christos #include <sys/stat.h>
41 1.1 christos #include <sys/malloc.h>
42 1.1 christos #include <sys/fcntl.h>
43 1.1 christos
44 1.1 christos #include <sys/mount.h>
45 1.1 christos
46 1.1 christos #include <sys/syscallargs.h>
47 1.1 christos
48 1.1 christos #ifndef SEM_MAX
49 1.1 christos #define SEM_MAX 30
50 1.1 christos #endif
51 1.1 christos
52 1.1 christos #define SEM_MAX_NAMELEN 14
53 1.1 christos #define SEM_VALUE_MAX (~0U)
54 1.1 christos
55 1.1 christos #define SEM_TO_ID(x) ((intptr_t)(x))
56 1.1 christos #define ID_TO_SEM(x) ksem_id_to_sem(x)
57 1.1 christos
58 1.1 christos struct kuser {
59 1.1 christos pid_t ku_pid;
60 1.1 christos LIST_ENTRY(kuser) ku_next;
61 1.1 christos };
62 1.1 christos
63 1.1 christos /* For sysctl eventually */
64 1.1 christos int nsems = 0;
65 1.1 christos
66 1.1 christos struct ksem {
67 1.1 christos LIST_ENTRY(ksem) ks_entry; /* global list entry */
68 1.1 christos int ks_onlist; /* boolean if on a list (ks_entry) */
69 1.1 christos char *ks_name; /* if named, this is the name */
70 1.1 christos int ks_ref; /* number of references */
71 1.1 christos mode_t ks_mode; /* protection bits */
72 1.1 christos uid_t ks_uid; /* creator uid */
73 1.1 christos gid_t ks_gid; /* creator gid */
74 1.1 christos unsigned int ks_value; /* current value */
75 1.1 christos int ks_waiters; /* number of waiters */
76 1.1 christos LIST_HEAD(, kuser) ks_users; /* pids using this sem */
77 1.1 christos };
78 1.1 christos
79 1.1 christos /*
80 1.2 christos * available semaphores go here, this includes sys__ksem_init and any semaphores
81 1.2 christos * created via sys__ksem_open that have not yet been unlinked.
82 1.1 christos */
83 1.1 christos LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
84 1.1 christos /*
85 1.1 christos * semaphores still in use but have been ksem_unlink()'d go here.
86 1.1 christos */
87 1.1 christos LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
88 1.1 christos
89 1.1 christos static struct simplelock ksem_slock;
90 1.1 christos
91 1.1 christos #ifdef SEM_DEBUG
92 1.1 christos #define DP(x) printf x
93 1.1 christos #else
94 1.1 christos #define DP(x)
95 1.1 christos #endif
96 1.1 christos
97 1.1 christos static __inline void ksem_ref(struct ksem *ks);
98 1.1 christos static __inline void ksem_rel(struct ksem *ks);
99 1.1 christos static __inline struct ksem *ksem_id_to_sem(semid_t id);
100 1.1 christos static __inline struct kuser *ksem_getuser(struct proc *p, struct ksem *ks);
101 1.1 christos
102 1.1 christos static struct ksem *ksem_lookup_byname(const char *name);
103 1.1 christos static int ksem_create(struct lwp *l, const char *name,
104 1.1 christos struct ksem **ksret, mode_t mode, unsigned int value);
105 1.1 christos static void ksem_free(struct ksem *ksnew);
106 1.1 christos static int ksem_perm(struct proc *p, struct ksem *ks);
107 1.1 christos static void ksem_enter(struct proc *p, struct ksem *ks);
108 1.1 christos static int ksem_leave(struct proc *p, struct ksem *ks);
109 1.1 christos static void ksem_exithook(struct proc *p, void *arg);
110 1.1 christos static int ksem_hasopen(struct proc *p, struct ksem *ks);
111 1.1 christos static int ksem_wait(struct lwp *l, semid_t id, int tryflag);
112 1.1 christos
113 1.1 christos
114 1.1 christos static __inline void
115 1.1 christos ksem_ref(struct ksem *ks)
116 1.1 christos {
117 1.1 christos
118 1.1 christos ks->ks_ref++;
119 1.1 christos DP(("ksem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
120 1.1 christos }
121 1.1 christos
122 1.1 christos static __inline void
123 1.1 christos ksem_rel(struct ksem *ks)
124 1.1 christos {
125 1.1 christos
126 1.1 christos DP(("ksem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
127 1.1 christos if (--ks->ks_ref == 0)
128 1.1 christos ksem_free(ks);
129 1.1 christos }
130 1.1 christos
131 1.1 christos static __inline struct ksem *
132 1.1 christos ksem_id_to_sem(id)
133 1.1 christos semid_t id;
134 1.1 christos {
135 1.1 christos struct ksem *ks;
136 1.1 christos
137 1.1 christos DP(("id_to_sem: id = 0x%ld\n", id));
138 1.1 christos LIST_FOREACH(ks, &ksem_head, ks_entry) {
139 1.1 christos DP(("id_to_sem: ks = %p\n", ks));
140 1.1 christos if (ks == (struct ksem *)id)
141 1.1 christos return (ks);
142 1.1 christos }
143 1.1 christos return (NULL);
144 1.1 christos }
145 1.1 christos
146 1.1 christos static struct ksem *
147 1.1 christos ksem_lookup_byname(name)
148 1.1 christos const char *name;
149 1.1 christos {
150 1.1 christos struct ksem *ks;
151 1.1 christos
152 1.1 christos LIST_FOREACH(ks, &ksem_head, ks_entry)
153 1.1 christos if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
154 1.1 christos return (ks);
155 1.1 christos return (NULL);
156 1.1 christos }
157 1.1 christos
158 1.1 christos static int
159 1.1 christos ksem_create(l, name, ksret, mode, value)
160 1.1 christos struct lwp *l;
161 1.1 christos const char *name;
162 1.1 christos struct ksem **ksret;
163 1.1 christos mode_t mode;
164 1.1 christos unsigned int value;
165 1.1 christos {
166 1.1 christos struct ksem *ret;
167 1.1 christos struct proc *p;
168 1.1 christos struct ucred *uc;
169 1.1 christos size_t len;
170 1.1 christos int error;
171 1.1 christos
172 1.1 christos DP(("ksem_create %s %p %d %u\n", name ? name : "(null)", ksret, mode,
173 1.1 christos value));
174 1.1 christos p = l->l_proc;
175 1.1 christos uc = p->p_ucred;
176 1.1 christos if (value > SEM_VALUE_MAX)
177 1.1 christos return (EINVAL);
178 1.1 christos ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
179 1.1 christos if (name != NULL) {
180 1.1 christos len = strlen(name);
181 1.1 christos if (len > SEM_MAX_NAMELEN) {
182 1.1 christos free(ret, M_SEM);
183 1.1 christos return (ENAMETOOLONG);
184 1.1 christos }
185 1.1 christos /* name must start with a '/' but not contain one. */
186 1.1 christos if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
187 1.1 christos free(ret, M_SEM);
188 1.1 christos return (EINVAL);
189 1.1 christos }
190 1.1 christos ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
191 1.1 christos strcpy(ret->ks_name, name);
192 1.1 christos } else {
193 1.1 christos ret->ks_name = NULL;
194 1.1 christos }
195 1.1 christos ret->ks_mode = mode;
196 1.1 christos ret->ks_value = value;
197 1.1 christos ret->ks_ref = 1;
198 1.1 christos ret->ks_waiters = 0;
199 1.1 christos ret->ks_uid = uc->cr_uid;
200 1.1 christos ret->ks_gid = uc->cr_gid;
201 1.1 christos ret->ks_onlist = 0;
202 1.1 christos LIST_INIT(&ret->ks_users);
203 1.1 christos if (name != NULL)
204 1.1 christos ksem_enter(l->l_proc, ret);
205 1.1 christos *ksret = ret;
206 1.1 christos simple_lock(&ksem_slock);
207 1.1 christos if (nsems >= SEM_MAX) {
208 1.1 christos ksem_leave(l->l_proc, ret);
209 1.1 christos ksem_free(ret);
210 1.1 christos error = ENFILE;
211 1.1 christos } else {
212 1.1 christos nsems++;
213 1.1 christos error = 0;
214 1.1 christos }
215 1.1 christos simple_unlock(&ksem_slock);
216 1.1 christos return (error);
217 1.1 christos }
218 1.1 christos
219 1.1 christos int
220 1.2 christos sys__ksem_init(struct lwp *l, void *v, register_t *retval)
221 1.1 christos {
222 1.2 christos struct sys__ksem_init_args /* {
223 1.1 christos unsigned int value;
224 1.1 christos semid_t *idp;
225 1.1 christos } */ *uap = v;
226 1.1 christos struct ksem *ks;
227 1.1 christos semid_t id;
228 1.1 christos int error;
229 1.1 christos
230 1.1 christos error = ksem_create(l, NULL, &ks, S_IRWXU | S_IRWXG, SCARG(uap, value));
231 1.1 christos if (error)
232 1.1 christos return (error);
233 1.1 christos id = SEM_TO_ID(ks);
234 1.1 christos error = copyout(&id, SCARG(uap, idp), sizeof(id));
235 1.1 christos if (error) {
236 1.1 christos simple_lock(&ksem_slock);
237 1.1 christos ksem_rel(ks);
238 1.1 christos simple_unlock(&ksem_slock);
239 1.1 christos return (error);
240 1.1 christos }
241 1.1 christos simple_lock(&ksem_slock);
242 1.1 christos LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
243 1.1 christos ks->ks_onlist = 1;
244 1.1 christos simple_unlock(&ksem_slock);
245 1.1 christos return (error);
246 1.1 christos }
247 1.1 christos
248 1.1 christos int
249 1.2 christos sys__ksem_open(struct lwp *l, void *v, register_t *retval)
250 1.1 christos {
251 1.2 christos struct sys__ksem_open_args /* {
252 1.1 christos const char *name;
253 1.1 christos int oflag;
254 1.1 christos mode_t mode;
255 1.1 christos unsigned int value;
256 1.1 christos semid_t *idp;
257 1.1 christos } */ *uap = v;
258 1.1 christos char name[SEM_MAX_NAMELEN + 1];
259 1.1 christos size_t done;
260 1.1 christos int error;
261 1.1 christos struct ksem *ksnew, *ks;
262 1.1 christos semid_t id;
263 1.1 christos
264 1.1 christos error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
265 1.1 christos if (error)
266 1.1 christos return (error);
267 1.1 christos
268 1.1 christos ksnew = NULL;
269 1.1 christos simple_lock(&ksem_slock);
270 1.1 christos ks = ksem_lookup_byname(name);
271 1.1 christos /*
272 1.1 christos * If we found it but O_EXCL is set, error.
273 1.1 christos */
274 1.1 christos if (ks != NULL && (SCARG(uap, oflag) & O_EXCL) != 0) {
275 1.1 christos simple_unlock(&ksem_slock);
276 1.1 christos return (EEXIST);
277 1.1 christos }
278 1.1 christos /*
279 1.1 christos * If we didn't find it...
280 1.1 christos */
281 1.1 christos if (ks == NULL) {
282 1.1 christos /*
283 1.1 christos * didn't ask for creation? error.
284 1.1 christos */
285 1.1 christos if ((SCARG(uap, oflag) & O_CREAT) == 0) {
286 1.1 christos simple_unlock(&ksem_slock);
287 1.1 christos return (ENOENT);
288 1.1 christos }
289 1.1 christos /*
290 1.1 christos * We may block during creation, so drop the lock.
291 1.1 christos */
292 1.1 christos simple_unlock(&ksem_slock);
293 1.1 christos error = ksem_create(l, name, &ksnew, SCARG(uap, mode),
294 1.1 christos SCARG(uap, value));
295 1.1 christos if (error != 0)
296 1.1 christos return (error);
297 1.1 christos id = SEM_TO_ID(ksnew);
298 1.1 christos DP(("about to copyout! 0x%lx to %p\n", id, SCARG(uap, idp)));
299 1.1 christos error = copyout(&id, SCARG(uap, idp), sizeof(id));
300 1.1 christos if (error) {
301 1.1 christos simple_lock(&ksem_slock);
302 1.1 christos ksem_leave(l->l_proc, ksnew);
303 1.1 christos ksem_rel(ksnew);
304 1.1 christos simple_unlock(&ksem_slock);
305 1.1 christos return (error);
306 1.1 christos }
307 1.1 christos /*
308 1.1 christos * We need to make sure we haven't lost a race while
309 1.1 christos * allocating during creation.
310 1.1 christos */
311 1.1 christos simple_lock(&ksem_slock);
312 1.1 christos ks = ksem_lookup_byname(name);
313 1.1 christos if (ks != NULL) {
314 1.1 christos /* we lost... */
315 1.1 christos ksem_leave(l->l_proc, ksnew);
316 1.1 christos ksem_rel(ksnew);
317 1.1 christos /* we lost and we can't loose... */
318 1.1 christos if ((SCARG(uap, oflag) & O_EXCL) != 0) {
319 1.1 christos simple_unlock(&ksem_slock);
320 1.1 christos return (EEXIST);
321 1.1 christos }
322 1.1 christos } else {
323 1.1 christos DP(("ksem_create: about to add to list...\n"));
324 1.1 christos LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
325 1.1 christos DP(("ksem_create: setting list bit...\n"));
326 1.1 christos ksnew->ks_onlist = 1;
327 1.1 christos DP(("ksem_create: done, about to unlock...\n"));
328 1.1 christos }
329 1.1 christos simple_unlock(&ksem_slock);
330 1.1 christos } else {
331 1.1 christos /*
332 1.1 christos * if we aren't the creator, then enforce permissions.
333 1.1 christos */
334 1.1 christos error = ksem_perm(l->l_proc, ks);
335 1.1 christos if (!error)
336 1.1 christos ksem_ref(ks);
337 1.1 christos simple_unlock(&ksem_slock);
338 1.1 christos if (error)
339 1.1 christos return (error);
340 1.1 christos id = SEM_TO_ID(ks);
341 1.1 christos error = copyout(&id, SCARG(uap, idp), sizeof(id));
342 1.1 christos if (error) {
343 1.1 christos simple_lock(&ksem_slock);
344 1.1 christos ksem_rel(ks);
345 1.1 christos simple_unlock(&ksem_slock);
346 1.1 christos return (error);
347 1.1 christos }
348 1.1 christos ksem_enter(l->l_proc, ks);
349 1.1 christos simple_lock(&ksem_slock);
350 1.1 christos ksem_rel(ks);
351 1.1 christos simple_unlock(&ksem_slock);
352 1.1 christos }
353 1.1 christos return (error);
354 1.1 christos }
355 1.1 christos
356 1.1 christos static int
357 1.1 christos ksem_perm(p, ks)
358 1.1 christos struct proc *p;
359 1.1 christos struct ksem *ks;
360 1.1 christos {
361 1.1 christos struct ucred *uc;
362 1.1 christos
363 1.1 christos uc = p->p_ucred;
364 1.1 christos DP(("ksem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
365 1.1 christos uc->cr_uid, uc->cr_gid,
366 1.1 christos ks->ks_uid, ks->ks_gid, ks->ks_mode));
367 1.1 christos if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
368 1.1 christos (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
369 1.1 christos (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
370 1.1 christos return (0);
371 1.1 christos return (EPERM);
372 1.1 christos }
373 1.1 christos
374 1.1 christos static void
375 1.1 christos ksem_free(struct ksem *ks)
376 1.1 christos {
377 1.1 christos nsems--;
378 1.1 christos if (ks->ks_onlist)
379 1.1 christos LIST_REMOVE(ks, ks_entry);
380 1.1 christos if (ks->ks_name != NULL)
381 1.1 christos free(ks->ks_name, M_SEM);
382 1.1 christos free(ks, M_SEM);
383 1.1 christos }
384 1.1 christos
385 1.1 christos static __inline struct kuser *
386 1.1 christos ksem_getuser(struct proc *p, struct ksem *ks)
387 1.1 christos {
388 1.1 christos struct kuser *k;
389 1.1 christos
390 1.1 christos LIST_FOREACH(k, &ks->ks_users, ku_next)
391 1.1 christos if (k->ku_pid == p->p_pid)
392 1.1 christos return (k);
393 1.1 christos return (NULL);
394 1.1 christos }
395 1.1 christos
396 1.1 christos static int
397 1.1 christos ksem_hasopen(struct proc *p, struct ksem *ks)
398 1.1 christos {
399 1.1 christos
400 1.1 christos return ((ks->ks_name == NULL && ksem_perm(p, ks))
401 1.1 christos || ksem_getuser(p, ks) != NULL);
402 1.1 christos }
403 1.1 christos
404 1.1 christos static int
405 1.1 christos ksem_leave(struct proc *p, struct ksem *ks)
406 1.1 christos {
407 1.1 christos struct kuser *k;
408 1.1 christos
409 1.1 christos DP(("ksem_leave: ks = %p\n", ks));
410 1.1 christos k = ksem_getuser(p, ks);
411 1.1 christos DP(("ksem_leave: ks = %p, k = %p\n", ks, k));
412 1.1 christos if (k != NULL) {
413 1.1 christos LIST_REMOVE(k, ku_next);
414 1.1 christos ksem_rel(ks);
415 1.1 christos DP(("ksem_leave: about to free k\n"));
416 1.1 christos free(k, M_SEM);
417 1.1 christos DP(("ksem_leave: returning\n"));
418 1.1 christos return (0);
419 1.1 christos }
420 1.1 christos return (EINVAL);
421 1.1 christos }
422 1.1 christos
423 1.1 christos static void
424 1.1 christos ksem_enter(struct proc *p, struct ksem *ks)
425 1.1 christos {
426 1.1 christos struct kuser *ku, *k;
427 1.1 christos
428 1.1 christos ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
429 1.1 christos ku->ku_pid = p->p_pid;
430 1.1 christos simple_lock(&ksem_slock);
431 1.1 christos k = ksem_getuser(p, ks);
432 1.1 christos if (k != NULL) {
433 1.1 christos simple_unlock(&ksem_slock);
434 1.1 christos free(ku, M_TEMP);
435 1.1 christos return;
436 1.1 christos }
437 1.1 christos LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
438 1.1 christos ksem_ref(ks);
439 1.1 christos simple_unlock(&ksem_slock);
440 1.1 christos }
441 1.1 christos
442 1.1 christos int
443 1.2 christos sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
444 1.1 christos {
445 1.2 christos struct sys__ksem_unlink_args /* {
446 1.1 christos const char *name;
447 1.1 christos } */ *uap = v;
448 1.1 christos char name[SEM_MAX_NAMELEN + 1];
449 1.1 christos size_t done;
450 1.1 christos struct ksem *ks;
451 1.1 christos int error;
452 1.1 christos
453 1.1 christos error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
454 1.1 christos if (error)
455 1.1 christos return error;
456 1.1 christos
457 1.1 christos simple_lock(&ksem_slock);
458 1.1 christos ks = ksem_lookup_byname(name);
459 1.1 christos if (ks == NULL)
460 1.1 christos error = ENOENT;
461 1.1 christos else
462 1.1 christos error = ksem_perm(l->l_proc, ks);
463 1.1 christos DP(("ksem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
464 1.1 christos if (error == 0) {
465 1.1 christos LIST_REMOVE(ks, ks_entry);
466 1.1 christos LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry);
467 1.1 christos ksem_rel(ks);
468 1.1 christos }
469 1.1 christos simple_unlock(&ksem_slock);
470 1.1 christos return (error);
471 1.1 christos }
472 1.1 christos
473 1.1 christos int
474 1.2 christos sys__ksem_close(struct lwp *l, void *v, register_t *retval)
475 1.1 christos {
476 1.2 christos struct sys__ksem_close_args /* {
477 1.1 christos semid_t id;
478 1.1 christos } */ *uap = v;
479 1.1 christos struct ksem *ks;
480 1.1 christos int error;
481 1.1 christos
482 1.1 christos error = EINVAL;
483 1.1 christos simple_lock(&ksem_slock);
484 1.1 christos ks = ID_TO_SEM(SCARG(uap, id));
485 1.1 christos /* this is not a valid operation for unnamed sems */
486 1.1 christos if (ks != NULL && ks->ks_name != NULL)
487 1.1 christos error = ksem_leave(l->l_proc, ks);
488 1.1 christos simple_unlock(&ksem_slock);
489 1.1 christos return (error);
490 1.1 christos }
491 1.1 christos
492 1.1 christos int
493 1.2 christos sys__ksem_post(struct lwp *l, void *v, register_t *retval)
494 1.1 christos {
495 1.2 christos struct sys__ksem_post_args /* {
496 1.1 christos semid_t id;
497 1.1 christos } */ *uap = v;
498 1.1 christos struct ksem *ks;
499 1.1 christos int error;
500 1.1 christos
501 1.1 christos simple_lock(&ksem_slock);
502 1.1 christos ks = ID_TO_SEM(SCARG(uap, id));
503 1.1 christos if (ks == NULL || !ksem_hasopen(l->l_proc, ks)) {
504 1.1 christos error = EINVAL;
505 1.1 christos goto err;
506 1.1 christos }
507 1.1 christos if (ks->ks_value == SEM_VALUE_MAX) {
508 1.1 christos error = EOVERFLOW;
509 1.1 christos goto err;
510 1.1 christos }
511 1.1 christos ++ks->ks_value;
512 1.1 christos if (ks->ks_waiters > 0)
513 1.1 christos wakeup(ks);
514 1.1 christos error = 0;
515 1.1 christos err:
516 1.1 christos simple_unlock(&ksem_slock);
517 1.1 christos return (error);
518 1.1 christos }
519 1.1 christos
520 1.1 christos int
521 1.2 christos sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
522 1.1 christos {
523 1.2 christos struct sys__ksem_wait_args /* {
524 1.1 christos semid_t id;
525 1.1 christos } */ *uap = v;
526 1.1 christos
527 1.1 christos return ksem_wait(l, SCARG(uap, id), 0);
528 1.1 christos }
529 1.1 christos
530 1.1 christos int
531 1.2 christos sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
532 1.1 christos {
533 1.2 christos struct sys__ksem_trywait_args /* {
534 1.1 christos semid_t id;
535 1.1 christos } */ *uap = v;
536 1.1 christos
537 1.1 christos return ksem_wait(l, SCARG(uap, id), 1);
538 1.1 christos }
539 1.1 christos
540 1.1 christos static int
541 1.1 christos ksem_wait(struct lwp *l, semid_t id, int tryflag)
542 1.1 christos {
543 1.1 christos struct ksem *ks;
544 1.1 christos int error;
545 1.1 christos
546 1.1 christos DP((">>> kern_sem_wait entered!\n"));
547 1.1 christos simple_lock(&ksem_slock);
548 1.1 christos ks = ID_TO_SEM(id);
549 1.1 christos if (ks == NULL) {
550 1.1 christos DP(("kern_sem_wait ks == NULL\n"));
551 1.1 christos error = EINVAL;
552 1.1 christos goto err;
553 1.1 christos }
554 1.1 christos ksem_ref(ks);
555 1.1 christos if (!ksem_hasopen(l->l_proc, ks)) {
556 1.1 christos DP(("kern_sem_wait hasopen failed\n"));
557 1.1 christos error = EINVAL;
558 1.1 christos goto err;
559 1.1 christos }
560 1.1 christos DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
561 1.1 christos if (ks->ks_value == 0) {
562 1.1 christos ks->ks_waiters++;
563 1.1 christos error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
564 1.1 christos &ksem_slock);
565 1.1 christos ks->ks_waiters--;
566 1.1 christos if (error)
567 1.1 christos goto err;
568 1.1 christos }
569 1.1 christos ks->ks_value--;
570 1.1 christos error = 0;
571 1.1 christos err:
572 1.1 christos if (ks != NULL)
573 1.1 christos ksem_rel(ks);
574 1.1 christos simple_unlock(&ksem_slock);
575 1.1 christos DP(("<<< kern_sem_wait leaving, error = %d\n", error));
576 1.1 christos return (error);
577 1.1 christos }
578 1.1 christos
579 1.1 christos int
580 1.2 christos sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
581 1.1 christos {
582 1.2 christos struct sys__ksem_getvalue_args /* {
583 1.1 christos semid_t id;
584 1.1 christos unsigned int *value;
585 1.1 christos } */ *uap = v;
586 1.1 christos struct ksem *ks;
587 1.1 christos unsigned int val;
588 1.1 christos
589 1.1 christos simple_lock(&ksem_slock);
590 1.1 christos ks = ID_TO_SEM(SCARG(uap, id));
591 1.1 christos if (ks == NULL || !ksem_hasopen(l->l_proc, ks)) {
592 1.1 christos simple_unlock(&ksem_slock);
593 1.1 christos return (EINVAL);
594 1.1 christos }
595 1.1 christos val = ks->ks_value;
596 1.1 christos simple_unlock(&ksem_slock);
597 1.1 christos return copyout(&val, SCARG(uap, value), sizeof(val));
598 1.1 christos }
599 1.1 christos
600 1.1 christos int
601 1.2 christos sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
602 1.1 christos {
603 1.2 christos struct sys__ksem_destroy_args /*{
604 1.1 christos semid_t id;
605 1.1 christos } */ *uap = v;
606 1.1 christos struct ksem *ks;
607 1.1 christos int error;
608 1.1 christos
609 1.1 christos simple_lock(&ksem_slock);
610 1.1 christos ks = ID_TO_SEM(SCARG(uap, id));
611 1.1 christos if (ks == NULL || !ksem_hasopen(l->l_proc, ks) ||
612 1.1 christos ks->ks_name != NULL) {
613 1.1 christos error = EINVAL;
614 1.1 christos goto err;
615 1.1 christos }
616 1.1 christos if (ks->ks_waiters != 0) {
617 1.1 christos error = EBUSY;
618 1.1 christos goto err;
619 1.1 christos }
620 1.1 christos ksem_rel(ks);
621 1.1 christos error = 0;
622 1.1 christos err:
623 1.1 christos simple_unlock(&ksem_slock);
624 1.1 christos return (error);
625 1.1 christos }
626 1.1 christos
627 1.1 christos static void
628 1.1 christos ksem_exithook(struct proc *p, void *arg)
629 1.1 christos {
630 1.1 christos struct ksem *ks, *ksnext;
631 1.1 christos
632 1.1 christos simple_lock(&ksem_slock);
633 1.1 christos ks = LIST_FIRST(&ksem_head);
634 1.1 christos while (ks != NULL) {
635 1.1 christos ksnext = LIST_NEXT(ks, ks_entry);
636 1.1 christos ksem_leave(p, ks);
637 1.1 christos ks = ksnext;
638 1.1 christos }
639 1.1 christos ks = LIST_FIRST(&ksem_deadhead);
640 1.1 christos while (ks != NULL) {
641 1.1 christos ksnext = LIST_NEXT(ks, ks_entry);
642 1.1 christos ksem_leave(p, ks);
643 1.1 christos ks = ksnext;
644 1.1 christos }
645 1.1 christos simple_unlock(&ksem_slock);
646 1.1 christos }
647 1.1 christos
648 1.1 christos void
649 1.1 christos ksem_init(void)
650 1.1 christos {
651 1.1 christos simple_lock_init(&ksem_slock);
652 1.1 christos exithook_establish(ksem_exithook, NULL);
653 1.1 christos exechook_establish(ksem_exithook, NULL);
654 1.1 christos }
655