LCOV - code coverage report
Current view: top level - gltests/glthread/glthread - lock.c (source / functions) Hit Total Coverage
Test: GNU SASL Lines: 0 22 0.0 %
Date: 2012-05-28 Functions: 0 2 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 10 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* Locking in multithreaded situations.
       2                 :            :    Copyright (C) 2005-2012 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 <http://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, gthr-solaris.h,
      19                 :            :    gthr-win32.h.  */
      20                 :            : 
      21                 :            : #include <config.h>
      22                 :            : 
      23                 :            : #include "glthread/lock.h"
      24                 :            : 
      25                 :            : /* ========================================================================= */
      26                 :            : 
      27                 :            : #if USE_POSIX_THREADS
      28                 :            : 
      29                 :            : /* -------------------------- gl_lock_t datatype -------------------------- */
      30                 :            : 
      31                 :            : /* ------------------------- gl_rwlock_t datatype ------------------------- */
      32                 :            : 
      33                 :            : # if HAVE_PTHREAD_RWLOCK
      34                 :            : 
      35                 :            : #  if !defined PTHREAD_RWLOCK_INITIALIZER
      36                 :            : 
      37                 :            : int
      38                 :            : glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
      39                 :            : {
      40                 :            :   int err;
      41                 :            : 
      42                 :            :   err = pthread_rwlock_init (&lock->rwlock, NULL);
      43                 :            :   if (err != 0)
      44                 :            :     return err;
      45                 :            :   lock->initialized = 1;
      46                 :            :   return 0;
      47                 :            : }
      48                 :            : 
      49                 :            : int
      50                 :            : glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
      51                 :            : {
      52                 :            :   if (!lock->initialized)
      53                 :            :     {
      54                 :            :       int err;
      55                 :            : 
      56                 :            :       err = pthread_mutex_lock (&lock->guard);
      57                 :            :       if (err != 0)
      58                 :            :         return err;
      59                 :            :       if (!lock->initialized)
      60                 :            :         {
      61                 :            :           err = glthread_rwlock_init_multithreaded (lock);
      62                 :            :           if (err != 0)
      63                 :            :             {
      64                 :            :               pthread_mutex_unlock (&lock->guard);
      65                 :            :               return err;
      66                 :            :             }
      67                 :            :         }
      68                 :            :       err = pthread_mutex_unlock (&lock->guard);
      69                 :            :       if (err != 0)
      70                 :            :         return err;
      71                 :            :     }
      72                 :            :   return pthread_rwlock_rdlock (&lock->rwlock);
      73                 :            : }
      74                 :            : 
      75                 :            : int
      76                 :            : glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
      77                 :            : {
      78                 :            :   if (!lock->initialized)
      79                 :            :     {
      80                 :            :       int err;
      81                 :            : 
      82                 :            :       err = pthread_mutex_lock (&lock->guard);
      83                 :            :       if (err != 0)
      84                 :            :         return err;
      85                 :            :       if (!lock->initialized)
      86                 :            :         {
      87                 :            :           err = glthread_rwlock_init_multithreaded (lock);
      88                 :            :           if (err != 0)
      89                 :            :             {
      90                 :            :               pthread_mutex_unlock (&lock->guard);
      91                 :            :               return err;
      92                 :            :             }
      93                 :            :         }
      94                 :            :       err = pthread_mutex_unlock (&lock->guard);
      95                 :            :       if (err != 0)
      96                 :            :         return err;
      97                 :            :     }
      98                 :            :   return pthread_rwlock_wrlock (&lock->rwlock);
      99                 :            : }
     100                 :            : 
     101                 :            : int
     102                 :            : glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
     103                 :            : {
     104                 :            :   if (!lock->initialized)
     105                 :            :     return EINVAL;
     106                 :            :   return pthread_rwlock_unlock (&lock->rwlock);
     107                 :            : }
     108                 :            : 
     109                 :            : int
     110                 :            : glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
     111                 :            : {
     112                 :            :   int err;
     113                 :            : 
     114                 :            :   if (!lock->initialized)
     115                 :            :     return EINVAL;
     116                 :            :   err = pthread_rwlock_destroy (&lock->rwlock);
     117                 :            :   if (err != 0)
     118                 :            :     return err;
     119                 :            :   lock->initialized = 0;
     120                 :            :   return 0;
     121                 :            : }
     122                 :            : 
     123                 :            : #  endif
     124                 :            : 
     125                 :            : # else
     126                 :            : 
     127                 :            : int
     128                 :            : glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
     129                 :            : {
     130                 :            :   int err;
     131                 :            : 
     132                 :            :   err = pthread_mutex_init (&lock->lock, NULL);
     133                 :            :   if (err != 0)
     134                 :            :     return err;
     135                 :            :   err = pthread_cond_init (&lock->waiting_readers, NULL);
     136                 :            :   if (err != 0)
     137                 :            :     return err;
     138                 :            :   err = pthread_cond_init (&lock->waiting_writers, NULL);
     139                 :            :   if (err != 0)
     140                 :            :     return err;
     141                 :            :   lock->waiting_writers_count = 0;
     142                 :            :   lock->runcount = 0;
     143                 :            :   return 0;
     144                 :            : }
     145                 :            : 
     146                 :            : int
     147                 :            : glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
     148                 :            : {
     149                 :            :   int err;
     150                 :            : 
     151                 :            :   err = pthread_mutex_lock (&lock->lock);
     152                 :            :   if (err != 0)
     153                 :            :     return err;
     154                 :            :   /* Test whether only readers are currently running, and whether the runcount
     155                 :            :      field will not overflow.  */
     156                 :            :   /* POSIX says: "It is implementation-defined whether the calling thread
     157                 :            :      acquires the lock when a writer does not hold the lock and there are
     158                 :            :      writers blocked on the lock."  Let's say, no: give the writers a higher
     159                 :            :      priority.  */
     160                 :            :   while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
     161                 :            :     {
     162                 :            :       /* This thread has to wait for a while.  Enqueue it among the
     163                 :            :          waiting_readers.  */
     164                 :            :       err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
     165                 :            :       if (err != 0)
     166                 :            :         {
     167                 :            :           pthread_mutex_unlock (&lock->lock);
     168                 :            :           return err;
     169                 :            :         }
     170                 :            :     }
     171                 :            :   lock->runcount++;
     172                 :            :   return pthread_mutex_unlock (&lock->lock);
     173                 :            : }
     174                 :            : 
     175                 :            : int
     176                 :            : glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
     177                 :            : {
     178                 :            :   int err;
     179                 :            : 
     180                 :            :   err = pthread_mutex_lock (&lock->lock);
     181                 :            :   if (err != 0)
     182                 :            :     return err;
     183                 :            :   /* Test whether no readers or writers are currently running.  */
     184                 :            :   while (!(lock->runcount == 0))
     185                 :            :     {
     186                 :            :       /* This thread has to wait for a while.  Enqueue it among the
     187                 :            :          waiting_writers.  */
     188                 :            :       lock->waiting_writers_count++;
     189                 :            :       err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
     190                 :            :       if (err != 0)
     191                 :            :         {
     192                 :            :           lock->waiting_writers_count--;
     193                 :            :           pthread_mutex_unlock (&lock->lock);
     194                 :            :           return err;
     195                 :            :         }
     196                 :            :       lock->waiting_writers_count--;
     197                 :            :     }
     198                 :            :   lock->runcount--; /* runcount becomes -1 */
     199                 :            :   return pthread_mutex_unlock (&lock->lock);
     200                 :            : }
     201                 :            : 
     202                 :            : int
     203                 :            : glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
     204                 :            : {
     205                 :            :   int err;
     206                 :            : 
     207                 :            :   err = pthread_mutex_lock (&lock->lock);
     208                 :            :   if (err != 0)
     209                 :            :     return err;
     210                 :            :   if (lock->runcount < 0)
     211                 :            :     {
     212                 :            :       /* Drop a writer lock.  */
     213                 :            :       if (!(lock->runcount == -1))
     214                 :            :         {
     215                 :            :           pthread_mutex_unlock (&lock->lock);
     216                 :            :           return EINVAL;
     217                 :            :         }
     218                 :            :       lock->runcount = 0;
     219                 :            :     }
     220                 :            :   else
     221                 :            :     {
     222                 :            :       /* Drop a reader lock.  */
     223                 :            :       if (!(lock->runcount > 0))
     224                 :            :         {
     225                 :            :           pthread_mutex_unlock (&lock->lock);
     226                 :            :           return EINVAL;
     227                 :            :         }
     228                 :            :       lock->runcount--;
     229                 :            :     }
     230                 :            :   if (lock->runcount == 0)
     231                 :            :     {
     232                 :            :       /* POSIX recommends that "write locks shall take precedence over read
     233                 :            :          locks", to avoid "writer starvation".  */
     234                 :            :       if (lock->waiting_writers_count > 0)
     235                 :            :         {
     236                 :            :           /* Wake up one of the waiting writers.  */
     237                 :            :           err = pthread_cond_signal (&lock->waiting_writers);
     238                 :            :           if (err != 0)
     239                 :            :             {
     240                 :            :               pthread_mutex_unlock (&lock->lock);
     241                 :            :               return err;
     242                 :            :             }
     243                 :            :         }
     244                 :            :       else
     245                 :            :         {
     246                 :            :           /* Wake up all waiting readers.  */
     247                 :            :           err = pthread_cond_broadcast (&lock->waiting_readers);
     248                 :            :           if (err != 0)
     249                 :            :             {
     250                 :            :               pthread_mutex_unlock (&lock->lock);
     251                 :            :               return err;
     252                 :            :             }
     253                 :            :         }
     254                 :            :     }
     255                 :            :   return pthread_mutex_unlock (&lock->lock);
     256                 :            : }
     257                 :            : 
     258                 :            : int
     259                 :            : glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
     260                 :            : {
     261                 :            :   int err;
     262                 :            : 
     263                 :            :   err = pthread_mutex_destroy (&lock->lock);
     264                 :            :   if (err != 0)
     265                 :            :     return err;
     266                 :            :   err = pthread_cond_destroy (&lock->waiting_readers);
     267                 :            :   if (err != 0)
     268                 :            :     return err;
     269                 :            :   err = pthread_cond_destroy (&lock->waiting_writers);
     270                 :            :   if (err != 0)
     271                 :            :     return err;
     272                 :            :   return 0;
     273                 :            : }
     274                 :            : 
     275                 :            : # endif
     276                 :            : 
     277                 :            : /* --------------------- gl_recursive_lock_t datatype --------------------- */
     278                 :            : 
     279                 :            : # if HAVE_PTHREAD_MUTEX_RECURSIVE
     280                 :            : 
     281                 :            : #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
     282                 :            : 
     283                 :            : int
     284                 :          0 : glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     285                 :            : {
     286                 :            :   pthread_mutexattr_t attributes;
     287                 :            :   int err;
     288                 :            : 
     289                 :          0 :   err = pthread_mutexattr_init (&attributes);
     290         [ #  # ]:          0 :   if (err != 0)
     291                 :          0 :     return err;
     292                 :          0 :   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
     293         [ #  # ]:          0 :   if (err != 0)
     294                 :            :     {
     295                 :          0 :       pthread_mutexattr_destroy (&attributes);
     296                 :          0 :       return err;
     297                 :            :     }
     298                 :          0 :   err = pthread_mutex_init (lock, &attributes);
     299         [ #  # ]:          0 :   if (err != 0)
     300                 :            :     {
     301                 :          0 :       pthread_mutexattr_destroy (&attributes);
     302                 :          0 :       return err;
     303                 :            :     }
     304                 :          0 :   err = pthread_mutexattr_destroy (&attributes);
     305         [ #  # ]:          0 :   if (err != 0)
     306                 :          0 :     return err;
     307                 :          0 :   return 0;
     308                 :            : }
     309                 :            : 
     310                 :            : #  else
     311                 :            : 
     312                 :            : int
     313                 :            : glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     314                 :            : {
     315                 :            :   pthread_mutexattr_t attributes;
     316                 :            :   int err;
     317                 :            : 
     318                 :            :   err = pthread_mutexattr_init (&attributes);
     319                 :            :   if (err != 0)
     320                 :            :     return err;
     321                 :            :   err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
     322                 :            :   if (err != 0)
     323                 :            :     {
     324                 :            :       pthread_mutexattr_destroy (&attributes);
     325                 :            :       return err;
     326                 :            :     }
     327                 :            :   err = pthread_mutex_init (&lock->recmutex, &attributes);
     328                 :            :   if (err != 0)
     329                 :            :     {
     330                 :            :       pthread_mutexattr_destroy (&attributes);
     331                 :            :       return err;
     332                 :            :     }
     333                 :            :   err = pthread_mutexattr_destroy (&attributes);
     334                 :            :   if (err != 0)
     335                 :            :     return err;
     336                 :            :   lock->initialized = 1;
     337                 :            :   return 0;
     338                 :            : }
     339                 :            : 
     340                 :            : int
     341                 :            : glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
     342                 :            : {
     343                 :            :   if (!lock->initialized)
     344                 :            :     {
     345                 :            :       int err;
     346                 :            : 
     347                 :            :       err = pthread_mutex_lock (&lock->guard);
     348                 :            :       if (err != 0)
     349                 :            :         return err;
     350                 :            :       if (!lock->initialized)
     351                 :            :         {
     352                 :            :           err = glthread_recursive_lock_init_multithreaded (lock);
     353                 :            :           if (err != 0)
     354                 :            :             {
     355                 :            :               pthread_mutex_unlock (&lock->guard);
     356                 :            :               return err;
     357                 :            :             }
     358                 :            :         }
     359                 :            :       err = pthread_mutex_unlock (&lock->guard);
     360                 :            :       if (err != 0)
     361                 :            :         return err;
     362                 :            :     }
     363                 :            :   return pthread_mutex_lock (&lock->recmutex);
     364                 :            : }
     365                 :            : 
     366                 :            : int
     367                 :            : glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
     368                 :            : {
     369                 :            :   if (!lock->initialized)
     370                 :            :     return EINVAL;
     371                 :            :   return pthread_mutex_unlock (&lock->recmutex);
     372                 :            : }
     373                 :            : 
     374                 :            : int
     375                 :            : glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
     376                 :            : {
     377                 :            :   int err;
     378                 :            : 
     379                 :            :   if (!lock->initialized)
     380                 :            :     return EINVAL;
     381                 :            :   err = pthread_mutex_destroy (&lock->recmutex);
     382                 :            :   if (err != 0)
     383                 :            :     return err;
     384                 :            :   lock->initialized = 0;
     385                 :            :   return 0;
     386                 :            : }
     387                 :            : 
     388                 :            : #  endif
     389                 :            : 
     390                 :            : # else
     391                 :            : 
     392                 :            : int
     393                 :            : glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     394                 :            : {
     395                 :            :   int err;
     396                 :            : 
     397                 :            :   err = pthread_mutex_init (&lock->mutex, NULL);
     398                 :            :   if (err != 0)
     399                 :            :     return err;
     400                 :            :   lock->owner = (pthread_t) 0;
     401                 :            :   lock->depth = 0;
     402                 :            :   return 0;
     403                 :            : }
     404                 :            : 
     405                 :            : int
     406                 :            : glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
     407                 :            : {
     408                 :            :   pthread_t self = pthread_self ();
     409                 :            :   if (lock->owner != self)
     410                 :            :     {
     411                 :            :       int err;
     412                 :            : 
     413                 :            :       err = pthread_mutex_lock (&lock->mutex);
     414                 :            :       if (err != 0)
     415                 :            :         return err;
     416                 :            :       lock->owner = self;
     417                 :            :     }
     418                 :            :   if (++(lock->depth) == 0) /* wraparound? */
     419                 :            :     {
     420                 :            :       lock->depth--;
     421                 :            :       return EAGAIN;
     422                 :            :     }
     423                 :            :   return 0;
     424                 :            : }
     425                 :            : 
     426                 :            : int
     427                 :            : glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
     428                 :            : {
     429                 :            :   if (lock->owner != pthread_self ())
     430                 :            :     return EPERM;
     431                 :            :   if (lock->depth == 0)
     432                 :            :     return EINVAL;
     433                 :            :   if (--(lock->depth) == 0)
     434                 :            :     {
     435                 :            :       lock->owner = (pthread_t) 0;
     436                 :            :       return pthread_mutex_unlock (&lock->mutex);
     437                 :            :     }
     438                 :            :   else
     439                 :            :     return 0;
     440                 :            : }
     441                 :            : 
     442                 :            : int
     443                 :            : glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
     444                 :            : {
     445                 :            :   if (lock->owner != (pthread_t) 0)
     446                 :            :     return EBUSY;
     447                 :            :   return pthread_mutex_destroy (&lock->mutex);
     448                 :            : }
     449                 :            : 
     450                 :            : # endif
     451                 :            : 
     452                 :            : /* -------------------------- gl_once_t datatype -------------------------- */
     453                 :            : 
     454                 :            : static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
     455                 :            : 
     456                 :            : int
     457                 :          0 : glthread_once_singlethreaded (pthread_once_t *once_control)
     458                 :            : {
     459                 :            :   /* We don't know whether pthread_once_t is an integer type, a floating-point
     460                 :            :      type, a pointer type, or a structure type.  */
     461                 :          0 :   char *firstbyte = (char *)once_control;
     462         [ #  # ]:          0 :   if (*firstbyte == *(const char *)&fresh_once)
     463                 :            :     {
     464                 :            :       /* First time use of once_control.  Invert the first byte.  */
     465                 :          0 :       *firstbyte = ~ *(const char *)&fresh_once;
     466                 :          0 :       return 1;
     467                 :            :     }
     468                 :            :   else
     469                 :          0 :     return 0;
     470                 :            : }
     471                 :            : 
     472                 :            : #endif
     473                 :            : 
     474                 :            : /* ========================================================================= */
     475                 :            : 
     476                 :            : #if USE_PTH_THREADS
     477                 :            : 
     478                 :            : /* Use the GNU Pth threads library.  */
     479                 :            : 
     480                 :            : /* -------------------------- gl_lock_t datatype -------------------------- */
     481                 :            : 
     482                 :            : /* ------------------------- gl_rwlock_t datatype ------------------------- */
     483                 :            : 
     484                 :            : /* --------------------- gl_recursive_lock_t datatype --------------------- */
     485                 :            : 
     486                 :            : /* -------------------------- gl_once_t datatype -------------------------- */
     487                 :            : 
     488                 :            : static void
     489                 :            : glthread_once_call (void *arg)
     490                 :            : {
     491                 :            :   void (**gl_once_temp_addr) (void) = (void (**) (void)) arg;
     492                 :            :   void (*initfunction) (void) = *gl_once_temp_addr;
     493                 :            :   initfunction ();
     494                 :            : }
     495                 :            : 
     496                 :            : int
     497                 :            : glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void))
     498                 :            : {
     499                 :            :   void (*temp) (void) = initfunction;
     500                 :            :   return (!pth_once (once_control, glthread_once_call, &temp) ? errno : 0);
     501                 :            : }
     502                 :            : 
     503                 :            : int
     504                 :            : glthread_once_singlethreaded (pth_once_t *once_control)
     505                 :            : {
     506                 :            :   /* We know that pth_once_t is an integer type.  */
     507                 :            :   if (*once_control == PTH_ONCE_INIT)
     508                 :            :     {
     509                 :            :       /* First time use of once_control.  Invert the marker.  */
     510                 :            :       *once_control = ~ PTH_ONCE_INIT;
     511                 :            :       return 1;
     512                 :            :     }
     513                 :            :   else
     514                 :            :     return 0;
     515                 :            : }
     516                 :            : 
     517                 :            : #endif
     518                 :            : 
     519                 :            : /* ========================================================================= */
     520                 :            : 
     521                 :            : #if USE_SOLARIS_THREADS
     522                 :            : 
     523                 :            : /* Use the old Solaris threads library.  */
     524                 :            : 
     525                 :            : /* -------------------------- gl_lock_t datatype -------------------------- */
     526                 :            : 
     527                 :            : /* ------------------------- gl_rwlock_t datatype ------------------------- */
     528                 :            : 
     529                 :            : /* --------------------- gl_recursive_lock_t datatype --------------------- */
     530                 :            : 
     531                 :            : int
     532                 :            : glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
     533                 :            : {
     534                 :            :   int err;
     535                 :            : 
     536                 :            :   err = mutex_init (&lock->mutex, USYNC_THREAD, NULL);
     537                 :            :   if (err != 0)
     538                 :            :     return err;
     539                 :            :   lock->owner = (thread_t) 0;
     540                 :            :   lock->depth = 0;
     541                 :            :   return 0;
     542                 :            : }
     543                 :            : 
     544                 :            : int
     545                 :            : glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
     546                 :            : {
     547                 :            :   thread_t self = thr_self ();
     548                 :            :   if (lock->owner != self)
     549                 :            :     {
     550                 :            :       int err;
     551                 :            : 
     552                 :            :       err = mutex_lock (&lock->mutex);
     553                 :            :       if (err != 0)
     554                 :            :         return err;
     555                 :            :       lock->owner = self;
     556                 :            :     }
     557                 :            :   if (++(lock->depth) == 0) /* wraparound? */
     558                 :            :     {
     559                 :            :       lock->depth--;
     560                 :            :       return EAGAIN;
     561                 :            :     }
     562                 :            :   return 0;
     563                 :            : }
     564                 :            : 
     565                 :            : int
     566                 :            : glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
     567                 :            : {
     568                 :            :   if (lock->owner != thr_self ())
     569                 :            :     return EPERM;
     570                 :            :   if (lock->depth == 0)
     571                 :            :     return EINVAL;
     572                 :            :   if (--(lock->depth) == 0)
     573                 :            :     {
     574                 :            :       lock->owner = (thread_t) 0;
     575                 :            :       return mutex_unlock (&lock->mutex);
     576                 :            :     }
     577                 :            :   else
     578                 :            :     return 0;
     579                 :            : }
     580                 :            : 
     581                 :            : int
     582                 :            : glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
     583                 :            : {
     584                 :            :   if (lock->owner != (thread_t) 0)
     585                 :            :     return EBUSY;
     586                 :            :   return mutex_destroy (&lock->mutex);
     587                 :            : }
     588                 :            : 
     589                 :            : /* -------------------------- gl_once_t datatype -------------------------- */
     590                 :            : 
     591                 :            : int
     592                 :            : glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void))
     593                 :            : {
     594                 :            :   if (!once_control->inited)
     595                 :            :     {
     596                 :            :       int err;
     597                 :            : 
     598                 :            :       /* Use the mutex to guarantee that if another thread is already calling
     599                 :            :          the initfunction, this thread waits until it's finished.  */
     600                 :            :       err = mutex_lock (&once_control->mutex);
     601                 :            :       if (err != 0)
     602                 :            :         return err;
     603                 :            :       if (!once_control->inited)
     604                 :            :         {
     605                 :            :           once_control->inited = 1;
     606                 :            :           initfunction ();
     607                 :            :         }
     608                 :            :       return mutex_unlock (&once_control->mutex);
     609                 :            :     }
     610                 :            :   else
     611                 :            :     return 0;
     612                 :            : }
     613                 :            : 
     614                 :            : int
     615                 :            : glthread_once_singlethreaded (gl_once_t *once_control)
     616                 :            : {
     617                 :            :   /* We know that gl_once_t contains an integer type.  */
     618                 :            :   if (!once_control->inited)
     619                 :            :     {
     620                 :            :       /* First time use of once_control.  Invert the marker.  */
     621                 :            :       once_control->inited = ~ 0;
     622                 :            :       return 1;
     623                 :            :     }
     624                 :            :   else
     625                 :            :     return 0;
     626                 :            : }
     627                 :            : 
     628                 :            : #endif
     629                 :            : 
     630                 :            : /* ========================================================================= */
     631                 :            : 
     632                 :            : #if USE_WINDOWS_THREADS
     633                 :            : 
     634                 :            : /* -------------------------- gl_lock_t datatype -------------------------- */
     635                 :            : 
     636                 :            : void
     637                 :            : glthread_lock_init_func (gl_lock_t *lock)
     638                 :            : {
     639                 :            :   InitializeCriticalSection (&lock->lock);
     640                 :            :   lock->guard.done = 1;
     641                 :            : }
     642                 :            : 
     643                 :            : int
     644                 :            : glthread_lock_lock_func (gl_lock_t *lock)
     645                 :            : {
     646                 :            :   if (!lock->guard.done)
     647                 :            :     {
     648                 :            :       if (InterlockedIncrement (&lock->guard.started) == 0)
     649                 :            :         /* This thread is the first one to need this lock.  Initialize it.  */
     650                 :            :         glthread_lock_init (lock);
     651                 :            :       else
     652                 :            :         /* Yield the CPU while waiting for another thread to finish
     653                 :            :            initializing this lock.  */
     654                 :            :         while (!lock->guard.done)
     655                 :            :           Sleep (0);
     656                 :            :     }
     657                 :            :   EnterCriticalSection (&lock->lock);
     658                 :            :   return 0;
     659                 :            : }
     660                 :            : 
     661                 :            : int
     662                 :            : glthread_lock_unlock_func (gl_lock_t *lock)
     663                 :            : {
     664                 :            :   if (!lock->guard.done)
     665                 :            :     return EINVAL;
     666                 :            :   LeaveCriticalSection (&lock->lock);
     667                 :            :   return 0;
     668                 :            : }
     669                 :            : 
     670                 :            : int
     671                 :            : glthread_lock_destroy_func (gl_lock_t *lock)
     672                 :            : {
     673                 :            :   if (!lock->guard.done)
     674                 :            :     return EINVAL;
     675                 :            :   DeleteCriticalSection (&lock->lock);
     676                 :            :   lock->guard.done = 0;
     677                 :            :   return 0;
     678                 :            : }
     679                 :            : 
     680                 :            : /* ------------------------- gl_rwlock_t datatype ------------------------- */
     681                 :            : 
     682                 :            : /* In this file, the waitqueues are implemented as circular arrays.  */
     683                 :            : #define gl_waitqueue_t gl_carray_waitqueue_t
     684                 :            : 
     685                 :            : static inline void
     686                 :            : gl_waitqueue_init (gl_waitqueue_t *wq)
     687                 :            : {
     688                 :            :   wq->array = NULL;
     689                 :            :   wq->count = 0;
     690                 :            :   wq->alloc = 0;
     691                 :            :   wq->offset = 0;
     692                 :            : }
     693                 :            : 
     694                 :            : /* Enqueues the current thread, represented by an event, in a wait queue.
     695                 :            :    Returns INVALID_HANDLE_VALUE if an allocation failure occurs.  */
     696                 :            : static HANDLE
     697                 :            : gl_waitqueue_add (gl_waitqueue_t *wq)
     698                 :            : {
     699                 :            :   HANDLE event;
     700                 :            :   unsigned int index;
     701                 :            : 
     702                 :            :   if (wq->count == wq->alloc)
     703                 :            :     {
     704                 :            :       unsigned int new_alloc = 2 * wq->alloc + 1;
     705                 :            :       HANDLE *new_array =
     706                 :            :         (HANDLE *) realloc (wq->array, new_alloc * sizeof (HANDLE));
     707                 :            :       if (new_array == NULL)
     708                 :            :         /* No more memory.  */
     709                 :            :         return INVALID_HANDLE_VALUE;
     710                 :            :       /* Now is a good opportunity to rotate the array so that its contents
     711                 :            :          starts at offset 0.  */
     712                 :            :       if (wq->offset > 0)
     713                 :            :         {
     714                 :            :           unsigned int old_count = wq->count;
     715                 :            :           unsigned int old_alloc = wq->alloc;
     716                 :            :           unsigned int old_offset = wq->offset;
     717                 :            :           unsigned int i;
     718                 :            :           if (old_offset + old_count > old_alloc)
     719                 :            :             {
     720                 :            :               unsigned int limit = old_offset + old_count - old_alloc;
     721                 :            :               for (i = 0; i < limit; i++)
     722                 :            :                 new_array[old_alloc + i] = new_array[i];
     723                 :            :             }
     724                 :            :           for (i = 0; i < old_count; i++)
     725                 :            :             new_array[i] = new_array[old_offset + i];
     726                 :            :           wq->offset = 0;
     727                 :            :         }
     728                 :            :       wq->array = new_array;
     729                 :            :       wq->alloc = new_alloc;
     730                 :            :     }
     731                 :            :   /* Whether the created event is a manual-reset one or an auto-reset one,
     732                 :            :      does not matter, since we will wait on it only once.  */
     733                 :            :   event = CreateEvent (NULL, TRUE, FALSE, NULL);
     734                 :            :   if (event == INVALID_HANDLE_VALUE)
     735                 :            :     /* No way to allocate an event.  */
     736                 :            :     return INVALID_HANDLE_VALUE;
     737                 :            :   index = wq->offset + wq->count;
     738                 :            :   if (index >= wq->alloc)
     739                 :            :     index -= wq->alloc;
     740                 :            :   wq->array[index] = event;
     741                 :            :   wq->count++;
     742                 :            :   return event;
     743                 :            : }
     744                 :            : 
     745                 :            : /* Notifies the first thread from a wait queue and dequeues it.  */
     746                 :            : static inline void
     747                 :            : gl_waitqueue_notify_first (gl_waitqueue_t *wq)
     748                 :            : {
     749                 :            :   SetEvent (wq->array[wq->offset + 0]);
     750                 :            :   wq->offset++;
     751                 :            :   wq->count--;
     752                 :            :   if (wq->count == 0 || wq->offset == wq->alloc)
     753                 :            :     wq->offset = 0;
     754                 :            : }
     755                 :            : 
     756                 :            : /* Notifies all threads from a wait queue and dequeues them all.  */
     757                 :            : static inline void
     758                 :            : gl_waitqueue_notify_all (gl_waitqueue_t *wq)
     759                 :            : {
     760                 :            :   unsigned int i;
     761                 :            : 
     762                 :            :   for (i = 0; i < wq->count; i++)
     763                 :            :     {
     764                 :            :       unsigned int index = wq->offset + i;
     765                 :            :       if (index >= wq->alloc)
     766                 :            :         index -= wq->alloc;
     767                 :            :       SetEvent (wq->array[index]);
     768                 :            :     }
     769                 :            :   wq->count = 0;
     770                 :            :   wq->offset = 0;
     771                 :            : }
     772                 :            : 
     773                 :            : void
     774                 :            : glthread_rwlock_init_func (gl_rwlock_t *lock)
     775                 :            : {
     776                 :            :   InitializeCriticalSection (&lock->lock);
     777                 :            :   gl_waitqueue_init (&lock->waiting_readers);
     778                 :            :   gl_waitqueue_init (&lock->waiting_writers);
     779                 :            :   lock->runcount = 0;
     780                 :            :   lock->guard.done = 1;
     781                 :            : }
     782                 :            : 
     783                 :            : int
     784                 :            : glthread_rwlock_rdlock_func (gl_rwlock_t *lock)
     785                 :            : {
     786                 :            :   if (!lock->guard.done)
     787                 :            :     {
     788                 :            :       if (InterlockedIncrement (&lock->guard.started) == 0)
     789                 :            :         /* This thread is the first one to need this lock.  Initialize it.  */
     790                 :            :         glthread_rwlock_init (lock);
     791                 :            :       else
     792                 :            :         /* Yield the CPU while waiting for another thread to finish
     793                 :            :            initializing this lock.  */
     794                 :            :         while (!lock->guard.done)
     795                 :            :           Sleep (0);
     796                 :            :     }
     797                 :            :   EnterCriticalSection (&lock->lock);
     798                 :            :   /* Test whether only readers are currently running, and whether the runcount
     799                 :            :      field will not overflow.  */
     800                 :            :   if (!(lock->runcount + 1 > 0))
     801                 :            :     {
     802                 :            :       /* This thread has to wait for a while.  Enqueue it among the
     803                 :            :          waiting_readers.  */
     804                 :            :       HANDLE event = gl_waitqueue_add (&lock->waiting_readers);
     805                 :            :       if (event != INVALID_HANDLE_VALUE)
     806                 :            :         {
     807                 :            :           DWORD result;
     808                 :            :           LeaveCriticalSection (&lock->lock);
     809                 :            :           /* Wait until another thread signals this event.  */
     810                 :            :           result = WaitForSingleObject (event, INFINITE);
     811                 :            :           if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
     812                 :            :             abort ();
     813                 :            :           CloseHandle (event);
     814                 :            :           /* The thread which signalled the event already did the bookkeeping:
     815                 :            :              removed us from the waiting_readers, incremented lock->runcount.  */
     816                 :            :           if (!(lock->runcount > 0))
     817                 :            :             abort ();
     818                 :            :           return 0;
     819                 :            :         }
     820                 :            :       else
     821                 :            :         {
     822                 :            :           /* Allocation failure.  Weird.  */
     823                 :            :           do
     824                 :            :             {
     825                 :            :               LeaveCriticalSection (&lock->lock);
     826                 :            :               Sleep (1);
     827                 :            :               EnterCriticalSection (&lock->lock);
     828                 :            :             }
     829                 :            :           while (!(lock->runcount + 1 > 0));
     830                 :            :         }
     831                 :            :     }
     832                 :            :   lock->runcount++;
     833                 :            :   LeaveCriticalSection (&lock->lock);
     834                 :            :   return 0;
     835                 :            : }
     836                 :            : 
     837                 :            : int
     838                 :            : glthread_rwlock_wrlock_func (gl_rwlock_t *lock)
     839                 :            : {
     840                 :            :   if (!lock->guard.done)
     841                 :            :     {
     842                 :            :       if (InterlockedIncrement (&lock->guard.started) == 0)
     843                 :            :         /* This thread is the first one to need this lock.  Initialize it.  */
     844                 :            :         glthread_rwlock_init (lock);
     845                 :            :       else
     846                 :            :         /* Yield the CPU while waiting for another thread to finish
     847                 :            :            initializing this lock.  */
     848                 :            :         while (!lock->guard.done)
     849                 :            :           Sleep (0);
     850                 :            :     }
     851                 :            :   EnterCriticalSection (&lock->lock);
     852                 :            :   /* Test whether no readers or writers are currently running.  */
     853                 :            :   if (!(lock->runcount == 0))
     854                 :            :     {
     855                 :            :       /* This thread has to wait for a while.  Enqueue it among the
     856                 :            :          waiting_writers.  */
     857                 :            :       HANDLE event = gl_waitqueue_add (&lock->waiting_writers);
     858                 :            :       if (event != INVALID_HANDLE_VALUE)
     859                 :            :         {
     860                 :            :           DWORD result;
     861                 :            :           LeaveCriticalSection (&lock->lock);
     862                 :            :           /* Wait until another thread signals this event.  */
     863                 :            :           result = WaitForSingleObject (event, INFINITE);
     864                 :            :           if (result == WAIT_FAILED || result == WAIT_TIMEOUT)
     865                 :            :             abort ();
     866                 :            :           CloseHandle (event);
     867                 :            :           /* The thread which signalled the event already did the bookkeeping:
     868                 :            :              removed us from the waiting_writers, set lock->runcount = -1.  */
     869                 :            :           if (!(lock->runcount == -1))
     870                 :            :             abort ();
     871                 :            :           return 0;
     872                 :            :         }
     873                 :            :       else
     874                 :            :         {
     875                 :            :           /* Allocation failure.  Weird.  */
     876                 :            :           do
     877                 :            :             {
     878                 :            :               LeaveCriticalSection (&lock->lock);
     879                 :            :               Sleep (1);
     880                 :            :               EnterCriticalSection (&lock->lock);
     881                 :            :             }
     882                 :            :           while (!(lock->runcount == 0));
     883                 :            :         }
     884                 :            :     }
     885                 :            :   lock->runcount--; /* runcount becomes -1 */
     886                 :            :   LeaveCriticalSection (&lock->lock);
     887                 :            :   return 0;
     888                 :            : }
     889                 :            : 
     890                 :            : int
     891                 :            : glthread_rwlock_unlock_func (gl_rwlock_t *lock)
     892                 :            : {
     893                 :            :   if (!lock->guard.done)
     894                 :            :     return EINVAL;
     895                 :            :   EnterCriticalSection (&lock->lock);
     896                 :            :   if (lock->runcount < 0)
     897                 :            :     {
     898                 :            :       /* Drop a writer lock.  */
     899                 :            :       if (!(lock->runcount == -1))
     900                 :            :         abort ();
     901                 :            :       lock->runcount = 0;
     902                 :            :     }
     903                 :            :   else
     904                 :            :     {
     905                 :            :       /* Drop a reader lock.  */
     906                 :            :       if (!(lock->runcount > 0))
     907                 :            :         {
     908                 :            :           LeaveCriticalSection (&lock->lock);
     909                 :            :           return EPERM;
     910                 :            :         }
     911                 :            :       lock->runcount--;
     912                 :            :     }
     913                 :            :   if (lock->runcount == 0)
     914                 :            :     {
     915                 :            :       /* POSIX recommends that "write locks shall take precedence over read
     916                 :            :          locks", to avoid "writer starvation".  */
     917                 :            :       if (lock->waiting_writers.count > 0)
     918                 :            :         {
     919                 :            :           /* Wake up one of the waiting writers.  */
     920                 :            :           lock->runcount--;
     921                 :            :           gl_waitqueue_notify_first (&lock->waiting_writers);
     922                 :            :         }
     923                 :            :       else
     924                 :            :         {
     925                 :            :           /* Wake up all waiting readers.  */
     926                 :            :           lock->runcount += lock->waiting_readers.count;
     927                 :            :           gl_waitqueue_notify_all (&lock->waiting_readers);
     928                 :            :         }
     929                 :            :     }
     930                 :            :   LeaveCriticalSection (&lock->lock);
     931                 :            :   return 0;
     932                 :            : }
     933                 :            : 
     934                 :            : int
     935                 :            : glthread_rwlock_destroy_func (gl_rwlock_t *lock)
     936                 :            : {
     937                 :            :   if (!lock->guard.done)
     938                 :            :     return EINVAL;
     939                 :            :   if (lock->runcount != 0)
     940                 :            :     return EBUSY;
     941                 :            :   DeleteCriticalSection (&lock->lock);
     942                 :            :   if (lock->waiting_readers.array != NULL)
     943                 :            :     free (lock->waiting_readers.array);
     944                 :            :   if (lock->waiting_writers.array != NULL)
     945                 :            :     free (lock->waiting_writers.array);
     946                 :            :   lock->guard.done = 0;
     947                 :            :   return 0;
     948                 :            : }
     949                 :            : 
     950                 :            : /* --------------------- gl_recursive_lock_t datatype --------------------- */
     951                 :            : 
     952                 :            : void
     953                 :            : glthread_recursive_lock_init_func (gl_recursive_lock_t *lock)
     954                 :            : {
     955                 :            :   lock->owner = 0;
     956                 :            :   lock->depth = 0;
     957                 :            :   InitializeCriticalSection (&lock->lock);
     958                 :            :   lock->guard.done = 1;
     959                 :            : }
     960                 :            : 
     961                 :            : int
     962                 :            : glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock)
     963                 :            : {
     964                 :            :   if (!lock->guard.done)
     965                 :            :     {
     966                 :            :       if (InterlockedIncrement (&lock->guard.started) == 0)
     967                 :            :         /* This thread is the first one to need this lock.  Initialize it.  */
     968                 :            :         glthread_recursive_lock_init (lock);
     969                 :            :       else
     970                 :            :         /* Yield the CPU while waiting for another thread to finish
     971                 :            :            initializing this lock.  */
     972                 :            :         while (!lock->guard.done)
     973                 :            :           Sleep (0);
     974                 :            :     }
     975                 :            :   {
     976                 :            :     DWORD self = GetCurrentThreadId ();
     977                 :            :     if (lock->owner != self)
     978                 :            :       {
     979                 :            :         EnterCriticalSection (&lock->lock);
     980                 :            :         lock->owner = self;
     981                 :            :       }
     982                 :            :     if (++(lock->depth) == 0) /* wraparound? */
     983                 :            :       {
     984                 :            :         lock->depth--;
     985                 :            :         return EAGAIN;
     986                 :            :       }
     987                 :            :   }
     988                 :            :   return 0;
     989                 :            : }
     990                 :            : 
     991                 :            : int
     992                 :            : glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock)
     993                 :            : {
     994                 :            :   if (lock->owner != GetCurrentThreadId ())
     995                 :            :     return EPERM;
     996                 :            :   if (lock->depth == 0)
     997                 :            :     return EINVAL;
     998                 :            :   if (--(lock->depth) == 0)
     999                 :            :     {
    1000                 :            :       lock->owner = 0;
    1001                 :            :       LeaveCriticalSection (&lock->lock);
    1002                 :            :     }
    1003                 :            :   return 0;
    1004                 :            : }
    1005                 :            : 
    1006                 :            : int
    1007                 :            : glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock)
    1008                 :            : {
    1009                 :            :   if (lock->owner != 0)
    1010                 :            :     return EBUSY;
    1011                 :            :   DeleteCriticalSection (&lock->lock);
    1012                 :            :   lock->guard.done = 0;
    1013                 :            :   return 0;
    1014                 :            : }
    1015                 :            : 
    1016                 :            : /* -------------------------- gl_once_t datatype -------------------------- */
    1017                 :            : 
    1018                 :            : void
    1019                 :            : glthread_once_func (gl_once_t *once_control, void (*initfunction) (void))
    1020                 :            : {
    1021                 :            :   if (once_control->inited <= 0)
    1022                 :            :     {
    1023                 :            :       if (InterlockedIncrement (&once_control->started) == 0)
    1024                 :            :         {
    1025                 :            :           /* This thread is the first one to come to this once_control.  */
    1026                 :            :           InitializeCriticalSection (&once_control->lock);
    1027                 :            :           EnterCriticalSection (&once_control->lock);
    1028                 :            :           once_control->inited = 0;
    1029                 :            :           initfunction ();
    1030                 :            :           once_control->inited = 1;
    1031                 :            :           LeaveCriticalSection (&once_control->lock);
    1032                 :            :         }
    1033                 :            :       else
    1034                 :            :         {
    1035                 :            :           /* Undo last operation.  */
    1036                 :            :           InterlockedDecrement (&once_control->started);
    1037                 :            :           /* Some other thread has already started the initialization.
    1038                 :            :              Yield the CPU while waiting for the other thread to finish
    1039                 :            :              initializing and taking the lock.  */
    1040                 :            :           while (once_control->inited < 0)
    1041                 :            :             Sleep (0);
    1042                 :            :           if (once_control->inited <= 0)
    1043                 :            :             {
    1044                 :            :               /* Take the lock.  This blocks until the other thread has
    1045                 :            :                  finished calling the initfunction.  */
    1046                 :            :               EnterCriticalSection (&once_control->lock);
    1047                 :            :               LeaveCriticalSection (&once_control->lock);
    1048                 :            :               if (!(once_control->inited > 0))
    1049                 :            :                 abort ();
    1050                 :            :             }
    1051                 :            :         }
    1052                 :            :     }
    1053                 :            : }
    1054                 :            : 
    1055                 :            : #endif
    1056                 :            : 
    1057                 :            : /* ========================================================================= */

Generated by: LCOV version 1.9