31#include "external/ThreadSafetyAnalysis.h"
46static inline double dt_pthread_get_wtime()
49 gettimeofday(&time, NULL);
50 return time.tv_sec - 1290608000 + (1.0 / 1000000.0) * time.tv_usec;
55typedef struct CAPABILITY(
"mutex") dt_pthread_mutex_t
57 pthread_mutex_t
mutex;
61 double time_sum_locked;
62 char top_locked_name[TOPN][256];
63 double top_locked_sum[TOPN];
64 char top_wait_name[TOPN][256];
65 double top_wait_sum[TOPN];
70 pthread_rwlock_t
lock;
79 const int ret = pthread_mutex_destroy(&(
mutex->mutex));
83 printf(
"\n[mutex] stats for mutex `%s':\n",
mutex->name);
84 printf(
"[mutex] total time locked: %.3f secs\n",
mutex->time_sum_locked);
85 printf(
"[mutex] total wait time : %.3f secs\n",
mutex->time_sum_wait);
86 printf(
"[mutex] top %d lockers :\n", TOPN);
87 for(
int k=0;
k<TOPN;
k++) printf(
"[mutex] %.3f secs : `%s'\n",
mutex->top_locked_sum[
k],
88 mutex->top_locked_name[
k]);
89 printf(
"[mutex] top %d waiters :\n", TOPN);
90 for(
int k=0;
k<TOPN;
k++) printf(
"[mutex] %.3f secs : `%s'\n",
mutex->top_wait_sum[
k],
97#define dt_pthread_mutex_init(A, B) dt_pthread_mutex_init_with_caller(A, B, __FILE__, __LINE__, __FUNCTION__)
98static inline int dt_pthread_mutex_init_with_caller(dt_pthread_mutex_t *
mutex,
99 const pthread_mutexattr_t *attr,
const char *file,
100 const int line,
const char *function)
102 memset(
mutex, 0x0,
sizeof(dt_pthread_mutex_t));
103 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
104#if defined(__OpenBSD__)
107 pthread_mutexattr_t a;
108 pthread_mutexattr_init(&a);
109 pthread_mutexattr_settype(&a, PTHREAD_MUTEX_NORMAL);
110 const int ret = pthread_mutex_init(&(
mutex->mutex), &a);
111 pthread_mutexattr_destroy(&a);
115 const int ret = pthread_mutex_init(&(
mutex->mutex), attr);
120#define dt_pthread_mutex_lock(A) dt_pthread_mutex_lock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
121static inline int dt_pthread_mutex_lock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
122 const int line,
const char *function)
125 const double t0 = dt_pthread_get_wtime();
126 const int ret = pthread_mutex_lock(&(
mutex->mutex));
128 mutex->time_locked = dt_pthread_get_wtime();
129 double wait =
mutex->time_locked - t0;
130 mutex->time_sum_wait += wait;
132 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
135 int min_wait_slot = 0;
136 for(
int k = 0;
k < TOPN;
k++)
138 if(
mutex->top_wait_sum[
k] <
mutex->top_wait_sum[min_wait_slot]) min_wait_slot =
k;
139 if(!strncmp(
name,
mutex->top_wait_name[
k], 256))
141 mutex->top_wait_sum[
k] += wait;
145 g_strlcpy(
mutex->top_wait_name[min_wait_slot],
name,
sizeof(
mutex->top_wait_name[min_wait_slot]));
146 mutex->top_wait_sum[min_wait_slot] = wait;
150#define dt_pthread_mutex_trylock(A) dt_pthread_mutex_trylock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
151static inline int dt_pthread_mutex_trylock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
152 const int line,
const char *function)
153 TRY_ACQUIRE(0,
mutex)
155 const double t0 = dt_pthread_get_wtime();
156 const int ret = pthread_mutex_trylock(&(
mutex->mutex));
157 assert(!ret || (ret == EBUSY));
159 mutex->time_locked = dt_pthread_get_wtime();
160 double wait =
mutex->time_locked - t0;
161 mutex->time_sum_wait += wait;
163 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
164 int min_wait_slot = 0;
165 for(
int k = 0;
k < TOPN;
k++)
167 if(
mutex->top_wait_sum[
k] <
mutex->top_wait_sum[min_wait_slot]) min_wait_slot =
k;
168 if(!strncmp(
name,
mutex->top_wait_name[
k], 256))
170 mutex->top_wait_sum[
k] += wait;
174 g_strlcpy(
mutex->top_wait_name[min_wait_slot],
name,
sizeof(
mutex->top_wait_name[min_wait_slot]));
175 mutex->top_wait_sum[min_wait_slot] = wait;
179#define dt_pthread_mutex_unlock(A) dt_pthread_mutex_unlock_with_caller(A, __FILE__, __LINE__, __FUNCTION__)
180static inline int dt_pthread_mutex_unlock_with_caller(dt_pthread_mutex_t *
mutex,
const char *file,
181 const int line,
const char *function)
182 RELEASE(
mutex) NO_THREAD_SAFETY_ANALYSIS
184 const double t0 = dt_pthread_get_wtime();
185 const double locked = t0 -
mutex->time_locked;
186 mutex->time_sum_locked += locked;
189 snprintf(
mutex->name,
sizeof(
mutex->name),
"%s:%d (%s)", file, line, function);
192 int min_locked_slot = 0;
193 for(
int k = 0;
k < TOPN;
k++)
195 if(
mutex->top_locked_sum[
k] <
mutex->top_locked_sum[min_locked_slot]) min_locked_slot =
k;
196 if(!strncmp(
name,
mutex->top_locked_name[
k], 256))
198 mutex->top_locked_sum[
k] += locked;
199 min_locked_slot = -1;
203 if(min_locked_slot >= 0)
205 g_strlcpy(
mutex->top_locked_name[min_locked_slot],
name,
sizeof(
mutex->top_locked_name[min_locked_slot]));
206 mutex->top_locked_sum[min_locked_slot] = locked;
210 const int ret = pthread_mutex_unlock(&(
mutex->mutex));
217 return pthread_cond_wait(cond, &(
mutex->mutex));
222 const pthread_rwlockattr_t *attr)
226 lock->writer_depth = 0;
227 const int res = pthread_rwlock_init(&
lock->lock, attr);
243 if(
lock->writer_depth != 0)
244 fprintf(stderr,
"ERROR: destroying rwlock still owned by writer (depth=%d cnt=%d last=%s)\n",
246 assert(
lock->writer_depth == 0);
247 snprintf(
lock->name,
sizeof(
lock->name),
"destroyed with cnt %d",
lock->cnt);
248 const int res = pthread_rwlock_destroy(&
lock->lock);
258#define dt_pthread_rwlock_unlock(A) dt_pthread_rwlock_unlock_with_caller(A, __FILE__, __LINE__)
259static inline int dt_pthread_rwlock_unlock_with_caller(
dt_pthread_rwlock_t *rwlock,
const char *file,
int line)
263 __sync_fetch_and_sub(&(rwlock->cnt), 1);
266 assert(rwlock->cnt >= 0);
267 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"nu:%s:%d", file, line);
268 fprintf(stdout,
"Warning: thread lock owned by the same thread is unlocked again by %s\n", rwlock->
name);
272 const gboolean writer_was_self = pthread_equal(rwlock->
writer, pthread_self());
273 const int res = pthread_rwlock_unlock(&rwlock->
lock);
275 __sync_fetch_and_sub(&(rwlock->cnt), 1);
276 assert(rwlock->cnt >= 0);
277 __sync_bool_compare_and_swap(&(rwlock->
writer), pthread_self(), 0);
279 if(!res) snprintf(rwlock->
name,
sizeof(rwlock->
name),
"u:%s:%d", file, line);
283#define dt_pthread_rwlock_rdlock(A) dt_pthread_rwlock_rdlock_with_caller(A, __FILE__, __LINE__)
288 __sync_fetch_and_add(&(rwlock->cnt), 1);
290 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"wr:%s:%d", file, line);
291 fprintf(stdout,
"Warning: thread lock owned by the same thread is locked again by %s\n", rwlock->
name);
295 const int res = pthread_rwlock_rdlock(&rwlock->
lock);
297 __sync_fetch_and_add(&(rwlock->cnt), 1);
299 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"r:%s:%d", file, line);
302#define dt_pthread_rwlock_wrlock(A) dt_pthread_rwlock_wrlock_with_caller(A, __FILE__, __LINE__)
307 __sync_fetch_and_add(&(rwlock->cnt), 1);
309 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"ww:%s:%d", file, line);
310 fprintf(stdout,
"Warning: thread lock owned by the same thread is locked again by %s\n", rwlock->
name);
314 const int res = pthread_rwlock_wrlock(&rwlock->
lock);
316 __sync_fetch_and_add(&(rwlock->cnt), 1);
319 __sync_lock_test_and_set(&(rwlock->
writer), pthread_self());
321 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"w:%s:%d", file, line);
325#define dt_pthread_rwlock_tryrdlock(A) dt_pthread_rwlock_tryrdlock_with_caller(A, __FILE__, __LINE__)
331 if(pthread_equal(rwlock->
writer, pthread_self()) && rwlock->
writer_depth >= 1)
return EBUSY;
333 const int res = pthread_rwlock_tryrdlock(&rwlock->
lock);
334 assert(!res || (res == EBUSY));
337 __sync_fetch_and_add(&(rwlock->cnt), 1);
338 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"tr:%s:%d", file, line);
342#define dt_pthread_rwlock_trywrlock(A) dt_pthread_rwlock_trywrlock_with_caller(A, __FILE__, __LINE__)
346 if(pthread_equal(rwlock->
writer, pthread_self()) && rwlock->
writer_depth >= 1)
return EBUSY;
348 const int res = pthread_rwlock_trywrlock(&rwlock->
lock);
349 assert(!res || (res == EBUSY));
352 __sync_fetch_and_add(&(rwlock->cnt), 1);
353 __sync_lock_test_and_set(&(rwlock->
writer), pthread_self());
355 snprintf(rwlock->
name,
sizeof(rwlock->
name),
"tw:%s:%d", file, line);
363typedef struct CAPABILITY(
"mutex") dt_pthread_mutex_t
365 pthread_mutex_t
mutex;