Bug 418229 - JobManager.join(null) does not return even if there are no jobs left.
Summary: JobManager.join(null) does not return even if there are no jobs left.
Status: RESOLVED INVALID
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Runtime (show other bugs)
Version: 3.8.2   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: platform-runtime-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: needinfo
Depends on:
Blocks:
 
Reported: 2013-09-27 17:17 EDT by Sandip Chitale CLA
Modified: 2014-01-16 07:28 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sandip Chitale CLA 2013-09-27 17:17:18 EDT
We have CLI (non-gui) Eclipse application. In the implementation of start() method we added a call to....

try {
    IJobManager jobManager = ...;
    jobManager.join(null);

} catch (...) {
}

to make sure that we wait for termination of all jobs and shutdown gracefully. When we did not have this code we use to see this message on the STDERR:

"Job found still running after platform shutdown.  Jobs should be canceled by the plugin that scheduled them during shutdown: "

which is emitted by this code:


org.eclipse.core.internal.jobs.JobManager:
:
:
:
      private void doShutdown() {
:
:
                        String msg = "Job found still running after platform shutdown.  Jobs should be canceled by the plugin that scheduled them during shutdown: " + jobName; //$NON-NLS-1$

:
:

                        // TODO the RuntimeLog.log in its current implementation won't produce a log 
                        // during this stage of shutdown. For now add a standard error output.
                        // One the logging story is improved, the System.err output below can be removed:
                        System.err.println(msg);

This message on STDERR use to fail our CLI application callers.

Anyhow it appears that the code in JobManager.join(null) manages a local HashSet of running/active jobs and only terminates when there is no job left in that set. Our suspicion is that there may be a bug in that logic.

----
                     jobs = Collections.synchronizedSet(new HashSet(select(family, states))); <------- All jobs are returned in a HashSet – please note that the select method build the list using a local variable.
                     jobCount = jobs.size();
                     if (jobCount > 0) {
                           //if there is only one blocking job, use it in the blockage callback below <----------- Code starting here to below
                           if (jobCount == 1)
                                  blocking = (Job) jobs.iterator().next();
                           listener = new JobChangeAdapter() {
                                  public void done(IJobChangeEvent event) {
                                         //don't remove from list if job is being rescheduled
                                         if (!((JobChangeEvent) event).reschedule)
                                                jobs.remove(event.getJob());
                                  }

                                  //update the list of jobs if new ones are added during the join
                                  public void scheduled(IJobChangeEvent event) {
                                         //don't add to list if job is being rescheduled
                                         if (((JobChangeEvent) event).reschedule)
                                                return;
                                         Job job = event.getJob();
                                         if (job.belongsTo(family))
                                                jobs.add(job);
                                  }
                           };
                           addJobChangeListener(listener); <------------ to here tries to then manage the addition/deletion and rescheduling of jobs 
-----

We suspect that because  I set a breakpoint at line:

:
:
:
                           Thread.sleep(100);
:
:


and evaluated the expression:

int states = suspended ? Job.RUNNING : Job.RUNNING | Job.WAITING | Job.SLEEPING;
select(family, states)

But it returned an empty list.
Comment 1 Szymon Ptaszkiewicz CLA 2014-01-16 07:28:38 EST
(In reply to Sandip Chitale from comment #0)
> We have CLI (non-gui) Eclipse application. In the implementation of start()
> method we added a call to....
> 
> try {
>     IJobManager jobManager = ...;
>     jobManager.join(null);
> 
> } catch (...) {
> }

I guess you meant BundleActivator.stop(BundleContext) method, right?
Note that IJobManager.join(Object, IProgressMonitor) doesn't guarantee that no job will be scheduled after join returns, so you could still get that error message on stderr even with the above code. It would be better if you found out which job is still running during shutdown and check why it didn't respond to the cancellation signal before reaching printing to stderr. The code above shouldn't be needed to have a clean shutdown.

However, if you think there is a bug somewhere, please provide more detailed information.