@@ -211,6 +211,7 @@ rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operat
211211 }
212212
213213 // Now we're executing - call the function
214+ fprintf (stderr , "[blocking_operation] execute: op=%p state=%p\n" , (void * )blocking_operation , (void * )blocking_operation -> state );
214215 blocking_operation -> state -> result = blocking_operation -> function (blocking_operation -> data );
215216 blocking_operation -> state -> saved_errno = errno ;
216217
@@ -1088,6 +1089,13 @@ rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname)
10881089 * Thread.new { blocking_operation.call }.join
10891090 * end
10901091 */
1092+ static VALUE
1093+ scheduler_blocking_operation_wait_call (VALUE _args )
1094+ {
1095+ VALUE * args = (VALUE * )_args ;
1096+ return rb_funcall (args [0 ], id_blocking_operation_wait , 1 , args [1 ]);
1097+ }
1098+
10911099VALUE rb_fiber_scheduler_blocking_operation_wait (VALUE scheduler , void * (* function )(void * ), void * data , rb_unblock_function_t * unblock_function , void * data2 , int flags , struct rb_fiber_scheduler_blocking_operation_state * state )
10921100{
10931101 // Check if scheduler supports blocking_operation_wait before creating the object
@@ -1098,10 +1106,22 @@ VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*functi
10981106 // Create a new BlockingOperation with the blocking operation
10991107 VALUE blocking_operation = rb_fiber_scheduler_blocking_operation_new (function , data , unblock_function , data2 , flags , state );
11001108
1101- VALUE result = rb_funcall (scheduler , id_blocking_operation_wait , 1 , blocking_operation );
1109+ rb_fiber_scheduler_blocking_operation_t * operation = get_blocking_operation (blocking_operation );
1110+ fprintf (stderr , "[blocking_operation] wait: op=%p state=%p\n" , (void * )operation , (void * )state );
1111+
1112+ int tag = 0 ;
1113+ VALUE call_args [2 ] = {scheduler , blocking_operation };
1114+ VALUE result = rb_protect (scheduler_blocking_operation_wait_call , (VALUE )call_args , & tag );
1115+
1116+ if (tag ) {
1117+ // Exception from blocking_operation_wait: cleanup still runs below,
1118+ // but log this so we can detect when a stale state pointer is later accessed.
1119+ fprintf (stderr , "[blocking_operation] wait exception: op=%p state=%p (now dangling!)\n" , (void * )operation , (void * )state );
1120+ }
11021121
1122+ // Get fresh operation pointer after rb_protect (GC may have run)
1123+ operation = get_blocking_operation (blocking_operation );
11031124 // Get the operation data to check if it was executed
1104- rb_fiber_scheduler_blocking_operation_t * operation = get_blocking_operation (blocking_operation );
11051125 rb_atomic_t current_status = RUBY_ATOMIC_LOAD (operation -> status );
11061126
11071127 // Invalidate the operation now that we're done with it
@@ -1114,6 +1134,9 @@ VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*functi
11141134 // Ensure that the blocking operation remains visible until this point:
11151135 RB_GC_GUARD (blocking_operation );
11161136
1137+ // Re-raise any exception from the scheduler after cleanup.
1138+ if (tag ) rb_jump_tag (tag );
1139+
11171140 // If the blocking operation was never executed, return Qundef to signal the caller to use rb_nogvl instead
11181141 if (current_status == RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_QUEUED ) {
11191142 return Qundef ;
@@ -1212,6 +1235,7 @@ rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operati
12121235
12131236 case RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_EXECUTING :
12141237 // Work is running - mark cancelled AND call unblock function
1238+ fprintf (stderr , "[blocking_operation] cancel(executing): op=%p state=%p\n" , (void * )blocking_operation , (void * )blocking_operation -> state );
12151239 if (RUBY_ATOMIC_CAS (blocking_operation -> status , current_state , RB_FIBER_SCHEDULER_BLOCKING_OPERATION_STATUS_CANCELLED ) != current_state ) {
12161240 // State changed between load and CAS - operation may have completed:
12171241 return 0 ;
0 commit comments