root/maint/gnulib/lib/pthread-spin.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pthread_spin_init
  2. pthread_spin_lock
  3. pthread_spin_trylock
  4. pthread_spin_unlock
  5. pthread_spin_destroy
  6. pthread_spin_init
  7. pthread_spin_lock
  8. pthread_spin_trylock
  9. pthread_spin_unlock
  10. pthread_spin_init
  11. pthread_spin_lock
  12. pthread_spin_trylock
  13. pthread_spin_unlock
  14. pthread_spin_destroy
  15. pthread_spin_init
  16. pthread_spin_lock
  17. pthread_spin_trylock
  18. pthread_spin_unlock
  19. pthread_spin_destroy
  20. pthread_spin_init
  21. pthread_spin_lock
  22. pthread_spin_trylock
  23. pthread_spin_unlock
  24. pthread_spin_destroy
  25. pthread_spin_init
  26. pthread_spin_lock
  27. pthread_spin_trylock
  28. pthread_spin_unlock
  29. pthread_spin_destroy

   1 /* POSIX spin locks.
   2    Copyright (C) 2010-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 2.1 of the
   7    License, or (at your option) any later version.
   8 
   9    This file is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Paul Eggert, 2010, and Bruno Haible <bruno@clisp.org>, 2019.  */
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include <pthread.h>
  23 
  24 #include <stdbool.h>
  25 
  26 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
  27 # include "windows-spin.h"
  28 #endif
  29 
  30 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
  31 /* Use Windows threads.  */
  32 
  33 int
  34 pthread_spin_init (pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
  35                    _GL_UNUSED int shared_across_processes)
  36 {
  37   glwthread_spin_init (lock);
  38   return 0;
  39 }
  40 
  41 int
  42 pthread_spin_lock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44   return glwthread_spin_lock (lock);
  45 }
  46 
  47 int
  48 pthread_spin_trylock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50   return glwthread_spin_trylock (lock);
  51 }
  52 
  53 int
  54 pthread_spin_unlock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56   return glwthread_spin_unlock (lock);
  57 }
  58 
  59 int
  60 pthread_spin_destroy (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62   return glwthread_spin_destroy (lock);
  63 }
  64 
  65 #elif HAVE_PTHREAD_H
  66 /* Provide workarounds for POSIX threads.  */
  67 
  68 /* We don't use the C11 <stdatomic.h> (available in GCC >= 4.9) because it would
  69    require to link with -latomic.  */
  70 
  71 # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) \
  72       || __clang_major > 3 || (__clang_major__ == 3 && __clang_minor__ >= 1)) \
  73      && !defined __ibmxl__
  74 /* Use GCC built-ins (available in GCC >= 4.7 and clang >= 3.1) that operate on
  75    the first byte of the lock.
  76    Documentation:
  77    <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html>  */
  78 
  79 #  if 1
  80 /* An implementation that verifies the unlocks.  */
  81 
  82 int
  83 pthread_spin_init (pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
  84                    _GL_UNUSED int shared_across_processes)
  85 {
  86   __atomic_store_n ((unsigned int *) lock, 0, __ATOMIC_SEQ_CST);
  87   return 0;
  88 }
  89 
  90 int
  91 pthread_spin_lock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93   /* Wait until *lock becomes 0, then replace it with 1.  */
  94   unsigned int zero;
  95   while (!(zero = 0,
  96            __atomic_compare_exchange_n ((unsigned int *) lock, &zero, 1, false,
  97                                         __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)))
  98     ;
  99   return 0;
 100 }
 101 
 102 int
 103 pthread_spin_trylock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105   unsigned int zero;
 106   if (!(zero = 0,
 107         __atomic_compare_exchange_n ((unsigned int *) lock, &zero, 1, false,
 108                                      __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)))
 109     return EBUSY;
 110   return 0;
 111 }
 112 
 113 int
 114 pthread_spin_unlock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   /* If *lock is 1, then replace it with 0.  */
 117   unsigned int one = 1;
 118   if (!__atomic_compare_exchange_n ((unsigned int *) lock, &one, 0, false,
 119                                     __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
 120     abort ();
 121   return 0;
 122 }
 123 
 124 #  else
 125 /* An implementation that is a little bit more optimized, but does not verify
 126    the unlocks.  */
 127 
 128 int
 129 pthread_spin_init (pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 130                    _GL_UNUSED int shared_across_processes)
 131 {
 132   __atomic_clear (lock, __ATOMIC_SEQ_CST);
 133   return 0;
 134 }
 135 
 136 int
 137 pthread_spin_lock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139   while (__atomic_test_and_set (lock, __ATOMIC_SEQ_CST))
 140     ;
 141   return 0;
 142 }
 143 
 144 int
 145 pthread_spin_trylock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   if (__atomic_test_and_set (lock, __ATOMIC_SEQ_CST))
 148     return EBUSY;
 149   return 0;
 150 }
 151 
 152 int
 153 pthread_spin_unlock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155   __atomic_clear (lock, __ATOMIC_SEQ_CST);
 156   return 0;
 157 }
 158 
 159 #  endif
 160 
 161 int
 162 pthread_spin_destroy (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164   return 0;
 165 }
 166 
 167 # elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) \
 168         || __clang_major__ >= 3) \
 169        && !defined __ibmxl__
 170 /* Use GCC built-ins (available in GCC >= 4.1 and clang >= 3.0).
 171    Documentation:
 172    <https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html>  */
 173 
 174 int
 175 pthread_spin_init (pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 176                    _GL_UNUSED int shared_across_processes)
 177 {
 178   * (volatile unsigned int *) lock = 0;
 179   __sync_synchronize ();
 180   return 0;
 181 }
 182 
 183 int
 184 pthread_spin_lock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186   /* Wait until *lock becomes 0, then replace it with 1.  */
 187   while (__sync_val_compare_and_swap ((unsigned int *) lock, 0, 1) != 0)
 188     ;
 189   return 0;
 190 }
 191 
 192 int
 193 pthread_spin_trylock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195   if (__sync_val_compare_and_swap ((unsigned int *) lock, 0, 1) != 0)
 196     return EBUSY;
 197   return 0;
 198 }
 199 
 200 int
 201 pthread_spin_unlock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203   /* If *lock is 1, then replace it with 0.  */
 204   if (__sync_val_compare_and_swap ((unsigned int *) lock, 1, 0) != 1)
 205     abort ();
 206   return 0;
 207 }
 208 
 209 int
 210 pthread_spin_destroy (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 211 {
 212   return 0;
 213 }
 214 
 215 # else
 216 /* Emulate a spin lock through a mutex.  */
 217 
 218 int
 219 pthread_spin_init (pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 220                    _GL_UNUSED int shared_across_processes)
 221 {
 222   return pthread_mutex_init (lock, NULL);
 223 }
 224 
 225 int
 226 pthread_spin_lock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228   return pthread_mutex_lock (lock);
 229 }
 230 
 231 int
 232 pthread_spin_trylock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234   return pthread_mutex_trylock (lock);
 235 }
 236 
 237 int
 238 pthread_spin_unlock (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 239 {
 240   return pthread_mutex_unlock (lock);
 241 }
 242 
 243 int
 244 pthread_spin_destroy (pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246   return pthread_mutex_destroy (lock);
 247 }
 248 
 249 # endif
 250 
 251 #else
 252 /* Provide a dummy implementation for single-threaded applications.  */
 253 
 254 int
 255 pthread_spin_init (_GL_UNUSED pthread_spinlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 256                    _GL_UNUSED int shared_across_processes)
 257 {
 258   return 0;
 259 }
 260 
 261 int
 262 pthread_spin_lock (_GL_UNUSED pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264   return 0;
 265 }
 266 
 267 int
 268 pthread_spin_trylock (_GL_UNUSED pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 269 {
 270   return 0;
 271 }
 272 
 273 int
 274 pthread_spin_unlock (_GL_UNUSED pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276   return 0;
 277 }
 278 
 279 int
 280 pthread_spin_destroy (_GL_UNUSED pthread_spinlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282   return 0;
 283 }
 284 
 285 #endif

/* [previous][next][first][last][top][bottom][index][help] */