DSL
Mutex_pthreads.cpp
1 //@AUTOHEADER@BEGIN@
2 /***********************************************************************\
3 | Drift Standard Libraries v1.01 |
4 | Copyright 2010-2023 Drift Solutions / Indy Sams |
5 | Docs and more information available at https://www.driftsolutions.dev |
6 | This file released under the 3-clause BSD license, |
7 | see included DSL.LICENSE.TXT file for details. |
8 \***********************************************************************/
9 //@AUTOHEADER@END@
10 
11 #include <drift/dslcore.h>
12 
13 #if !defined(WIN32)
14 
15 #include <drift/Mutex.h>
16 #include <drift/Threading.h>
17 #include <assert.h>
18 
19 DSL_Mutex_pthreads::DSL_Mutex_pthreads(int timeout) {
20  refcnt = 0;
21  lock_timeout = timeout;
22  memset(&hMutex, 0, sizeof(hMutex));
23 
24  // I like my mutex'es recursive
25  pthread_mutexattr_t pma;
26  memset(&pma, 0, sizeof(pma));
27  pthread_mutexattr_init(&pma);
28  pthread_mutexattr_settype(&pma, PTHREAD_MUTEX_RECURSIVE);
29  pthread_mutex_init(&hMutex, &pma);
30  pthread_mutexattr_destroy(&pma);
31 }
32 
33 DSL_Mutex_pthreads::~DSL_Mutex_pthreads() {
34  pthread_mutex_destroy(&hMutex);
35 }
36 
37 bool DSL_Mutex_pthreads::Lock() {
38  if (lock_timeout >= 0) {
39  return Lock(lock_timeout);
40  }
41 
42  int n = pthread_mutex_lock(&hMutex);
43  if (n != 0) {
44  printf("Error locking mutex! (%p, %p, %d, %s)\n", this, &hMutex, n, strerror(n));
45  assert(0);
46  }
47  LockingThreadID = pthread_self();
48  refcnt++;
49  if (refcnt <= 0) { refcnt = 1; }
50  return true;
51 }
52 
53 bool DSL_Mutex_pthreads::Lock(int timeo) {
54  int64 timeout = timeo;
55  struct timespec abs_time;
56  memset(&abs_time, 0, sizeof(abs_time));
57  if (clock_gettime(CLOCK_REALTIME, &abs_time) == 0) {
58  abs_time.tv_sec += (timeout / 1000);
59  timeout -= (timeout / 1000);
60  abs_time.tv_nsec += timeout * 1000000;
61  while (abs_time.tv_nsec >= 1000000000LL) {
62  abs_time.tv_sec++;
63  abs_time.tv_nsec -= 1000000000LL;
64  }
65  if (abs_time.tv_nsec < 0) {
66  printf("Timed mutex lock nsec < 0! (%p, %p, %llu, %llu)\n", this, &hMutex, abs_time.tv_sec, abs_time.tv_nsec);
67  abs_time.tv_nsec = 0;
68  }
69  int n = pthread_mutex_timedlock(&hMutex, &abs_time);
70  if (n != 0) {
71  if (timeout > 1000) {
72  printf("Error locking mutex! (%p, %p, %d, %s)\n", this, &hMutex, n, strerror(n));
73  printf("" I64FMT " / " I64FMT "\n", abs_time.tv_sec, abs_time.tv_nsec);
74  }
75  return false;
76  }
77  } else {
78  //fallback in case clock_gettime fails
79  int left = timeout;
80  int amIn = pthread_mutex_trylock(&hMutex);
81  while (amIn != 0) {
82  if (left > 0) {
83  safe_sleep(100, true);
84  left -= 100;
85  amIn = pthread_mutex_trylock(&hMutex);
86  } else {
87  if (timeout > 1000) {
88  printf("Error locking mutex! (%p, %p, %s)\n", this, &hMutex, strerror(errno));
89  }
90  return false;
91  }
92  }
93  }
94 
95  LockingThreadID = GetCurrentThreadId();
96  refcnt++;
97  if (refcnt <= 0) { refcnt = 1; }
98  return true;
99 }
100 
101 void DSL_Mutex_pthreads::Release() {
102  refcnt--;
103  if (refcnt <= 0) {
104  LockingThreadID = 0;
105  }
106  int n = pthread_mutex_unlock(&hMutex);
107  if (n != 0) {
108  printf("Error unlocking mutex! (%p, %p, %d, %s)\n", this, &hMutex, n, strerror(n));
109  assert(0);
110  }
111 }
112 
113 THREADIDTYPE DSL_Mutex_pthreads::LockingThread() {
114  return LockingThreadID;
115 }
116 
117 bool DSL_Mutex_pthreads::IsLockMine() {
118  if (refcnt > 0 && pthread_equal(pthread_self(), LockingThreadID)) { return true; }
119  return false;
120 }
121 
122 bool DSL_Mutex_pthreads::IsLocked() {
123  if (refcnt > 0) { return true; }
124  return false;
125 }
126 
127 #endif