• Rémi Denis-Courmont's avatar
    input: add per-thread sleep interruption framework · 2d099490
    Rémi Denis-Courmont authored
    For the sake of simplicity and for historical reasons, access and demux
    modules perform I/O in blocking mode. If no data is available (or more
    generally no I/O events), the blocking I/O calls will sleep and hold
    the whole input thread. This can lead to long time-outs or even
    complete deadlocks, e.g. notably in case of network error.
    Originally, a volatile flag (b_die) was checked at frequent interval to
    ascertain whether to abort. This violated the threaded memory model,
    and was incompatible with race-to-idle power management.
    In 2007, the VLC object thread signaling functions were introduced
    (vlc_object_wait, vlc_object_signal, ...) in an attempt to solve this.
    They proved inflexible and were not compatible with poll/select-style
    I/O events multiplexing. Those functions were ultimately removed a
    little over a year later.
    In the mean time, the "wait pipe" had been introduced. It was focused
    on network/socket data reception. While it continues to be used, it
    suffers several limitations:
     - it affects other threads using the same VLC object,
       and indistinctly disrupts all I/O after the "kill",
     - it incorrectly assumes that the same VLC object is used everywhere
       (leading to race conditions and live loops),
     - the convenience wrappers around the wait pipe can only wait on one
       single I/O event direction on a single file descriptor at a time,
     - it is currently tied to the VLC input thread.
    Also at about the same time, thread cancellation was reintroduced.
    Thread cancellation has proven helpful for simple thread main loops.
    But it ranges from impractical to unusable when sleeping deep within
    layers of code, such as in access and stream modules.
    Generally the problem of interrupting I/O is an intractable halting
    problem. And in practice a given reading operations inside a demuxer
    cannot be interrupted without breaking the state machine of the
    demuxer - in many or most cases. This changes set is only an attempt
    to complement thread cancellation, This does overcome most limitations
    of the existing "wait pipe" system and of former VLC object signals:
     - It is triggered by a function call specifying a target context.
     The context is tied to the thread that needs to be woken up from
     sleep. This works quite well because the problem essentially relates
     to the call flow of the sleeping thread. On the trigger side, this is
     similar to thread cancellation.
     - It leaves some flexibility w.r.t. choice of sleeping primitives.
     This initial change uses semaphores. Low-level file I/O will be
     introduced later.
     - The wake-up mechanism is edge-triggered and can be fired multiple
     times. Thus it does not irreversibly prevent all I/O and sleeping
     operations once fired. It only interrupts the ongoing or next sleep.
     In principles non-fatal interruptions could be handled that way, for
     instance input thread seek (rather than forceful stop) although that
     is not part of the changes set.
     - It is not tied to any specific event. The initial use case is
     stopping the input thread and checking vlc_object_alive() but it can
     be used for other purposes.
vlc_interrupt.h 2.96 KB