"Fossies" - the Fresh Open Source Software Archive

Member "nano-4.5/lib/glthread/lock.c" (4 Oct 2019, 12295 Bytes) of package /linux/misc/nano-4.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lock.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.3_vs_4.4.

    1 /* Locking in multithreaded situations.
    2    Copyright (C) 2005-2019 Free Software Foundation, Inc.
    3 
    4    This program is free software; you can redistribute it and/or modify
    5    it under the terms of the GNU General Public License as published by
    6    the Free Software Foundation; either version 3, or (at your option)
    7    any later version.
    8 
    9    This program 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 General Public License for more details.
   13 
   14    You should have received a copy of the GNU 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_POSIX_THREADS
   27 
   28 /* -------------------------- gl_lock_t datatype -------------------------- */
   29 
   30 /* ------------------------- gl_rwlock_t datatype ------------------------- */
   31 
   32 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
   33 
   34 #  ifdef PTHREAD_RWLOCK_INITIALIZER
   35 
   36 #   if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
   37      /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
   38 
   39 int
   40 glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
   41 {
   42   pthread_rwlockattr_t attributes;
   43   int err;
   44 
   45   err = pthread_rwlockattr_init (&attributes);
   46   if (err != 0)
   47     return err;
   48   /* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
   49      causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
   50      do this; see
   51      http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
   52   err = pthread_rwlockattr_setkind_np (&attributes,
   53                                        PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
   54   if (err == 0)
   55     err = pthread_rwlock_init(lock, &attributes);
   56   /* pthread_rwlockattr_destroy always returns 0.  It cannot influence the
   57      return value.  */
   58   pthread_rwlockattr_destroy (&attributes);
   59   return err;
   60 }
   61 
   62 #   endif
   63 #  else
   64 
   65 int
   66 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
   67 {
   68   int err;
   69 
   70   err = pthread_rwlock_init (&lock->rwlock, NULL);
   71   if (err != 0)
   72     return err;
   73   lock->initialized = 1;
   74   return 0;
   75 }
   76 
   77 int
   78 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
   79 {
   80   if (!lock->initialized)
   81     {
   82       int err;
   83 
   84       err = pthread_mutex_lock (&lock->guard);
   85       if (err != 0)
   86         return err;
   87       if (!lock->initialized)
   88         {
   89           err = glthread_rwlock_init_multithreaded (lock);
   90           if (err != 0)
   91             {
   92               pthread_mutex_unlock (&lock->guard);
   93               return err;
   94             }
   95         }
   96       err = pthread_mutex_unlock (&lock->guard);
   97       if (err != 0)
   98         return err;
   99     }
  100   return pthread_rwlock_rdlock (&lock->rwlock);
  101 }
  102 
  103 int
  104 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
  105 {
  106   if (!lock->initialized)
  107     {
  108       int err;
  109 
  110       err = pthread_mutex_lock (&lock->guard);
  111       if (err != 0)
  112         return err;
  113       if (!lock->initialized)
  114         {
  115           err = glthread_rwlock_init_multithreaded (lock);
  116           if (err != 0)
  117             {
  118               pthread_mutex_unlock (&lock->guard);
  119               return err;
  120             }
  121         }
  122       err = pthread_mutex_unlock (&lock->guard);
  123       if (err != 0)
  124         return err;
  125     }
  126   return pthread_rwlock_wrlock (&lock->rwlock);
  127 }
  128 
  129 int
  130 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
  131 {
  132   if (!lock->initialized)
  133     return EINVAL;
  134   return pthread_rwlock_unlock (&lock->rwlock);
  135 }
  136 
  137 int
  138 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
  139 {
  140   int err;
  141 
  142   if (!lock->initialized)
  143     return EINVAL;
  144   err = pthread_rwlock_destroy (&lock->rwlock);
  145   if (err != 0)
  146     return err;
  147   lock->initialized = 0;
  148   return 0;
  149 }
  150 
  151 #  endif
  152 
  153 # else
  154 
  155 int
  156 glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
  157 {
  158   int err;
  159 
  160   err = pthread_mutex_init (&lock->lock, NULL);
  161   if (err != 0)
  162     return err;
  163   err = pthread_cond_init (&lock->waiting_readers, NULL);
  164   if (err != 0)
  165     return err;
  166   err = pthread_cond_init (&lock->waiting_writers, NULL);
  167   if (err != 0)
  168     return err;
  169   lock->waiting_writers_count = 0;
  170   lock->runcount = 0;
  171   return 0;
  172 }
  173 
  174 int
  175 glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
  176 {
  177   int err;
  178 
  179   err = pthread_mutex_lock (&lock->lock);
  180   if (err != 0)
  181     return err;
  182   /* Test whether only readers are currently running, and whether the runcount
  183      field will not overflow, and whether no writer is waiting.  The latter
  184      condition is because POSIX recommends that "write locks shall take
  185      precedence over read locks", to avoid "writer starvation".  */
  186   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
  187     {
  188       /* This thread has to wait for a while.  Enqueue it among the
  189          waiting_readers.  */
  190       err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
  191       if (err != 0)
  192         {
  193           pthread_mutex_unlock (&lock->lock);
  194           return err;
  195         }
  196     }
  197   lock->runcount++;
  198   return pthread_mutex_unlock (&lock->lock);
  199 }
  200 
  201 int
  202 glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
  203 {
  204   int err;
  205 
  206   err = pthread_mutex_lock (&lock->lock);
  207   if (err != 0)
  208     return err;
  209   /* Test whether no readers or writers are currently running.  */
  210   while (!(lock->runcount == 0))
  211     {
  212       /* This thread has to wait for a while.  Enqueue it among the
  213          waiting_writers.  */
  214       lock->waiting_writers_count++;
  215       err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
  216       if (err != 0)
  217         {
  218           lock->waiting_writers_count--;
  219           pthread_mutex_unlock (&lock->lock);
  220           return err;
  221         }
  222       lock->waiting_writers_count--;
  223     }
  224   lock->runcount--; /* runcount becomes -1 */
  225   return pthread_mutex_unlock (&lock->lock);
  226 }
  227 
  228 int
  229 glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
  230 {
  231   int err;
  232 
  233   err = pthread_mutex_lock (&lock->lock);
  234   if (err != 0)
  235     return err;
  236   if (lock->runcount < 0)
  237     {
  238       /* Drop a writer lock.  */
  239       if (!(lock->runcount == -1))
  240         {
  241           pthread_mutex_unlock (&lock->lock);
  242           return EINVAL;
  243         }
  244       lock->runcount = 0;
  245     }
  246   else
  247     {
  248       /* Drop a reader lock.  */
  249       if (!(lock->runcount > 0))
  250         {
  251           pthread_mutex_unlock (&lock->lock);
  252           return EINVAL;
  253         }
  254       lock->runcount--;
  255     }
  256   if (lock->runcount == 0)
  257     {
  258       /* POSIX recommends that "write locks shall take precedence over read
  259          locks", to avoid "writer starvation".  */
  260       if (lock->waiting_writers_count > 0)
  261         {
  262           /* Wake up one of the waiting writers.  */
  263           err = pthread_cond_signal (&lock->waiting_writers);
  264           if (err != 0)
  265             {
  266               pthread_mutex_unlock (&lock->lock);
  267               return err;
  268             }
  269         }
  270       else
  271         {
  272           /* Wake up all waiting readers.  */
  273           err = pthread_cond_broadcast (&lock->waiting_readers);
  274           if (err != 0)
  275             {
  276               pthread_mutex_unlock (&lock->lock);
  277               return err;
  278             }
  279         }
  280     }
  281   return pthread_mutex_unlock (&lock->lock);
  282 }
  283 
  284 int
  285 glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
  286 {
  287   int err;
  288 
  289   err = pthread_mutex_destroy (&lock->lock);
  290   if (err != 0)
  291     return err;
  292   err = pthread_cond_destroy (&lock->waiting_readers);
  293   if (err != 0)
  294     return err;
  295   err = pthread_cond_destroy (&lock->waiting_writers);
  296   if (err != 0)
  297     return err;
  298   return 0;
  299 }
  300 
  301 # endif
  302 
  303 /* --------------------- gl_recursive_lock_t datatype --------------------- */
  304 
  305 # if HAVE_PTHREAD_MUTEX_RECURSIVE
  306 
  307 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
  308 
  309 int
  310 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  311 {
  312   pthread_mutexattr_t attributes;
  313   int err;
  314 
  315   err = pthread_mutexattr_init (&attributes);
  316   if (err != 0)
  317     return err;
  318   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
  319   if (err != 0)
  320     {
  321       pthread_mutexattr_destroy (&attributes);
  322       return err;
  323     }
  324   err = pthread_mutex_init (lock, &attributes);
  325   if (err != 0)
  326     {
  327       pthread_mutexattr_destroy (&attributes);
  328       return err;
  329     }
  330   err = pthread_mutexattr_destroy (&attributes);
  331   if (err != 0)
  332     return err;
  333   return 0;
  334 }
  335 
  336 #  else
  337 
  338 int
  339 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  340 {
  341   pthread_mutexattr_t attributes;
  342   int err;
  343 
  344   err = pthread_mutexattr_init (&attributes);
  345   if (err != 0)
  346     return err;
  347   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
  348   if (err != 0)
  349     {
  350       pthread_mutexattr_destroy (&attributes);
  351       return err;
  352     }
  353   err = pthread_mutex_init (&lock->recmutex, &attributes);
  354   if (err != 0)
  355     {
  356       pthread_mutexattr_destroy (&attributes);
  357       return err;
  358     }
  359   err = pthread_mutexattr_destroy (&attributes);
  360   if (err != 0)
  361     return err;
  362   lock->initialized = 1;
  363   return 0;
  364 }
  365 
  366 int
  367 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
  368 {
  369   if (!lock->initialized)
  370     {
  371       int err;
  372 
  373       err = pthread_mutex_lock (&lock->guard);
  374       if (err != 0)
  375         return err;
  376       if (!lock->initialized)
  377         {
  378           err = glthread_recursive_lock_init_multithreaded (lock);
  379           if (err != 0)
  380             {
  381               pthread_mutex_unlock (&lock->guard);
  382               return err;
  383             }
  384         }
  385       err = pthread_mutex_unlock (&lock->guard);
  386       if (err != 0)
  387         return err;
  388     }
  389   return pthread_mutex_lock (&lock->recmutex);
  390 }
  391 
  392 int
  393 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
  394 {
  395   if (!lock->initialized)
  396     return EINVAL;
  397   return pthread_mutex_unlock (&lock->recmutex);
  398 }
  399 
  400 int
  401 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
  402 {
  403   int err;
  404 
  405   if (!lock->initialized)
  406     return EINVAL;
  407   err = pthread_mutex_destroy (&lock->recmutex);
  408   if (err != 0)
  409     return err;
  410   lock->initialized = 0;
  411   return 0;
  412 }
  413 
  414 #  endif
  415 
  416 # else
  417 
  418 int
  419 glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
  420 {
  421   int err;
  422 
  423   err = pthread_mutex_init (&lock->mutex, NULL);
  424   if (err != 0)
  425     return err;
  426   lock->owner = (pthread_t) 0;
  427   lock->depth = 0;
  428   return 0;
  429 }
  430 
  431 int
  432 glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
  433 {
  434   pthread_t self = pthread_self ();
  435   if (lock->owner != self)
  436     {
  437       int err;
  438 
  439       err = pthread_mutex_lock (&lock->mutex);
  440       if (err != 0)
  441         return err;
  442       lock->owner = self;
  443     }
  444   if (++(lock->depth) == 0) /* wraparound? */
  445     {
  446       lock->depth--;
  447       return EAGAIN;
  448     }
  449   return 0;
  450 }
  451 
  452 int
  453 glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
  454 {
  455   if (lock->owner != pthread_self ())
  456     return EPERM;
  457   if (lock->depth == 0)
  458     return EINVAL;
  459   if (--(lock->depth) == 0)
  460     {
  461       lock->owner = (pthread_t) 0;
  462       return pthread_mutex_unlock (&lock->mutex);
  463     }
  464   else
  465     return 0;
  466 }
  467 
  468 int
  469 glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
  470 {
  471   if (lock->owner != (pthread_t) 0)
  472     return EBUSY;
  473   return pthread_mutex_destroy (&lock->mutex);
  474 }
  475 
  476 # endif
  477 
  478 /* -------------------------- gl_once_t datatype -------------------------- */
  479 
  480 static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
  481 
  482 int
  483 glthread_once_singlethreaded (pthread_once_t *once_control)
  484 {
  485   /* We don't know whether pthread_once_t is an integer type, a floating-point
  486      type, a pointer type, or a structure type.  */
  487   char *firstbyte = (char *)once_control;
  488   if (*firstbyte == *(const char *)&fresh_once)
  489     {
  490       /* First time use of once_control.  Invert the first byte.  */
  491       *firstbyte = ~ *(const char *)&fresh_once;
  492       return 1;
  493     }
  494   else
  495     return 0;
  496 }
  497 
  498 #endif
  499 
  500 /* ========================================================================= */
  501 
  502 #if USE_WINDOWS_THREADS
  503 
  504 #endif
  505 
  506 /* ========================================================================= */