diff options
author | amodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-11-30 03:43:57 +0000 |
---|---|---|
committer | amodra <amodra@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-11-30 03:43:57 +0000 |
commit | df17b94dcaa40e7e13e24a2a8ce6984d70254692 (patch) | |
tree | 28027834dab96be18e7642ddac8d7a2dc9223272 /libgomp/config/linux/sem.h | |
parent | 3eb0217ca6de584509a9922075b14417f82a11d5 (diff) | |
download | gcc-df17b94dcaa40e7e13e24a2a8ce6984d70254692.tar.gz |
PR libgomp/51249
* config/linux/sem.h: Rewrite.
* config/linux/sem.c: Rewrite.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@181831 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgomp/config/linux/sem.h')
-rw-r--r-- | libgomp/config/linux/sem.h | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/libgomp/config/linux/sem.h b/libgomp/config/linux/sem.h index 9b0f0f82bac..9bf480ded36 100644 --- a/libgomp/config/linux/sem.h +++ b/libgomp/config/linux/sem.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005, 2009 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2009, 2011 Free Software Foundation, Inc. Contributed by Richard Henderson <rth@redhat.com>. This file is part of the GNU OpenMP Library (libgomp). @@ -24,34 +24,64 @@ /* This is a Linux specific implementation of a semaphore synchronization mechanism for libgomp. This type is private to the library. This - implementation uses atomic instructions and the futex syscall. */ + counting semaphore implementation uses atomic instructions and the + futex syscall, and a single 32-bit int to store semaphore state. + The low 31 bits are the count, the top bit is a flag set when some + threads may be waiting. */ #ifndef GOMP_SEM_H #define GOMP_SEM_H 1 +#include <limits.h> /* For INT_MIN */ + typedef int gomp_sem_t; +#define SEM_WAIT INT_MIN +#define SEM_INC 1 + +extern void gomp_sem_wait_slow (gomp_sem_t *, int); +extern void gomp_sem_post_slow (gomp_sem_t *); -static inline void gomp_sem_init (gomp_sem_t *sem, int value) +static inline void +gomp_sem_init (gomp_sem_t *sem, int value) { - *sem = value; + *sem = value * SEM_INC; } -extern void gomp_sem_wait_slow (gomp_sem_t *); -static inline void gomp_sem_wait (gomp_sem_t *sem) +static inline void +gomp_sem_destroy (gomp_sem_t *sem) { - if (!__sync_bool_compare_and_swap (sem, 1, 0)) - gomp_sem_wait_slow (sem); } -extern void gomp_sem_post_slow (gomp_sem_t *); -static inline void gomp_sem_post (gomp_sem_t *sem) +static inline void +gomp_sem_wait (gomp_sem_t *sem) { - if (!__sync_bool_compare_and_swap (sem, 0, 1)) - gomp_sem_post_slow (sem); + int count = *sem; + + while ((count & ~SEM_WAIT) != 0) + if (__atomic_compare_exchange_n (sem, &count, count - SEM_INC, true, + MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) + return; + gomp_sem_wait_slow (sem, count); } -static inline void gomp_sem_destroy (gomp_sem_t *sem) +static inline void +gomp_sem_post (gomp_sem_t *sem) { -} + int count = *sem; + + /* Clear SEM_WAIT here so that if there are no more waiting threads + we transition back to the uncontended state that does not make + futex syscalls. If there are waiting threads then when one is + awoken it will set SEM_WAIT again, so other waiting threads are + woken on a future gomp_sem_post. Furthermore, the awoken thread + will wake other threads in case gomp_sem_post was called again + before it had time to set SEM_WAIT. */ + while (!__atomic_compare_exchange_n (sem, &count, + (count + SEM_INC) & ~SEM_WAIT, true, + MEMMODEL_RELEASE, MEMMODEL_RELAXED)) + continue; + if (__builtin_expect (count & SEM_WAIT, 0)) + gomp_sem_post_slow (sem); +} #endif /* GOMP_SEM_H */ |