diff options
-rw-r--r-- | include/limits.h | 1 | ||||
-rw-r--r-- | src/conf/sysconf.c | 10 | ||||
-rw-r--r-- | src/thread/sem_close.c | 7 | ||||
-rw-r--r-- | src/thread/sem_open.c | 106 |
4 files changed, 86 insertions, 38 deletions
diff --git a/include/limits.h b/include/limits.h index e12819ba..55ad8231 100644 --- a/include/limits.h +++ b/include/limits.h @@ -30,6 +30,7 @@ #define PTHREAD_STACK_MIN PAGE_SIZE #define PTHREAD_DESTRUCTOR_ITERATIONS 4 #define SEM_VALUE_MAX 0x7fffffff +#define SEM_NSEMS_MAX 256 /* Arbitrary numbers... */ diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c index cdaeb2a6..a660257d 100644 --- a/src/conf/sysconf.c +++ b/src/conf/sysconf.c @@ -40,8 +40,8 @@ long sysconf(int name) [_SC_VERSION] = VER, [_SC_PAGE_SIZE] = PAGE_SIZE, [_SC_RTSIG_MAX] = 63, /* ?? */ - [_SC_SEM_NSEMS_MAX] = _POSIX_SEM_NSEMS_MAX, - [_SC_SEM_VALUE_MAX] = _POSIX_SEM_VALUE_MAX, + [_SC_SEM_NSEMS_MAX] = SEM_NSEMS_MAX, + [_SC_SEM_VALUE_MAX] = OFLOW, [_SC_SIGQUEUE_MAX] = -1, [_SC_TIMER_MAX] = -1, [_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX, @@ -215,8 +215,8 @@ long sysconf(int name) } else if (values[name] == VER) { return _POSIX_VERSION; } else if (values[name] == OFLOW) { - return ARG_MAX; - } else { - return values[name]; + if (name == _SC_ARG_MAX) return ARG_MAX; + if (name == _SC_SEM_VALUE_MAX) return SEM_VALUE_MAX; } + return values[name]; } diff --git a/src/thread/sem_close.c b/src/thread/sem_close.c deleted file mode 100644 index 036ee540..00000000 --- a/src/thread/sem_close.c +++ /dev/null @@ -1,7 +0,0 @@ -#include <semaphore.h> -#include <sys/mman.h> - -int sem_close(sem_t *sem) -{ - return munmap(sem, sizeof *sem); -} diff --git a/src/thread/sem_open.c b/src/thread/sem_open.c index 55d5ef6b..6fff71a8 100644 --- a/src/thread/sem_open.c +++ b/src/thread/sem_open.c @@ -9,32 +9,32 @@ #include <time.h> #include <stdio.h> #include <sys/stat.h> +#include <stdlib.h> +#include <pthread.h> -static void *find_map(int fd) +static struct { + ino_t ino; + sem_t *sem; + int refcnt; +} *semtab; + +static int semcnt; +static pthread_spinlock_t lock; +static pthread_once_t once; + +static void init() { - char c; - struct stat st; - FILE *f; - void *addr; - unsigned long long off, ino; - char buf[100]; + semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX); +} - if (fstat(fd, &st) < 0) return 0; - if (!(f = fopen("/proc/self/maps", "rb"))) return 0; - - while (fgets(buf, sizeof buf, f)) { - sscanf(buf, "%lx-%*lx %*s %llx %*x:%*x %llu /dev/shm%c", - (long *)&addr, &off, &ino, &c); - while (!strchr(buf, '\n') && fgets(buf, sizeof buf, f)); - if (c!='/') continue; - c = 0; - if (!off && st.st_ino == ino) { - fclose(f); - return addr; - } - } - fclose(f); - return 0; +static sem_t *find_map(ino_t ino) +{ + int i; + for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != ino; i++); + if (i==SEM_NSEMS_MAX) return 0; + if (semtab[i].refcnt == INT_MAX) return (sem_t *)-1; + semtab[i].refcnt++; + return semtab[i].sem; } sem_t *sem_open(const char *name, int flags, ...) @@ -47,6 +47,8 @@ sem_t *sem_open(const char *name, int flags, ...) void *map; char tmp[64]; struct timespec ts; + struct stat st; + int i; while (*name=='/') name++; if (strchr(name, '/')) { @@ -54,6 +56,12 @@ sem_t *sem_open(const char *name, int flags, ...) return SEM_FAILED; } + pthread_once(&once, init); + if (!semtab) { + errno = ENOMEM; + return SEM_FAILED; + } + if (flags & O_CREAT) { va_start(ap, flags); mode = va_arg(ap, mode_t) & 0666; @@ -81,6 +89,8 @@ sem_t *sem_open(const char *name, int flags, ...) flags &= ~O_ACCMODE; flags |= O_RDWR; + pthread_spin_lock(&lock); + for (;;) { if (!(flags & O_EXCL)) { fd = shm_open(name, flags&~O_CREAT, mode); @@ -90,9 +100,21 @@ sem_t *sem_open(const char *name, int flags, ...) close(tfd); unlink(tmp); } - if (fd < 0) return SEM_FAILED; - if ((map = find_map(fd))) + if (fstat(fd, &st) < 0) { + close(fd); + fd = -1; + } + if (fd < 0) { + pthread_spin_unlock(&lock); + return SEM_FAILED; + } + if ((map = find_map(st.st_ino))) { + pthread_spin_unlock(&lock); + close(fd); + if (map == (sem_t *)-1) + return SEM_FAILED; return map; + } break; } } @@ -109,8 +131,40 @@ sem_t *sem_open(const char *name, int flags, ...) return SEM_FAILED; } } + if (fstat(fd, &st) < 0) { + pthread_spin_unlock(&lock); + close(fd); + return SEM_FAILED; + } + if (semcnt == SEM_NSEMS_MAX) { + pthread_spin_unlock(&lock); + close(fd); + errno = EMFILE; + return SEM_FAILED; + } + for (i=0; i<SEM_NSEMS_MAX && semtab[i].sem; i++); map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); - if (map == MAP_FAILED) return SEM_FAILED; + if (map == MAP_FAILED) { + pthread_spin_unlock(&lock); + return SEM_FAILED; + } + semtab[i].ino = st.st_ino; + semtab[i].sem = map; + semtab[i].refcnt = 1; + pthread_spin_unlock(&lock); return map; } + +int sem_close(sem_t *sem) +{ + int i; + pthread_spin_lock(&lock); + for (i=0; i<SEM_NSEMS_MAX && semtab[i].sem != sem; i++); + if (!--semtab[i].refcnt) { + semtab[i].sem = 0; + semtab[i].ino = 0; + } + pthread_spin_unlock(&lock); + return munmap(sem, sizeof *sem); +} |