21#include "external/ThreadSafetyAnalysis.h"
35static inline double dt_pthread_get_wtime()
38 gettimeofday(&time, NULL);
39 return time.tv_sec - 1290608000 + (1.0 / 1000000.0) * time.tv_usec;
44typedef struct CAPABILITY(
"mutex") dt_pthread_mutex_t
46 pthread_mutex_t
mutex;
50 double time_sum_locked;
51 char top_locked_name[TOPN][256];
52 double top_locked_sum[TOPN];
53 char top_wait_name[TOPN][256];
54 double top_wait_sum[TOPN];
59 pthread_rwlock_t lock;
67 const int ret = pthread_mutex_destroy(&(
mutex->mutex));
71 printf(
"\n[mutex] stats for mutex `%s':\n",
mutex->name);
72 printf(
"[mutex] total time locked: %.3f secs\n",
mutex->time_sum_locked);
73 printf(
"[mutex] total wait time : %.3f secs\n",
mutex->time_sum_wait);
74 printf(
"[mutex] top %d lockers :\n", TOPN);
75 for(
int k=0;
k<TOPN;
k++) printf(
"[mutex] %.3f secs : `%s'\n",
mutex->top_locked_sum[k],
76 mutex->top_locked_name[k]);
77 printf(
"[mutex] top %d waiters :\n", TOPN);
78 for(
int k=0;
k<TOPN;
k++) printf(
"[mutex] %.3f secs : `%s'\n",
mutex->top_wait_sum[k],
79 mutex->top_wait_name[k]);
85#define dt_pthread_mutex_init(A, B) dt_pthread_mutex_init_with_caller(A, B, __FILE__, __LINE__, __FUNCTION__)
86static inline int dt_pthread_mutex_init_with_caller(dt_pthread_mutex_t *
mutex,
87 const pthread_mutexattr_t *attr,
const char *file,
88 const int line,
const char *function)
90 memset(
mutex, 0x0,
sizeof(dt_pthread_mutex_t));
91 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
92#if defined(__OpenBSD__)
95 pthread_mutexattr_t a;
96 pthread_mutexattr_init(&a);
97 pthread_mutexattr_settype(&a, PTHREAD_MUTEX_NORMAL);
98 const int ret = pthread_mutex_init(&(
mutex->mutex), &a);
99 pthread_mutexattr_destroy(&a);
103 const int ret = pthread_mutex_init(&(
mutex->mutex), attr);
108#define dt_pthread_mutex_lock(A) dt_pthread_mutex_lock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
109static inline int dt_pthread_mutex_lock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
110 const int line,
const char *function)
113 const double t0 = dt_pthread_get_wtime();
114 const int ret = pthread_mutex_lock(&(
mutex->mutex));
116 mutex->time_locked = dt_pthread_get_wtime();
117 double wait =
mutex->time_locked - t0;
118 mutex->time_sum_wait += wait;
120 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
123 int min_wait_slot = 0;
124 for(
int k = 0;
k < TOPN;
k++)
126 if(
mutex->top_wait_sum[k] <
mutex->top_wait_sum[min_wait_slot]) min_wait_slot =
k;
127 if(!strncmp(
name,
mutex->top_wait_name[k], 256))
129 mutex->top_wait_sum[
k] += wait;
133 g_strlcpy(
mutex->top_wait_name[min_wait_slot],
name,
sizeof(
mutex->top_wait_name[min_wait_slot]));
134 mutex->top_wait_sum[min_wait_slot] = wait;
138#define dt_pthread_mutex_trylock(A) dt_pthread_mutex_trylock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
139static inline int dt_pthread_mutex_trylock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
140 const int line,
const char *function)
141 TRY_ACQUIRE(0,
mutex)
143 const double t0 = dt_pthread_get_wtime();
144 const int ret = pthread_mutex_trylock(&(
mutex->mutex));
145 assert(!ret || (ret == EBUSY));
147 mutex->time_locked = dt_pthread_get_wtime();
148 double wait =
mutex->time_locked - t0;
149 mutex->time_sum_wait += wait;
151 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
152 int min_wait_slot = 0;
153 for(
int k = 0;
k < TOPN;
k++)
155 if(
mutex->top_wait_sum[k] <
mutex->top_wait_sum[min_wait_slot]) min_wait_slot =
k;
156 if(!strncmp(
name,
mutex->top_wait_name[k], 256))
158 mutex->top_wait_sum[
k] += wait;
162 g_strlcpy(
mutex->top_wait_name[min_wait_slot],
name,
sizeof(
mutex->top_wait_name[min_wait_slot]));
163 mutex->top_wait_sum[min_wait_slot] = wait;
167#define dt_pthread_mutex_unlock(A) dt_pthread_mutex_unlock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
168static inline int dt_pthread_mutex_unlock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
169 const int line,
const char *function)
170 RELEASE(
mutex) NO_THREAD_SAFETY_ANALYSIS
172 const double t0 = dt_pthread_get_wtime();
173 const double locked = t0 -
mutex->time_locked;
174 mutex->time_sum_locked += locked;
177 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
180 int min_locked_slot = 0;
181 for(
int k = 0;
k < TOPN;
k++)
183 if(
mutex->top_locked_sum[k] <
mutex->top_locked_sum[min_locked_slot]) min_locked_slot =
k;
184 if(!strncmp(
name,
mutex->top_locked_name[k], 256))
186 mutex->top_locked_sum[
k] += locked;
187 min_locked_slot = -1;
191 if(min_locked_slot >= 0)
193 g_strlcpy(
mutex->top_locked_name[min_locked_slot],
name,
sizeof(
mutex->top_locked_name[min_locked_slot]));
194 mutex->top_locked_sum[min_locked_slot] = locked;
198 const int ret = pthread_mutex_unlock(&(
mutex->mutex));
205 return pthread_cond_wait(cond, &(
mutex->mutex));
210 const pthread_rwlockattr_t *attr)
214 const int res = pthread_rwlock_init(&lock->lock, attr);
221 snprintf(lock->name,
sizeof(lock->name),
"destroyed with cnt %d", lock->cnt);
222 const int res = pthread_rwlock_destroy(&lock->lock);
232#define dt_pthread_rwlock_unlock(A) dt_pthread_rwlock_unlock_with_caller(A, __FILE__, __LINE__)
233static inline int dt_pthread_rwlock_unlock_with_caller(
dt_pthread_rwlock_t *rwlock,
const char *file,
int line)
235 const int res = pthread_rwlock_unlock(&rwlock->lock);
239 __sync_fetch_and_sub(&(rwlock->cnt), 1);
240 assert(rwlock->cnt >= 0);
241 __sync_bool_compare_and_swap(&(rwlock->writer), pthread_self(), 0);
242 if(!res) snprintf(rwlock->name,
sizeof(rwlock->name),
"u:%s:%d", file, line);
246#define dt_pthread_rwlock_rdlock(A) dt_pthread_rwlock_rdlock_with_caller(A, __FILE__, __LINE__)
249 const int res = pthread_rwlock_rdlock(&rwlock->lock);
251 assert(!(res && pthread_equal(rwlock->writer, pthread_self())));
252 __sync_fetch_and_add(&(rwlock->cnt), 1);
254 snprintf(rwlock->name,
sizeof(rwlock->name),
"r:%s:%d", file, line);
257#define dt_pthread_rwlock_wrlock(A) dt_pthread_rwlock_wrlock_with_caller(A, __FILE__, __LINE__)
260 const int res = pthread_rwlock_wrlock(&rwlock->lock);
262 __sync_fetch_and_add(&(rwlock->cnt), 1);
265 __sync_lock_test_and_set(&(rwlock->writer), pthread_self());
266 snprintf(rwlock->name,
sizeof(rwlock->name),
"w:%s:%d", file, line);
270#define dt_pthread_rwlock_tryrdlock(A) dt_pthread_rwlock_tryrdlock_with_caller(A, __FILE__, __LINE__)
273 const int res = pthread_rwlock_tryrdlock(&rwlock->lock);
274 assert(!res || (res == EBUSY));
275 assert(!(res && pthread_equal(rwlock->writer, pthread_self())));
278 __sync_fetch_and_add(&(rwlock->cnt), 1);
279 snprintf(rwlock->name,
sizeof(rwlock->name),
"tr:%s:%d", file, line);
283#define dt_pthread_rwlock_trywrlock(A) dt_pthread_rwlock_trywrlock_with_caller(A, __FILE__, __LINE__)
286 const int res = pthread_rwlock_trywrlock(&rwlock->lock);
287 assert(!res || (res == EBUSY));
290 __sync_fetch_and_add(&(rwlock->cnt), 1);
291 __sync_lock_test_and_set(&(rwlock->writer), pthread_self());
292 snprintf(rwlock->name,
sizeof(rwlock->name),
"tw:%s:%d", file, line);
300typedef struct CAPABILITY(
"mutex") dt_pthread_mutex_t
302 pthread_mutex_t
mutex;