1*8feb0f0bSmrg /* Copyright (C) 2005-2020 Free Software Foundation, Inc.
236ac495dSmrg Contributed by Richard Henderson <rth@redhat.com>.
336ac495dSmrg
436ac495dSmrg This file is part of the GNU Offloading and Multi Processing Library
536ac495dSmrg (libgomp).
636ac495dSmrg
736ac495dSmrg Libgomp is free software; you can redistribute it and/or modify it
836ac495dSmrg under the terms of the GNU General Public License as published by
936ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
1036ac495dSmrg any later version.
1136ac495dSmrg
1236ac495dSmrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
1336ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1436ac495dSmrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1536ac495dSmrg more details.
1636ac495dSmrg
1736ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1836ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1936ac495dSmrg 3.1, as published by the Free Software Foundation.
2036ac495dSmrg
2136ac495dSmrg You should have received a copy of the GNU General Public License and
2236ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2336ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2436ac495dSmrg <http://www.gnu.org/licenses/>. */
2536ac495dSmrg
2636ac495dSmrg /* This is a Linux specific implementation of a semaphore synchronization
2736ac495dSmrg mechanism for libgomp. This type is private to the library. This
2836ac495dSmrg implementation uses atomic instructions and the futex syscall. */
2936ac495dSmrg
3036ac495dSmrg #include "wait.h"
3136ac495dSmrg
3236ac495dSmrg void
gomp_sem_wait_slow(gomp_sem_t * sem,int count)3336ac495dSmrg gomp_sem_wait_slow (gomp_sem_t *sem, int count)
3436ac495dSmrg {
3536ac495dSmrg /* First loop spins a while. */
3636ac495dSmrg while (count == 0)
3736ac495dSmrg if (do_spin (sem, 0)
3836ac495dSmrg /* Spin timeout, nothing changed. Set waiting flag. */
3936ac495dSmrg && __atomic_compare_exchange_n (sem, &count, SEM_WAIT, false,
4036ac495dSmrg MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
4136ac495dSmrg {
4236ac495dSmrg futex_wait (sem, SEM_WAIT);
4336ac495dSmrg count = *sem;
4436ac495dSmrg break;
4536ac495dSmrg }
4636ac495dSmrg /* Something changed. If it wasn't the wait flag, we're good to go. */
4736ac495dSmrg else if (__builtin_expect (((count = *sem) & SEM_WAIT) == 0 && count != 0,
4836ac495dSmrg 1))
4936ac495dSmrg {
5036ac495dSmrg if (__atomic_compare_exchange_n (sem, &count, count - SEM_INC, false,
5136ac495dSmrg MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
5236ac495dSmrg return;
5336ac495dSmrg }
5436ac495dSmrg
5536ac495dSmrg /* Second loop waits until semaphore is posted. We always exit this
5636ac495dSmrg loop with wait flag set, so next post will awaken a thread. */
5736ac495dSmrg while (1)
5836ac495dSmrg {
5936ac495dSmrg unsigned int wake = count & ~SEM_WAIT;
6036ac495dSmrg int newval = SEM_WAIT;
6136ac495dSmrg
6236ac495dSmrg if (wake != 0)
6336ac495dSmrg newval |= wake - SEM_INC;
6436ac495dSmrg if (__atomic_compare_exchange_n (sem, &count, newval, false,
6536ac495dSmrg MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
6636ac495dSmrg {
6736ac495dSmrg if (wake != 0)
6836ac495dSmrg {
6936ac495dSmrg /* If we can wake more threads, do so now. */
7036ac495dSmrg if (wake > SEM_INC)
7136ac495dSmrg gomp_sem_post_slow (sem);
7236ac495dSmrg break;
7336ac495dSmrg }
7436ac495dSmrg do_wait (sem, SEM_WAIT);
7536ac495dSmrg count = *sem;
7636ac495dSmrg }
7736ac495dSmrg }
7836ac495dSmrg }
7936ac495dSmrg
8036ac495dSmrg void
gomp_sem_post_slow(gomp_sem_t * sem)8136ac495dSmrg gomp_sem_post_slow (gomp_sem_t *sem)
8236ac495dSmrg {
8336ac495dSmrg futex_wake (sem, 1);
8436ac495dSmrg }
85