diff options
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-07-28 03:10:10 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-07-28 03:10:10 +0000
commit856bd77aea9450e63a3acdc2deba04613050da43 (patch)
parent297ae3437e168e8cdeae24c44f56fc373a83d098 (diff)
thread.c (blocking_region_end): clear ubf before unregister_ubf_list
If we keep ubf set after unregistering, there is a window for other threads (including timer thread) to put this thread back on the ubf_list right away. Entering ubf_list unexpectedly after GVL acquisition may cause spurious wakeup and trigger unexpected behavior. Finally, clear ubf before acquiring GVL, to since ubf is useless during GVL acquisition anyways and we don't want to waste cycles in other threads calling ubf for useless work. [ruby-core:88141] [Bug #14945] git-svn-id: svn+ssh:// b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 files changed, 5 insertions, 2 deletions
diff --git a/thread.c b/thread.c
index 6181a75..a7d48a4 100644
--- a/thread.c
+++ b/thread.c
@@ -1397,12 +1397,15 @@ blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region,
static inline void
blocking_region_end(rb_thread_t *th, struct rb_blocking_region_buffer *region)
+ /* entry to ubf_list still permitted at this point, make it impossible: */
+ unblock_function_clear(th);
+ /* entry to ubf_list impossible at this point, so unregister is safe: */
+ unregister_ubf_list(th);
gvl_acquire(th->vm, th);
thread_debug("leave blocking region (%p)\n", (void *)th);
- unregister_ubf_list(th);
th->blocking_region_buffer = 0;
- unblock_function_clear(th);
if (th->status == THREAD_STOPPED) {
th->status = region->prev_status;