Skip to content
  • Philippe Gerum's avatar
    copperplate: work-around glibc race in cancel state handling · 75cc5dac
    Philippe Gerum authored
    This is a SMP race which seems to affect NPTL-based glibc releases
    (2.9 and 2.18 checked, other releases are likely concerned as
    well). The issue requires SMP setups to pop up, when
    --enable-async-cancel is mentioned on the Xenomai build configuration
    line. It was detected over the Mercury core, not checked on the Cobalt
    core. The work-around will fit both.
    
    The bug creates a situation where
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, ...) does not actually
    prevent subsequent asynchronous cancellation of the caller, in the
    following scenario:
    
    threadB has its cancellability set to PTHREAD_CANCEL_ENABLE,
    PTHREAD_CANCEL_ASYNCHRONOUS on entry:
    
    threadA[CPU0]: pthread_cancel(threadB)
    		(SIGCANCEL queued to threadB[CPU1])
    threadB[CPU1]: pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)
    		(SIGCANCEL delivered to threadB[CPU1])
    		<sigcancel_handler>
    			if (cancel_type(threadB) == PTHREAD_CANCEL_ASYNCHRONOUS)
    				__do_cancel();
    			...
    
    As illustrated, the source of this issue is in glibc's SIGCANCEL
    handler, which only (re-)checks the cancellability TYPE prior to
    entering the thread deletion process on the target CPU, omitting the
    cancellability STATE from this check. High concurrency may therefore
    cause the target CPU to receive an asynchronous cancellation signal
    out of sync, which contradicts the current cancellability state of the
    recipient thread, due to the delayed signal propagation induced by SMP
    activities.
    
    Considering this, the cancellability state seems only safe for
    disabling the internal cancellation points, but can't be relied on for
    blocking asynchronous requests in SMP configurations.
    
    The work-around is to make sure to turn the cancellability type to
    PTHREAD_CANCEL_DEFERRED in addition to disabling cancellation with
    PTHREAD_CANCEL_DISABLE.
    
    Copperplate, and all Copperplate-based APIs are affected by the
    change.
    75cc5dac