Home | History | Annotate | Download | only in pthreads-win32
      1 /*
      2  * pthread_mutex_lock.c
      3  *
      4  * Description:
      5  * This translation unit implements mutual exclusion (mutex) primitives.
      6  *
      7  * --------------------------------------------------------------------------
      8  *
      9  *      Pthreads-win32 - POSIX Threads Library for Win32
     10  *      Copyright(C) 1998 John E. Bossom
     11  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
     12  *
     13  *      Contact Email: rpj (at) callisto.canberra.edu.au
     14  *
     15  *      The current list of contributors is contained
     16  *      in the file CONTRIBUTORS included with the source
     17  *      code distribution. The list can also be seen at the
     18  *      following World Wide Web location:
     19  *      http://sources.redhat.com/pthreads-win32/contributors.html
     20  *
     21  *      This library is free software; you can redistribute it and/or
     22  *      modify it under the terms of the GNU Lesser General Public
     23  *      License as published by the Free Software Foundation; either
     24  *      version 2 of the License, or (at your option) any later version.
     25  *
     26  *      This library is distributed in the hope that it will be useful,
     27  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
     28  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     29  *      Lesser General Public License for more details.
     30  *
     31  *      You should have received a copy of the GNU Lesser General Public
     32  *      License along with this library in the file COPYING.LIB;
     33  *      if not, write to the Free Software Foundation, Inc.,
     34  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
     35  */
     36 
     37 #if !defined(_UWIN)
     38 /*#   include <process.h> */
     39 #endif
     40 #include "pthread.h"
     41 #include "implement.h"
     42 
     43 int
     44 pthread_mutex_lock (pthread_mutex_t * mutex)
     45 {
     46   int kind;
     47   pthread_mutex_t mx;
     48   int result = 0;
     49 
     50   /*
     51    * Let the system deal with invalid pointers.
     52    */
     53   if (*mutex == NULL)
     54     {
     55       return EINVAL;
     56     }
     57 
     58   /*
     59    * We do a quick check to see if we need to do more work
     60    * to initialise a static mutex. We check
     61    * again inside the guarded section of ptw32_mutex_check_need_init()
     62    * to avoid race conditions.
     63    */
     64   if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
     65     {
     66       if ((result = ptw32_mutex_check_need_init (mutex)) != 0)
     67 	{
     68 	  return (result);
     69 	}
     70     }
     71 
     72   mx = *mutex;
     73   kind = mx->kind;
     74 
     75   if (kind >= 0)
     76     {
     77       /* Non-robust */
     78       if (PTHREAD_MUTEX_NORMAL == kind)
     79         {
     80           if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
     81 		       (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
     82 		       (PTW32_INTERLOCKED_LONG) 1) != 0)
     83 	    {
     84 	      while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
     85                               (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
     86 			      (PTW32_INTERLOCKED_LONG) -1) != 0)
     87 	        {
     88 	          if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE))
     89 	            {
     90 	              result = EINVAL;
     91 		      break;
     92 	            }
     93 	        }
     94 	    }
     95         }
     96       else
     97         {
     98           pthread_t self = pthread_self();
     99 
    100           if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
    101                        (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    102 		       (PTW32_INTERLOCKED_LONG) 1,
    103 		       (PTW32_INTERLOCKED_LONG) 0) == 0)
    104 	    {
    105 	      mx->recursive_count = 1;
    106 	      mx->ownerThread = self;
    107 	    }
    108           else
    109 	    {
    110 	      if (pthread_equal (mx->ownerThread, self))
    111 	        {
    112 	          if (kind == PTHREAD_MUTEX_RECURSIVE)
    113 		    {
    114 		      mx->recursive_count++;
    115 		    }
    116 	          else
    117 		    {
    118 		      result = EDEADLK;
    119 		    }
    120 	        }
    121 	      else
    122 	        {
    123 	          while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    124                                   (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    125 			          (PTW32_INTERLOCKED_LONG) -1) != 0)
    126 		    {
    127 	              if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE))
    128 		        {
    129 	                  result = EINVAL;
    130 		          break;
    131 		        }
    132 		    }
    133 
    134 	          if (0 == result)
    135 		    {
    136 		      mx->recursive_count = 1;
    137 		      mx->ownerThread = self;
    138 		    }
    139 	        }
    140 	    }
    141         }
    142     }
    143   else
    144     {
    145       /*
    146        * Robust types
    147        * All types record the current owner thread.
    148        * The mutex is added to a per thread list when ownership is acquired.
    149        */
    150       ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent;
    151 
    152       if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    153                                                  (PTW32_INTERLOCKED_LONGPTR)statePtr,
    154                                                  (PTW32_INTERLOCKED_LONG)0))
    155         {
    156           result = ENOTRECOVERABLE;
    157         }
    158       else
    159         {
    160           pthread_t self = pthread_self();
    161 
    162           kind = -kind - 1; /* Convert to non-robust range */
    163 
    164           if (PTHREAD_MUTEX_NORMAL == kind)
    165             {
    166               if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    167                            (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    168                            (PTW32_INTERLOCKED_LONG) 1) != 0)
    169                 {
    170                   while (0 == (result = ptw32_robust_mutex_inherit(mutex))
    171                            && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    172                                        (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    173                                        (PTW32_INTERLOCKED_LONG) -1) != 0)
    174                     {
    175                       if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE))
    176                         {
    177                           result = EINVAL;
    178                           break;
    179                         }
    180                       if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE ==
    181                                   PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    182                                     (PTW32_INTERLOCKED_LONGPTR)statePtr,
    183                                     (PTW32_INTERLOCKED_LONG)0))
    184                         {
    185                           /* Unblock the next thread */
    186                           SetEvent(mx->event);
    187                           result = ENOTRECOVERABLE;
    188                           break;
    189                         }
    190                     }
    191                 }
    192               if (0 == result || EOWNERDEAD == result)
    193                 {
    194                   /*
    195                    * Add mutex to the per-thread robust mutex currently-held list.
    196                    * If the thread terminates, all mutexes in this list will be unlocked.
    197                    */
    198                   ptw32_robust_mutex_add(mutex, self);
    199                 }
    200             }
    201           else
    202             {
    203               if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
    204                            (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    205                            (PTW32_INTERLOCKED_LONG) 1,
    206                            (PTW32_INTERLOCKED_LONG) 0) == 0)
    207                 {
    208                   mx->recursive_count = 1;
    209                   /*
    210                    * Add mutex to the per-thread robust mutex currently-held list.
    211                    * If the thread terminates, all mutexes in this list will be unlocked.
    212                    */
    213                   ptw32_robust_mutex_add(mutex, self);
    214                 }
    215               else
    216                 {
    217                   if (pthread_equal (mx->ownerThread, self))
    218                     {
    219                       if (PTHREAD_MUTEX_RECURSIVE == kind)
    220                         {
    221                           mx->recursive_count++;
    222                         }
    223                       else
    224                         {
    225                           result = EDEADLK;
    226                         }
    227                     }
    228                   else
    229                     {
    230                       while (0 == (result = ptw32_robust_mutex_inherit(mutex))
    231                                && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    232                                            (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    233                                            (PTW32_INTERLOCKED_LONG) -1) != 0)
    234                         {
    235                           if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE))
    236                             {
    237                               result = EINVAL;
    238                               break;
    239                             }
    240                           if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE ==
    241                                       PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    242                                         (PTW32_INTERLOCKED_LONGPTR)statePtr,
    243                                         (PTW32_INTERLOCKED_LONG)0))
    244                             {
    245                               /* Unblock the next thread */
    246                               SetEvent(mx->event);
    247                               result = ENOTRECOVERABLE;
    248                               break;
    249                             }
    250                         }
    251 
    252                       if (0 == result || EOWNERDEAD == result)
    253                         {
    254                           mx->recursive_count = 1;
    255                           /*
    256                            * Add mutex to the per-thread robust mutex currently-held list.
    257                            * If the thread terminates, all mutexes in this list will be unlocked.
    258                            */
    259                           ptw32_robust_mutex_add(mutex, self);
    260                         }
    261                     }
    262 	        }
    263             }
    264         }
    265     }
    266 
    267   return (result);
    268 }
    269 
    270