KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > jobs > ImplicitJobs


1 /*******************************************************************************
2  * Copyright (c) 2003, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM - Initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.jobs;
12
13 import java.util.*;
14 import org.eclipse.core.internal.runtime.RuntimeLog;
15 import org.eclipse.core.runtime.*;
16 import org.eclipse.core.runtime.jobs.ISchedulingRule;
17 import org.eclipse.core.runtime.jobs.Job;
18
19 /**
20  * Implicit jobs are jobs that are running by virtue of a JobManager.begin/end
21  * pair. They act like normal jobs, except they are tied to an arbitrary thread
22  * of the client's choosing, and they can be nested.
23  */

24 class ImplicitJobs {
25     /**
26      * Cached unused instance that can be reused
27      */

28     private ThreadJob jobCache = null;
29     protected JobManager manager;
30
31     /**
32      * Set of suspended scheduling rules.
33      */

34     private final Set suspendedRules = new HashSet(20);
35
36     /**
37      * Maps (Thread->ThreadJob), threads to the currently running job for that
38      * thread.
39      */

40     private final Map threadJobs = new HashMap(20);
41
42     ImplicitJobs(JobManager manager) {
43         this.manager = manager;
44     }
45
46     /* (Non-javadoc)
47      * @see IJobManager#beginRule
48      */

49     void begin(ISchedulingRule rule, IProgressMonitor monitor, boolean suspend) {
50         if (JobManager.DEBUG_BEGIN_END)
51             JobManager.debug("Begin rule: " + rule); //$NON-NLS-1$
52
final Thread JavaDoc currentThread = Thread.currentThread();
53         ThreadJob threadJob;
54         synchronized (this) {
55             threadJob = (ThreadJob) threadJobs.get(currentThread);
56             if (threadJob != null) {
57                 //nested rule, just push on stack and return
58
threadJob.push(rule);
59                 return;
60             }
61             //no need to schedule a thread job for a null rule
62
if (rule == null)
63                 return;
64             //create a thread job for this thread, use the rule from the real job if it has one
65
Job realJob = manager.currentJob();
66             if (realJob != null && realJob.getRule() != null)
67                 threadJob = newThreadJob(realJob.getRule());
68             else {
69                 threadJob = newThreadJob(rule);
70                 threadJob.acquireRule = true;
71             }
72             //don't acquire rule if it is a suspended rule
73
if (isSuspended(rule))
74                 threadJob.acquireRule = false;
75             //indicate if it is a system job to ensure isBlocking works correctly
76
threadJob.setRealJob(realJob);
77             threadJob.setThread(currentThread);
78         }
79         try {
80             threadJob.push(rule);
81             //join the thread job outside sync block
82
if (threadJob.acquireRule) {
83                 //no need to re-acquire any locks because the thread did not wait to get this lock
84
if (manager.runNow(threadJob))
85                     manager.getLockManager().addLockThread(Thread.currentThread(), rule);
86                 else
87                     threadJob = threadJob.joinRun(monitor);
88             }
89         } finally {
90             //remember this thread job - only do this
91
//after the rule is acquired because it is ok for this thread to acquire
92
//and release other rules while waiting.
93
synchronized (this) {
94                 threadJobs.put(currentThread, threadJob);
95                 if (suspend)
96                     suspendedRules.add(rule);
97             }
98             if (threadJob.isBlocked) {
99                 threadJob.isBlocked = false;
100                 manager.reportUnblocked(monitor);
101             }
102         }
103     }
104
105     /* (Non-javadoc)
106      * @see IJobManager#endRule
107      */

108     synchronized void end(ISchedulingRule rule, boolean resume) {
109         if (JobManager.DEBUG_BEGIN_END)
110             JobManager.debug("End rule: " + rule); //$NON-NLS-1$
111
ThreadJob threadJob = (ThreadJob) threadJobs.get(Thread.currentThread());
112         if (threadJob == null)
113             Assert.isLegal(rule == null, "endRule without matching beginRule: " + rule); //$NON-NLS-1$
114
else if (threadJob.pop(rule)) {
115             endThreadJob(threadJob, resume);
116         }
117     }
118
119     /**
120      * Called when a worker thread has finished running a job. At this
121      * point, the worker thread must not own any scheduling rules
122      * @param lastJob The last job to run in this thread
123      */

124     void endJob(InternalJob lastJob) {
125         final Thread JavaDoc currentThread = Thread.currentThread();
126         IStatus error;
127         synchronized (this) {
128             ThreadJob threadJob = (ThreadJob) threadJobs.get(currentThread);
129             if (threadJob == null) {
130                 if (lastJob.getRule() != null)
131                     notifyWaitingThreadJobs();
132                 return;
133             }
134             String JavaDoc msg = "Worker thread ended job: " + lastJob + ", but still holds rule: " + threadJob; //$NON-NLS-1$ //$NON-NLS-2$
135
error = new Status(IStatus.ERROR, JobManager.PI_JOBS, 1, msg, null);
136             //end the thread job
137
endThreadJob(threadJob, false);
138         }
139         try {
140             RuntimeLog.log(error);
141         } catch (RuntimeException JavaDoc e) {
142             //failed to log, so print to console instead
143
System.err.println(error.getMessage());
144         }
145     }
146
147     private void endThreadJob(ThreadJob threadJob, boolean resume) {
148         Thread JavaDoc currentThread = Thread.currentThread();
149         //clean up when last rule scope exits
150
threadJobs.remove(currentThread);
151         ISchedulingRule rule = threadJob.getRule();
152         if (resume && rule != null)
153             suspendedRules.remove(rule);
154         //if this job had a rule, then we are essentially releasing a lock
155
//note it is safe to do this even if the acquire was aborted
156
if (threadJob.acquireRule) {
157             manager.getLockManager().removeLockThread(currentThread, rule);
158             notifyWaitingThreadJobs();
159         }
160         //if the job was started, we need to notify job manager to end it
161
if (threadJob.isRunning())
162             manager.endJob(threadJob, Status.OK_STATUS, false);
163         recycle(threadJob);
164     }
165
166     /**
167      * Returns true if this rule has been suspended, and false otherwise.
168      */

169     private boolean isSuspended(ISchedulingRule rule) {
170         if (suspendedRules.size() == 0)
171             return false;
172         for (Iterator it = suspendedRules.iterator(); it.hasNext();)
173             if (((ISchedulingRule) it.next()).contains(rule))
174                 return true;
175         return false;
176     }
177
178     /**
179      * Returns a new or reused ThreadJob instance.
180      */

181     private ThreadJob newThreadJob(ISchedulingRule rule) {
182         if (jobCache != null) {
183             ThreadJob job = jobCache;
184             job.setRule(rule);
185             job.acquireRule = job.isRunning = false;
186             job.realJob = null;
187             jobCache = null;
188             return job;
189         }
190         return new ThreadJob(manager, rule);
191     }
192
193     /**
194      * A job has just finished that was holding a scheduling rule, and the
195      * scheduling rule is now free. Wake any blocked thread jobs so they can
196      * compete for the newly freed lock
197      */

198     private void notifyWaitingThreadJobs() {
199         synchronized (ThreadJob.notifier) {
200             ThreadJob.notifier.notifyAll();
201         }
202     }
203
204     /**
205      * Indicates that a thread job is no longer in use and can be reused.
206      */

207     private void recycle(ThreadJob job) {
208         if (jobCache == null && job.recycle())
209             jobCache = job;
210     }
211
212     /**
213      * Implements IJobManager#resume(ISchedulingRule)
214      * @param rule
215      */

216     void resume(ISchedulingRule rule) {
217         //resume happens as a consequence of freeing the last rule in the stack
218
end(rule, true);
219         if (JobManager.DEBUG_BEGIN_END)
220             JobManager.debug("Resume rule: " + rule); //$NON-NLS-1$
221
}
222
223     /**
224      * Implements IJobManager#suspend(ISchedulingRule, IProgressMonitor)
225      * @param rule
226      * @param monitor
227      */

228     void suspend(ISchedulingRule rule, IProgressMonitor monitor) {
229         if (JobManager.DEBUG_BEGIN_END)
230             JobManager.debug("Suspend rule: " + rule); //$NON-NLS-1$
231
//the suspend job will be remembered once the rule is acquired
232
begin(rule, monitor, true);
233     }
234
235     /**
236      * Implements IJobManager#transferRule(ISchedulingRule, Thread)
237      */

238     synchronized void transfer(ISchedulingRule rule, Thread JavaDoc destinationThread) {
239         //nothing to do for null
240
if (rule == null)
241             return;
242         final Thread JavaDoc currentThread = Thread.currentThread();
243         //nothing to do if transferring to the same thread
244
if (currentThread == destinationThread)
245             return;
246         //ensure destination thread doesn't already have a rule
247
ThreadJob job = (ThreadJob) threadJobs.get(destinationThread);
248         Assert.isLegal(job == null);
249         //ensure calling thread owns the job being transferred
250
job = (ThreadJob) threadJobs.get(currentThread);
251         Assert.isNotNull(job);
252         Assert.isLegal(job.getRule() == rule);
253         //transfer the thread job without ending it
254
job.setThread(destinationThread);
255         threadJobs.remove(currentThread);
256         threadJobs.put(destinationThread, job);
257         //transfer lock
258
if (job.acquireRule) {
259             manager.getLockManager().removeLockThread(currentThread, rule);
260             manager.getLockManager().addLockThread(destinationThread, rule);
261         }
262     }
263 }
264
Popular Tags