PBEasyPipe: Wait until exit if we're not in the main thread
commit8fde62f1b0a440376ab92a99431ebafd16af9438
authorPieter de Bie <pdebie@ai.rug.nl>
Sat, 24 Jan 2009 14:16:34 +0000 (24 15:16 +0100)
committerPieter de Bie <pdebie@ai.rug.nl>
Sun, 25 Jan 2009 02:14:13 +0000 (25 02:14 +0000)
treed0e20944a88bae3e120fabdd4c7359e8edd92c54
parentddc9ae76547efe58cb2cf5ff8c54102e8acc2d96
PBEasyPipe: Wait until exit if we're not in the main thread

There have been numerous bug reports about zombie processes in GitX,
because if an NSThread dies before an NSTask is finished it won't
kill the child process properly.

We tried to fix this by adding an [NSTask waitUntilExit] to wait for the
process to die, fixing the problem with the zombies. However, this caused
another problem: rendering glitches in the history view.

The problem is that [NSTask waitUntilExit] does NOT wait until the task has
finished (yeah, took me some time to figure that one out). Instead, it runs
the main loop and periodically queries if the task has finished yet.

What happens then is that during the drawing of one of the cells a call
is made to [repository headRef] to determine whether we should show the
cell in bold or not.

[repository headRef] then invokes an NSTask to figure out what the HEAD ref
really is. This in turn runs the [NSTask waitUntilExit].

Now, rather than really wait, the NSTask continues the main loop, and Cocoa
tries to display the next cell. This cell again calls an NSTask, etc...

So, what we basically have then is that halfway through the NSCell's drawing
code, the NSCell will be asked to draw another cell. It then changes the
data members and calls the [drawInRect] stuff again. the cell finishes
drawing, and control is returned to the previous draw. This path happily
continues, but now its data members are changed because of the second
draw, so it continues drawing something different than what it started
with.

As you might imagine, it took me some time to figure that one out :) The
next part is to fix it, of course, which might be somewhat tougher.
There's the easy fix to only [waitUntilExit] if the current thread is
not the main thread. This fixes our problem because nothing is drawn
in other threads, and nothing is zombie'd if it's called from the
main thread.

Another way is to fix the drawing code not to use data members. That
way the drawing can continue happily as if nothing ever happend

A third way is to fix the drawing part to never execute a git call.

I think the first and third way are OK to do. The second option doesn't
look very entertaining or practical.

Of course, the first option is only working around the problem, and
only solves this particular case. I guess this is one of those cases
of "I'll work around it this time.. if it bugs me later, I'll fix
it properly".
PBEasyPipe.m