sem.c revision 1.1.1.9
1169092Sdeischen/* Copyright (C) 2005-2019 Free Software Foundation, Inc. 2169092Sdeischen Contributed by Richard Henderson <rth@redhat.com>. 3169092Sdeischen 4164190Sjkoshy This file is part of the GNU Offloading and Multi Processing Library 5164190Sjkoshy (libgomp). 6164190Sjkoshy 7164190Sjkoshy Libgomp is free software; you can redistribute it and/or modify it 8164190Sjkoshy under the terms of the GNU General Public License as published by 9164190Sjkoshy the Free Software Foundation; either version 3, or (at your option) 10164190Sjkoshy any later version. 11164190Sjkoshy 12164190Sjkoshy Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 13164190Sjkoshy WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14164190Sjkoshy FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15164190Sjkoshy more details. 16164190Sjkoshy 17164190Sjkoshy Under Section 7 of GPL version 3, you are granted additional 18164190Sjkoshy permissions described in the GCC Runtime Library Exception, version 19164190Sjkoshy 3.1, as published by the Free Software Foundation. 20164190Sjkoshy 21164190Sjkoshy You should have received a copy of the GNU General Public License and 22164190Sjkoshy a copy of the GCC Runtime Library Exception along with this program; 23164190Sjkoshy see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24164190Sjkoshy <http://www.gnu.org/licenses/>. */ 25164190Sjkoshy 26164190Sjkoshy/* This is a Linux specific implementation of a semaphore synchronization 27164190Sjkoshy mechanism for libgomp. This type is private to the library. This 28164190Sjkoshy implementation uses atomic instructions and the futex syscall. */ 29164190Sjkoshy 30164190Sjkoshy#include "wait.h" 31164190Sjkoshy 32164190Sjkoshyvoid 33164190Sjkoshygomp_sem_wait_slow (gomp_sem_t *sem, int count) 34164190Sjkoshy{ 35164190Sjkoshy /* First loop spins a while. */ 36164190Sjkoshy while (count == 0) 37164190Sjkoshy if (do_spin (sem, 0) 38164190Sjkoshy /* Spin timeout, nothing changed. Set waiting flag. */ 39164190Sjkoshy && __atomic_compare_exchange_n (sem, &count, SEM_WAIT, false, 40164190Sjkoshy MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 41164190Sjkoshy { 42165535Sjkoshy futex_wait (sem, SEM_WAIT); 43164190Sjkoshy count = *sem; 44164190Sjkoshy break; 45164190Sjkoshy } 46164190Sjkoshy /* Something changed. If it wasn't the wait flag, we're good to go. */ 47164190Sjkoshy else if (__builtin_expect (((count = *sem) & SEM_WAIT) == 0 && count != 0, 48164190Sjkoshy 1)) 49164190Sjkoshy { 50164190Sjkoshy if (__atomic_compare_exchange_n (sem, &count, count - SEM_INC, false, 51164190Sjkoshy MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 52164190Sjkoshy return; 53164190Sjkoshy } 54164190Sjkoshy 55164190Sjkoshy /* Second loop waits until semaphore is posted. We always exit this 56164190Sjkoshy loop with wait flag set, so next post will awaken a thread. */ 57164190Sjkoshy while (1) 58164190Sjkoshy { 59164190Sjkoshy unsigned int wake = count & ~SEM_WAIT; 60164190Sjkoshy int newval = SEM_WAIT; 61164190Sjkoshy 62164190Sjkoshy if (wake != 0) 63164190Sjkoshy newval |= wake - SEM_INC; 64164190Sjkoshy if (__atomic_compare_exchange_n (sem, &count, newval, false, 65164190Sjkoshy MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 66164190Sjkoshy { 67164190Sjkoshy if (wake != 0) 68164190Sjkoshy { 69164190Sjkoshy /* If we can wake more threads, do so now. */ 70164190Sjkoshy if (wake > SEM_INC) 71164190Sjkoshy gomp_sem_post_slow (sem); 72164190Sjkoshy break; 73164190Sjkoshy } 74164190Sjkoshy do_wait (sem, SEM_WAIT); 75164190Sjkoshy count = *sem; 76164190Sjkoshy } 77164190Sjkoshy } 78164190Sjkoshy} 79164190Sjkoshy 80164190Sjkoshyvoid 81164190Sjkoshygomp_sem_post_slow (gomp_sem_t *sem) 82164190Sjkoshy{ 83164190Sjkoshy futex_wake (sem, 1); 84164190Sjkoshy} 85164190Sjkoshy