Skip to content
  • KJ Tsanaktsidis's avatar
    f8effa20
    Change the semantics of rb_postponed_job_register · f8effa20
    KJ Tsanaktsidis authored
    Our current implementation of rb_postponed_job_register suffers from
    some safety issues that can lead to interpreter crashes (see bug #1991).
    Essentially, the issue is that jobs can be called with the wrong
    arguments.
    
    We made two attempts to fix this whilst keeping the promised semantics,
    but:
      * The first one involved masking/unmasking when flushing jobs, which
        was believed to be too expensive
      * The second one involved a lock-free, multi-producer, single-consumer
        ringbuffer, which was too complex
    
    The critical insight behind this third solution is that essentially the
    only user of these APIs are a) internal, or b) profiling gems.
    
    For a), none of the usages actually require variable data; they will
    work just fine with the preregistration interface.
    
    For b), generally profiling gems only call a single callback with a
    single piece of data (which is actually usually just zero) for the life
    of the program. The ringbuffer is complex because it needs to support
    multi-word inserts of job & data (which can't be atomic); but nobody
    actually even needs that functionality, really.
    
    So, this comit:
      * Introduces a pre-registration API for jobs, with a GVL-requiring
        rb_postponed_job_prereigster, which returns a handle which can be
        used with an async-signal-safe rb_postponed_job_trigger.
      * Deprecates rb_postponed_job_register (and re-implements it on top of
        the preregister function for compatability)
      * Moves all the internal usages of postponed job register
        pre-registration
    f8effa20
    Change the semantics of rb_postponed_job_register
    KJ Tsanaktsidis authored
    Our current implementation of rb_postponed_job_register suffers from
    some safety issues that can lead to interpreter crashes (see bug #1991).
    Essentially, the issue is that jobs can be called with the wrong
    arguments.
    
    We made two attempts to fix this whilst keeping the promised semantics,
    but:
      * The first one involved masking/unmasking when flushing jobs, which
        was believed to be too expensive
      * The second one involved a lock-free, multi-producer, single-consumer
        ringbuffer, which was too complex
    
    The critical insight behind this third solution is that essentially the
    only user of these APIs are a) internal, or b) profiling gems.
    
    For a), none of the usages actually require variable data; they will
    work just fine with the preregistration interface.
    
    For b), generally profiling gems only call a single callback with a
    single piece of data (which is actually usually just zero) for the life
    of the program. The ringbuffer is complex because it needs to support
    multi-word inserts of job & data (which can't be atomic); but nobody
    actually even needs that functionality, really.
    
    So, this comit:
      * Introduces a pre-registration API for jobs, with a GVL-requiring
        rb_postponed_job_prereigster, which returns a handle which can be
        used with an async-signal-safe rb_postponed_job_trigger.
      * Deprecates rb_postponed_job_register (and re-implements it on top of
        the preregister function for compatability)
      * Moves all the internal usages of postponed job register
        pre-registration
Loading