Home | History | Annotate | Download | only in pthreads-win32
      1 /*
      2  * pthread_mutex_timedlock.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 #include "pthread.h"
     38 #include "implement.h"
     39 
     40 
     41 static INLINE int
     42 ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime)
     43      /*
     44       * ------------------------------------------------------
     45       * DESCRIPTION
     46       *      This function waits on an event until signaled or until
     47       *      abstime passes.
     48       *      If abstime has passed when this routine is called then
     49       *      it returns a result to indicate this.
     50       *
     51       *      If 'abstime' is a NULL pointer then this function will
     52       *      block until it can successfully decrease the value or
     53       *      until interrupted by a signal.
     54       *
     55       *      This routine is not a cancelation point.
     56       *
     57       * RESULTS
     58       *              0               successfully signaled,
     59       *              ETIMEDOUT       abstime passed
     60       *              EINVAL          'event' is not a valid event,
     61       *
     62       * ------------------------------------------------------
     63       */
     64 {
     65 
     66   DWORD milliseconds;
     67   DWORD status;
     68 
     69   if (event == NULL)
     70     {
     71       return EINVAL;
     72     }
     73   else
     74     {
     75       if (abstime == NULL)
     76 	{
     77 	  milliseconds = INFINITE;
     78 	}
     79       else
     80 	{
     81 	  /*
     82 	   * Calculate timeout as milliseconds from current system time.
     83 	   */
     84 	  milliseconds = ptw32_relmillisecs (abstime);
     85 	}
     86 
     87       status = WaitForSingleObject (event, milliseconds);
     88 
     89       if (status == WAIT_OBJECT_0)
     90 	{
     91 	  return 0;
     92 	}
     93       else if (status == WAIT_TIMEOUT)
     94 	{
     95 	  return ETIMEDOUT;
     96 	}
     97       else
     98 	{
     99 	  return EINVAL;
    100 	}
    101     }
    102 
    103   return 0;
    104 
    105 }				/* ptw32_timed_semwait */
    106 
    107 
    108 int
    109 pthread_mutex_timedlock (pthread_mutex_t * mutex,
    110 			 const struct timespec *abstime)
    111 {
    112   pthread_mutex_t mx;
    113   int kind;
    114   int result = 0;
    115 
    116   /*
    117    * Let the system deal with invalid pointers.
    118    */
    119 
    120   /*
    121    * We do a quick check to see if we need to do more work
    122    * to initialise a static mutex. We check
    123    * again inside the guarded section of ptw32_mutex_check_need_init()
    124    * to avoid race conditions.
    125    */
    126   if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER)
    127     {
    128       if ((result = ptw32_mutex_check_need_init (mutex)) != 0)
    129 	{
    130 	  return (result);
    131 	}
    132     }
    133 
    134   mx = *mutex;
    135   kind = mx->kind;
    136 
    137   if (kind >= 0)
    138     {
    139       if (mx->kind == PTHREAD_MUTEX_NORMAL)
    140         {
    141           if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    142 		       (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    143 		       (PTW32_INTERLOCKED_LONG) 1) != 0)
    144 	    {
    145               while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    146                               (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    147 			      (PTW32_INTERLOCKED_LONG) -1) != 0)
    148                 {
    149 	          if (0 != (result = ptw32_timed_eventwait (mx->event, abstime)))
    150 		    {
    151 		      return result;
    152 		    }
    153 	        }
    154 	    }
    155         }
    156       else
    157         {
    158           pthread_t self = pthread_self();
    159 
    160           if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
    161                        (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    162 		       (PTW32_INTERLOCKED_LONG) 1,
    163 		       (PTW32_INTERLOCKED_LONG) 0) == 0)
    164 	    {
    165 	      mx->recursive_count = 1;
    166 	      mx->ownerThread = self;
    167 	    }
    168           else
    169 	    {
    170 	      if (pthread_equal (mx->ownerThread, self))
    171 	        {
    172 	          if (mx->kind == PTHREAD_MUTEX_RECURSIVE)
    173 		    {
    174 		      mx->recursive_count++;
    175 		    }
    176 	          else
    177 		    {
    178 		      return EDEADLK;
    179 		    }
    180 	        }
    181 	      else
    182 	        {
    183                   while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    184                                   (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    185 			          (PTW32_INTERLOCKED_LONG) -1) != 0)
    186                     {
    187 		      if (0 != (result = ptw32_timed_eventwait (mx->event, abstime)))
    188 		        {
    189 		          return result;
    190 		        }
    191 		    }
    192 
    193 	          mx->recursive_count = 1;
    194 	          mx->ownerThread = self;
    195 	        }
    196 	    }
    197         }
    198     }
    199   else
    200     {
    201       /*
    202        * Robust types
    203        * All types record the current owner thread.
    204        * The mutex is added to a per thread list when ownership is acquired.
    205        */
    206       ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent;
    207 
    208       if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    209                                                  (PTW32_INTERLOCKED_LONGPTR)statePtr,
    210                                                  (PTW32_INTERLOCKED_LONG)0))
    211         {
    212           result = ENOTRECOVERABLE;
    213         }
    214       else
    215         {
    216           pthread_t self = pthread_self();
    217 
    218           kind = -kind - 1; /* Convert to non-robust range */
    219 
    220           if (PTHREAD_MUTEX_NORMAL == kind)
    221             {
    222               if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    223 		           (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    224 		           (PTW32_INTERLOCKED_LONG) 1) != 0)
    225 	        {
    226                   while (0 == (result = ptw32_robust_mutex_inherit(mutex))
    227                            && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    228                                   (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    229 			          (PTW32_INTERLOCKED_LONG) -1) != 0)
    230                     {
    231 	              if (0 != (result = ptw32_timed_eventwait (mx->event, abstime)))
    232 		        {
    233 		          return result;
    234 		        }
    235                       if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE ==
    236                                   PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    237                                     (PTW32_INTERLOCKED_LONGPTR)statePtr,
    238                                     (PTW32_INTERLOCKED_LONG)0))
    239                         {
    240                           /* Unblock the next thread */
    241                           SetEvent(mx->event);
    242                           result = ENOTRECOVERABLE;
    243                           break;
    244                         }
    245 	            }
    246 
    247                   if (0 == result || EOWNERDEAD == result)
    248                     {
    249                       /*
    250                        * Add mutex to the per-thread robust mutex currently-held list.
    251                        * If the thread terminates, all mutexes in this list will be unlocked.
    252                        */
    253                       ptw32_robust_mutex_add(mutex, self);
    254                     }
    255 	        }
    256             }
    257           else
    258             {
    259               pthread_t self = pthread_self();
    260 
    261               if (0 == (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
    262                            (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    263 		           (PTW32_INTERLOCKED_LONG) 1,
    264 		           (PTW32_INTERLOCKED_LONG) 0))
    265 	        {
    266 	          mx->recursive_count = 1;
    267                   /*
    268                    * Add mutex to the per-thread robust mutex currently-held list.
    269                    * If the thread terminates, all mutexes in this list will be unlocked.
    270                    */
    271                   ptw32_robust_mutex_add(mutex, self);
    272 	        }
    273               else
    274 	        {
    275 	          if (pthread_equal (mx->ownerThread, self))
    276 	            {
    277 	              if (PTHREAD_MUTEX_RECURSIVE == kind)
    278 		        {
    279 		          mx->recursive_count++;
    280 		        }
    281 	              else
    282 		        {
    283 		          return EDEADLK;
    284 		        }
    285 	            }
    286 	          else
    287 	            {
    288                       while (0 == (result = ptw32_robust_mutex_inherit(mutex))
    289                                && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG(
    290                                           (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx,
    291 			                  (PTW32_INTERLOCKED_LONG) -1) != 0)
    292                         {
    293 		          if (0 != (result = ptw32_timed_eventwait (mx->event, abstime)))
    294 		            {
    295 		              return result;
    296 		            }
    297 		        }
    298 
    299                       if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE ==
    300                                   PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(
    301                                     (PTW32_INTERLOCKED_LONGPTR)statePtr,
    302                                     (PTW32_INTERLOCKED_LONG)0))
    303                         {
    304                           /* Unblock the next thread */
    305                           SetEvent(mx->event);
    306                           result = ENOTRECOVERABLE;
    307                         }
    308                       else if (0 == result || EOWNERDEAD == result)
    309                         {
    310                           mx->recursive_count = 1;
    311                           /*
    312                            * Add mutex to the per-thread robust mutex currently-held list.
    313                            * If the thread terminates, all mutexes in this list will be unlocked.
    314                            */
    315                           ptw32_robust_mutex_add(mutex, self);
    316                         }
    317 	            }
    318 	        }
    319             }
    320         }
    321     }
    322 
    323   return result;
    324 }
    325