root/maint/gnulib/lib/glthread/lock.c

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

DEFINITIONS

This source file includes following definitions.
  1. glthread_lock_init
  2. glthread_lock_lock
  3. glthread_lock_unlock
  4. glthread_lock_destroy
  5. glthread_rwlock_init
  6. glthread_rwlock_rdlock
  7. glthread_rwlock_wrlock
  8. glthread_rwlock_unlock
  9. glthread_rwlock_destroy
  10. glthread_recursive_lock_init
  11. glthread_recursive_lock_lock
  12. glthread_recursive_lock_unlock
  13. glthread_recursive_lock_destroy
  14. glthread_rwlock_init_for_glibc
  15. glthread_rwlock_init_multithreaded
  16. glthread_rwlock_rdlock_multithreaded
  17. glthread_rwlock_wrlock_multithreaded
  18. glthread_rwlock_unlock_multithreaded
  19. glthread_rwlock_destroy_multithreaded
  20. glthread_rwlock_init_multithreaded
  21. glthread_rwlock_rdlock_multithreaded
  22. glthread_rwlock_wrlock_multithreaded
  23. glthread_rwlock_unlock_multithreaded
  24. glthread_rwlock_destroy_multithreaded
  25. glthread_recursive_lock_init_multithreaded
  26. glthread_recursive_lock_init_multithreaded
  27. glthread_recursive_lock_lock_multithreaded
  28. glthread_recursive_lock_unlock_multithreaded
  29. glthread_recursive_lock_destroy_multithreaded
  30. glthread_recursive_lock_init_multithreaded
  31. glthread_recursive_lock_lock_multithreaded
  32. glthread_recursive_lock_unlock_multithreaded
  33. glthread_recursive_lock_destroy_multithreaded
  34. glthread_once_singlethreaded
  35. glthread_once_multithreaded

   1 /* Locking in multithreaded situations.
   2    Copyright (C) 2005-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 Bruno Haible <bruno@clisp.org>, 2005.
  18    Based on GCC's gthr-posix.h, gthr-posix95.h.  */
  19 
  20 #include <config.h>
  21 
  22 #include "glthread/lock.h"
  23 
  24 /* ========================================================================= */
  25 
  26 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
  27 
  28 /* -------------------------- gl_lock_t datatype -------------------------- */
  29 
  30 int
  31 glthread_lock_init (gl_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33   if (mtx_init (&lock->mutex, mtx_plain) != thrd_success)
  34     return ENOMEM;
  35   lock->init_needed = 0;
  36   return 0;
  37 }
  38 
  39 int
  40 glthread_lock_lock (gl_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42   if (lock->init_needed)
  43     call_once (&lock->init_once, lock->init_func);
  44   if (mtx_lock (&lock->mutex) != thrd_success)
  45     return EAGAIN;
  46   return 0;
  47 }
  48 
  49 int
  50 glthread_lock_unlock (gl_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52   if (lock->init_needed)
  53     call_once (&lock->init_once, lock->init_func);
  54   if (mtx_unlock (&lock->mutex) != thrd_success)
  55     return EINVAL;
  56   return 0;
  57 }
  58 
  59 int
  60 glthread_lock_destroy (gl_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62   if (lock->init_needed)
  63     call_once (&lock->init_once, lock->init_func);
  64   mtx_destroy (&lock->mutex);
  65   return 0;
  66 }
  67 
  68 /* ------------------------- gl_rwlock_t datatype ------------------------- */
  69 
  70 int
  71 glthread_rwlock_init (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73   if (mtx_init (&lock->lock, mtx_plain) != thrd_success
  74       || cnd_init (&lock->waiting_readers) != thrd_success
  75       || cnd_init (&lock->waiting_writers) != thrd_success)
  76     return ENOMEM;
  77   lock->waiting_writers_count = 0;
  78   lock->runcount = 0;
  79   lock->init_needed = 0;
  80   return 0;
  81 }
  82 
  83 int
  84 glthread_rwlock_rdlock (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86   if (lock->init_needed)
  87     call_once (&lock->init_once, lock->init_func);
  88   if (mtx_lock (&lock->lock) != thrd_success)
  89     return EAGAIN;
  90   /* Test whether only readers are currently running, and whether the runcount
  91      field will not overflow, and whether no writer is waiting.  The latter
  92      condition is because POSIX recommends that "write locks shall take
  93      precedence over read locks", to avoid "writer starvation".  */
  94   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
  95     {
  96       /* This thread has to wait for a while.  Enqueue it among the
  97          waiting_readers.  */
  98       if (cnd_wait (&lock->waiting_readers, &lock->lock) != thrd_success)
  99         {
 100           mtx_unlock (&lock->lock);
 101           return EINVAL;
 102         }
 103     }
 104   lock->runcount++;
 105   if (mtx_unlock (&lock->lock) != thrd_success)
 106     return EINVAL;
 107   return 0;
 108 }
 109 
 110 int
 111 glthread_rwlock_wrlock (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113   if (lock->init_needed)
 114     call_once (&lock->init_once, lock->init_func);
 115   if (mtx_lock (&lock->lock) != thrd_success)
 116     return EAGAIN;
 117   /* Test whether no readers or writers are currently running.  */
 118   while (!(lock->runcount == 0))
 119     {
 120       /* This thread has to wait for a while.  Enqueue it among the
 121          waiting_writers.  */
 122       lock->waiting_writers_count++;
 123       if (cnd_wait (&lock->waiting_writers, &lock->lock) != thrd_success)
 124         {
 125           lock->waiting_writers_count--;
 126           mtx_unlock (&lock->lock);
 127           return EINVAL;
 128         }
 129       lock->waiting_writers_count--;
 130     }
 131   lock->runcount--; /* runcount becomes -1 */
 132   if (mtx_unlock (&lock->lock) != thrd_success)
 133     return EINVAL;
 134   return 0;
 135 }
 136 
 137 int
 138 glthread_rwlock_unlock (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140   if (lock->init_needed)
 141     call_once (&lock->init_once, lock->init_func);
 142   if (mtx_lock (&lock->lock) != thrd_success)
 143     return EAGAIN;
 144   if (lock->runcount < 0)
 145     {
 146       /* Drop a writer lock.  */
 147       if (!(lock->runcount == -1))
 148         {
 149           mtx_unlock (&lock->lock);
 150           return EINVAL;
 151         }
 152       lock->runcount = 0;
 153     }
 154   else
 155     {
 156       /* Drop a reader lock.  */
 157       if (!(lock->runcount > 0))
 158         {
 159           mtx_unlock (&lock->lock);
 160           return EINVAL;
 161         }
 162       lock->runcount--;
 163     }
 164   if (lock->runcount == 0)
 165     {
 166       /* POSIX recommends that "write locks shall take precedence over read
 167          locks", to avoid "writer starvation".  */
 168       if (lock->waiting_writers_count > 0)
 169         {
 170           /* Wake up one of the waiting writers.  */
 171           if (cnd_signal (&lock->waiting_writers) != thrd_success)
 172             {
 173               mtx_unlock (&lock->lock);
 174               return EINVAL;
 175             }
 176         }
 177       else
 178         {
 179           /* Wake up all waiting readers.  */
 180           if (cnd_broadcast (&lock->waiting_readers) != thrd_success)
 181             {
 182               mtx_unlock (&lock->lock);
 183               return EINVAL;
 184             }
 185         }
 186     }
 187   if (mtx_unlock (&lock->lock) != thrd_success)
 188     return EINVAL;
 189   return 0;
 190 }
 191 
 192 int
 193 glthread_rwlock_destroy (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195   if (lock->init_needed)
 196     call_once (&lock->init_once, lock->init_func);
 197   mtx_destroy (&lock->lock);
 198   cnd_destroy (&lock->waiting_readers);
 199   cnd_destroy (&lock->waiting_writers);
 200   return 0;
 201 }
 202 
 203 /* --------------------- gl_recursive_lock_t datatype --------------------- */
 204 
 205 int
 206 glthread_recursive_lock_init (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 207 {
 208   if (mtx_init (&lock->mutex, mtx_plain | mtx_recursive) != thrd_success)
 209     return ENOMEM;
 210   lock->init_needed = 0;
 211   return 0;
 212 }
 213 
 214 int
 215 glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217   if (lock->init_needed)
 218     call_once (&lock->init_once, lock->init_func);
 219   if (mtx_lock (&lock->mutex) != thrd_success)
 220     return EAGAIN;
 221   return 0;
 222 }
 223 
 224 int
 225 glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227   if (lock->init_needed)
 228     call_once (&lock->init_once, lock->init_func);
 229   if (mtx_unlock (&lock->mutex) != thrd_success)
 230     return EINVAL;
 231   return 0;
 232 }
 233 
 234 int
 235 glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237   if (lock->init_needed)
 238     call_once (&lock->init_once, lock->init_func);
 239   mtx_destroy (&lock->mutex);
 240   return 0;
 241 }
 242 
 243 /* -------------------------- gl_once_t datatype -------------------------- */
 244 
 245 #endif
 246 
 247 /* ========================================================================= */
 248 
 249 #if USE_POSIX_THREADS
 250 
 251 /* -------------------------- gl_lock_t datatype -------------------------- */
 252 
 253 /* ------------------------- gl_rwlock_t datatype ------------------------- */
 254 
 255 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
 256 
 257 #  if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
 258 
 259 #   if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
 260      /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
 261 
 262 int
 263 glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265   pthread_rwlockattr_t attributes;
 266   int err;
 267 
 268   err = pthread_rwlockattr_init (&attributes);
 269   if (err != 0)
 270     return err;
 271   /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
 272      causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
 273      do this; see
 274      http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
 275   err = pthread_rwlockattr_setkind_np (&attributes,
 276                                        PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
 277   if (err == 0)
 278     err = pthread_rwlock_init(lock, &attributes);
 279   /* pthread_rwlockattr_destroy always returns 0.  It cannot influence the
 280      return value.  */
 281   pthread_rwlockattr_destroy (&attributes);
 282   return err;
 283 }
 284 
 285 #   endif
 286 #  else
 287 
 288 int
 289 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291   int err;
 292 
 293   err = pthread_rwlock_init (&lock->rwlock, NULL);
 294   if (err != 0)
 295     return err;
 296   lock->initialized = 1;
 297   return 0;
 298 }
 299 
 300 int
 301 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303   if (!lock->initialized)
 304     {
 305       int err;
 306 
 307       err = pthread_mutex_lock (&lock->guard);
 308       if (err != 0)
 309         return err;
 310       if (!lock->initialized)
 311         {
 312           err = glthread_rwlock_init_multithreaded (lock);
 313           if (err != 0)
 314             {
 315               pthread_mutex_unlock (&lock->guard);
 316               return err;
 317             }
 318         }
 319       err = pthread_mutex_unlock (&lock->guard);
 320       if (err != 0)
 321         return err;
 322     }
 323   return pthread_rwlock_rdlock (&lock->rwlock);
 324 }
 325 
 326 int
 327 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329   if (!lock->initialized)
 330     {
 331       int err;
 332 
 333       err = pthread_mutex_lock (&lock->guard);
 334       if (err != 0)
 335         return err;
 336       if (!lock->initialized)
 337         {
 338           err = glthread_rwlock_init_multithreaded (lock);
 339           if (err != 0)
 340             {
 341               pthread_mutex_unlock (&lock->guard);
 342               return err;
 343             }
 344         }
 345       err = pthread_mutex_unlock (&lock->guard);
 346       if (err != 0)
 347         return err;
 348     }
 349   return pthread_rwlock_wrlock (&lock->rwlock);
 350 }
 351 
 352 int
 353 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 354 {
 355   if (!lock->initialized)
 356     return EINVAL;
 357   return pthread_rwlock_unlock (&lock->rwlock);
 358 }
 359 
 360 int
 361 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363   int err;
 364 
 365   if (!lock->initialized)
 366     return EINVAL;
 367   err = pthread_rwlock_destroy (&lock->rwlock);
 368   if (err != 0)
 369     return err;
 370   lock->initialized = 0;
 371   return 0;
 372 }
 373 
 374 #  endif
 375 
 376 # else
 377 
 378 int
 379 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 380 {
 381   int err;
 382 
 383   err = pthread_mutex_init (&lock->lock, NULL);
 384   if (err != 0)
 385     return err;
 386   err = pthread_cond_init (&lock->waiting_readers, NULL);
 387   if (err != 0)
 388     return err;
 389   err = pthread_cond_init (&lock->waiting_writers, NULL);
 390   if (err != 0)
 391     return err;
 392   lock->waiting_writers_count = 0;
 393   lock->runcount = 0;
 394   return 0;
 395 }
 396 
 397 int
 398 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 399 {
 400   int err;
 401 
 402   err = pthread_mutex_lock (&lock->lock);
 403   if (err != 0)
 404     return err;
 405   /* Test whether only readers are currently running, and whether the runcount
 406      field will not overflow, and whether no writer is waiting.  The latter
 407      condition is because POSIX recommends that "write locks shall take
 408      precedence over read locks", to avoid "writer starvation".  */
 409   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 410     {
 411       /* This thread has to wait for a while.  Enqueue it among the
 412          waiting_readers.  */
 413       err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
 414       if (err != 0)
 415         {
 416           pthread_mutex_unlock (&lock->lock);
 417           return err;
 418         }
 419     }
 420   lock->runcount++;
 421   return pthread_mutex_unlock (&lock->lock);
 422 }
 423 
 424 int
 425 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427   int err;
 428 
 429   err = pthread_mutex_lock (&lock->lock);
 430   if (err != 0)
 431     return err;
 432   /* Test whether no readers or writers are currently running.  */
 433   while (!(lock->runcount == 0))
 434     {
 435       /* This thread has to wait for a while.  Enqueue it among the
 436          waiting_writers.  */
 437       lock->waiting_writers_count++;
 438       err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
 439       if (err != 0)
 440         {
 441           lock->waiting_writers_count--;
 442           pthread_mutex_unlock (&lock->lock);
 443           return err;
 444         }
 445       lock->waiting_writers_count--;
 446     }
 447   lock->runcount--; /* runcount becomes -1 */
 448   return pthread_mutex_unlock (&lock->lock);
 449 }
 450 
 451 int
 452 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454   int err;
 455 
 456   err = pthread_mutex_lock (&lock->lock);
 457   if (err != 0)
 458     return err;
 459   if (lock->runcount < 0)
 460     {
 461       /* Drop a writer lock.  */
 462       if (!(lock->runcount == -1))
 463         {
 464           pthread_mutex_unlock (&lock->lock);
 465           return EINVAL;
 466         }
 467       lock->runcount = 0;
 468     }
 469   else
 470     {
 471       /* Drop a reader lock.  */
 472       if (!(lock->runcount > 0))
 473         {
 474           pthread_mutex_unlock (&lock->lock);
 475           return EINVAL;
 476         }
 477       lock->runcount--;
 478     }
 479   if (lock->runcount == 0)
 480     {
 481       /* POSIX recommends that "write locks shall take precedence over read
 482          locks", to avoid "writer starvation".  */
 483       if (lock->waiting_writers_count > 0)
 484         {
 485           /* Wake up one of the waiting writers.  */
 486           err = pthread_cond_signal (&lock->waiting_writers);
 487           if (err != 0)
 488             {
 489               pthread_mutex_unlock (&lock->lock);
 490               return err;
 491             }
 492         }
 493       else
 494         {
 495           /* Wake up all waiting readers.  */
 496           err = pthread_cond_broadcast (&lock->waiting_readers);
 497           if (err != 0)
 498             {
 499               pthread_mutex_unlock (&lock->lock);
 500               return err;
 501             }
 502         }
 503     }
 504   return pthread_mutex_unlock (&lock->lock);
 505 }
 506 
 507 int
 508 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510   int err;
 511 
 512   err = pthread_mutex_destroy (&lock->lock);
 513   if (err != 0)
 514     return err;
 515   err = pthread_cond_destroy (&lock->waiting_readers);
 516   if (err != 0)
 517     return err;
 518   err = pthread_cond_destroy (&lock->waiting_writers);
 519   if (err != 0)
 520     return err;
 521   return 0;
 522 }
 523 
 524 # endif
 525 
 526 /* --------------------- gl_recursive_lock_t datatype --------------------- */
 527 
 528 # if HAVE_PTHREAD_MUTEX_RECURSIVE
 529 
 530 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 531 
 532 int
 533 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 534 {
 535   pthread_mutexattr_t attributes;
 536   int err;
 537 
 538   err = pthread_mutexattr_init (&attributes);
 539   if (err != 0)
 540     return err;
 541   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
 542   if (err != 0)
 543     {
 544       pthread_mutexattr_destroy (&attributes);
 545       return err;
 546     }
 547   err = pthread_mutex_init (lock, &attributes);
 548   if (err != 0)
 549     {
 550       pthread_mutexattr_destroy (&attributes);
 551       return err;
 552     }
 553   err = pthread_mutexattr_destroy (&attributes);
 554   if (err != 0)
 555     return err;
 556   return 0;
 557 }
 558 
 559 #  else
 560 
 561 int
 562 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 563 {
 564   pthread_mutexattr_t attributes;
 565   int err;
 566 
 567   err = pthread_mutexattr_init (&attributes);
 568   if (err != 0)
 569     return err;
 570   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
 571   if (err != 0)
 572     {
 573       pthread_mutexattr_destroy (&attributes);
 574       return err;
 575     }
 576   err = pthread_mutex_init (&lock->recmutex, &attributes);
 577   if (err != 0)
 578     {
 579       pthread_mutexattr_destroy (&attributes);
 580       return err;
 581     }
 582   err = pthread_mutexattr_destroy (&attributes);
 583   if (err != 0)
 584     return err;
 585   lock->initialized = 1;
 586   return 0;
 587 }
 588 
 589 int
 590 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592   if (!lock->initialized)
 593     {
 594       int err;
 595 
 596       err = pthread_mutex_lock (&lock->guard);
 597       if (err != 0)
 598         return err;
 599       if (!lock->initialized)
 600         {
 601           err = glthread_recursive_lock_init_multithreaded (lock);
 602           if (err != 0)
 603             {
 604               pthread_mutex_unlock (&lock->guard);
 605               return err;
 606             }
 607         }
 608       err = pthread_mutex_unlock (&lock->guard);
 609       if (err != 0)
 610         return err;
 611     }
 612   return pthread_mutex_lock (&lock->recmutex);
 613 }
 614 
 615 int
 616 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618   if (!lock->initialized)
 619     return EINVAL;
 620   return pthread_mutex_unlock (&lock->recmutex);
 621 }
 622 
 623 int
 624 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 625 {
 626   int err;
 627 
 628   if (!lock->initialized)
 629     return EINVAL;
 630   err = pthread_mutex_destroy (&lock->recmutex);
 631   if (err != 0)
 632     return err;
 633   lock->initialized = 0;
 634   return 0;
 635 }
 636 
 637 #  endif
 638 
 639 # else
 640 
 641 int
 642 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 643 {
 644   int err;
 645 
 646   err = pthread_mutex_init (&lock->mutex, NULL);
 647   if (err != 0)
 648     return err;
 649   lock->owner = (pthread_t) 0;
 650   lock->depth = 0;
 651   return 0;
 652 }
 653 
 654 int
 655 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 656 {
 657   pthread_t self = pthread_self ();
 658   if (lock->owner != self)
 659     {
 660       int err;
 661 
 662       err = pthread_mutex_lock (&lock->mutex);
 663       if (err != 0)
 664         return err;
 665       lock->owner = self;
 666     }
 667   if (++(lock->depth) == 0) /* wraparound? */
 668     {
 669       lock->depth--;
 670       return EAGAIN;
 671     }
 672   return 0;
 673 }
 674 
 675 int
 676 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 677 {
 678   if (lock->owner != pthread_self ())
 679     return EPERM;
 680   if (lock->depth == 0)
 681     return EINVAL;
 682   if (--(lock->depth) == 0)
 683     {
 684       lock->owner = (pthread_t) 0;
 685       return pthread_mutex_unlock (&lock->mutex);
 686     }
 687   else
 688     return 0;
 689 }
 690 
 691 int
 692 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 693 {
 694   if (lock->owner != (pthread_t) 0)
 695     return EBUSY;
 696   return pthread_mutex_destroy (&lock->mutex);
 697 }
 698 
 699 # endif
 700 
 701 /* -------------------------- gl_once_t datatype -------------------------- */
 702 
 703 static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
 704 
 705 int
 706 glthread_once_singlethreaded (pthread_once_t *once_control)
     /* [previous][next][first][last][top][bottom][index][help] */
 707 {
 708   /* We don't know whether pthread_once_t is an integer type, a floating-point
 709      type, a pointer type, or a structure type.  */
 710   char *firstbyte = (char *)once_control;
 711   if (*firstbyte == *(const char *)&fresh_once)
 712     {
 713       /* First time use of once_control.  Invert the first byte.  */
 714       *firstbyte = ~ *(const char *)&fresh_once;
 715       return 1;
 716     }
 717   else
 718     return 0;
 719 }
 720 
 721 # if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
 722 
 723 int
 724 glthread_once_multithreaded (pthread_once_t *once_control,
     /* [previous][next][first][last][top][bottom][index][help] */
 725                              void (*init_function) (void))
 726 {
 727   int err = pthread_once (once_control, init_function);
 728   if (err == ENOSYS)
 729     {
 730       /* This happens on FreeBSD 11: The pthread_once function in libc returns
 731          ENOSYS.  */
 732       if (glthread_once_singlethreaded (once_control))
 733         init_function ();
 734       return 0;
 735     }
 736   return err;
 737 }
 738 
 739 # endif
 740 
 741 #endif
 742 
 743 /* ========================================================================= */
 744 
 745 #if USE_WINDOWS_THREADS
 746 
 747 #endif
 748 
 749 /* ========================================================================= */

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