summaryrefslogtreecommitdiff
path: root/thread_pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'thread_pthread.c')
-rw-r--r--thread_pthread.c108
1 files changed, 107 insertions, 1 deletions
diff --git a/thread_pthread.c b/thread_pthread.c
index 125cf57c77..fee32bae34 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -98,6 +98,95 @@
# endif
#endif
+struct rb_internal_thread_event_hook {
+ rb_internal_thread_event_callback callback;
+ rb_event_flag_t event;
+ void *user_data;
+
+ struct rb_internal_thread_event_hook *next;
+};
+
+static rb_internal_thread_event_hook_t *rb_internal_thread_event_hooks = NULL;
+static pthread_rwlock_t rb_internal_thread_event_hooks_rw_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+rb_internal_thread_event_hook_t *
+rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data)
+{
+ rb_internal_thread_event_hook_t *hook = ALLOC_N(rb_internal_thread_event_hook_t, 1);
+ hook->callback = callback;
+ hook->user_data = user_data;
+ hook->event = internal_event;
+
+ int r;
+ if ((r = pthread_rwlock_wrlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_wrlock", r);
+ }
+
+ hook->next = rb_internal_thread_event_hooks;
+ ATOMIC_PTR_EXCHANGE(rb_internal_thread_event_hooks, hook);
+
+ if ((r = pthread_rwlock_unlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_unlock", r);
+ }
+ return hook;
+}
+
+bool
+rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook)
+{
+ int r;
+ if ((r = pthread_rwlock_wrlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_wrlock", r);
+ }
+
+ bool success = FALSE;
+
+ if (rb_internal_thread_event_hooks == hook) {
+ ATOMIC_PTR_EXCHANGE(rb_internal_thread_event_hooks, hook->next);
+ success = TRUE;
+ } else {
+ rb_internal_thread_event_hook_t *h = rb_internal_thread_event_hooks;
+
+ do {
+ if (h->next == hook) {
+ h->next = hook->next;
+ success = TRUE;
+ break;
+ }
+ } while ((h = h->next));
+ }
+
+ if ((r = pthread_rwlock_unlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_unlock", r);
+ }
+
+ if (success) {
+ ruby_xfree(hook);
+ }
+ return success;
+}
+
+static void
+rb_thread_execute_hooks(rb_event_flag_t event)
+{
+ int r;
+ if ((r = pthread_rwlock_rdlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_rdlock", r);
+ }
+
+ if (rb_internal_thread_event_hooks) {
+ rb_internal_thread_event_hook_t *h = rb_internal_thread_event_hooks;
+ do {
+ if (h->event & event) {
+ (*h->callback)(event, NULL, h->user_data);
+ }
+ } while((h = h->next));
+ }
+ if ((r = pthread_rwlock_unlock(&rb_internal_thread_event_hooks_rw_lock))) {
+ rb_bug_errno("pthread_rwlock_unlock", r);
+ }
+}
+
enum rtimer_state {
/* alive, after timer_create: */
RTIMER_DISARM,
@@ -295,6 +384,10 @@ thread_sched_to_running_common(struct rb_thread_sched *sched, rb_thread_t *th)
// waiting -> ready
thread_sched_to_ready_common(sched, th);
+ if (rb_internal_thread_event_hooks) {
+ rb_thread_execute_hooks(RUBY_INTERNAL_THREAD_EVENT_READY);
+ }
+
// wait for running chance
do {
if (!sched->timer) {
@@ -319,6 +412,10 @@ thread_sched_to_running_common(struct rb_thread_sched *sched, rb_thread_t *th)
// ready -> running
sched->running = th;
+ if (rb_internal_thread_event_hooks) {
+ rb_thread_execute_hooks(RUBY_INTERNAL_THREAD_EVENT_RESUMED);
+ }
+
if (!sched->timer) {
if (!designate_timer_thread(sched) && !ubf_threads_empty()) {
rb_thread_wakeup_timer_thread(-1);
@@ -337,6 +434,10 @@ thread_sched_to_running(struct rb_thread_sched *sched, rb_thread_t *th)
static rb_thread_t *
thread_sched_to_waiting_common(struct rb_thread_sched *sched)
{
+ if (rb_internal_thread_event_hooks) {
+ rb_thread_execute_hooks(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED);
+ }
+
rb_thread_t *next;
sched->running = NULL;
next = ccan_list_top(&sched->readyq, rb_thread_t, sched.node.readyq);
@@ -687,9 +788,14 @@ native_thread_init(struct rb_native_thread *nt)
void
Init_native_thread(rb_thread_t *main_th)
{
+ int r;
+ if ((r = pthread_rwlock_init(&rb_internal_thread_event_hooks_rw_lock, NULL))) {
+ rb_bug_errno("pthread_rwlock_init", r);
+ }
+
#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK)
if (condattr_monotonic) {
- int r = pthread_condattr_init(condattr_monotonic);
+ r = pthread_condattr_init(condattr_monotonic);
if (r == 0) {
r = pthread_condattr_setclock(condattr_monotonic, CLOCK_MONOTONIC);
}