xref: /netbsd-src/external/gpl3/gcc.old/dist/libgomp/config/linux/sem.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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