(root)/
gcc-13.2.0/
libgomp/
config/
linux/
lock.c
       1  /* Copyright (C) 2005-2023 Free Software Foundation, Inc.
       2     Contributed by Richard Henderson <rth@redhat.com>.
       3  
       4     This file is part of the GNU Offloading and Multi Processing Library
       5     (libgomp).
       6  
       7     Libgomp is free software; you can redistribute it and/or modify it
       8     under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3, or (at your option)
      10     any later version.
      11  
      12     Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
      13     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      14     FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      15     more details.
      16  
      17     Under Section 7 of GPL version 3, you are granted additional
      18     permissions described in the GCC Runtime Library Exception, version
      19     3.1, as published by the Free Software Foundation.
      20  
      21     You should have received a copy of the GNU General Public License and
      22     a copy of the GCC Runtime Library Exception along with this program;
      23     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      24     <http://www.gnu.org/licenses/>.  */
      25  
      26  /* This is a Linux specific implementation of the public OpenMP locking
      27     primitives.  This implementation uses atomic instructions and the futex
      28     syscall.  */
      29  
      30  #include <string.h>
      31  #include <unistd.h>
      32  #include <sys/syscall.h>
      33  #include "wait.h"
      34  
      35  /* Reuse the generic implementation in terms of gomp_mutex_t.  */
      36  #include "../../lock.c"
      37  
      38  #ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
      39  /* gomp_mutex_* can be safely locked in one thread and
      40     unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
      41     non-nested locks can be the same.  */
      42  strong_alias (gomp_init_lock_30, gomp_init_lock_25)
      43  strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
      44  strong_alias (gomp_set_lock_30, gomp_set_lock_25)
      45  strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
      46  strong_alias (gomp_test_lock_30, gomp_test_lock_25)
      47  
      48  /* The external recursive omp_nest_lock_25_t form requires additional work.  */
      49  
      50  /* We need an integer to uniquely identify this thread.  Most generally
      51     this is the thread's TID, which ideally we'd get this straight from
      52     the TLS block where glibc keeps it.  Unfortunately, we can't get at
      53     that directly.
      54  
      55     If we don't support (or have disabled) TLS, one function call is as
      56     good (or bad) as any other.  Use the syscall all the time.
      57  
      58     On an ILP32 system (defined here as not LP64), we can make do with
      59     any thread-local pointer.  Ideally we'd use the TLS base address,
      60     since that requires the least amount of arithmetic, but that's not
      61     always available directly.  Make do with the gomp_thread pointer
      62     since it's handy.  */
      63  
      64  # if !defined (HAVE_TLS)
      65  static inline int gomp_tid (void)
      66  {
      67    return syscall (SYS_gettid);
      68  }
      69  # elif !defined(__LP64__)
      70  static inline int gomp_tid (void)
      71  {
      72    return (int) gomp_thread ();
      73  }
      74  # else
      75  static __thread int tid_cache;
      76  static inline int gomp_tid (void)
      77  {
      78    int tid = tid_cache;
      79    if (__builtin_expect (tid == 0, 0))
      80      tid_cache = tid = syscall (SYS_gettid);
      81    return tid;
      82  }
      83  # endif
      84  
      85  
      86  void
      87  gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
      88  {
      89    memset (lock, 0, sizeof (*lock));
      90  }
      91  
      92  void
      93  gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
      94  {
      95  }
      96  
      97  void
      98  gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
      99  {
     100    int otid, tid = gomp_tid ();
     101  
     102    while (1)
     103      {
     104        otid = 0;
     105        if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
     106  				       MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
     107  	{
     108  	  lock->count = 1;
     109  	  return;
     110  	}
     111        if (otid == tid)
     112  	{
     113  	  lock->count++;
     114  	  return;
     115  	}
     116  
     117        do_wait (&lock->owner, otid);
     118      }
     119  }
     120  
     121  void
     122  gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
     123  {
     124    /* ??? Validate that we own the lock here.  */
     125  
     126    if (--lock->count == 0)
     127      {
     128        __atomic_store_n (&lock->owner, 0, MEMMODEL_RELEASE);
     129        futex_wake (&lock->owner, 1);
     130      }
     131  }
     132  
     133  int
     134  gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
     135  {
     136    int otid, tid = gomp_tid ();
     137  
     138    otid = 0;
     139    if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
     140  				   MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
     141      {
     142        lock->count = 1;
     143        return 1;
     144      }
     145    if (otid == tid)
     146      return ++lock->count;
     147  
     148    return 0;
     149  }
     150  
     151  omp_lock_symver (omp_init_lock)
     152  omp_lock_symver (omp_destroy_lock)
     153  omp_lock_symver (omp_set_lock)
     154  omp_lock_symver (omp_unset_lock)
     155  omp_lock_symver (omp_test_lock)
     156  omp_lock_symver (omp_init_nest_lock)
     157  omp_lock_symver (omp_destroy_nest_lock)
     158  omp_lock_symver (omp_set_nest_lock)
     159  omp_lock_symver (omp_unset_nest_lock)
     160  omp_lock_symver (omp_test_nest_lock)
     161  
     162  #else
     163  
     164  ialias (omp_init_lock)
     165  ialias (omp_init_nest_lock)
     166  ialias (omp_destroy_lock)
     167  ialias (omp_destroy_nest_lock)
     168  ialias (omp_set_lock)
     169  ialias (omp_set_nest_lock)
     170  ialias (omp_unset_lock)
     171  ialias (omp_unset_nest_lock)
     172  ialias (omp_test_lock)
     173  ialias (omp_test_nest_lock)
     174  
     175  #endif