]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/uipc_sem.c
Move definitions of 'struct kuser' and 'struct ksem' from uipc_sem.c
[FreeBSD/FreeBSD.git] / sys / kern / uipc_sem.c
1 /*-
2  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
3  * Copyright (c) 2005 Robert N. M. Watson
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, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_posix.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/eventhandler.h>
37 #include <sys/kernel.h>
38 #include <sys/proc.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/module.h>
42 #include <sys/condvar.h>
43 #include <sys/sem.h>
44 #include <sys/uio.h>
45 #include <sys/syscall.h>
46 #include <sys/stat.h>
47 #include <sys/sysent.h>
48 #include <sys/sysctl.h>
49 #include <sys/time.h>
50 #include <sys/malloc.h>
51 #include <sys/fcntl.h>
52
53 #include <posix4/ksem.h>
54 #include <posix4/posix4.h>
55 #include <posix4/semaphore.h>
56 #include <posix4/_semaphore.h>
57
58 static int sem_count_proc(struct proc *p);
59 static struct ksem *sem_lookup_byname(const char *name);
60 static int sem_create(struct thread *td, const char *name,
61     struct ksem **ksret, mode_t mode, unsigned int value);
62 static void sem_free(struct ksem *ksnew);
63 static int sem_perm(struct thread *td, struct ksem *ks);
64 static void sem_enter(struct proc *p, struct ksem *ks);
65 static int sem_leave(struct proc *p, struct ksem *ks);
66 static void sem_exithook(void *arg, struct proc *p);
67 static void sem_forkhook(void *arg, struct proc *p1, struct proc *p2,
68     int flags);
69 static int sem_hasopen(struct thread *td, struct ksem *ks);
70
71 static int kern_sem_close(struct thread *td, semid_t id);
72 static int kern_sem_post(struct thread *td, semid_t id);
73 static int kern_sem_wait(struct thread *td, semid_t id, int tryflag,
74     struct timespec *abstime);
75 static int kern_sem_init(struct thread *td, int dir, unsigned int value,
76     semid_t *idp);
77 static int kern_sem_open(struct thread *td, int dir, const char *name,
78     int oflag, mode_t mode, unsigned int value, semid_t *idp);
79 static int kern_sem_unlink(struct thread *td, const char *name);
80
81 #ifndef SEM_MAX
82 #define SEM_MAX 30
83 #endif
84
85 #define SEM_MAX_NAMELEN 14
86
87 #define SEM_TO_ID(x)    ((intptr_t)(x))
88 #define ID_TO_SEM(x)    id_to_sem(x)
89
90 /*
91  * available semaphores go here, this includes sem_init and any semaphores
92  * created via sem_open that have not yet been unlinked.
93  */
94 LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
95 /*
96  * semaphores still in use but have been sem_unlink()'d go here.
97  */
98 LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
99
100 static struct mtx sem_lock;
101 static MALLOC_DEFINE(M_SEM, "sems", "semaphore data");
102
103 static int nsems = 0;
104 SYSCTL_DECL(_p1003_1b);
105 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0, "");
106
107 static eventhandler_tag sem_exit_tag, sem_exec_tag, sem_fork_tag;
108
109 #ifdef SEM_DEBUG
110 #define DP(x)   printf x
111 #else
112 #define DP(x)
113 #endif
114
115 static __inline
116 void
117 sem_ref(struct ksem *ks)
118 {
119
120         mtx_assert(&sem_lock, MA_OWNED);
121         ks->ks_ref++;
122         DP(("sem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
123 }
124
125 static __inline
126 void
127 sem_rel(struct ksem *ks)
128 {
129
130         mtx_assert(&sem_lock, MA_OWNED);
131         DP(("sem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
132         if (--ks->ks_ref == 0)
133                 sem_free(ks);
134 }
135
136 static __inline struct ksem *id_to_sem(semid_t id);
137
138 static __inline
139 struct ksem *
140 id_to_sem(id)
141         semid_t id;
142 {
143         struct ksem *ks;
144
145         mtx_assert(&sem_lock, MA_OWNED);
146         DP(("id_to_sem: id = %0x,%p\n", id, (struct ksem *)id));
147         LIST_FOREACH(ks, &ksem_head, ks_entry) {
148                 DP(("id_to_sem: ks = %p\n", ks));
149                 if (ks == (struct ksem *)id)
150                         return (ks);
151         }
152         return (NULL);
153 }
154
155 static struct ksem *
156 sem_lookup_byname(name)
157         const char *name;
158 {
159         struct ksem *ks;
160
161         mtx_assert(&sem_lock, MA_OWNED);
162         LIST_FOREACH(ks, &ksem_head, ks_entry)
163                 if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
164                         return (ks);
165         return (NULL);
166 }
167
168 static int
169 sem_create(td, name, ksret, mode, value)
170         struct thread *td;
171         const char *name;
172         struct ksem **ksret;
173         mode_t mode;
174         unsigned int value;
175 {
176         struct ksem *ret;
177         struct proc *p;
178         struct ucred *uc;
179         size_t len;
180         int error;
181
182         DP(("sem_create\n"));
183         p = td->td_proc;
184         uc = td->td_ucred;
185         if (value > SEM_VALUE_MAX)
186                 return (EINVAL);
187         ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
188         if (name != NULL) {
189                 len = strlen(name);
190                 if (len > SEM_MAX_NAMELEN) {
191                         free(ret, M_SEM);
192                         return (ENAMETOOLONG);
193                 }
194                 /* name must start with a '/' but not contain one. */
195                 if (*name != '/' || len < 2 || index(name + 1, '/') != NULL) {
196                         free(ret, M_SEM);
197                         return (EINVAL);
198                 }
199                 ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
200                 strcpy(ret->ks_name, name);
201         } else {
202                 ret->ks_name = NULL;
203         }
204         ret->ks_mode = mode;
205         ret->ks_value = value;
206         ret->ks_ref = 1;
207         ret->ks_waiters = 0;
208         ret->ks_uid = uc->cr_uid;
209         ret->ks_gid = uc->cr_gid;
210         ret->ks_onlist = 0;
211         cv_init(&ret->ks_cv, "sem");
212         LIST_INIT(&ret->ks_users);
213         if (name != NULL)
214                 sem_enter(td->td_proc, ret);
215         *ksret = ret;
216         mtx_lock(&sem_lock);
217         if (nsems >= p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX)) {
218                 sem_leave(td->td_proc, ret);
219                 sem_free(ret);
220                 error = ENFILE;
221         } else {
222                 nsems++;
223                 error = 0;
224         }
225         mtx_unlock(&sem_lock);
226         return (error);
227 }
228
229 #ifndef _SYS_SYSPROTO_H_
230 struct ksem_init_args {
231         unsigned int value;
232         semid_t *idp;
233 };
234 int ksem_init(struct thread *td, struct ksem_init_args *uap);
235 #endif
236 int
237 ksem_init(td, uap)
238         struct thread *td;
239         struct ksem_init_args *uap;
240 {
241         int error;
242
243         error = kern_sem_init(td, UIO_USERSPACE, uap->value, uap->idp);
244         return (error);
245 }
246
247 static int
248 kern_sem_init(td, dir, value, idp)
249         struct thread *td;
250         int dir;
251         unsigned int value;
252         semid_t *idp;
253 {
254         struct ksem *ks;
255         semid_t id;
256         int error;
257
258         error = sem_create(td, NULL, &ks, S_IRWXU | S_IRWXG, value);
259         if (error)
260                 return (error);
261         id = SEM_TO_ID(ks);
262         if (dir == UIO_USERSPACE) {
263                 error = copyout(&id, idp, sizeof(id));
264                 if (error) {
265                         mtx_lock(&sem_lock);
266                         sem_rel(ks);
267                         mtx_unlock(&sem_lock);
268                         return (error);
269                 }
270         } else {
271                 *idp = id;
272         }
273         mtx_lock(&sem_lock);
274         LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
275         ks->ks_onlist = 1;
276         mtx_unlock(&sem_lock);
277         return (error);
278 }
279
280 #ifndef _SYS_SYSPROTO_H_
281 struct ksem_open_args {
282         char *name;
283         int oflag;
284         mode_t mode;
285         unsigned int value;
286         semid_t *idp;   
287 };
288 int ksem_open(struct thread *td, struct ksem_open_args *uap);
289 #endif
290 int
291 ksem_open(td, uap)
292         struct thread *td;
293         struct ksem_open_args *uap;
294 {
295         char name[SEM_MAX_NAMELEN + 1];
296         size_t done;
297         int error;
298
299         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
300         if (error)
301                 return (error);
302         DP((">>> sem_open start\n"));
303         error = kern_sem_open(td, UIO_USERSPACE,
304             name, uap->oflag, uap->mode, uap->value, uap->idp);
305         DP(("<<< sem_open end\n"));
306         return (error);
307 }
308
309 static int
310 kern_sem_open(td, dir, name, oflag, mode, value, idp)
311         struct thread *td;
312         int dir;
313         const char *name;
314         int oflag;
315         mode_t mode;
316         unsigned int value;
317         semid_t *idp;
318 {
319         struct ksem *ksnew, *ks;
320         int error;
321         semid_t id;
322
323         ksnew = NULL;
324         mtx_lock(&sem_lock);
325         ks = sem_lookup_byname(name);
326         /*
327          * If we found it but O_EXCL is set, error.
328          */
329         if (ks != NULL && (oflag & O_EXCL) != 0) {
330                 mtx_unlock(&sem_lock);
331                 return (EEXIST);
332         }
333         /*
334          * If we didn't find it...
335          */
336         if (ks == NULL) {
337                 /*
338                  * didn't ask for creation? error.
339                  */
340                 if ((oflag & O_CREAT) == 0) {
341                         mtx_unlock(&sem_lock);
342                         return (ENOENT);
343                 }
344                 /*
345                  * We may block during creation, so drop the lock.
346                  */
347                 mtx_unlock(&sem_lock);
348                 error = sem_create(td, name, &ksnew, mode, value);
349                 if (error != 0)
350                         return (error);
351                 id = SEM_TO_ID(ksnew);
352                 if (dir == UIO_USERSPACE) {
353                         DP(("about to copyout! %d to %p\n", id, idp));
354                         error = copyout(&id, idp, sizeof(id));
355                         if (error) {
356                                 mtx_lock(&sem_lock);
357                                 sem_leave(td->td_proc, ksnew);
358                                 sem_rel(ksnew);
359                                 mtx_unlock(&sem_lock);
360                                 return (error);
361                         }
362                 } else {
363                         DP(("about to set! %d to %p\n", id, idp));
364                         *idp = id;
365                 }
366                 /*
367                  * We need to make sure we haven't lost a race while
368                  * allocating during creation.
369                  */
370                 mtx_lock(&sem_lock);
371                 ks = sem_lookup_byname(name);
372                 if (ks != NULL) {
373                         /* we lost... */
374                         sem_leave(td->td_proc, ksnew);
375                         sem_rel(ksnew);
376                         /* we lost and we can't loose... */
377                         if ((oflag & O_EXCL) != 0) {
378                                 mtx_unlock(&sem_lock);
379                                 return (EEXIST);
380                         }
381                 } else {
382                         DP(("sem_create: about to add to list...\n"));
383                         LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry); 
384                         DP(("sem_create: setting list bit...\n"));
385                         ksnew->ks_onlist = 1;
386                         DP(("sem_create: done, about to unlock...\n"));
387                 }
388                 mtx_unlock(&sem_lock);
389         } else {
390                 /*
391                  * if we aren't the creator, then enforce permissions.
392                  */
393                 error = sem_perm(td, ks);
394                 if (!error)
395                         sem_ref(ks);
396                 mtx_unlock(&sem_lock);
397                 if (error)
398                         return (error);
399                 id = SEM_TO_ID(ks);
400                 if (dir == UIO_USERSPACE) {
401                         error = copyout(&id, idp, sizeof(id));
402                         if (error) {
403                                 mtx_lock(&sem_lock);
404                                 sem_rel(ks);
405                                 mtx_unlock(&sem_lock);
406                                 return (error);
407                         }
408                 } else {
409                         *idp = id;
410                 }
411                 sem_enter(td->td_proc, ks);
412                 mtx_lock(&sem_lock);
413                 sem_rel(ks);
414                 mtx_unlock(&sem_lock);
415         }
416         return (error);
417 }
418
419 static int
420 sem_perm(td, ks)
421         struct thread *td;
422         struct ksem *ks;
423 {
424         struct ucred *uc;
425
426         uc = td->td_ucred;
427         DP(("sem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
428             uc->cr_uid, uc->cr_gid,
429              ks->ks_uid, ks->ks_gid, ks->ks_mode));
430         if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
431             (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
432             (ks->ks_mode & S_IWOTH) != 0 || suser(td) == 0)
433                 return (0);
434         return (EPERM);
435 }
436
437 static void
438 sem_free(struct ksem *ks)
439 {
440
441         nsems--;
442         if (ks->ks_onlist)
443                 LIST_REMOVE(ks, ks_entry);
444         if (ks->ks_name != NULL)
445                 free(ks->ks_name, M_SEM);
446         cv_destroy(&ks->ks_cv);
447         free(ks, M_SEM);
448 }
449
450 static __inline struct kuser *sem_getuser(struct proc *p, struct ksem *ks);
451
452 static __inline struct kuser *
453 sem_getuser(p, ks)
454         struct proc *p;
455         struct ksem *ks;
456 {
457         struct kuser *k;
458
459         LIST_FOREACH(k, &ks->ks_users, ku_next)
460                 if (k->ku_pid == p->p_pid)
461                         return (k);
462         return (NULL);
463 }
464
465 static int
466 sem_hasopen(td, ks)
467         struct thread *td;
468         struct ksem *ks;
469 {
470         
471         return ((ks->ks_name == NULL && sem_perm(td, ks) == 0)
472             || sem_getuser(td->td_proc, ks) != NULL);
473 }
474
475 static int
476 sem_leave(p, ks)
477         struct proc *p;
478         struct ksem *ks;
479 {
480         struct kuser *k;
481
482         DP(("sem_leave: ks = %p\n", ks));
483         k = sem_getuser(p, ks);
484         DP(("sem_leave: ks = %p, k = %p\n", ks, k));
485         if (k != NULL) {
486                 LIST_REMOVE(k, ku_next);
487                 sem_rel(ks);
488                 DP(("sem_leave: about to free k\n"));
489                 free(k, M_SEM);
490                 DP(("sem_leave: returning\n"));
491                 return (0);
492         }
493         return (EINVAL);
494 }
495
496 static void
497 sem_enter(p, ks)
498         struct proc *p;
499         struct ksem *ks;
500 {
501         struct kuser *ku, *k;
502
503         ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
504         ku->ku_pid = p->p_pid;
505         mtx_lock(&sem_lock);
506         k = sem_getuser(p, ks);
507         if (k != NULL) {
508                 mtx_unlock(&sem_lock);
509                 free(ku, M_TEMP);
510                 return;
511         }
512         LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
513         sem_ref(ks);
514         mtx_unlock(&sem_lock);
515 }
516
517 #ifndef _SYS_SYSPROTO_H_
518 struct ksem_unlink_args {
519         char *name;
520 };
521 int ksem_unlink(struct thread *td, struct ksem_unlink_args *uap);
522 #endif
523         
524 int
525 ksem_unlink(td, uap)
526         struct thread *td;
527         struct ksem_unlink_args *uap;
528 {
529         char name[SEM_MAX_NAMELEN + 1];
530         size_t done;
531         int error;
532
533         error = copyinstr(uap->name, name, SEM_MAX_NAMELEN + 1, &done);
534         return (error ? error :
535             kern_sem_unlink(td, name));
536 }
537
538 static int
539 kern_sem_unlink(td, name)
540         struct thread *td;
541         const char *name;
542 {
543         struct ksem *ks;
544         int error;
545
546         mtx_lock(&sem_lock);
547         ks = sem_lookup_byname(name);
548         if (ks == NULL)
549                 error = ENOENT;
550         else
551                 error = sem_perm(td, ks);
552         DP(("sem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
553         if (error == 0) {
554                 LIST_REMOVE(ks, ks_entry);
555                 LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry); 
556                 sem_rel(ks);
557         }
558         mtx_unlock(&sem_lock);
559         return (error);
560 }
561
562 #ifndef _SYS_SYSPROTO_H_
563 struct ksem_close_args {
564         semid_t id;
565 };
566 int ksem_close(struct thread *td, struct ksem_close_args *uap);
567 #endif
568
569 int
570 ksem_close(struct thread *td, struct ksem_close_args *uap)
571 {
572
573         return (kern_sem_close(td, uap->id));
574 }
575
576 static int
577 kern_sem_close(td, id)
578         struct thread *td;
579         semid_t id;
580 {
581         struct ksem *ks;
582         int error;
583
584         error = EINVAL;
585         mtx_lock(&sem_lock);
586         ks = ID_TO_SEM(id);
587         /* this is not a valid operation for unnamed sems */
588         if (ks != NULL && ks->ks_name != NULL)
589                 error = sem_leave(td->td_proc, ks);
590         mtx_unlock(&sem_lock);
591         return (error);
592 }
593
594 #ifndef _SYS_SYSPROTO_H_
595 struct ksem_post_args {
596         semid_t id;
597 };
598 int ksem_post(struct thread *td, struct ksem_post_args *uap);
599 #endif
600 int
601 ksem_post(td, uap)
602         struct thread *td;
603         struct ksem_post_args *uap;
604 {
605
606         return (kern_sem_post(td, uap->id));
607 }
608
609 static int
610 kern_sem_post(td, id)
611         struct thread *td;
612         semid_t id;
613 {
614         struct ksem *ks;
615         int error;
616
617         mtx_lock(&sem_lock);
618         ks = ID_TO_SEM(id);
619         if (ks == NULL || !sem_hasopen(td, ks)) {
620                 error = EINVAL;
621                 goto err;
622         }
623         if (ks->ks_value == SEM_VALUE_MAX) {
624                 error = EOVERFLOW;
625                 goto err;
626         }
627         ++ks->ks_value;
628         if (ks->ks_waiters > 0)
629                 cv_signal(&ks->ks_cv);
630         error = 0;
631 err:
632         mtx_unlock(&sem_lock);
633         return (error);
634 }
635
636 #ifndef _SYS_SYSPROTO_H_
637 struct ksem_wait_args {
638         semid_t id;
639 };
640 int ksem_wait(struct thread *td, struct ksem_wait_args *uap);
641 #endif
642
643 int
644 ksem_wait(td, uap)
645         struct thread *td;
646         struct ksem_wait_args *uap;
647 {
648
649         return (kern_sem_wait(td, uap->id, 0, NULL));
650 }
651
652 #ifndef _SYS_SYSPROTO_H_
653 struct ksem_timedwait_args {
654         semid_t id;
655         struct timespec *abstime;
656 };
657 int ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap);
658 #endif
659 int
660 ksem_timedwait(td, uap)
661         struct thread *td;
662         struct ksem_timedwait_args *uap;
663 {
664         struct timespec abstime;
665         struct timespec *ts;
666         int error;
667
668         /* We allow a null timespec (wait forever). */
669         if (uap->abstime == NULL)
670                 ts = NULL;
671         else {
672                 error = copyin(uap->abstime, &abstime, sizeof(abstime));
673                 if (error != 0)
674                         return (error);
675                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
676                         return (EINVAL);
677                 ts = &abstime;
678         }
679         return (kern_sem_wait(td, uap->id, 0, ts));
680 }
681
682 #ifndef _SYS_SYSPROTO_H_
683 struct ksem_trywait_args {
684         semid_t id;
685 };
686 int ksem_trywait(struct thread *td, struct ksem_trywait_args *uap);
687 #endif
688 int
689 ksem_trywait(td, uap)
690         struct thread *td;
691         struct ksem_trywait_args *uap;
692 {
693
694         return (kern_sem_wait(td, uap->id, 1, NULL));
695 }
696
697 static int
698 kern_sem_wait(td, id, tryflag, abstime)
699         struct thread *td;
700         semid_t id;
701         int tryflag;
702         struct timespec *abstime;
703 {
704         struct timespec ts1, ts2;
705         struct timeval tv;
706         struct ksem *ks;
707         int error;
708
709         DP((">>> kern_sem_wait entered!\n"));
710         mtx_lock(&sem_lock);
711         ks = ID_TO_SEM(id);
712         if (ks == NULL) {
713                 DP(("kern_sem_wait ks == NULL\n"));
714                 error = EINVAL;
715                 goto err;
716         }
717         sem_ref(ks);
718         if (!sem_hasopen(td, ks)) {
719                 DP(("kern_sem_wait hasopen failed\n"));
720                 error = EINVAL;
721                 goto err;
722         }
723         DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
724         if (ks->ks_value == 0) {
725                 ks->ks_waiters++;
726                 if (tryflag != 0)
727                         error = EAGAIN;
728                 else if (abstime == NULL)
729                         error = cv_wait_sig(&ks->ks_cv, &sem_lock);
730                 else {
731                         for (;;) {
732                                 ts1 = *abstime;
733                                 getnanotime(&ts2);
734                                 timespecsub(&ts1, &ts2);
735                                 TIMESPEC_TO_TIMEVAL(&tv, &ts1);
736                                 if (tv.tv_sec < 0) {
737                                         error = ETIMEDOUT;
738                                         break;
739                                 }
740                                 error = cv_timedwait_sig(&ks->ks_cv,
741                                     &sem_lock, tvtohz(&tv));
742                                 if (error != EWOULDBLOCK)
743                                         break;
744                         }
745                 }
746                 ks->ks_waiters--;
747                 if (error)
748                         goto err;
749         }
750         ks->ks_value--;
751         error = 0;
752 err:
753         if (ks != NULL)
754                 sem_rel(ks);
755         mtx_unlock(&sem_lock);
756         DP(("<<< kern_sem_wait leaving, error = %d\n", error));
757         return (error);
758 }
759
760 #ifndef _SYS_SYSPROTO_H_
761 struct ksem_getvalue_args {
762         semid_t id;
763         int *val;
764 };
765 int ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap);
766 #endif
767 int
768 ksem_getvalue(td, uap)
769         struct thread *td;
770         struct ksem_getvalue_args *uap;
771 {
772         struct ksem *ks;
773         int error, val;
774
775         mtx_lock(&sem_lock);
776         ks = ID_TO_SEM(uap->id);
777         if (ks == NULL || !sem_hasopen(td, ks)) {
778                 mtx_unlock(&sem_lock);
779                 return (EINVAL);
780         }
781         val = ks->ks_value;
782         mtx_unlock(&sem_lock);
783         error = copyout(&val, uap->val, sizeof(val));
784         return (error);
785 }
786
787 #ifndef _SYS_SYSPROTO_H_
788 struct ksem_destroy_args {
789         semid_t id;
790 };
791 int ksem_destroy(struct thread *td, struct ksem_destroy_args *uap);
792 #endif
793 int
794 ksem_destroy(td, uap)
795         struct thread *td;
796         struct ksem_destroy_args *uap;
797 {
798         struct ksem *ks;
799         int error;
800
801         mtx_lock(&sem_lock);
802         ks = ID_TO_SEM(uap->id);
803         if (ks == NULL || !sem_hasopen(td, ks) ||
804             ks->ks_name != NULL) {
805                 error = EINVAL;
806                 goto err;
807         }
808         if (ks->ks_waiters != 0) {
809                 error = EBUSY;
810                 goto err;
811         }
812         sem_rel(ks);
813         error = 0;
814 err:
815         mtx_unlock(&sem_lock);
816         return (error);
817 }
818
819 /*
820  * Count the number of kusers associated with a proc, so as to guess at how
821  * many to allocate when forking.
822  */
823 static int
824 sem_count_proc(p)
825         struct proc *p;
826 {
827         struct ksem *ks;
828         struct kuser *ku;
829         int count;
830
831         mtx_assert(&sem_lock, MA_OWNED);
832
833         count = 0;
834         LIST_FOREACH(ks, &ksem_head, ks_entry) {
835                 LIST_FOREACH(ku, &ks->ks_users, ku_next) {
836                         if (ku->ku_pid == p->p_pid)
837                                 count++;
838                 }
839         }
840         LIST_FOREACH(ks, &ksem_deadhead, ks_entry) {
841                 LIST_FOREACH(ku, &ks->ks_users, ku_next) {
842                         if (ku->ku_pid == p->p_pid)
843                                 count++;
844                 }
845         }
846         return (count);
847 }
848
849 /*
850  * When a process forks, the child process must gain a reference to each open
851  * semaphore in the parent process, whether it is unlinked or not.  This
852  * requires allocating a kuser structure for each semaphore reference in the
853  * new process.  Because the set of semaphores in the parent can change while
854  * the fork is in progress, we have to handle races -- first we attempt to
855  * allocate enough storage to acquire references to each of the semaphores,
856  * then we enter the semaphores and release the temporary references.
857  */
858 static void
859 sem_forkhook(arg, p1, p2, flags)
860         void *arg;
861         struct proc *p1;
862         struct proc *p2;
863         int flags;
864 {
865         struct ksem *ks, **sem_array;
866         int count, i, new_count;
867         struct kuser *ku;
868
869         mtx_lock(&sem_lock);
870         count = sem_count_proc(p1);
871 race_lost:
872         mtx_assert(&sem_lock, MA_OWNED);
873         mtx_unlock(&sem_lock);
874         sem_array = malloc(sizeof(struct ksem *) * count, M_TEMP, M_WAITOK);
875         mtx_lock(&sem_lock);
876         new_count = sem_count_proc(p1);
877         if (count < new_count) {
878                 /* Lost race, repeat and allocate more storage. */
879                 free(sem_array, M_TEMP);
880                 count = new_count;
881                 goto race_lost;
882         }
883         /*
884          * Given an array capable of storing an adequate number of semaphore
885          * references, now walk the list of semaphores and acquire a new
886          * reference for any semaphore opened by p1.
887          */
888         count = new_count;
889         i = 0;
890         LIST_FOREACH(ks, &ksem_head, ks_entry) {
891                 LIST_FOREACH(ku, &ks->ks_users, ku_next) {
892                         if (ku->ku_pid == p1->p_pid) {
893                                 sem_ref(ks);
894                                 sem_array[i] = ks;
895                                 i++;
896                                 break;
897                         }
898                 }
899         }
900         LIST_FOREACH(ks, &ksem_deadhead, ks_entry) {
901                 LIST_FOREACH(ku, &ks->ks_users, ku_next) {
902                         if (ku->ku_pid == p1->p_pid) {
903                                 sem_ref(ks);
904                                 sem_array[i] = ks;
905                                 i++;
906                                 break;
907                         }
908                 }
909         }
910         mtx_unlock(&sem_lock);
911         KASSERT(i == count, ("sem_forkhook: i != count (%d, %d)", i, count));
912         /*
913          * Now cause p2 to enter each of the referenced semaphores, then
914          * release our temporary reference.  This is pretty inefficient.
915          * Finally, free our temporary array.
916          */
917         for (i = 0; i < count; i++) {
918                 sem_enter(p2, sem_array[i]);
919                 mtx_lock(&sem_lock);
920                 sem_rel(sem_array[i]);
921                 mtx_unlock(&sem_lock);
922         }
923         free(sem_array, M_TEMP);
924 }
925
926 static void
927 sem_exithook(arg, p)
928         void *arg;
929         struct proc *p;
930 {
931         struct ksem *ks, *ksnext;
932
933         mtx_lock(&sem_lock);
934         ks = LIST_FIRST(&ksem_head);
935         while (ks != NULL) {
936                 ksnext = LIST_NEXT(ks, ks_entry);
937                 sem_leave(p, ks);
938                 ks = ksnext;
939         }
940         ks = LIST_FIRST(&ksem_deadhead);
941         while (ks != NULL) {
942                 ksnext = LIST_NEXT(ks, ks_entry);
943                 sem_leave(p, ks);
944                 ks = ksnext;
945         }
946         mtx_unlock(&sem_lock);
947 }
948
949 static int
950 sem_modload(struct module *module, int cmd, void *arg)
951 {
952         int error = 0;
953
954         switch (cmd) {
955         case MOD_LOAD:
956                 mtx_init(&sem_lock, "sem", "semaphore", MTX_DEF);
957                 p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
958                 p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
959                 sem_exit_tag = EVENTHANDLER_REGISTER(process_exit, sem_exithook,
960                     NULL, EVENTHANDLER_PRI_ANY);
961                 sem_exec_tag = EVENTHANDLER_REGISTER(process_exec, sem_exithook,
962                     NULL, EVENTHANDLER_PRI_ANY);
963                 sem_fork_tag = EVENTHANDLER_REGISTER(process_fork, sem_forkhook, NULL, EVENTHANDLER_PRI_ANY);
964                 break;
965         case MOD_UNLOAD:
966                 if (nsems != 0) {
967                         error = EOPNOTSUPP;
968                         break;
969                 }
970                 EVENTHANDLER_DEREGISTER(process_exit, sem_exit_tag);
971                 EVENTHANDLER_DEREGISTER(process_exec, sem_exec_tag);
972                 EVENTHANDLER_DEREGISTER(process_fork, sem_fork_tag);
973                 mtx_destroy(&sem_lock);
974                 break;
975         case MOD_SHUTDOWN:
976                 break;
977         default:
978                 error = EINVAL;
979                 break;
980         }
981         return (error);
982 }
983
984 static moduledata_t sem_mod = {
985         "sem",
986         &sem_modload,
987         NULL
988 };
989
990 SYSCALL_MODULE_HELPER(ksem_init);
991 SYSCALL_MODULE_HELPER(ksem_open);
992 SYSCALL_MODULE_HELPER(ksem_unlink);
993 SYSCALL_MODULE_HELPER(ksem_close);
994 SYSCALL_MODULE_HELPER(ksem_post);
995 SYSCALL_MODULE_HELPER(ksem_wait);
996 SYSCALL_MODULE_HELPER(ksem_timedwait);
997 SYSCALL_MODULE_HELPER(ksem_trywait);
998 SYSCALL_MODULE_HELPER(ksem_getvalue);
999 SYSCALL_MODULE_HELPER(ksem_destroy);
1000
1001 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
1002 MODULE_VERSION(sem, 1);