FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_sem.c
1 /*
2 * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/5.2/sys/kern/uipc_sem.c 116182 2003-06-11 00:56:59Z obrien $");
29
30 #include "opt_posix.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sysproto.h>
35 #include <sys/eventhandler.h>
36 #include <sys/kernel.h>
37 #include <sys/proc.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/condvar.h>
41 #include <sys/sem.h>
42 #include <sys/uio.h>
43 #include <sys/syscall.h>
44 #include <sys/stat.h>
45 #include <sys/sysent.h>
46 #include <sys/sysctl.h>
47 #include <sys/malloc.h>
48 #include <sys/jail.h>
49 #include <sys/fcntl.h>
50
51 #include <posix4/posix4.h>
52 #include <posix4/semaphore.h>
53 #include <posix4/_semaphore.h>
54
55 static struct ksem *sem_lookup_byname(const char *name);
56 static int sem_create(struct thread *td, const char *name,
57 struct ksem **ksret, mode_t mode, unsigned int value);
58 static void sem_free(struct ksem *ksnew);
59 static int sem_perm(struct thread *td, struct ksem *ks);
60 static void sem_enter(struct proc *p, struct ksem *ks);
61 static int sem_leave(struct proc *p, struct ksem *ks);
62 static void sem_exithook(void *arg, struct proc *p);
63 static int sem_hasopen(struct thread *td, struct ksem *ks);
64
65 static int kern_sem_close(struct thread *td, semid_t id);
66 static int kern_sem_post(struct thread *td, semid_t id);
67 static int kern_sem_wait(struct thread *td, semid_t id, int tryflag);
68 static int kern_sem_init(struct thread *td, int dir, unsigned int value,
69 semid_t *idp);
70 static int kern_sem_open(struct thread *td, int dir, const char *name,
71 int oflag, mode_t mode, unsigned int value, semid_t *idp);
72 static int kern_sem_unlink(struct thread *td, const char *name);
73
74 #ifndef SEM_MAX
75 #define SEM_MAX 30
76 #endif
77
78 #define SEM_MAX_NAMELEN 14
79
80 #define SEM_TO_ID(x) ((intptr_t)(x))
81 #define ID_TO_SEM(x) id_to_sem(x)
82
83 struct kuser {
84 pid_t ku_pid;
85 LIST_ENTRY(kuser) ku_next;
86 };
87
88 struct ksem {
89 LIST_ENTRY(ksem) ks_entry; /* global list entry */
90 int ks_onlist; /* boolean if on a list (ks_entry) */
91 char *ks_name; /* if named, this is the name */
92 int ks_ref; /* number of references */
93 mode_t ks_mode; /* protection bits */
94 uid_t ks_uid; /* creator uid */
95 gid_t ks_gid; /* creator gid */
96 unsigned int ks_value; /* current value */
97 struct cv ks_cv; /* waiters sleep here */
98 int ks_waiters; /* number of waiters */
99 LIST_HEAD(, kuser) ks_users; /* pids using this sem */
100 };
101
102 /*
103 * available semaphores go here, this includes sem_init and any semaphores
104 * created via sem_open that have not yet been unlinked.
105 */
106 LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
107 /*
108 * semaphores still in use but have been sem_unlink()'d go here.
109 */
110 LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
111
112 static struct mtx sem_lock;
113 static MALLOC_DEFINE(M_SEM, "sems", "semaphore data");
114
115 static int nsems = 0;
116 SYSCTL_DECL(_p1003_1b);
117 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0, "");
118
119 static eventhandler_tag sem_exit_tag, sem_exec_tag;
120
121 #ifdef SEM_DEBUG
122 #define DP(x) printf x
123 #else
124 #define DP(x)
125 #endif
126
127 static __inline
128 void
129 sem_ref(struct ksem *ks)
130 {
131
132 ks->ks_ref++;
133 DP(("sem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
134 }
135
136 static __inline
137 void
138 sem_rel(struct ksem *ks)
139 {
140
141 DP(("sem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
142 if (--ks->ks_ref == 0)
143 sem_free(ks);
144 }
145
146 static __inline struct ksem *id_to_sem(semid_t id);
147
148 static __inline
149 struct ksem *
150 id_to_sem(id)
151 semid_t id;
152 {
153 struct ksem *ks;
154
155 DP(("id_to_sem: id = %0x,%p\n", id, (struct ksem *)id));
156 LIST_FOREACH(ks, &ksem_head, ks_entry) {
157 DP(("id_to_sem: ks = %p\n", ks));
158 if (ks == (struct ksem *)id)
159 return (ks);
160 }
161 return (NULL);
162 }
163
164 static struct ksem *
165 sem_lookup_byname(name)
166 const char *name;
167 {
168 struct ksem *ks;
169
170 LIST_FOREACH(ks, &ksem_head, ks_entry)
171 if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
172 return (ks);
173 return (NULL);
174 }
175
176 static int
177 sem_create(td, name, ksret, mode, value)
178 struct thread *td;
179 const char *name;
180 struct ksem **ksret;
181 mode_t mode;
182 unsigned int value;
183 {
184 struct ksem *ret;
185 struct proc *p;
186 struct ucred *uc;
187 size_t len;
188 int error;
189
190 DP(("sem_create\n"));
191 p = td->td_proc;
192 uc = td->td_ucred;
193 if (value > SEM_VALUE_MAX)
194 return (EINVAL);
195 ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
196 if (name != NULL) {
197 len = strlen(name);
198 if (len > SEM_MAX_NAMELEN) {
199 free(ret, M_SEM);
200 return (ENAMETOOLONG);
201 }
202 /* name must start with a '/' but not contain one. */
203 if (*name != '/' || len < 2 || index(name + 1, '/') != NULL) {
204 free(ret, M_SEM);
205 return (EINVAL);
206 }
207 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
208 strcpy(ret->ks_name, name);
209 } else {
210 ret->ks_name = NULL;
211 }
212 ret->ks_mode = mode;
213 ret->ks_value = value;
214 ret->ks_ref = 1;
215 ret->ks_waiters = 0;
216 ret->ks_uid = uc->cr_uid;
217 ret->ks_gid = uc->cr_gid;
218 ret->ks_onlist = 0;
219 cv_init(&ret->ks_cv, "sem");
220 LIST_INIT(&ret->ks_users);
221 if (name != NULL)
222 sem_enter(td->td_proc, ret);
223 *ksret = ret;
224 mtx_lock(&sem_lock);
225 if (nsems >= p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX)) {
226 sem_leave(td->td_proc, ret);
227 sem_free(ret);
228 error = ENFILE;
229 } else {
230 nsems++;
231 error = 0;
232 }
233 mtx_unlock(&sem_lock);
234 return (error);
235 }
236
237 #ifndef _SYS_SYSPROTO_H_
238 struct ksem_init_args {
239 unsigned int value;
240 semid_t *idp;
241 };
242 int ksem_init(struct thread *td, struct ksem_init_args *uap);
243 #endif
244 int
245 ksem_init(td, uap)
246 struct thread *td;
247 struct ksem_init_args *uap;
248 {
249 int error;
250
251 error = kern_sem_init(td, UIO_USERSPACE, uap->value, uap->idp);
252 return (error);
253 }
254
255 static int
256 kern_sem_init(td, dir, value, idp)
257 struct thread *td;
258 int dir;
259 unsigned int value;
260 semid_t *idp;
261 {
262 struct ksem *ks;
263 semid_t id;
264 int error;
265
266 error = sem_create(td, NULL, &ks, S_IRWXU | S_IRWXG, value);
267 if (error)
268 return (error);
269 id = SEM_TO_ID(ks);
270 if (dir == UIO_USERSPACE) {
271 error = copyout(&id, idp, sizeof(id));
272 if (error) {
273 mtx_lock(&sem_lock);
274 sem_rel(ks);
275 mtx_unlock(&sem_lock);
276 return (error);
277 }
278 } else {
279 *idp = id;
280 }
281 mtx_lock(&sem_lock);
282 LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
283 ks->ks_onlist = 1;
284 mtx_unlock(&sem_lock);
285 return (error);
286 }
287
288 #ifndef _SYS_SYSPROTO_H_
289 struct ksem_open_args {
290 char *name;
291 int oflag;
292 mode_t mode;
293 unsigned int value;
294 semid_t *idp;
295 };
296 int ksem_open(struct thread *td, struct ksem_open_args *uap);
297 #endif
298 int
299 ksem_open(td, uap)
300 struct thread *td;
301 struct ksem_open_args *uap;
302 {
303 char name[SEM_MAX_NAMELEN + 1];
304 size_t done;
305 int error;
306
307 error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
308 if (error)
309 return (error);
310 DP((">>> sem_open start\n"));
311 error = kern_sem_open(td, UIO_USERSPACE,
312 name, uap->oflag, uap->mode, uap->value, uap->idp);
313 DP(("<<< sem_open end\n"));
314 return (error);
315 }
316
317 static int
318 kern_sem_open(td, dir, name, oflag, mode, value, idp)
319 struct thread *td;
320 int dir;
321 const char *name;
322 int oflag;
323 mode_t mode;
324 unsigned int value;
325 semid_t *idp;
326 {
327 struct ksem *ksnew, *ks;
328 int error;
329 semid_t id;
330
331 ksnew = NULL;
332 mtx_lock(&sem_lock);
333 ks = sem_lookup_byname(name);
334 /*
335 * If we found it but O_EXCL is set, error.
336 */
337 if (ks != NULL && (oflag & O_EXCL) != 0) {
338 mtx_unlock(&sem_lock);
339 return (EEXIST);
340 }
341 /*
342 * If we didn't find it...
343 */
344 if (ks == NULL) {
345 /*
346 * didn't ask for creation? error.
347 */
348 if ((oflag & O_CREAT) == 0) {
349 mtx_unlock(&sem_lock);
350 return (ENOENT);
351 }
352 /*
353 * We may block during creation, so drop the lock.
354 */
355 mtx_unlock(&sem_lock);
356 error = sem_create(td, name, &ksnew, mode, value);
357 if (error != 0)
358 return (error);
359 id = SEM_TO_ID(ksnew);
360 if (dir == UIO_USERSPACE) {
361 DP(("about to copyout! %d to %p\n", id, idp));
362 error = copyout(&id, idp, sizeof(id));
363 if (error) {
364 mtx_lock(&sem_lock);
365 sem_leave(td->td_proc, ksnew);
366 sem_rel(ksnew);
367 mtx_unlock(&sem_lock);
368 return (error);
369 }
370 } else {
371 DP(("about to set! %d to %p\n", id, idp));
372 *idp = id;
373 }
374 /*
375 * We need to make sure we haven't lost a race while
376 * allocating during creation.
377 */
378 mtx_lock(&sem_lock);
379 ks = sem_lookup_byname(name);
380 if (ks != NULL) {
381 /* we lost... */
382 sem_leave(td->td_proc, ksnew);
383 sem_rel(ksnew);
384 /* we lost and we can't loose... */
385 if ((oflag & O_EXCL) != 0) {
386 mtx_unlock(&sem_lock);
387 return (EEXIST);
388 }
389 } else {
390 DP(("sem_create: about to add to list...\n"));
391 LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
392 DP(("sem_create: setting list bit...\n"));
393 ksnew->ks_onlist = 1;
394 DP(("sem_create: done, about to unlock...\n"));
395 }
396 mtx_unlock(&sem_lock);
397 } else {
398 /*
399 * if we aren't the creator, then enforce permissions.
400 */
401 error = sem_perm(td, ks);
402 if (!error)
403 sem_ref(ks);
404 mtx_unlock(&sem_lock);
405 if (error)
406 return (error);
407 id = SEM_TO_ID(ks);
408 if (dir == UIO_USERSPACE) {
409 error = copyout(&id, idp, sizeof(id));
410 if (error) {
411 mtx_lock(&sem_lock);
412 sem_rel(ks);
413 mtx_unlock(&sem_lock);
414 return (error);
415 }
416 } else {
417 *idp = id;
418 }
419 sem_enter(td->td_proc, ks);
420 mtx_lock(&sem_lock);
421 sem_rel(ks);
422 mtx_unlock(&sem_lock);
423 }
424 return (error);
425 }
426
427 static int
428 sem_perm(td, ks)
429 struct thread *td;
430 struct ksem *ks;
431 {
432 struct ucred *uc;
433
434 uc = td->td_ucred;
435 DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
436 uc->cr_uid, uc->cr_gid,
437 ks->ks_uid, ks->ks_gid, ks->ks_mode));
438 if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
439 (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
440 (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0)
441 return (0);
442 return (EPERM);
443 }
444
445 static void
446 sem_free(struct ksem *ks)
447 {
448
449 nsems--;
450 if (ks->ks_onlist)
451 LIST_REMOVE(ks, ks_entry);
452 if (ks->ks_name != NULL)
453 free(ks->ks_name, M_SEM);
454 cv_destroy(&ks->ks_cv);
455 free(ks, M_SEM);
456 }
457
458 static __inline struct kuser *sem_getuser(struct proc *p, struct ksem *ks);
459
460 static __inline struct kuser *
461 sem_getuser(p, ks)
462 struct proc *p;
463 struct ksem *ks;
464 {
465 struct kuser *k;
466
467 LIST_FOREACH(k, &ks->ks_users, ku_next)
468 if (k->ku_pid == p->p_pid)
469 return (k);
470 return (NULL);
471 }
472
473 static int
474 sem_hasopen(td, ks)
475 struct thread *td;
476 struct ksem *ks;
477 {
478
479 return ((ks->ks_name == NULL && sem_perm(td, ks))
480 || sem_getuser(td->td_proc, ks) != NULL);
481 }
482
483 static int
484 sem_leave(p, ks)
485 struct proc *p;
486 struct ksem *ks;
487 {
488 struct kuser *k;
489
490 DP(("sem_leave: ks = %p\n", ks));
491 k = sem_getuser(p, ks);
492 DP(("sem_leave: ks = %p, k = %p\n", ks, k));
493 if (k != NULL) {
494 LIST_REMOVE(k, ku_next);
495 sem_rel(ks);
496 DP(("sem_leave: about to free k\n"));
497 free(k, M_SEM);
498 DP(("sem_leave: returning\n"));
499 return (0);
500 }
501 return (EINVAL);
502 }
503
504 static void
505 sem_enter(p, ks)
506 struct proc *p;
507 struct ksem *ks;
508 {
509 struct kuser *ku, *k;
510
511 ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
512 ku->ku_pid = p->p_pid;
513 mtx_lock(&sem_lock);
514 k = sem_getuser(p, ks);
515 if (k != NULL) {
516 mtx_unlock(&sem_lock);
517 free(ku, M_TEMP);
518 return;
519 }
520 LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
521 sem_ref(ks);
522 mtx_unlock(&sem_lock);
523 }
524
525 #ifndef _SYS_SYSPROTO_H_
526 struct ksem_unlink_args {
527 char *name;
528 };
529 int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap);
530 #endif
531
532 int
533 ksem_unlink(td, uap)
534 struct thread *td;
535 struct ksem_unlink_args *uap;
536 {
537 char name[SEM_MAX_NAMELEN + 1];
538 size_t done;
539 int error;
540
541 error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
542 return (error ? error :
543 kern_sem_unlink(td, name));
544 }
545
546 static int
547 kern_sem_unlink(td, name)
548 struct thread *td;
549 const char *name;
550 {
551 struct ksem *ks;
552 int error;
553
554 mtx_lock(&sem_lock);
555 ks = sem_lookup_byname(name);
556 if (ks == NULL)
557 error = ENOENT;
558 else
559 error = sem_perm(td, ks);
560 DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
561 if (error == 0) {
562 LIST_REMOVE(ks, ks_entry);
563 LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry);
564 sem_rel(ks);
565 }
566 mtx_unlock(&sem_lock);
567 return (error);
568 }
569
570 #ifndef _SYS_SYSPROTO_H_
571 struct ksem_close_args {
572 semid_t id;
573 };
574 int ksem_close(struct thread *td, struct ksem_close_args *uap);
575 #endif
576
577 int
578 ksem_close(struct thread *td, struct ksem_close_args *uap)
579 {
580
581 return (kern_sem_close(td, uap->id));
582 }
583
584 static int
585 kern_sem_close(td, id)
586 struct thread *td;
587 semid_t id;
588 {
589 struct ksem *ks;
590 int error;
591
592 error = EINVAL;
593 mtx_lock(&sem_lock);
594 ks = ID_TO_SEM(id);
595 /* this is not a valid operation for unnamed sems */
596 if (ks != NULL && ks->ks_name != NULL)
597 error = sem_leave(td->td_proc, ks);
598 mtx_unlock(&sem_lock);
599 return (error);
600 }
601
602 #ifndef _SYS_SYSPROTO_H_
603 struct ksem_post_args {
604 semid_t id;
605 };
606 int ksem_post(struct thread *td, struct ksem_post_args *uap);
607 #endif
608 int
609 ksem_post(td, uap)
610 struct thread *td;
611 struct ksem_post_args *uap;
612 {
613
614 return (kern_sem_post(td, uap->id));
615 }
616
617 static int
618 kern_sem_post(td, id)
619 struct thread *td;
620 semid_t id;
621 {
622 struct ksem *ks;
623 int error;
624
625 mtx_lock(&sem_lock);
626 ks = ID_TO_SEM(id);
627 if (ks == NULL || !sem_hasopen(td, ks)) {
628 error = EINVAL;
629 goto err;
630 }
631 if (ks->ks_value == SEM_VALUE_MAX) {
632 error = EOVERFLOW;
633 goto err;
634 }
635 ++ks->ks_value;
636 if (ks->ks_waiters > 0)
637 cv_signal(&ks->ks_cv);
638 error = 0;
639 err:
640 mtx_unlock(&sem_lock);
641 return (error);
642 }
643
644 #ifndef _SYS_SYSPROTO_H_
645 struct ksem_wait_args {
646 semid_t id;
647 };
648 int ksem_wait(struct thread *td, struct ksem_wait_args *uap);
649 #endif
650
651 int
652 ksem_wait(td, uap)
653 struct thread *td;
654 struct ksem_wait_args *uap;
655 {
656
657 return (kern_sem_wait(td, uap->id, 0));
658 }
659
660 #ifndef _SYS_SYSPROTO_H_
661 struct ksem_trywait_args {
662 semid_t id;
663 };
664 int ksem_trywait(struct thread *td, struct ksem_trywait_args *uap);
665 #endif
666 int
667 ksem_trywait(td, uap)
668 struct thread *td;
669 struct ksem_trywait_args *uap;
670 {
671
672 return (kern_sem_wait(td, uap->id, 1));
673 }
674
675 static int
676 kern_sem_wait(td, id, tryflag)
677 struct thread *td;
678 semid_t id;
679 int tryflag;
680 {
681 struct ksem *ks;
682 int error;
683
684 DP((">>> kern_sem_wait entered!\n"));
685 mtx_lock(&sem_lock);
686 ks = ID_TO_SEM(id);
687 if (ks == NULL) {
688 DP(("kern_sem_wait ks == NULL\n"));
689 error = EINVAL;
690 goto err;
691 }
692 sem_ref(ks);
693 if (!sem_hasopen(td, ks)) {
694 DP(("kern_sem_wait hasopen failed\n"));
695 error = EINVAL;
696 goto err;
697 }
698 DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
699 if (ks->ks_value == 0) {
700 ks->ks_waiters++;
701 error = tryflag ? EAGAIN : cv_wait_sig(&ks->ks_cv, &sem_lock);
702 ks->ks_waiters--;
703 if (error)
704 goto err;
705 }
706 ks->ks_value--;
707 error = 0;
708 err:
709 if (ks != NULL)
710 sem_rel(ks);
711 mtx_unlock(&sem_lock);
712 DP(("<<< kern_sem_wait leaving, error = %d\n", error));
713 return (error);
714 }
715
716 #ifndef _SYS_SYSPROTO_H_
717 struct ksem_getvalue_args {
718 semid_t id;
719 int *val;
720 };
721 int ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap);
722 #endif
723 int
724 ksem_getvalue(td, uap)
725 struct thread *td;
726 struct ksem_getvalue_args *uap;
727 {
728 struct ksem *ks;
729 int error, val;
730
731 mtx_lock(&sem_lock);
732 ks = ID_TO_SEM(uap->id);
733 if (ks == NULL || !sem_hasopen(td, ks)) {
734 mtx_unlock(&sem_lock);
735 return (EINVAL);
736 }
737 val = ks->ks_value;
738 mtx_unlock(&sem_lock);
739 error = copyout(&val, uap->val, sizeof(val));
740 return (error);
741 }
742
743 #ifndef _SYS_SYSPROTO_H_
744 struct ksem_destroy_args {
745 semid_t id;
746 };
747 int ksem_destroy(struct thread *td, struct ksem_destroy_args *uap);
748 #endif
749 int
750 ksem_destroy(td, uap)
751 struct thread *td;
752 struct ksem_destroy_args *uap;
753 {
754 struct ksem *ks;
755 int error;
756
757 mtx_lock(&sem_lock);
758 ks = ID_TO_SEM(uap->id);
759 if (ks == NULL || !sem_hasopen(td, ks) ||
760 ks->ks_name != NULL) {
761 error = EINVAL;
762 goto err;
763 }
764 if (ks->ks_waiters != 0) {
765 error = EBUSY;
766 goto err;
767 }
768 sem_rel(ks);
769 error = 0;
770 err:
771 mtx_unlock(&sem_lock);
772 return (error);
773 }
774
775 static void
776 sem_exithook(arg, p)
777 void *arg;
778 struct proc *p;
779 {
780 struct ksem *ks, *ksnext;
781
782 mtx_lock(&sem_lock);
783 ks = LIST_FIRST(&ksem_head);
784 while (ks != NULL) {
785 ksnext = LIST_NEXT(ks, ks_entry);
786 sem_leave(p, ks);
787 ks = ksnext;
788 }
789 ks = LIST_FIRST(&ksem_deadhead);
790 while (ks != NULL) {
791 ksnext = LIST_NEXT(ks, ks_entry);
792 sem_leave(p, ks);
793 ks = ksnext;
794 }
795 mtx_unlock(&sem_lock);
796 }
797
798 static int
799 sem_modload(struct module *module, int cmd, void *arg)
800 {
801 int error = 0;
802
803 switch (cmd) {
804 case MOD_LOAD:
805 mtx_init(&sem_lock, "sem", "semaphore", MTX_DEF);
806 p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
807 p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
808 sem_exit_tag = EVENTHANDLER_REGISTER(process_exit, sem_exithook,
809 NULL, EVENTHANDLER_PRI_ANY);
810 sem_exec_tag = EVENTHANDLER_REGISTER(process_exec, sem_exithook,
811 NULL, EVENTHANDLER_PRI_ANY);
812 break;
813 case MOD_UNLOAD:
814 if (nsems != 0) {
815 error = EOPNOTSUPP;
816 break;
817 }
818 EVENTHANDLER_DEREGISTER(process_exit, sem_exit_tag);
819 EVENTHANDLER_DEREGISTER(process_exec, sem_exec_tag);
820 mtx_destroy(&sem_lock);
821 break;
822 case MOD_SHUTDOWN:
823 break;
824 default:
825 error = EINVAL;
826 break;
827 }
828 return (error);
829 }
830
831 static moduledata_t sem_mod = {
832 "sem",
833 &sem_modload,
834 NULL
835 };
836
837 SYSCALL_MODULE_HELPER(ksem_init);
838 SYSCALL_MODULE_HELPER(ksem_open);
839 SYSCALL_MODULE_HELPER(ksem_unlink);
840 SYSCALL_MODULE_HELPER(ksem_close);
841 SYSCALL_MODULE_HELPER(ksem_post);
842 SYSCALL_MODULE_HELPER(ksem_wait);
843 SYSCALL_MODULE_HELPER(ksem_trywait);
844 SYSCALL_MODULE_HELPER(ksem_getvalue);
845 SYSCALL_MODULE_HELPER(ksem_destroy);
846
847 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
848 MODULE_VERSION(sem, 1);
Cache object: 39ccb7a0f3d2e76d375ebcac6e650fc4
|