diff options
| -rw-r--r-- | src/internal/pthread_impl.h | 8 | ||||
| -rw-r--r-- | src/mman/mmap.c | 13 | ||||
| -rw-r--r-- | src/mman/munmap.c | 11 | ||||
| -rw-r--r-- | src/thread/pthread_barrier_destroy.c | 6 | ||||
| -rw-r--r-- | src/thread/pthread_barrier_init.c | 4 | ||||
| -rw-r--r-- | src/thread/pthread_barrier_wait.c | 74 | ||||
| -rw-r--r-- | src/thread/pthread_barrierattr_setpshared.c | 2 | 
7 files changed, 102 insertions, 16 deletions
| diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index bbb4502f..82d62426 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -73,10 +73,12 @@ struct __timer {  #define _c_waiters2 __u.__i[7]  #define _rw_lock __u.__i[0]  #define _rw_waiters __u.__i[1] -#define _b_inst __u.__p[0] +#define _b_lock __u.__i[0] +#define _b_waiters __u.__i[1]  #define _b_limit __u.__i[2] -#define _b_lock __u.__i[3] -#define _b_waiters __u.__i[4] +#define _b_count __u.__i[3] +#define _b_seq __u.__i[4] +#define _b_inst __u.__p[4]  #include "pthread_arch.h" diff --git a/src/mman/mmap.c b/src/mman/mmap.c index 883acb28..fd2bb07e 100644 --- a/src/mman/mmap.c +++ b/src/mman/mmap.c @@ -5,16 +5,25 @@  #include "syscall.h"  #include "libc.h" +static void dummy1(int x) { } +static void dummy0(void) { } +weak_alias(dummy1, __vm_lock); +weak_alias(dummy0, __vm_unlock); +  void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)  { +	void *ret;  	if (sizeof(off_t) > sizeof(long))  		if (((long)off & 0xfff) | ((long)((unsigned long long)off>>(12 + 8*(sizeof(off_t)-sizeof(long))))))  			start = (void *)-1; +	if (flags & MAP_FIXED) __vm_lock(-1);  #ifdef SYS_mmap2 -	return (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off>>12); +	ret = (void *)syscall(SYS_mmap2, start, len, prot, flags, fd, off>>12);  #else -	return (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off); +	ret = (void *)syscall(SYS_mmap, start, len, prot, flags, fd, off);  #endif +	if (flags & MAP_FIXED) __vm_unlock(); +	return ret;  }  weak_alias(__mmap, mmap); diff --git a/src/mman/munmap.c b/src/mman/munmap.c index ab7da9e2..91aefd40 100644 --- a/src/mman/munmap.c +++ b/src/mman/munmap.c @@ -3,9 +3,18 @@  #include "syscall.h"  #include "libc.h" +static void dummy1(int x) { } +static void dummy0(void) { } +weak_alias(dummy1, __vm_lock); +weak_alias(dummy0, __vm_unlock); +  int __munmap(void *start, size_t len)  { -	return syscall(SYS_munmap, start, len); +	int ret; +	__vm_lock(-1); +	ret = syscall(SYS_munmap, start, len); +	__vm_unlock(); +	return ret;  }  weak_alias(__munmap, munmap); diff --git a/src/thread/pthread_barrier_destroy.c b/src/thread/pthread_barrier_destroy.c index 2898c41a..f82664d5 100644 --- a/src/thread/pthread_barrier_destroy.c +++ b/src/thread/pthread_barrier_destroy.c @@ -1,6 +1,12 @@  #include "pthread_impl.h" +void __vm_lock(int), __vm_unlock(void); +  int pthread_barrier_destroy(pthread_barrier_t *b)  { +	if (b->_b_limit < 0) { +		__vm_lock(-1); +		__vm_unlock(); +	}  	return 0;  } diff --git a/src/thread/pthread_barrier_init.c b/src/thread/pthread_barrier_init.c index 736d1014..ccaab4eb 100644 --- a/src/thread/pthread_barrier_init.c +++ b/src/thread/pthread_barrier_init.c @@ -2,7 +2,7 @@  int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *a, unsigned count)  { -	if (!count) return EINVAL; -	*b = (pthread_barrier_t){ ._b_limit = count-1 }; +	if (count-1 > INT_MAX-1) return EINVAL; +	*b = (pthread_barrier_t){ ._b_limit = count-1 | (a?*a:0) };  	return 0;  } diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c index aed1adc8..db432ba3 100644 --- a/src/thread/pthread_barrier_wait.c +++ b/src/thread/pthread_barrier_wait.c @@ -1,5 +1,62 @@  #include "pthread_impl.h" +static int vmlock[2]; + +void __vm_lock(int inc) +{ +	for (;;) { +		int v = vmlock[0]; +		if (inc*v < 0) __wait(vmlock, vmlock+1, v, 1); +		else if (a_cas(vmlock, v, v+inc)==v) break; +	} +} + +void __vm_unlock(void) +{ +	if (vmlock[0]>0) a_dec(vmlock); +	else a_inc(vmlock); +	if (vmlock[1]) __wake(vmlock, 1, 1); +} + +static int pshared_barrier_wait(pthread_barrier_t *b) +{ +	int limit = (b->_b_limit & INT_MAX) + 1; +	int seq; +	int ret = 0; + +	if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD; + +	while (a_swap(&b->_b_lock, 1)) +		__wait(&b->_b_lock, &b->_b_waiters, 1, 0); + +	seq = b->_b_seq; + +	if (++b->_b_count == limit) { +		ret = PTHREAD_BARRIER_SERIAL_THREAD; +		b->_b_seq++; +		__wake(&b->_b_seq, -1, 0); +	} else { +		a_store(&b->_b_lock, 0); +		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0); +		__wait(&b->_b_seq, 0, seq, 0); +	} + +	__vm_lock(+1); + +	if (a_fetch_add(&b->_b_count, -1)==1) { +		b->_b_seq++; +		__wake(&b->_b_seq, -1, 0); +		a_store(&b->_b_lock, 0); +		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0); +	} else { +		__wait(&b->_b_seq, 0, seq+1, 0); +	} +	 +	__vm_unlock(); + +	return 0; +} +  struct instance  {  	int count; @@ -16,9 +73,12 @@ int pthread_barrier_wait(pthread_barrier_t *b)  	/* Trivial case: count was set at 1 */  	if (!limit) return PTHREAD_BARRIER_SERIAL_THREAD; +	/* Process-shared barriers require a separate, inefficient wait */ +	if (limit < 0) return pshared_barrier_wait(b); +  	/* Otherwise we need a lock on the barrier object */  	while (a_swap(&b->_b_lock, 1)) -		__wait(&b->_b_lock, &b->_b_waiters, 1, 0); +		__wait(&b->_b_lock, &b->_b_waiters, 1, 1);  	inst = b->_b_inst;  	/* First thread to enter the barrier becomes the "instance owner" */ @@ -27,7 +87,7 @@ int pthread_barrier_wait(pthread_barrier_t *b)  		int spins = 10000;  		b->_b_inst = inst = &new_inst;  		a_store(&b->_b_lock, 0); -		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0); +		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);  		while (spins-- && !inst->finished)  			a_spin();  		a_inc(&inst->finished); @@ -40,19 +100,19 @@ int pthread_barrier_wait(pthread_barrier_t *b)  	if (++inst->count == limit) {  		b->_b_inst = 0;  		a_store(&b->_b_lock, 0); -		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0); +		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1);  		a_store(&inst->last, 1);  		if (inst->waiters) -			__wake(&inst->last, -1, 0); +			__wake(&inst->last, -1, 1);  	} else {  		a_store(&b->_b_lock, 0); -		if (b->_b_waiters) __wake(&b->_b_lock, 1, 0); -		__wait(&inst->last, &inst->waiters, 0, 0); +		if (b->_b_waiters) __wake(&b->_b_lock, 1, 1); +		__wait(&inst->last, &inst->waiters, 0, 1);  	}  	/* Last thread to exit the barrier wakes the instance owner */  	if (a_fetch_add(&inst->count,-1)==1 && a_fetch_add(&inst->finished,1)) -		__wake(&inst->finished, 1, 0); +		__wake(&inst->finished, 1, 1);  	return 0;  } diff --git a/src/thread/pthread_barrierattr_setpshared.c b/src/thread/pthread_barrierattr_setpshared.c index d6c7f9a3..1edc95dc 100644 --- a/src/thread/pthread_barrierattr_setpshared.c +++ b/src/thread/pthread_barrierattr_setpshared.c @@ -2,6 +2,6 @@  int pthread_barrierattr_setpshared(pthread_barrierattr_t *a, int pshared)  { -	*a = !!pshared; +	*a = pshared ? INT_MIN : 0;  	return 0;  } | 
