diff options
Diffstat (limited to 'usr/src/lib/libc/port/sys/shmsys.c')
-rw-r--r-- | usr/src/lib/libc/port/sys/shmsys.c | 90 |
1 files changed, 84 insertions, 6 deletions
diff --git a/usr/src/lib/libc/port/sys/shmsys.c b/usr/src/lib/libc/port/sys/shmsys.c index 141dedf1c9..89d5b8b113 100644 --- a/usr/src/lib/libc/port/sys/shmsys.c +++ b/usr/src/lib/libc/port/sys/shmsys.c @@ -20,15 +20,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - #pragma weak _shmat = shmat #pragma weak _shmctl = shmctl #pragma weak _shmctl64 = shmctl64 @@ -37,6 +35,7 @@ #pragma weak _shmids = shmids #include "lint.h" +#include "thr_uberdata.h" #include <sys/types.h> #include <sys/ipc.h> #include <sys/ipc_impl.h> @@ -45,16 +44,92 @@ #include <sys/syscall.h> #include <errno.h> +/* + * List of all shared memory segments. + * We need this to keep track of the sizes so that we can unregister + * any robust locks that are contained in a segment that is detached. + */ +static struct shm_size { + void *shm_addr; + size_t shm_size; + struct shm_size *shm_next; +} *shm_list = NULL; + +static mutex_t shm_lock = DEFAULTMUTEX; /* protects shm_list */ + +extern void unregister_locks(caddr_t, size_t); + +/* + * Add a shared memory address and size to the remembered list. + */ +static void +add_shm_size(void *addr, size_t size) +{ + struct shm_size **list; + struct shm_size *elem; + + lmutex_lock(&shm_lock); + + for (list = &shm_list; (elem = *list) != NULL; list = &elem->shm_next) { + if (elem->shm_addr == addr) { /* won't happen? */ + elem->shm_size = size; + lmutex_unlock(&shm_lock); + return; + } + } + elem = lmalloc(sizeof (*elem)); + elem->shm_addr = addr; + elem->shm_size = size; + elem->shm_next = NULL; + *list = elem; + + lmutex_unlock(&shm_lock); +} + +/* + * Delete the shared memory address from the remembered list + * and unregister all of the robust locks contained therein. + */ +static void +delete_shm_size(void *addr) +{ + struct shm_size **list; + struct shm_size *elem; + size_t size = 0; + + lmutex_lock(&shm_lock); + + for (list = &shm_list; (elem = *list) != NULL; list = &elem->shm_next) { + if (elem->shm_addr == addr) { + size = elem->shm_size; + *list = elem->shm_next; + lfree(elem, sizeof (*elem)); + break; + } + } + + lmutex_unlock(&shm_lock); + + if (size != 0) + unregister_locks(addr, size); +} + void * shmat(int shmid, const void *shmaddr, int shmflg) { sysret_t rval; int error; + void *addr; + struct shmid_ds shmds; error = __systemcall(&rval, SYS_shmsys, SHMAT, shmid, shmaddr, shmflg); - if (error) + addr = (void *)rval.sys_rval1; + if (error) { (void) __set_errno(error); - return ((void *)rval.sys_rval1); + } else if (shmctl(shmid, IPC_STAT, &shmds) == 0) { + add_shm_size(addr, shmds.shm_segsz); + } + return (addr); } int @@ -80,7 +155,10 @@ shmctl64(int shmid, int cmd, struct shmid_ds64 *buf) int shmdt(char *shmaddr) { - return (syscall(SYS_shmsys, SHMDT, shmaddr)); + int rval = syscall(SYS_shmsys, SHMDT, shmaddr); + if (rval == 0) + delete_shm_size(shmaddr); + return (rval); } int |