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

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

DEFINITIONS

This source file includes following definitions.
  1. pthread_rwlockattr_init
  2. pthread_rwlockattr_destroy
  3. pthread_rwlock_init
  4. pthread_rwlock_rdlock
  5. pthread_rwlock_wrlock
  6. pthread_rwlock_tryrdlock
  7. pthread_rwlock_trywrlock
  8. pthread_rwlock_timedrdlock
  9. pthread_rwlock_timedwrlock
  10. pthread_rwlock_unlock
  11. pthread_rwlock_destroy
  12. pthread_rwlock_init
  13. pthread_rwlock_rdlock
  14. pthread_rwlock_wrlock
  15. pthread_rwlock_tryrdlock
  16. pthread_rwlock_trywrlock
  17. pthread_rwlock_timedrdlock
  18. pthread_rwlock_timedwrlock
  19. pthread_rwlock_unlock
  20. pthread_rwlock_destroy
  21. pthread_rwlock_timedrdlock
  22. pthread_rwlock_timedwrlock
  23. pthread_rwlock_init
  24. pthread_rwlock_rdlock
  25. pthread_rwlock_wrlock
  26. pthread_rwlock_tryrdlock
  27. pthread_rwlock_trywrlock
  28. pthread_rwlock_timedrdlock
  29. pthread_rwlock_timedwrlock
  30. pthread_rwlock_unlock
  31. pthread_rwlock_destroy

   1 /* POSIX read-write locks.
   2    Copyright (C) 2019-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>, 2019.  */
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include <pthread.h>
  23 
  24 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
  25 # include "windows-timedrwlock.h"
  26 #else
  27 # include <errno.h>
  28 # include <limits.h>
  29 # include <sys/time.h>
  30 # include <time.h>
  31 #endif
  32 
  33 #if ((defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS) || !HAVE_PTHREAD_H
  34 
  35 int
  36 pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38   *attr = 0;
  39   return 0;
  40 }
  41 
  42 int
  43 pthread_rwlockattr_destroy (_GL_UNUSED pthread_rwlockattr_t *attr)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45   return 0;
  46 }
  47 
  48 #endif
  49 
  50 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
  51 /* Use Windows threads.  */
  52 
  53 int
  54 pthread_rwlock_init (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
  55                      _GL_UNUSED const pthread_rwlockattr_t *attr)
  56 {
  57   glwthread_timedrwlock_init (lock);
  58   return 0;
  59 }
  60 
  61 int
  62 pthread_rwlock_rdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64   return glwthread_timedrwlock_rdlock (lock);
  65 }
  66 
  67 int
  68 pthread_rwlock_wrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70   return glwthread_timedrwlock_wrlock (lock);
  71 }
  72 
  73 int
  74 pthread_rwlock_tryrdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76   return glwthread_timedrwlock_tryrdlock (lock);
  77 }
  78 
  79 int
  80 pthread_rwlock_trywrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82   return glwthread_timedrwlock_trywrlock (lock);
  83 }
  84 
  85 int
  86 pthread_rwlock_timedrdlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
  87                             const struct timespec *abstime)
  88 {
  89   return glwthread_timedrwlock_timedrdlock (lock, abstime);
  90 }
  91 
  92 int
  93 pthread_rwlock_timedwrlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
  94                             const struct timespec *abstime)
  95 {
  96   return glwthread_timedrwlock_timedwrlock (lock, abstime);
  97 }
  98 
  99 int
 100 pthread_rwlock_unlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102   return glwthread_timedrwlock_unlock (lock);
 103 }
 104 
 105 int
 106 pthread_rwlock_destroy (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108   return glwthread_timedrwlock_destroy (lock);
 109 }
 110 
 111 #elif HAVE_PTHREAD_H
 112 /* Provide workarounds for POSIX threads.  */
 113 
 114 # if PTHREAD_RWLOCK_UNIMPLEMENTED
 115 
 116 int
 117 pthread_rwlock_init (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 118                      _GL_UNUSED const pthread_rwlockattr_t *attr)
 119 {
 120   int err;
 121 
 122   err = pthread_mutex_init (&lock->lock, NULL);
 123   if (err != 0)
 124     return err;
 125   err = pthread_cond_init (&lock->waiting_readers, NULL);
 126   if (err != 0)
 127     return err;
 128   err = pthread_cond_init (&lock->waiting_writers, NULL);
 129   if (err != 0)
 130     return err;
 131   lock->waiting_writers_count = 0;
 132   lock->runcount = 0;
 133   return 0;
 134 }
 135 
 136 int
 137 pthread_rwlock_rdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139   int err;
 140 
 141   err = pthread_mutex_lock (&lock->lock);
 142   if (err != 0)
 143     return err;
 144   /* Test whether only readers are currently running, and whether the runcount
 145      field will not overflow, and whether no writer is waiting.  The latter
 146      condition is because POSIX recommends that "write locks shall take
 147      precedence over read locks", to avoid "writer starvation".  */
 148   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 149     {
 150       /* This thread has to wait for a while.  Enqueue it among the
 151          waiting_readers.  */
 152       err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
 153       if (err != 0)
 154         {
 155           pthread_mutex_unlock (&lock->lock);
 156           return err;
 157         }
 158     }
 159   lock->runcount++;
 160   return pthread_mutex_unlock (&lock->lock);
 161 }
 162 
 163 int
 164 pthread_rwlock_wrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166   int err;
 167 
 168   err = pthread_mutex_lock (&lock->lock);
 169   if (err != 0)
 170     return err;
 171   /* Test whether no readers or writers are currently running.  */
 172   while (!(lock->runcount == 0))
 173     {
 174       /* This thread has to wait for a while.  Enqueue it among the
 175          waiting_writers.  */
 176       lock->waiting_writers_count++;
 177       err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
 178       if (err != 0)
 179         {
 180           lock->waiting_writers_count--;
 181           pthread_mutex_unlock (&lock->lock);
 182           return err;
 183         }
 184       lock->waiting_writers_count--;
 185     }
 186   lock->runcount--; /* runcount becomes -1 */
 187   return pthread_mutex_unlock (&lock->lock);
 188 }
 189 
 190 int
 191 pthread_rwlock_tryrdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193   int err;
 194 
 195   err = pthread_mutex_lock (&lock->lock);
 196   if (err != 0)
 197     return err;
 198   /* Test whether only readers are currently running, and whether the runcount
 199      field will not overflow, and whether no writer is waiting.  The latter
 200      condition is because POSIX recommends that "write locks shall take
 201      precedence over read locks", to avoid "writer starvation".  */
 202   if (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 203     {
 204       /* This thread would have to wait for a while.  Return instead.  */
 205       pthread_mutex_unlock (&lock->lock);
 206       return EBUSY;
 207     }
 208   lock->runcount++;
 209   return pthread_mutex_unlock (&lock->lock);
 210 }
 211 
 212 int
 213 pthread_rwlock_trywrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215   int err;
 216 
 217   err = pthread_mutex_lock (&lock->lock);
 218   if (err != 0)
 219     return err;
 220   /* Test whether no readers or writers are currently running.  */
 221   if (!(lock->runcount == 0))
 222     {
 223       /* This thread would have to wait for a while.  Return instead.  */
 224       pthread_mutex_unlock (&lock->lock);
 225       return EBUSY;
 226     }
 227   lock->runcount--; /* runcount becomes -1 */
 228   return pthread_mutex_unlock (&lock->lock);
 229 }
 230 
 231 int
 232 pthread_rwlock_timedrdlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 233                             const struct timespec *abstime)
 234 {
 235   int err;
 236 
 237   err = pthread_mutex_lock (&lock->lock);
 238   if (err != 0)
 239     return err;
 240   /* Test whether only readers are currently running, and whether the runcount
 241      field will not overflow, and whether no writer is waiting.  The latter
 242      condition is because POSIX recommends that "write locks shall take
 243      precedence over read locks", to avoid "writer starvation".  */
 244   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
 245     {
 246       /* This thread has to wait for a while.  Enqueue it among the
 247          waiting_readers.  */
 248       err = pthread_cond_timedwait (&lock->waiting_readers, &lock->lock,
 249                                     abstime);
 250       if (err != 0)
 251         {
 252           pthread_mutex_unlock (&lock->lock);
 253           return err;
 254         }
 255     }
 256   lock->runcount++;
 257   return pthread_mutex_unlock (&lock->lock);
 258 }
 259 
 260 int
 261 pthread_rwlock_timedwrlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 262                             const struct timespec *abstime)
 263 {
 264   int err;
 265 
 266   err = pthread_mutex_lock (&lock->lock);
 267   if (err != 0)
 268     return err;
 269   /* Test whether no readers or writers are currently running.  */
 270   while (!(lock->runcount == 0))
 271     {
 272       /* This thread has to wait for a while.  Enqueue it among the
 273          waiting_writers.  */
 274       lock->waiting_writers_count++;
 275       err = pthread_cond_timedwait (&lock->waiting_writers, &lock->lock,
 276                                     abstime);
 277       if (err != 0)
 278         {
 279           lock->waiting_writers_count--;
 280           pthread_mutex_unlock (&lock->lock);
 281           return err;
 282         }
 283       lock->waiting_writers_count--;
 284     }
 285   lock->runcount--; /* runcount becomes -1 */
 286   return pthread_mutex_unlock (&lock->lock);
 287 }
 288 
 289 int
 290 pthread_rwlock_unlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292   int err;
 293 
 294   err = pthread_mutex_lock (&lock->lock);
 295   if (err != 0)
 296     return err;
 297   if (lock->runcount < 0)
 298     {
 299       /* Drop a writer lock.  */
 300       if (!(lock->runcount == -1))
 301         {
 302           pthread_mutex_unlock (&lock->lock);
 303           return EINVAL;
 304         }
 305       lock->runcount = 0;
 306     }
 307   else
 308     {
 309       /* Drop a reader lock.  */
 310       if (!(lock->runcount > 0))
 311         {
 312           pthread_mutex_unlock (&lock->lock);
 313           return EINVAL;
 314         }
 315       lock->runcount--;
 316     }
 317   if (lock->runcount == 0)
 318     {
 319       /* POSIX recommends that "write locks shall take precedence over read
 320          locks", to avoid "writer starvation".  */
 321       if (lock->waiting_writers_count > 0)
 322         {
 323           /* Wake up one of the waiting writers.  */
 324           err = pthread_cond_signal (&lock->waiting_writers);
 325           if (err != 0)
 326             {
 327               pthread_mutex_unlock (&lock->lock);
 328               return err;
 329             }
 330         }
 331       else
 332         {
 333           /* Wake up all waiting readers.  */
 334           err = pthread_cond_broadcast (&lock->waiting_readers);
 335           if (err != 0)
 336             {
 337               pthread_mutex_unlock (&lock->lock);
 338               return err;
 339             }
 340         }
 341     }
 342   return pthread_mutex_unlock (&lock->lock);
 343 }
 344 
 345 int
 346 pthread_rwlock_destroy (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 347 {
 348   int err;
 349 
 350   err = pthread_mutex_destroy (&lock->lock);
 351   if (err != 0)
 352     return err;
 353   err = pthread_cond_destroy (&lock->waiting_readers);
 354   if (err != 0)
 355     return err;
 356   err = pthread_cond_destroy (&lock->waiting_writers);
 357   if (err != 0)
 358     return err;
 359   return 0;
 360 }
 361 
 362 # elif PTHREAD_RWLOCK_LACKS_TIMEOUT
 363 
 364 int
 365 pthread_rwlock_timedrdlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 366                             const struct timespec *abstime)
 367 {
 368   /* Poll the lock's state in regular intervals.  Ugh.  */
 369   for (;;)
 370     {
 371       int err;
 372       struct timeval currtime;
 373       unsigned long remaining;
 374       struct timespec duration;
 375 
 376       err = pthread_rwlock_tryrdlock (lock);
 377       if (err != EBUSY)
 378         return err;
 379 
 380       gettimeofday (&currtime, NULL);
 381 
 382       if (currtime.tv_sec > abstime->tv_sec)
 383         remaining = 0;
 384       else
 385         {
 386           unsigned long seconds = abstime->tv_sec - currtime.tv_sec;
 387           remaining = seconds * 1000000000;
 388           if (remaining / 1000000000 != seconds) /* overflow? */
 389             remaining = ULONG_MAX;
 390           else
 391             {
 392               long nanoseconds =
 393                 abstime->tv_nsec - currtime.tv_usec * 1000;
 394               if (nanoseconds >= 0)
 395                 {
 396                   remaining += nanoseconds;
 397                   if (remaining < nanoseconds) /* overflow? */
 398                     remaining = ULONG_MAX;
 399                 }
 400               else
 401                 {
 402                   if (remaining >= - nanoseconds)
 403                     remaining -= (- nanoseconds);
 404                   else
 405                     remaining = 0;
 406                 }
 407             }
 408         }
 409       if (remaining == 0)
 410         return ETIMEDOUT;
 411 
 412       /* Sleep 1 ms.  */
 413       duration.tv_sec = 0;
 414       duration.tv_nsec = 1000000;
 415       if (duration.tv_nsec > remaining)
 416         duration.tv_nsec = remaining;
 417       nanosleep (&duration, NULL);
 418     }
 419 }
 420 
 421 int
 422 pthread_rwlock_timedwrlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 423                             const struct timespec *abstime)
 424 {
 425   /* Poll the lock's state in regular intervals.  Ugh.  */
 426   for (;;)
 427     {
 428       int err;
 429       struct timeval currtime;
 430       unsigned long remaining;
 431       struct timespec duration;
 432 
 433       err = pthread_rwlock_trywrlock (lock);
 434       if (err != EBUSY)
 435         return err;
 436 
 437       gettimeofday (&currtime, NULL);
 438 
 439       if (currtime.tv_sec > abstime->tv_sec)
 440         remaining = 0;
 441       else
 442         {
 443           unsigned long seconds = abstime->tv_sec - currtime.tv_sec;
 444           remaining = seconds * 1000000000;
 445           if (remaining / 1000000000 != seconds) /* overflow? */
 446             remaining = ULONG_MAX;
 447           else
 448             {
 449               long nanoseconds =
 450                 abstime->tv_nsec - currtime.tv_usec * 1000;
 451               if (nanoseconds >= 0)
 452                 {
 453                   remaining += nanoseconds;
 454                   if (remaining < nanoseconds) /* overflow? */
 455                     remaining = ULONG_MAX;
 456                 }
 457               else
 458                 {
 459                   if (remaining >= - nanoseconds)
 460                     remaining -= (- nanoseconds);
 461                   else
 462                     remaining = 0;
 463                 }
 464             }
 465         }
 466       if (remaining == 0)
 467         return ETIMEDOUT;
 468 
 469       /* Sleep 1 ms.  */
 470       duration.tv_sec = 0;
 471       duration.tv_nsec = 1000000;
 472       if (duration.tv_nsec > remaining)
 473         duration.tv_nsec = remaining;
 474       nanosleep (&duration, NULL);
 475     }
 476 }
 477 
 478 # endif
 479 
 480 #else
 481 /* Provide a dummy implementation for single-threaded applications.  */
 482 
 483 /* The pthread_rwlock_t is an 'int', representing the number of readers running,
 484    or -1 when a writer runs.  */
 485 
 486 int
 487 pthread_rwlock_init (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 488                      _GL_UNUSED const pthread_rwlockattr_t *attr)
 489 {
 490   *lock = 0;
 491   return 0;
 492 }
 493 
 494 int
 495 pthread_rwlock_rdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 496 {
 497   if (*lock < 0)
 498     return EDEADLK;
 499   (*lock)++;
 500   return 0;
 501 }
 502 
 503 int
 504 pthread_rwlock_wrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506   if (*lock != 0)
 507     return EDEADLK;
 508   *lock = -1;
 509   return 0;
 510 }
 511 
 512 int
 513 pthread_rwlock_tryrdlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 514 {
 515   return pthread_rwlock_rdlock (lock);
 516 }
 517 
 518 int
 519 pthread_rwlock_trywrlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 520 {
 521   return pthread_rwlock_wrlock (lock);
 522 }
 523 
 524 int
 525 pthread_rwlock_timedrdlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 526                             _GL_UNUSED const struct timespec *abstime)
 527 {
 528   return pthread_rwlock_rdlock (lock);
 529 }
 530 
 531 int
 532 pthread_rwlock_timedwrlock (pthread_rwlock_t *lock,
     /* [previous][next][first][last][top][bottom][index][help] */
 533                             _GL_UNUSED const struct timespec *abstime)
 534 {
 535   return pthread_rwlock_wrlock (lock);
 536 }
 537 
 538 int
 539 pthread_rwlock_unlock (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541   if (*lock == 0)
 542     return EPERM;
 543   if (*lock < 0)
 544     *lock = 0;
 545   else /* *lock > 0 */
 546     (*lock)--;
 547   return 0;
 548 }
 549 
 550 int
 551 pthread_rwlock_destroy (pthread_rwlock_t *lock)
     /* [previous][next][first][last][top][bottom][index][help] */
 552 {
 553   if (*lock)
 554     return EBUSY;
 555   return 0;
 556 }
 557 
 558 #endif

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