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