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