Well, normally a ProgressMonitor is *not* thread-safe.  Callers who need one to be are responsible for ensuring that is true.

EGit supplies a thread-safe ProgressMonitor, but only because its invoking JGit from a worker thread and wants the updates visible to the UI thread.  So EGit is responsible for supplying a thread-safe ProgressMonitor to JGit when it calls JGit.

However within JGit we assume the ProgressMonitor is "owned" by the thread that it is given to.  If that thread then spawns its own helper threads, that spawn site is responsible for making the supplied ProgressMonitor thread-safe.  To do that we wrap it in the ThreadSafeProgressMonitor. Unfortunately it seems that isn't compatible with the PipeOutputStream so we need to arrange for a different use of the ThreadSafeProgressMonitor.

I would prefer rewriting ThreadSafeProgressMonitor to use a different API definition and behavior, than to rewrite the pipe stream code.  We can't ensure callers won't give us the stock J2SE pipe stream types... and if they do we would have this bug you are reporting.  And there is currently only 1 caller in JGit (PackWriter, for threaded delta search).


Maybe instead the ThreadSafeProgressMonitor remembers what thread allocated it, and only pushes updates to the underlying ProgressMonitor if they are being made by the allocation thread.  If they are made by a different thread, then the updates are pushed into an update queue that the allocation thread must spin-out through a new public method.

We'd have to change some of the logic in PackWriter so that we spin out the update queue of the ThreadSafeProgressMonitor if the tasks are running on background threads.  That gets somewhat ugly because we can't easily determine when to stop spinning the queue because the threads are all completed.  One way to do that would be to also associate a worker count-down into the ThreadSafeProgressMonitor.  Use two new APIs to tell it when a worker starts, and when a worker ends.  PackWriter can tell it how many tasks its about to start, and then have each task use a finally block to tell the ThreadSafeProgressMonitor when the task is terminating.  The spin-out method would stop spinning the update queue when the active task count drops to 0.