Skip to content

Commit 9434e5c

Browse files
Fix blocking_operation_wait use-after-free bug.
1 parent 75c030b commit 9434e5c

File tree

5 files changed

+372
-47
lines changed

5 files changed

+372
-47
lines changed

include/ruby/fiber/scheduler.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,67 @@ VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exc
437437
*/
438438
VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat);
439439

440+
/**
441+
* BlockingOperation APIs for native work pools
442+
*
443+
* These functions provide a C API for creating and executing blocking operations
444+
* in native work pools without the use-after-free issues of the old proc-based approach.
445+
*/
446+
447+
// Forward declaration for the opaque struct
448+
typedef struct rb_fiber_scheduler_blocking_operation rb_fiber_scheduler_blocking_operation_t;
449+
450+
/**
451+
* Extract blocking operation struct from Ruby object (GVL required).
452+
*
453+
* This function safely extracts the opaque struct from a BlockingOperation VALUE
454+
* while holding the GVL. The returned pointer can be passed to worker threads
455+
* and used with rb_fiber_scheduler_blocking_operation_execute_opaque_nogvl.
456+
*
457+
* @param self The BlockingOperation VALUE to extract from
458+
* @return The opaque struct pointer on success, NULL on error
459+
* @note Must be called while holding the GVL
460+
*/
461+
rb_fiber_scheduler_blocking_operation_t *rb_fiber_scheduler_blocking_operation_extract(VALUE self);
462+
463+
/**
464+
* Execute blocking operation from opaque struct (GVL not required).
465+
*
466+
* This function executes a blocking operation using the opaque struct pointer
467+
* obtained from rb_fiber_scheduler_blocking_operation_extract.
468+
* It can be called from native threads without holding the GVL.
469+
*
470+
* @param blocking_operation The opaque struct pointer
471+
* @return 0 on success, -1 on error
472+
* @note Can be called from any thread without holding the GVL
473+
*/
474+
int rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
475+
476+
/**
477+
* Cancel a blocking operation.
478+
*
479+
* This function cancels a blocking operation. If the operation is queued,
480+
* it just marks it as cancelled. If it's executing, it marks it as cancelled
481+
* and calls the unblock function to interrupt the operation.
482+
*
483+
* @param blocking_operation The opaque struct pointer
484+
* @return 1 if unblock function was called, 0 if just marked cancelled, -1 on error
485+
* @note Can be called from any thread
486+
*/
487+
int rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
488+
489+
/**
490+
* Check if blocking operation was cancelled.
491+
*
492+
* This function checks if a blocking operation has been cancelled.
493+
* It can be called from worker threads to check cancellation status.
494+
*
495+
* @param blocking_operation The opaque struct pointer
496+
* @return 1 if cancelled, 0 if not cancelled
497+
* @note Can be called from any thread without holding the GVL
498+
*/
499+
int rb_fiber_scheduler_blocking_operation_cancelled_p(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
500+
440501
RBIMPL_SYMBOL_EXPORT_END()
441502

442503
#endif /* RUBY_FIBER_SCHEDULER_H */

inits.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ rb_call_inits(void)
6363
CALL(ISeq);
6464
CALL(Thread);
6565
CALL(signal);
66+
CALL(Cont);
6667
CALL(Fiber_Scheduler);
6768
CALL(process);
68-
CALL(Cont);
6969
CALL(Rational);
7070
CALL(Complex);
7171
CALL(MemoryView);

0 commit comments

Comments
 (0)