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@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
43int
44pthread_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