[vlc-devel] The interruption problem

Rémi Denis-Courmont rem at videolan.org
Thu Aug 28 18:04:33 CEST 2008


	Hello,

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 
their wisdom.

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[1] 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 
platform.

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.


[1] I humbly remind the reader that the call stack grows downward, so it 
conversely shrinks upward.

-- 
Rémi Denis-Courmont



More information about the vlc-devel mailing list