mirror of
https://github.com/fluencelabs/musl
synced 2025-05-09 22:02:18 +00:00
fix sem_open and sem_close to obey posix semantics
multiple opens of the same named semaphore must return the same pointer, and only the last close can unmap it. thus the ugly global state keeping track of mappings. the maximum number of distinct named semaphores that can be opened is limited sufficiently small that the linear searches take trivial time, especially compared to the syscall overhead of these functions.
This commit is contained in:
parent
5fcebcde6a
commit
81af503610
@ -30,6 +30,7 @@
|
|||||||
#define PTHREAD_STACK_MIN PAGE_SIZE
|
#define PTHREAD_STACK_MIN PAGE_SIZE
|
||||||
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
||||||
#define SEM_VALUE_MAX 0x7fffffff
|
#define SEM_VALUE_MAX 0x7fffffff
|
||||||
|
#define SEM_NSEMS_MAX 256
|
||||||
|
|
||||||
/* Arbitrary numbers... */
|
/* Arbitrary numbers... */
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ long sysconf(int name)
|
|||||||
[_SC_VERSION] = VER,
|
[_SC_VERSION] = VER,
|
||||||
[_SC_PAGE_SIZE] = PAGE_SIZE,
|
[_SC_PAGE_SIZE] = PAGE_SIZE,
|
||||||
[_SC_RTSIG_MAX] = 63, /* ?? */
|
[_SC_RTSIG_MAX] = 63, /* ?? */
|
||||||
[_SC_SEM_NSEMS_MAX] = _POSIX_SEM_NSEMS_MAX,
|
[_SC_SEM_NSEMS_MAX] = SEM_NSEMS_MAX,
|
||||||
[_SC_SEM_VALUE_MAX] = _POSIX_SEM_VALUE_MAX,
|
[_SC_SEM_VALUE_MAX] = OFLOW,
|
||||||
[_SC_SIGQUEUE_MAX] = -1,
|
[_SC_SIGQUEUE_MAX] = -1,
|
||||||
[_SC_TIMER_MAX] = -1,
|
[_SC_TIMER_MAX] = -1,
|
||||||
[_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX,
|
[_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX,
|
||||||
@ -215,8 +215,8 @@ long sysconf(int name)
|
|||||||
} else if (values[name] == VER) {
|
} else if (values[name] == VER) {
|
||||||
return _POSIX_VERSION;
|
return _POSIX_VERSION;
|
||||||
} else if (values[name] == OFLOW) {
|
} else if (values[name] == OFLOW) {
|
||||||
return ARG_MAX;
|
if (name == _SC_ARG_MAX) return ARG_MAX;
|
||||||
} else {
|
if (name == _SC_SEM_VALUE_MAX) return SEM_VALUE_MAX;
|
||||||
return values[name];
|
|
||||||
}
|
}
|
||||||
|
return values[name];
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#include <semaphore.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
int sem_close(sem_t *sem)
|
|
||||||
{
|
|
||||||
return munmap(sem, sizeof *sem);
|
|
||||||
}
|
|
@ -9,32 +9,32 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.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;
|
semtab = calloc(sizeof *semtab, SEM_NSEMS_MAX);
|
||||||
struct stat st;
|
}
|
||||||
FILE *f;
|
|
||||||
void *addr;
|
|
||||||
unsigned long long off, ino;
|
|
||||||
char buf[100];
|
|
||||||
|
|
||||||
if (fstat(fd, &st) < 0) return 0;
|
static sem_t *find_map(ino_t ino)
|
||||||
if (!(f = fopen("/proc/self/maps", "rb"))) return 0;
|
{
|
||||||
|
int i;
|
||||||
while (fgets(buf, sizeof buf, f)) {
|
for (i=0; i<SEM_NSEMS_MAX && semtab[i].ino != ino; i++);
|
||||||
sscanf(buf, "%lx-%*lx %*s %llx %*x:%*x %llu /dev/shm%c",
|
if (i==SEM_NSEMS_MAX) return 0;
|
||||||
(long *)&addr, &off, &ino, &c);
|
if (semtab[i].refcnt == INT_MAX) return (sem_t *)-1;
|
||||||
while (!strchr(buf, '\n') && fgets(buf, sizeof buf, f));
|
semtab[i].refcnt++;
|
||||||
if (c!='/') continue;
|
return semtab[i].sem;
|
||||||
c = 0;
|
|
||||||
if (!off && st.st_ino == ino) {
|
|
||||||
fclose(f);
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sem_t *sem_open(const char *name, int flags, ...)
|
sem_t *sem_open(const char *name, int flags, ...)
|
||||||
@ -47,6 +47,8 @@ sem_t *sem_open(const char *name, int flags, ...)
|
|||||||
void *map;
|
void *map;
|
||||||
char tmp[64];
|
char tmp[64];
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
struct stat st;
|
||||||
|
int i;
|
||||||
|
|
||||||
while (*name=='/') name++;
|
while (*name=='/') name++;
|
||||||
if (strchr(name, '/')) {
|
if (strchr(name, '/')) {
|
||||||
@ -54,6 +56,12 @@ sem_t *sem_open(const char *name, int flags, ...)
|
|||||||
return SEM_FAILED;
|
return SEM_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_once(&once, init);
|
||||||
|
if (!semtab) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return SEM_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & O_CREAT) {
|
if (flags & O_CREAT) {
|
||||||
va_start(ap, flags);
|
va_start(ap, flags);
|
||||||
mode = va_arg(ap, mode_t) & 0666;
|
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_ACCMODE;
|
||||||
flags |= O_RDWR;
|
flags |= O_RDWR;
|
||||||
|
|
||||||
|
pthread_spin_lock(&lock);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!(flags & O_EXCL)) {
|
if (!(flags & O_EXCL)) {
|
||||||
fd = shm_open(name, flags&~O_CREAT, mode);
|
fd = shm_open(name, flags&~O_CREAT, mode);
|
||||||
@ -90,9 +100,21 @@ sem_t *sem_open(const char *name, int flags, ...)
|
|||||||
close(tfd);
|
close(tfd);
|
||||||
unlink(tmp);
|
unlink(tmp);
|
||||||
}
|
}
|
||||||
if (fd < 0) return SEM_FAILED;
|
if (fstat(fd, &st) < 0) {
|
||||||
if ((map = find_map(fd)))
|
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;
|
return map;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,8 +131,40 @@ sem_t *sem_open(const char *name, int flags, ...)
|
|||||||
return SEM_FAILED;
|
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);
|
map = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
close(fd);
|
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;
|
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);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user