1 /*
2  * pthread_mutex_consistent.c
3  *
4  * Description:
5  * This translation unit implements mutual exclusion (mutex) primitives.
6  *
7  * --------------------------------------------------------------------------
8  *
9  *      Pthreads4w - POSIX Threads for Windows
10  *      Copyright 1998 John E. Bossom
11  *      Copyright 1999-2018, Pthreads4w contributors
12  *
13  *      Homepage: https://sourceforge.net/projects/pthreads4w/
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  *
20  *      https://sourceforge.net/p/pthreads4w/wiki/Contributors/
21  *
22  * Licensed under the Apache License, Version 2.0 (the "License");
23  * you may not use this file except in compliance with the License.
24  * You may obtain a copy of the License at
25  *
26  *     http://www.apache.org/licenses/LICENSE-2.0
27  *
28  * Unless required by applicable law or agreed to in writing, software
29  * distributed under the License is distributed on an "AS IS" BASIS,
30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  * See the License for the specific language governing permissions and
32  * limitations under the License.
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 # include <config.h>
37 #endif
38 
39 /*
40  * From the Sun Multi-threaded Programming Guide
41  *
42  * robustness defines the behavior when the owner of the mutex terminates without unlocking the
43  * mutex, usually because its process terminated abnormally. The value of robustness that is
44  * defined in pthread.h is PTHREAD_MUTEX_ROBUST or PTHREAD_MUTEX_STALLED. The
45  * default value is PTHREAD_MUTEX_STALLED .
46  * [] PTHREAD_MUTEX_STALLED
47  * When the owner of the mutex terminates without unlocking the mutex, all subsequent calls
48  * to pthread_mutex_lock() are blocked from progress in an unspecified manner.
49  * [] PTHREAD_MUTEX_ROBUST
50  * When the owner of the mutex terminates without unlocking the mutex, the mutex is
51  * unlocked. The next owner of this mutex acquires the mutex with an error return of
52  * EOWNERDEAD.
53  * Note - Your application must always check the return code from pthread_mutex_lock() for
54  * a mutex initialized with the PTHREAD_MUTEX_ROBUST attribute.
55  * [] The new owner of this mutex should make the state protected by the mutex consistent.
56  * This state might have been left inconsistent when the previous owner terminated.
57  * [] If the new owner is able to make the state consistent, call
58  * pthread_mutex_consistent() for the mutex before unlocking the mutex. This
59  * marks the mutex as consistent and subsequent calls to pthread_mutex_lock() and
60  * pthread_mutex_unlock() will behave in the normal manner.
61  * [] If the new owner is not able to make the state consistent, do not call
62  * pthread_mutex_consistent() for the mutex, but unlock the mutex.
63  * All waiters are woken up and all subsequent calls to pthread_mutex_lock() fail to
64  * acquire the mutex. The return code is ENOTRECOVERABLE. The mutex can be made
65  * consistent by calling pthread_mutex_destroy() to uninitialize the mutex, and calling
66  * pthread_mutex_int() to reinitialize the mutex.However, the state that was protected
67  * by the mutex remains inconsistent and some form of application recovery is required.
68  * [] If the thread that acquires the lock with EOWNERDEAD terminates without unlocking the
69  * mutex, the next owner acquires the lock with an EOWNERDEAD return code.
70  */
71 #if !defined(_UWIN)
72 /*#   include <process.h> */
73 #endif
74 #include "pthread.h"
75 #include "implement.h"
76 
77 INLINE
78 int
__ptw32_robust_mutex_inherit(pthread_mutex_t * mutex)79 __ptw32_robust_mutex_inherit(pthread_mutex_t * mutex)
80 {
81   int result;
82   pthread_mutex_t mx = *mutex;
83   __ptw32_robust_node_t* robust = mx->robustNode;
84 
85   switch ((LONG)__PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
86              (__PTW32_INTERLOCKED_LONGPTR)&robust->stateInconsistent,
87              (__PTW32_INTERLOCKED_LONG)__PTW32_ROBUST_INCONSISTENT,
88              (__PTW32_INTERLOCKED_LONG)-1 /* The terminating thread sets this */))
89     {
90       case -1L:
91           result = EOWNERDEAD;
92           break;
93       case (LONG)__PTW32_ROBUST_NOTRECOVERABLE:
94           result = ENOTRECOVERABLE;
95           break;
96       default:
97           result = 0;
98           break;
99     }
100 
101   return result;
102 }
103 
104 /*
105  * The next two internal support functions depend on being
106  * called only by the thread that owns the robust mutex. This
107  * enables us to avoid additional locks.
108  * Any mutex currently in the thread's robust mutex list is held
109  * by the thread, again eliminating the need for locks.
110  * The forward/backward links allow the thread to unlock mutexes
111  * in any order, not necessarily the reverse locking order.
112  * This is all possible because it is an error if a thread that
113  * does not own the [robust] mutex attempts to unlock it.
114  */
115 
116 INLINE
117 void
__ptw32_robust_mutex_add(pthread_mutex_t * mutex,pthread_t self)118 __ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self)
119 {
120   __ptw32_robust_node_t** list;
121   pthread_mutex_t mx = *mutex;
122   __ptw32_thread_t* tp = (__ptw32_thread_t*)self.p;
123   __ptw32_robust_node_t* robust = mx->robustNode;
124 
125   list = &tp->robustMxList;
126   mx->ownerThread = self;
127   if (NULL == *list)
128     {
129       robust->prev = NULL;
130       robust->next = NULL;
131       *list = robust;
132     }
133   else
134     {
135       robust->prev = NULL;
136       robust->next = *list;
137       (*list)->prev = robust;
138       *list = robust;
139     }
140 }
141 
142 INLINE
143 void
__ptw32_robust_mutex_remove(pthread_mutex_t * mutex,__ptw32_thread_t * otp)144 __ptw32_robust_mutex_remove(pthread_mutex_t* mutex, __ptw32_thread_t* otp)
145 {
146   __ptw32_robust_node_t** list;
147   pthread_mutex_t mx = *mutex;
148   __ptw32_robust_node_t* robust = mx->robustNode;
149 
150   list = &(((__ptw32_thread_t*)mx->ownerThread.p)->robustMxList);
151   mx->ownerThread.p = otp;
152   if (robust->next != NULL)
153     {
154       robust->next->prev = robust->prev;
155     }
156   if (robust->prev != NULL)
157     {
158       robust->prev->next = robust->next;
159     }
160   if (*list == robust)
161     {
162       *list = robust->next;
163     }
164 }
165 
166 
167 int
pthread_mutex_consistent(pthread_mutex_t * mutex)168 pthread_mutex_consistent (pthread_mutex_t* mutex)
169 {
170   pthread_mutex_t mx = *mutex;
171   int result = 0;
172 
173   /*
174    * Let the system deal with invalid pointers.
175    */
176   if (mx == NULL)
177     {
178       return EINVAL;
179     }
180 
181   if (mx->kind >= 0
182         ||  (__PTW32_INTERLOCKED_LONG)__PTW32_ROBUST_INCONSISTENT !=  __PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(
183                                                  (__PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent,
184                                                  (__PTW32_INTERLOCKED_LONG)__PTW32_ROBUST_CONSISTENT,
185                                                  (__PTW32_INTERLOCKED_LONG)__PTW32_ROBUST_INCONSISTENT))
186     {
187       result = EINVAL;
188     }
189 
190   return (result);
191 }
192 
193