Mercurial > hg > CbC > CbC_gcc
diff libgomp/config/linux/sem.h @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | a06113de4d67 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/libgomp/config/linux/sem.h Sun Aug 21 07:07:55 2011 +0900 +++ b/libgomp/config/linux/sem.h Fri Oct 27 22:46:09 2017 +0900 @@ -1,7 +1,8 @@ -/* Copyright (C) 2005, 2009 Free Software Foundation, Inc. +/* Copyright (C) 2005-2017 Free Software Foundation, Inc. Contributed by Richard Henderson <rth@redhat.com>. - This file is part of the GNU OpenMP Library (libgomp). + This file is part of the GNU Offloading and Multi Processing Library + (libgomp). Libgomp is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,34 +25,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 -static inline void gomp_sem_init (gomp_sem_t *sem, int value) +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) { - *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) -{ - 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) -{ - if (!__sync_bool_compare_and_swap (sem, 0, 1)) - gomp_sem_post_slow (sem); -} - -static inline void gomp_sem_destroy (gomp_sem_t *sem) +static inline void +gomp_sem_destroy (gomp_sem_t *sem) { } +static inline void +gomp_sem_wait (gomp_sem_t *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_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 */