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