|
@@ -1,11 +1,31 @@
|
|
#if defined(GB_SYSTEM_LINUX)
|
|
#if defined(GB_SYSTEM_LINUX)
|
|
#include <signal.h>
|
|
#include <signal.h>
|
|
|
|
+#if __has_include(<valgrind/helgrind.h>)
|
|
|
|
+#include <valgrind/helgrind.h>
|
|
|
|
+#define HAS_VALGRIND
|
|
|
|
+#endif
|
|
#endif
|
|
#endif
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
|
#pragma warning(push)
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4505)
|
|
#pragma warning(disable: 4505)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+#if defined(HAS_VALGRIND)
|
|
|
|
+#define ANNOTATE_LOCK_PRE(m, t) VALGRIND_HG_MUTEX_LOCK_PRE(m, t)
|
|
|
|
+#define ANNOTATE_LOCK_POST(m) VALGRIND_HG_MUTEX_LOCK_POST(m)
|
|
|
|
+#define ANNOTATE_UNLOCK_PRE(m) VALGRIND_HG_MUTEX_UNLOCK_PRE(m)
|
|
|
|
+#define ANNOTATE_UNLOCK_POST(m) VALGRIND_HG_MUTEX_UNLOCK_POST(m)
|
|
|
|
+#define ANNOTATE_SEM_WAIT_POST(s) VALGRIND_HG_SEM_WAIT_POST(s)
|
|
|
|
+#define ANNOTATE_SEM_POST_PRE(s) VALGRIND_HG_SEM_POST_PRE(s)
|
|
|
|
+#else
|
|
|
|
+#define ANNOTATE_LOCK_PRE(m, t)
|
|
|
|
+#define ANNOTATE_LOCK_POST(m)
|
|
|
|
+#define ANNOTATE_UNLOCK_PRE(m)
|
|
|
|
+#define ANNOTATE_UNLOCK_POST(m)
|
|
|
|
+#define ANNOTATE_SEM_WAIT_POST(s)
|
|
|
|
+#define ANNOTATE_SEM_POST_PRE(s)
|
|
|
|
+#endif
|
|
|
|
+
|
|
struct BlockingMutex;
|
|
struct BlockingMutex;
|
|
struct RecursiveMutex;
|
|
struct RecursiveMutex;
|
|
struct RwMutex;
|
|
struct RwMutex;
|
|
@@ -32,7 +52,7 @@ struct Thread {
|
|
#else
|
|
#else
|
|
pthread_t posix_handle;
|
|
pthread_t posix_handle;
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
|
|
+
|
|
isize idx;
|
|
isize idx;
|
|
|
|
|
|
WorkerTask *queue;
|
|
WorkerTask *queue;
|
|
@@ -208,7 +228,7 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
|
struct Condition {
|
|
struct Condition {
|
|
CONDITION_VARIABLE cond;
|
|
CONDITION_VARIABLE cond;
|
|
};
|
|
};
|
|
-
|
|
|
|
|
|
+
|
|
gb_internal void condition_broadcast(Condition *c) {
|
|
gb_internal void condition_broadcast(Condition *c) {
|
|
WakeAllConditionVariable(&c->cond);
|
|
WakeAllConditionVariable(&c->cond);
|
|
}
|
|
}
|
|
@@ -250,6 +270,14 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
|
};
|
|
};
|
|
|
|
|
|
struct BlockingMutex {
|
|
struct BlockingMutex {
|
|
|
|
+ #if defined(HAS_VALGRIND)
|
|
|
|
+ BlockingMutex() {
|
|
|
|
+ VALGRIND_HG_MUTEX_INIT_POST(this, 0);
|
|
|
|
+ }
|
|
|
|
+ ~BlockingMutex() {
|
|
|
|
+ VALGRIND_HG_MUTEX_DESTROY_PRE(this);
|
|
|
|
+ }
|
|
|
|
+ #endif
|
|
i32 state_;
|
|
i32 state_;
|
|
|
|
|
|
Futex &state() {
|
|
Futex &state() {
|
|
@@ -289,14 +317,21 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
|
}
|
|
}
|
|
|
|
|
|
gb_internal void mutex_lock(BlockingMutex *m) {
|
|
gb_internal void mutex_lock(BlockingMutex *m) {
|
|
|
|
+ ANNOTATE_LOCK_PRE(m, 0);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
|
|
if (v != Internal_Mutex_State_Unlocked) {
|
|
if (v != Internal_Mutex_State_Unlocked) {
|
|
mutex_lock_slow(m, v);
|
|
mutex_lock_slow(m, v);
|
|
}
|
|
}
|
|
|
|
+ ANNOTATE_LOCK_POST(m);
|
|
}
|
|
}
|
|
gb_internal bool mutex_try_lock(BlockingMutex *m) {
|
|
gb_internal bool mutex_try_lock(BlockingMutex *m) {
|
|
|
|
+ ANNOTATE_LOCK_PRE(m, 1);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Locked, std::memory_order_acquire);
|
|
- return v == Internal_Mutex_State_Unlocked;
|
|
|
|
|
|
+ if (v == Internal_Mutex_State_Unlocked) {
|
|
|
|
+ ANNOTATE_LOCK_POST(m);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
|
|
gb_no_inline gb_internal void mutex_unlock_slow(BlockingMutex *m) {
|
|
gb_no_inline gb_internal void mutex_unlock_slow(BlockingMutex *m) {
|
|
@@ -304,6 +339,7 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
|
}
|
|
}
|
|
|
|
|
|
gb_internal void mutex_unlock(BlockingMutex *m) {
|
|
gb_internal void mutex_unlock(BlockingMutex *m) {
|
|
|
|
+ ANNOTATE_UNLOCK_PRE(m);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Unlocked, std::memory_order_release);
|
|
i32 v = m->state().exchange(Internal_Mutex_State_Unlocked, std::memory_order_release);
|
|
switch (v) {
|
|
switch (v) {
|
|
case Internal_Mutex_State_Unlocked:
|
|
case Internal_Mutex_State_Unlocked:
|
|
@@ -316,8 +352,9 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
|
mutex_unlock_slow(m);
|
|
mutex_unlock_slow(m);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ ANNOTATE_UNLOCK_POST(m);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
struct Condition {
|
|
struct Condition {
|
|
i32 state_;
|
|
i32 state_;
|
|
|
|
|
|
@@ -472,7 +509,7 @@ gb_internal void *internal_thread_proc(void *arg) {
|
|
sigfillset(&mask);
|
|
sigfillset(&mask);
|
|
GB_ASSERT_MSG(pthread_sigmask(SIG_BLOCK, &mask, nullptr) == 0, "failed to block signals");
|
|
GB_ASSERT_MSG(pthread_sigmask(SIG_BLOCK, &mask, nullptr) == 0, "failed to block signals");
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
|
|
+
|
|
Thread *t = cast(Thread *)arg;
|
|
Thread *t = cast(Thread *)arg;
|
|
thread_pool_thread_proc(t);
|
|
thread_pool_thread_proc(t);
|
|
return NULL;
|
|
return NULL;
|
|
@@ -767,4 +804,4 @@ gb_internal void futex_wait(Futex *f, Footex val) {
|
|
|
|
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
|
#if defined(GB_SYSTEM_WINDOWS)
|
|
#pragma warning(pop)
|
|
#pragma warning(pop)
|
|
-#endif
|
|
|
|
|
|
+#endif
|