@@ -63,8 +63,10 @@ typedef enum {
6363struct rb_fiber_scheduler_blocking_operation {
6464 void * (* function )(void * );
6565 void * data ;
66+
6667 rb_unblock_function_t * unblock_function ;
6768 void * data2 ;
69+
6870 int flags ;
6971 struct rb_fiber_scheduler_blocking_operation_state * state ;
7072
@@ -208,7 +210,10 @@ rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operat
208210 return -1 ; // Invalid blocking operation
209211 }
210212
211- // Atomically check if we can transition from QUEUED to EXECUTING
213+ // Resolve sentinel values for unblock_function and data2:
214+ rb_thread_resolve_unblock_function (& blocking_operation -> unblock_function , & blocking_operation -> data2 , GET_THREAD ());
215+
216+ // Atomically check if we can transition from QUEUED to EXECUTING
212217 rb_atomic_t expected = RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED ;
213218 if (RUBY_ATOMIC_CAS (blocking_operation -> status , expected , RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING ) != expected ) {
214219 // Already cancelled or in wrong state
@@ -1124,25 +1129,33 @@ rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operati
11241129
11251130 rb_atomic_t current_state = RUBY_ATOMIC_LOAD (blocking_operation -> status );
11261131
1127- switch (current_state ) {
1132+ switch (current_state ) {
11281133 case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED :
1129- // Work hasn't started - just mark as cancelled
1134+ // Work hasn't started - just mark as cancelled:
11301135 if (RUBY_ATOMIC_CAS (blocking_operation -> status , current_state , RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED ) == current_state ) {
1131- return 0 ; // Successfully cancelled before execution
1136+ // Successfully cancelled before execution:
1137+ return 0 ;
11321138 }
11331139 // Fall through if state changed between load and CAS
11341140
11351141 case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING :
11361142 // Work is running - mark cancelled AND call unblock function
1137- RUBY_ATOMIC_SET (blocking_operation -> status , RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED );
1138- if (blocking_operation -> unblock_function ) {
1143+ if (RUBY_ATOMIC_CAS (blocking_operation -> status , current_state , RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED ) != current_state ) {
1144+ // State changed between load and CAS - operation may have completed:
1145+ return 0 ;
1146+ }
1147+ // Otherwise, we successfully marked it as cancelled, so we can call the unblock function:
1148+ rb_unblock_function_t * unblock_function = blocking_operation -> unblock_function ;
1149+ if (unblock_function ) {
1150+ RUBY_ASSERT (unblock_function != (rb_unblock_function_t * )-1 && "unblock_function is still sentinel value -1, should have been resolved earlier" );
11391151 blocking_operation -> unblock_function (blocking_operation -> data2 );
11401152 }
1141- return 1 ; // Cancelled during execution (unblock function called)
1153+ // Cancelled during execution (unblock function called):
1154+ return 1 ;
11421155
11431156 case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_COMPLETED :
11441157 case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED :
1145- // Already finished or cancelled
1158+ // Already finished or cancelled:
11461159 return 0 ;
11471160 }
11481161
0 commit comments