From 87fa5199ed4ac02b0da9cf92d1795ef360902f14 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 13 Mar 2014 03:06:54 +0000 Subject: [PATCH 2/2] speedup IO#close with many living threads We only need to scan threads waiting on FDs on IO#close, not every single thread. A future improvement could be using a per-FD array of linked lists for machines with many blocking threads. This would cost 2 words of memory for every open FD, however. Performance increases (over trunk) drastically with many threads not waiting on IO: vm_thread_close 7.552 --- thread.c | 25 ++++++++++++------------- vm_core.h | 3 +++ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/thread.c b/thread.c index 43a522a..0592afe 100644 --- a/thread.c +++ b/thread.c @@ -1341,6 +1341,7 @@ rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd) int state; th->waiting_fd = fd; + list_add(&th->vm->waitfd_threads, &th->waitfd_node); TH_PUSH_TAG(th); if ((state = EXEC_TAG()) == 0) { @@ -1353,6 +1354,7 @@ rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd) /* clear waiting_fd anytime */ th->waiting_fd = -1; + list_del(&th->waitfd_node); if (state) { JUMP_TAG(state); @@ -2059,22 +2061,19 @@ rb_threadptr_reset_raised(rb_thread_t *th) return 1; } -static int -thread_fd_close_i(rb_thread_t *th, void *fdp) -{ - int *fd = fdp; - if (th->waiting_fd == *fd) { - VALUE err = th->vm->special_exceptions[ruby_error_closed_stream]; - rb_threadptr_pending_interrupt_enque(th, err); - rb_threadptr_interrupt(th); - } - return ST_CONTINUE; -} - void rb_thread_fd_close(int fd) { - rb_vm_living_threads_foreach(GET_THREAD()->vm, thread_fd_close_i, &fd); + rb_thread_t *th; + rb_vm_t *vm = GET_THREAD()->vm; + + list_for_each(&vm->waitfd_threads, th, waitfd_node) { + if (th->waiting_fd == fd) { + VALUE err = vm->special_exceptions[ruby_error_closed_stream]; + rb_threadptr_pending_interrupt_enque(th, err); + rb_threadptr_interrupt(th); + } + } } /* diff --git a/vm_core.h b/vm_core.h index b71bb7a..262124b 100644 --- a/vm_core.h +++ b/vm_core.h @@ -333,6 +333,7 @@ typedef struct rb_vm_struct { struct rb_thread_struct *main_thread; struct rb_thread_struct *running_thread; + struct list_head waitfd_threads; struct list_head living_threads; size_t living_thread_num; VALUE thgroup_default; @@ -519,6 +520,7 @@ typedef struct rb_thread_struct { int state; int waiting_fd; + struct list_node waitfd_node; /* for rb_iterate */ const rb_block_t *passed_block; @@ -860,6 +862,7 @@ void rb_thread_wakeup_timer_thread(void); static inline void rb_vm_living_threads_init(rb_vm_t *vm) { + list_head_init(&vm->waitfd_threads); list_head_init(&vm->living_threads); vm->living_thread_num = 0; } -- 1.9.rc2