Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_sem.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/uipc_sem.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.12 retrieving revision 1.12.6.1 diff -u -p -r1.12 -r1.12.6.1 --- src/sys/kern/uipc_sem.c 2005/12/24 19:12:23 1.12 +++ src/sys/kern/uipc_sem.c 2006/04/22 11:39:59 1.12.6.1 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_sem.c,v 1.12 2005/12/24 19:12:23 perry Exp $ */ +/* $NetBSD: uipc_sem.c,v 1.12.6.1 2006/04/22 11:39:59 simonb Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -63,7 +63,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.12 2005/12/24 19:12:23 perry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.12.6.1 2006/04/22 11:39:59 simonb Exp $"); #include "opt_posix.h" @@ -89,8 +89,10 @@ __KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v #define SEM_MAX_NAMELEN 14 #define SEM_VALUE_MAX (~0U) +#define SEM_HASHTBL_SIZE 13 -#define SEM_TO_ID(x) ((intptr_t)(x)) +#define SEM_TO_ID(x) (((x)->ks_id)) +#define SEM_HASH(id) ((id) % SEM_HASHTBL_SIZE) MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores"); @@ -101,6 +103,7 @@ MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1 */ struct ksem { LIST_ENTRY(ksem) ks_entry; /* global list entry */ + LIST_ENTRY(ksem) ks_hash; /* hash list entry */ struct simplelock ks_interlock; /* lock on this ksem */ char *ks_name; /* if named, this is the name */ unsigned int ks_ref; /* number of references */ @@ -109,6 +112,7 @@ struct ksem { gid_t ks_gid; /* creator gid */ unsigned int ks_value; /* current value */ unsigned int ks_waiters; /* number of waiters */ + semid_t ks_id; /* unique identifier */ }; struct ksem_ref { @@ -121,14 +125,24 @@ struct ksem_proc { LIST_HEAD(, ksem_ref) kp_ksems; }; +LIST_HEAD(ksem_list, ksem); + /* * ksem_slock protects ksem_head and nsems. Only named semaphores go * onto ksem_head. */ static struct simplelock ksem_slock; -static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head); +static struct ksem_list ksem_head = LIST_HEAD_INITIALIZER(&ksem_head); +static struct ksem_list ksem_hash[SEM_HASHTBL_SIZE]; static int nsems = 0; +/* + * ksem_counter is the last assigned semid_t. It needs to be COMPAT_NETBSD32 + * friendly, even though semid_t itself is defined as uintptr_t. + */ +static uint32_t ksem_counter = 1; + + static void ksem_free(struct ksem *ks) { @@ -140,11 +154,13 @@ ksem_free(struct ksem *ks) */ if (ks->ks_name == NULL) { simple_unlock(&ks->ks_interlock); - free(ks, M_SEM); simple_lock(&ksem_slock); nsems--; + LIST_REMOVE(ks, ks_hash); simple_unlock(&ksem_slock); + + free(ks, M_SEM); return; } simple_unlock(&ks->ks_interlock); @@ -239,6 +255,19 @@ ksem_perm(struct proc *p, struct ksem *k } static struct ksem * +ksem_lookup_byid(semid_t id) +{ + struct ksem *ks; + + LOCK_ASSERT(simple_lock_held(&ksem_slock)); + LIST_FOREACH(ks, &ksem_hash[SEM_HASH(id)], ks_hash) { + if (ks->ks_id == id) + return ks; + } + return NULL; +} + +static struct ksem * ksem_lookup_byname(const char *name) { struct ksem *ks; @@ -297,6 +326,14 @@ ksem_create(struct proc *p, const char * return (ENFILE); } nsems++; + while (ksem_lookup_byid(ksem_counter) != NULL) { + ksem_counter++; + /* 0 is a special value for libpthread */ + if (ksem_counter == 0) + ksem_counter++; + } + ret->ks_id = ksem_counter; + LIST_INSERT_HEAD(&ksem_hash[SEM_HASH(ret->ks_id)], ret, ks_hash); simple_unlock(&ksem_slock); *ksret = ret; @@ -310,16 +347,24 @@ sys__ksem_init(struct lwp *l, void *v, r unsigned int value; semid_t *idp; } */ *uap = v; + + return do_ksem_init(l, SCARG(uap, value), SCARG(uap, idp), copyout); +} + +int +do_ksem_init(struct lwp *l, unsigned int value, semid_t *idp, + copyout_t docopyout) +{ struct ksem *ks; semid_t id; int error; /* Note the mode does not matter for anonymous semaphores. */ - error = ksem_create(l->l_proc, NULL, &ks, 0, SCARG(uap, value)); + error = ksem_create(l->l_proc, NULL, &ks, 0, value); if (error) return (error); id = SEM_TO_ID(ks); - error = copyout(&id, SCARG(uap, idp), sizeof(id)); + error = (*docopyout)(&id, idp, sizeof(id)); if (error) { simple_lock(&ks->ks_interlock); ksem_delref(ks); @@ -341,13 +386,22 @@ sys__ksem_open(struct lwp *l, void *v, r unsigned int value; semid_t *idp; } */ *uap = v; + + return do_ksem_open(l, SCARG(uap, name), SCARG(uap, oflag), + SCARG(uap, mode), SCARG(uap, value), SCARG(uap, idp), copyout); +} + +int +do_ksem_open(struct lwp *l, const char *semname, int oflag, mode_t mode, + unsigned int value, semid_t *idp, copyout_t docopyout) +{ char name[SEM_MAX_NAMELEN + 1]; size_t done; int error; struct ksem *ksnew, *ks; semid_t id; - error = copyinstr(SCARG(uap, name), name, sizeof(name), &done); + error = copyinstr(semname, name, sizeof(name), &done); if (error) return (error); @@ -358,7 +412,7 @@ sys__ksem_open(struct lwp *l, void *v, r /* Found one? */ if (ks != NULL) { /* Check for exclusive create. */ - if (SCARG(uap, oflag) & O_EXCL) { + if (oflag & O_EXCL) { simple_unlock(&ks->ks_interlock); simple_unlock(&ksem_slock); return (EEXIST); @@ -378,7 +432,7 @@ sys__ksem_open(struct lwp *l, void *v, r return (error); id = SEM_TO_ID(ks); - error = copyout(&id, SCARG(uap, idp), sizeof(id)); + error = (*docopyout)(&id, idp, sizeof(id)); if (error) { simple_lock(&ks->ks_interlock); ksem_delref(ks); @@ -393,7 +447,7 @@ sys__ksem_open(struct lwp *l, void *v, r /* * didn't ask for creation? error. */ - if ((SCARG(uap, oflag) & O_CREAT) == 0) { + if ((oflag & O_CREAT) == 0) { simple_unlock(&ksem_slock); return (ENOENT); } @@ -402,13 +456,12 @@ sys__ksem_open(struct lwp *l, void *v, r * We may block during creation, so drop the lock. */ simple_unlock(&ksem_slock); - error = ksem_create(l->l_proc, name, &ksnew, SCARG(uap, mode), - SCARG(uap, value)); + error = ksem_create(l->l_proc, name, &ksnew, mode, value); if (error != 0) return (error); id = SEM_TO_ID(ksnew); - error = copyout(&id, SCARG(uap, idp), sizeof(id)); + error = (*docopyout)(&id, idp, sizeof(id)); if (error) { free(ksnew->ks_name, M_SEM); ksnew->ks_name = NULL; @@ -424,7 +477,7 @@ sys__ksem_open(struct lwp *l, void *v, r */ simple_lock(&ksem_slock); if ((ks = ksem_lookup_byname(name)) != NULL) { - if (SCARG(uap, oflag) & O_EXCL) { + if (oflag & O_EXCL) { simple_unlock(&ks->ks_interlock); simple_unlock(&ksem_slock); @@ -453,7 +506,7 @@ ksem_lookup_proc(struct ksem_proc *kp, s struct ksem_ref *ksr; LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) { - if (id == (semid_t) ksr->ksr_ksem) { + if (id == SEM_TO_ID(ksr->ksr_ksem)) { simple_lock(&ksr->ksr_ksem->ks_interlock); return (ksr->ksr_ksem); } @@ -748,9 +801,13 @@ ksem_exithook(struct proc *p, void *arg) void ksem_init(void) { + int i; simple_lock_init(&ksem_slock); exithook_establish(ksem_exithook, NULL); exechook_establish(ksem_exithook, NULL); forkhook_establish(ksem_forkhook); + + for (i = 0; i < SEM_HASHTBL_SIZE; i++) + LIST_INIT(&ksem_hash[i]); }