[vlc-devel] The interruption problem
rem at videolan.org
Thu Aug 28 18:04:33 CEST 2008
One of the rampant issue during the development of 0.9.0 has been the proper
(clean, safe and timely) interruption of -other- threads. This is a very
generic events handling programming issue. For instance, when the user
presses stop, you need to interrupt a whole bunch of threads upon an
asynchronous: input, decoders, video output, all kind of plugin specific
threads (audio output, access...), etc. That is to say, it does not occur
within the normal flow of the thread operation: the video output threads
normally waits for the next frame, not for the user to press stop.
This brings two interdependent issues: how to deliver the event, and how to do
any necessary cleanup. Let alone the dirty little platform specifics, there
are several high-level ways to handle this:
0/ Let the lower-layer do it. If you use processes, kill the other processes
(the OS will then do the cleanup). If you use .Net domains, destroy domains.
Unfortunately, there is _no_ way to do this with native multiple threads.
Resources from the interrupted threads would be leaked, with the possible
only exception of thread-local variables. Also, detaching the target threads
brings the risk of crashes for any non-refcounted subsystem (e.g. the
messages bank in LibVLC).
That's for that.
1/ Use an event loop. Then there is no thread to destroy, you just need to get
re-entrancy right. I think nobody wants to open the debate of switching VLC
to an event-based architecture (I definitely don't). The old developpers
decided to use threads quite a long time. Then threads support was not quite
as good as it is today, so they had to have a very good reason. A posteriori,
I personnaly think that was a right choice anyway, and I have to acknowledge
So with these two options eliminated, asynchronous event delivery schemes are
left. When a to-be-interrupted thread calls some function, especially any
blocking call, it needs to be able to wake up, clean up and exit.
2/ Pass interruption as an error/exception, in a bottom up fashion. So
whenever a thread wakes up, it needs to explicitly check whether it's been
interrupted. If so it cleans up, return an error up. The caller needs to
catch the error, clean up, and so on, until we reach the top of the call
stack and exit. That is what old VLC versions pretended to do. That's
pretty much what version 0.9 does (yeah, my fault).
3/ Unwind upon interruption, in a top down fashion. Sort of. Exceptions do not
exist in pure C. Instead, you register exception handlers for any cleanup
that would need to done. That's what the last big patchset of mine enables.
Now, you have to either register cleanup handlers, (and/)or disable
interruptions as appropriate. For the time being, most of the threads just
disable interruptions and continue to follow the bottom up model. The API is
a slightly simplified variant of the POSIX cancellation API. I wrote the
Win32 API and pthread backends already - I let other porters add any other
Note that in _either_case_, more boiler plate code is needed than I would like
to. Such is the cost of using C instead of a slower language with a garbage
collector. With bottom up, you need to handle errors and/or call
vlc_object_alive at every blocking function call. With the top down model,
you need to register a cleanup handler for any resource that is held while a
blocking function call is made.
The main reason why I added this, is that the bottom up approach sucks in many
cases: It essentially requires that you always wait on the thread object, so
that you can call vlc_object_wait, or the shaky vlc_object_waitpipe. And you
cannot make any blocking function call otherwise. Sucks badly with msleep(),
block_FifoGet(), DNS functions, etc.
 I humbly remind the reader that the call stack grows downward, so it
conversely shrinks upward.
More information about the vlc-devel