diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/sys/membarrier.h | 9 | ||||
| -rw-r--r-- | src/internal/pthread_impl.h | 2 | ||||
| -rw-r--r-- | src/linux/membarrier.c | 76 | ||||
| -rw-r--r-- | src/thread/pthread_create.c | 4 | 
4 files changed, 88 insertions, 3 deletions
diff --git a/src/include/sys/membarrier.h b/src/include/sys/membarrier.h new file mode 100644 index 00000000..3654491c --- /dev/null +++ b/src/include/sys/membarrier.h @@ -0,0 +1,9 @@ +#ifndef SYS_MEMBARRIER_H +#define SYS_MEMBARRIER_H + +#include "../../../include/sys/membarrier.h" +#include <features.h> + +hidden int __membarrier(int, int); + +#endif diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index de089967..9b001421 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -130,7 +130,7 @@ hidden int __init_tp(void *);  hidden void *__copy_tls(unsigned char *);  hidden void __reset_tls(); -hidden void __dl_prepare_for_threads(void); +hidden void __membarrier_init(void);  hidden void __dl_thread_cleanup(void);  hidden void __testcancel();  hidden void __do_cleanup_push(struct __ptcb *); diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c new file mode 100644 index 00000000..26d143e7 --- /dev/null +++ b/src/linux/membarrier.c @@ -0,0 +1,76 @@ +#include <sys/membarrier.h> +#include <semaphore.h> +#include <signal.h> +#include <string.h> +#include "pthread_impl.h" +#include "syscall.h" + +static void dummy_0(void) +{ +} + +static void dummy_1(pthread_t t) +{ +} + +weak_alias(dummy_0, __tl_lock); +weak_alias(dummy_0, __tl_unlock); +weak_alias(dummy_1, __tl_sync); + +static sem_t barrier_sem; + +static void bcast_barrier(int s) +{ +	sem_post(&barrier_sem); +} + +int __membarrier(int cmd, int flags) +{ +	int r = __syscall(SYS_membarrier, cmd, flags); +	/* Emulate the private expedited command, which is needed by the +	 * dynamic linker for installation of dynamic TLS, for older +	 * kernels that lack the syscall. Unlike the syscall, this only +	 * synchronizes with threads of the process, not other processes +	 * sharing the VM, but such sharing is not a supported usage +	 * anyway. */ +	if (r && cmd == MEMBARRIER_CMD_PRIVATE_EXPEDITED && !flags) { +		pthread_t self=__pthread_self(), td; +		sigset_t set; +		__block_app_sigs(&set); +		__tl_lock(); +		sem_init(&barrier_sem, 0, 0); +		struct sigaction sa = { +			.sa_flags = SA_RESTART, +			.sa_handler = bcast_barrier +		}; +		memset(&sa.sa_mask, -1, sizeof sa.sa_mask); +		__libc_sigaction(SIGSYNCCALL, &sa, 0);	 +		for (td=self->next; td!=self; td=td->next) +			__syscall(SYS_tkill, td->tid, SIGSYNCCALL); +		for (td=self->next; td!=self; td=td->next) +			sem_wait(&barrier_sem); +		sa.sa_handler = SIG_IGN; +		__libc_sigaction(SIGSYNCCALL, &sa, 0); +		sem_destroy(&barrier_sem); +		__tl_unlock(); +		__restore_sigs(&set); +		return 0; +	} +	return __syscall_ret(r); +} + +void __membarrier_init(void) +{ +	/* If membarrier is linked, attempt to pre-register to be able to use +	 * the private expedited command before the process becomes multi- +	 * threaded, since registering later has bad, potentially unbounded +	 * latency. This syscall should be essentially free, and it's arguably +	 * a mistake in the API design that registration was even required. +	 * For other commands, registration may impose some cost, so it's left +	 * to the application to do so if desired. Unfortunately this means +	 * library code initialized after the process becomes multi-threaded +	 * cannot use these features without accepting registration latency. */ +	__syscall(SYS_membarrier, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0); +} + +weak_alias(__membarrier, membarrier); diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 54c03554..7d4dc2ed 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -15,7 +15,7 @@ weak_alias(dummy_0, __release_ptc);  weak_alias(dummy_0, __pthread_tsd_run_dtors);  weak_alias(dummy_0, __do_orphaned_stdio_locks);  weak_alias(dummy_0, __dl_thread_cleanup); -weak_alias(dummy_0, __dl_prepare_for_threads); +weak_alias(dummy_0, __membarrier_init);  static int tl_lock_count;  static int tl_lock_waiters; @@ -246,7 +246,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att  		init_file_lock(__stderr_used);  		__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK, SIGPT_SET, 0, _NSIG/8);  		self->tsd = (void **)__pthread_tsd_main; -		__dl_prepare_for_threads(); +		__membarrier_init();  		libc.threaded = 1;  	}  	if (attrp && !c11) attr = *attrp;  | 
