This is Unofficial EPICS BASE Doxygen Site
osdMutex.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE Versions 3.13.7
7 * and higher are distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /* osi/os/posix/osdMutex.c */
11 
12 /* Author: Marty Kraimer Date: 13AUG1999 */
13 
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <pthread.h>
22 
23 #include "epicsMutex.h"
24 #include "cantProceed.h"
25 #include "epicsTime.h"
26 #include "errlog.h"
27 #include "epicsAssert.h"
28 
29 #define checkStatus(status,message) \
30  if((status)) { \
31  errlogPrintf("epicsMutex %s failed: error %s\n", \
32  (message), strerror((status))); \
33  }
34 #define checkStatusQuit(status,message,method) \
35  if(status) { \
36  errlogPrintf("epicsMutex %s failed: error %s\n", \
37  (message), strerror((status))); \
38  cantProceed((method)); \
39  }
40 
41 static int mutexLock(pthread_mutex_t *id)
42 {
43  int status;
44 
45  while ((status = pthread_mutex_lock(id)) == EINTR) {
46  errlogPrintf("pthread_mutex_lock returned EINTR. Violates SUSv3\n");
47  }
48  return status;
49 }
50 
51 /* Until these can be demonstrated to work leave them undefined*/
52 /* On solaris 8 _POSIX_THREAD_PRIO_INHERIT fails*/
53 #undef _POSIX_THREAD_PROCESS_SHARED
54 #undef _POSIX_THREAD_PRIO_INHERIT
55 
56 /* Two completely different implementations are provided below
57  * If support is available for PTHREAD_MUTEX_RECURSIVE then
58  * only pthread_mutex is used.
59  * If support is not available for PTHREAD_MUTEX_RECURSIVE then
60  * a much more complicated solution is required
61  */
62 
63 
64 #if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500
65 typedef struct epicsMutexOSD {
66  pthread_mutex_t lock;
67  pthread_mutexattr_t mutexAttr;
69 
71  epicsMutexOSD *pmutex;
72  int status;
73 
74  pmutex = calloc(1, sizeof(*pmutex));
75  if(!pmutex)
76  goto fail;
77 
78  status = pthread_mutexattr_init(&pmutex->mutexAttr);
79  if (status)
80  goto fail;
81 
82 #if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT > 0
83  status = pthread_mutexattr_setprotocol(&pmutex->mutexAttr,
84  PTHREAD_PRIO_INHERIT);
85  if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal");
86 #endif /*_POSIX_THREAD_PRIO_INHERIT*/
87 
88  status = pthread_mutexattr_settype(&pmutex->mutexAttr,
89  PTHREAD_MUTEX_RECURSIVE);
90  checkStatus(status, "pthread_mutexattr_settype");
91  if (status)
92  goto fail;
93 
94  status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr);
95  if (status)
96  goto dattr;
97  return pmutex;
98 
99 dattr:
100  pthread_mutexattr_destroy(&pmutex->mutexAttr);
101 fail:
102  free(pmutex);
103  return NULL;
104 }
105 
106 void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex)
107 {
108  int status;
109 
110  status = pthread_mutex_destroy(&pmutex->lock);
111  checkStatus(status, "pthread_mutex_destroy");
112  status = pthread_mutexattr_destroy(&pmutex->mutexAttr);
113  checkStatus(status, "pthread_mutexattr_destroy");
114  free(pmutex);
115 }
116 
117 void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex)
118 {
119  int status;
120 
121  status = pthread_mutex_unlock(&pmutex->lock);
122  checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock");
123 }
124 
126 {
127  int status;
128 
129  status = mutexLock(&pmutex->lock);
130  if (status == EINVAL) return epicsMutexLockError;
131  if(status) {
132  errlogMessage("epicsMutex pthread_mutex_lock failed: error epicsMutexOsdLock\n");
133  return epicsMutexLockError;
134  }
135  return epicsMutexLockOK;
136 }
137 
139 {
140  int status;
141 
142  if (!pmutex) return epicsMutexLockError;
143  status = pthread_mutex_trylock(&pmutex->lock);
144  if (status == EINVAL) return epicsMutexLockError;
145  if (status == EBUSY) return epicsMutexLockTimeout;
146  if(status) {
147  errlogMessage("epicsMutex pthread_mutex_trylock failed: error epicsMutexOsdTryLock");
148  return epicsMutexLockError;
149  }
150  return epicsMutexLockOK;
151 }
152 
153 void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level)
154 {
155  /* GLIBC w/ NTPL is passing the &lock.__data.__lock as the first argument (UADDR)
156  * of the futex() syscall. __lock is at offset 0 of the enclosing structures.
157  */
158  printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock);
159 }
160 
161 #else /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
162 
163 typedef struct epicsMutexOSD {
164  pthread_mutex_t lock;
165  pthread_mutexattr_t mutexAttr;
166  pthread_cond_t waitToBeOwner;
167 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0
168  pthread_condattr_t condAttr;
169 #endif /*_POSIX_THREAD_PROCESS_SHARED*/
170  int count;
171  int owned; /* TRUE | FALSE */
172  pthread_t ownerTid;
173 } epicsMutexOSD;
174 
176  epicsMutexOSD *pmutex;
177  int status;
178 
179  pmutex = calloc(1, sizeof(*pmutex));
180  if(!pmutex)
181  return NULL;
182 
183  status = pthread_mutexattr_init(&pmutex->mutexAttr);
184  if(status)
185  goto fail;
186 
187 #if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT > 0
188  status = pthread_mutexattr_setprotocol(
189  &pmutex->mutexAttr,PTHREAD_PRIO_INHERIT);
190  if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal");
191 #endif /*_POSIX_THREAD_PRIO_INHERIT*/
192 
193  status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr);
194  if(status)
195  goto dattr;
196 
197 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0
198  status = pthread_condattr_init(&pmutex->condAttr);
199  checkStatus(status, "pthread_condattr_init");
200  status = pthread_condattr_setpshared(&pmutex->condAttr,
201  PTHREAD_PROCESS_PRIVATE);
202  checkStatus(status, "pthread_condattr_setpshared");
203  status = pthread_cond_init(&pmutex->waitToBeOwner, &pmutex->condAttr);
204 #else
205  status = pthread_cond_init(&pmutex->waitToBeOwner, 0);
206 #endif /*_POSIX_THREAD_PROCESS_SHARED*/
207  if(status)
208  goto dmutex;
209 
210  return pmutex;
211 
212 dmutex:
213  pthread_mutex_destroy(&pmutex->lock);
214 dattr:
215  pthread_mutexattr_destroy(&pmutex->mutexAttr);
216 fail:
217  free(pmutex);
218  return NULL;
219 }
220 
221 void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex)
222 {
223  int status;
224 
225  status = pthread_cond_destroy(&pmutex->waitToBeOwner);
226  checkStatus(status, "pthread_cond_destroy");
227 #if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0
228  status = pthread_condattr_destroy(&pmutex->condAttr);
229 #endif /*_POSIX_THREAD_PROCESS_SHARED*/
230  status = pthread_mutex_destroy(&pmutex->lock);
231  checkStatus(status, "pthread_mutex_destroy");
232  status = pthread_mutexattr_destroy(&pmutex->mutexAttr);
233  checkStatus(status, "pthread_mutexattr_destroy");
234  free(pmutex);
235 }
236 
237 void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex)
238 {
239  int status;
240 
241  status = mutexLock(&pmutex->lock);
242  checkStatus(status, "pthread_mutex_lock epicsMutexOsdUnlock");
243  if(status)
244  return;
245 
246  if ((pmutex->count <= 0) || (pmutex->ownerTid != pthread_self())) {
247  pthread_mutex_unlock(&pmutex->lock);
248  checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock");
249  errlogPrintf("epicsMutexOsdUnlock but caller is not owner\n");
250  cantProceed("epicsMutexOsdUnlock but caller is not owner");
251  return;
252  }
253 
254  pmutex->count--;
255  if (pmutex->count == 0) {
256  pmutex->owned = 0;
257  pmutex->ownerTid = 0;
258  status = pthread_cond_signal(&pmutex->waitToBeOwner);
259  checkStatusQuit(status, "pthread_cond_signal epicsMutexOsdUnlock", "epicsMutexOsdUnlock");
260  }
261 
262  status = pthread_mutex_unlock(&pmutex->lock);
263  checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock");
264 }
265 
266 static int condWait(pthread_cond_t *condId, pthread_mutex_t *mutexId)
267 {
268  int status;
269 
270  while ((status = pthread_cond_wait(condId, mutexId)) == EINTR) {
271  errlogPrintf("pthread_cond_wait returned EINTR. Violates SUSv3\n");
272  }
273  return status;
274 }
275 
277 {
278  pthread_t tid = pthread_self();
279  int status;
280 
281  if (!pmutex || !tid) return epicsMutexLockError;
282  status = mutexLock(&pmutex->lock);
283  if (status == EINVAL) return epicsMutexLockError;
284  checkStatus(status, "pthread_mutex_lock epicsMutexOsdLock");
285  if(status)
286  return epicsMutexLockError;
287 
288  while (pmutex->owned && !pthread_equal(pmutex->ownerTid, tid))
289  condWait(&pmutex->waitToBeOwner, &pmutex->lock);
290  pmutex->ownerTid = tid;
291  pmutex->owned = 1;
292  pmutex->count++;
293 
294  status = pthread_mutex_unlock(&pmutex->lock);
295  checkStatus(status, "pthread_mutex_unlock epicsMutexOsdLock");
296  if(status)
297  return epicsMutexLockError;
298  return epicsMutexLockOK;
299 }
300 
302 {
303  pthread_t tid = pthread_self();
305  int status;
306 
307  status = mutexLock(&pmutex->lock);
308  if (status == EINVAL) return epicsMutexLockError;
309  checkStatus(status, "pthread_mutex_lock epicsMutexOsdTryLock");
310  if(status)
311  return epicsMutexLockError;
312 
313  if (!pmutex->owned || pthread_equal(pmutex->ownerTid, tid)) {
314  pmutex->ownerTid = tid;
315  pmutex->owned = 1;
316  pmutex->count++;
317  result = epicsMutexLockOK;
318  } else {
319  result = epicsMutexLockTimeout;
320  }
321 
322  status = pthread_mutex_unlock(&pmutex->lock);
323  checkStatus(status, "pthread_mutex_unlock epicsMutexOsdTryLock");
324  if(status)
325  return epicsMutexLockError;
326  return result;
327 }
328 
329 void epicsMutexOsdShow(struct epicsMutexOSD *pmutex,unsigned int level)
330 {
331  printf("ownerTid %p count %d owned %d\n",
332  (void *)pmutex->ownerTid, pmutex->count, pmutex->owned);
333 }
334 #endif /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */
pvac::PutEvent result
Definition: clientSync.cpp:117
pvd::Status status
An EPICS-specific replacement for ANSI C&#39;s assert.
pthread_mutex_t lock
Definition: osdMutex.c:164
pthread_t ownerTid
Definition: osdMutex.c:172
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
void epicsMutexOsdUnlock(struct epicsMutexOSD *pmutex)
Definition: osdMutex.c:237
#define checkStatus(status, message)
Definition: osdMutex.c:29
struct epicsMutexOSD epicsMutexOSD
epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD *pmutex)
Definition: osdMutex.c:276
#define checkStatusQuit(status, message, method)
Definition: osdMutex.c:34
epicsMutexOSD * epicsMutexOsdCreate(void)
Definition: osdMutex.c:175
int errVerbose
Definition: errlog.c:41
APIs for the epicsMutex mutual exclusion semaphore.
pthread_mutexattr_t mutexAttr
Definition: osdMutex.c:165
epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD *pmutex)
Definition: osdMutex.c:301
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
epicsMutexLockStatus
Definition: epicsMutex.h:51
int errlogMessage(const char *message)
Definition: errlog.c:180
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
Routines for code that can&#39;t continue or return after an error.
void epicsMutexOsdDestroy(struct epicsMutexOSD *pmutex)
Definition: osdMutex.c:221
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
pthread_cond_t waitToBeOwner
Definition: osdMutex.c:166
void epicsMutexOsdShow(struct epicsMutexOSD *pmutex, unsigned int level)
Definition: osdMutex.c:329