1 /*******************************************************************************
2  * Copyright (c) 2003, 2012 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.core.runtime.jobs;
15 
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.OperationCanceledException;
18 
19 /**
20  * The job manager provides facilities for scheduling, querying, and maintaining jobs
21  * and locks.  In particular, the job manager provides the following services:
22  * <ul>
23  * <li>Maintains a queue of jobs that are waiting to be run.  Items can be added to
24  * the queue using the <code>schedule</code> method.</li>
25  * <li>Allows manipulation of groups of jobs called job families.  Job families can
26  * be canceled, put to sleep, or woken up atomically.  There is also a mechanism
27  * for querying the set of known jobs in a given family.</li>
28  * <li>Allows listeners to find out about progress on running jobs, and to find out
29  * when jobs have changed states.</li>
30  * <li>Provides a factory for creating lock objects.  Lock objects are smart monitors
31  * that have strategies for avoiding deadlock.</li>
32  * <li>Provide feedback to a client that is waiting for a given job or family of jobs
33  * to complete.</li>
34  * </ul>
35  *
36  * @see Job
37  * @see ILock
38  * @since 3.0
39  * @noimplement This interface is not intended to be implemented by clients.
40  * @noextend This interface is not intended to be extended by clients.
41  */
42 public interface IJobManager {
43 	/**
44 	 * A system property key indicating whether the job manager should create
45 	 * job threads as daemon threads.  Set to <code>true</code> to force all worker
46 	 * threads to be created as daemon threads. Set to <code>false</code> to force
47 	 * all worker threads to be created as non-daemon threads.
48 	 * @since 3.3
49 	 */
50 	String PROP_USE_DAEMON_THREADS = "eclipse.jobs.daemon"; //$NON-NLS-1$
51 
52 	/**
53 	 * Registers a job listener with the job manager.
54 	 * Has no effect if an identical listener is already registered.
55 	 *
56 	 * @param listener the listener to be added
57 	 * @see #removeJobChangeListener(IJobChangeListener)
58 	 * @see IJobChangeListener
59 	 */
addJobChangeListener(IJobChangeListener listener)60 	void addJobChangeListener(IJobChangeListener listener);
61 
62 	/**
63 	 * Begins applying this rule in the calling thread.  If the rule conflicts with another
64 	 * rule currently running in another thread, this method blocks until there are
65 	 * no conflicting rules.  Calls to <code>beginRule</code> must eventually be followed
66 	 * by a matching call to <code>endRule</code> in the same thread and with the identical
67 	 * rule instance.
68 	 * <p>
69 	 * Rules can be nested only if the rule for the inner <code>beginRule</code>
70 	 * is contained within the rule for the outer <code>beginRule</code>.  Rule containment
71 	 * is tested with the API method <code>ISchedulingRule.contains</code>.  Also, begin/end
72 	 * pairs must be strictly nested.  Only the rule that has most recently begun
73 	 * can be ended at any given time.
74 	 * <p>
75 	 * A rule of <code>null</code> can be used, but will be ignored for scheduling
76 	 * purposes.  The outermost non-null rule in the thread will be used for scheduling. A
77 	 * <code>null</code> rule that is begun must still be ended.
78 	 * <p>
79 	 * If this method is called from within a job that has a scheduling rule, the
80 	 * given rule must also be contained within the rule for the running job.
81 	 * <p>
82 	 * Note that <code>endRule</code> must be called even if <code>beginRule</code> fails.
83 	 * The recommended usage is:
84 	 * <pre>
85 	 * final ISchedulingRule rule = ...;
86 	 * try {
87 	 * 	manager.beginRule(rule, monitor);
88 	 * } finally {
89 	 * 	manager.endRule(rule);
90 	 * }
91 	 * </pre>
92 	 *
93 	 * @param rule the rule to begin applying in this thread, or <code>null</code>
94 	 * @param monitor a progress monitor, or <code>null</code> if progress
95 	 *    reporting and cancellation are not desired
96 	 * @throws IllegalArgumentException if the rule is not strictly nested within
97 	 * 	all other rules currently active for this thread
98 	 * @throws OperationCanceledException if the supplied monitor reports cancelation
99 	 * 	before the rule becomes available
100 	 * @see ISchedulingRule#contains(ISchedulingRule)
101 	 */
beginRule(ISchedulingRule rule, IProgressMonitor monitor)102 	void beginRule(ISchedulingRule rule, IProgressMonitor monitor);
103 
104 	/**
105 	 * Cancels all jobs in the given job family.  Jobs in the family that are currently waiting
106 	 * will be removed from the queue.  Sleeping jobs will be discarded without having
107 	 * a chance to wake up.  Currently executing jobs will be asked to cancel but there
108 	 * is no guarantee that they will do so.
109 	 *
110 	 * @param family the job family to cancel, or <code>null</code> to cancel all jobs
111 	 * @see Job#belongsTo(Object)
112 	 */
cancel(Object family)113 	void cancel(Object family);
114 
115 	/**
116 	 * Returns a progress monitor that can be used to provide aggregated progress
117 	 * feedback on a set of running jobs. A user interface will typically group all
118 	 * jobs in a progress group together, providing progress feedback for individual
119 	 * jobs as well as aggregated progress for the entire group. Jobs in the group
120 	 * may be run sequentially, in parallel, or some combination of the two.
121 	 * <p>
122 	 * Recommended usage (this snippet runs two jobs in sequence in a single
123 	 * progress group):
124 	 *
125 	 * <pre>
126 	 * Job parseJob, compileJob;
127 	 * IProgressMonitor pm = Job.getJobManager().createProgressGroup();
128 	 * try {
129 	 * 	pm.beginTask("Building", 10);
130 	 * 	parseJob.setProgressGroup(pm, 5);
131 	 * 	parseJob.schedule();
132 	 * 	compileJob.setProgressGroup(pm, 5);
133 	 * 	compileJob.schedule();
134 	 * 	parseJob.join();
135 	 * 	compileJob.join();
136 	 * } finally {
137 	 * 	pm.done();
138 	 * }
139 	 * </pre>
140 	 *
141 	 * @see Job#setProgressGroup(IProgressMonitor, int)
142 	 * @see IProgressMonitor
143 	 * @return a progress monitor
144 	 */
createProgressGroup()145 	IProgressMonitor createProgressGroup();
146 
147 	/**
148 	 * Returns the scheduling rule currently held by this thread, or <code>null</code>
149 	 * if the current thread does not hold any scheduling rule.
150 	 * <p>
151 	 * If this method is called from within the scope of a running job with a non-null
152 	 * scheduling rule, then this method is equivalent to calling <code>currentJob().getRule()</code>.
153 	 * Otherwise, this method will return the first scheduling rule obtained by this
154 	 * thread via {@link #beginRule(ISchedulingRule, IProgressMonitor)} that has not
155 	 * yet had a corresponding call to {@link #endRule(ISchedulingRule)}.
156 	 * </p>
157 	 *
158 	 * @return the current rule or <code>null</code>
159 	 * @since 3.5
160 	 */
currentRule()161 	ISchedulingRule currentRule();
162 
163 	/**
164 	 * Returns the job that is currently running in this thread, or <code>null</code> if there
165 	 * is no currently running job.
166 	 *
167 	 * @return the job or <code>null</code>
168 	 */
currentJob()169 	Job currentJob();
170 
171 	/**
172 	 * Ends the application of a rule to the calling thread.  Calls to <code>endRule</code>
173 	 * must be preceded by a matching call to <code>beginRule</code> in the same thread
174 	 * with an identical rule instance.
175 	 * <p>
176 	 * Rules can be nested only if the rule for the inner <code>beginRule</code>
177 	 * is contained within the rule for the outer <code>beginRule</code>.  Also, begin/end
178 	 * pairs must be strictly nested.  Only the rule that has most recently begun
179 	 * can be ended at any given time.
180 	 *
181 	 * @param rule the rule to end applying in this thread
182 	 * @throws IllegalArgumentException if this method is called on a rule for which
183 	 * there is no matching begin, or that does not match the most recent begin.
184 	 * @see ISchedulingRule#contains(ISchedulingRule)
185 	 */
endRule(ISchedulingRule rule)186 	void endRule(ISchedulingRule rule);
187 
188 	/**
189 	 * Returns all waiting, executing and sleeping jobs belonging
190 	 * to the given family. If no jobs are found, an empty array is returned.
191 	 *
192 	 * @param family the job family to find, or <code>null</code> to find all jobs
193 	 * @return the job array
194 	 * @see Job#belongsTo(Object)
195 	 */
find(Object family)196 	Job[] find(Object family);
197 
198 	/**
199 	 * Returns whether the job manager is currently idle.  The job manager is
200 	 * idle if no jobs are currently running or waiting to run.
201 	 *
202 	 * @return <code>true</code> if the job manager is idle, and
203 	 * <code>false</code> otherwise
204 	 * @since 3.1
205 	 */
isIdle()206 	boolean isIdle();
207 
208 	/**
209 	 * Returns whether the job manager is currently suspended.
210 	 *
211 	 * @return <code>true</code> if the job manager is suspended, and
212 	 * <code>false</code> otherwise
213 	 * @since 3.4
214 	 * @see #suspend()
215 	 * @see #resume()
216 	 */
isSuspended()217 	boolean isSuspended();
218 
219 	/**
220 	 * Waits until all jobs of the given family are finished.  This method will block the
221 	 * calling thread until all such jobs have finished executing, or until this thread is
222 	 * interrupted.   If there are no jobs in the family that are currently waiting, running,
223 	 * or sleeping, this method returns immediately.  Feedback on how the join is
224 	 * progressing is provided to a  progress monitor.
225 	 * <p>
226 	 * If this method is called while the job manager is suspended, only jobs
227 	 * that are currently running will be joined; Once there are no jobs
228 	 * in the family in the {@link Job#RUNNING} state, this method returns.
229 	 * </p>
230 	 * <p>
231 	 * Note that there is a deadlock risk when using join.  If the calling thread owns
232 	 * a lock or object monitor that the joined thread is waiting for, deadlock
233 	 * will occur. This method can also result in starvation of the current thread if
234 	 * another thread continues to add jobs of the given family, or if a
235 	 * job in the given family reschedules itself in an infinite loop.
236 	 * </p>
237 	 *
238 	 * @param family the job family to join, or <code>null</code> to join all jobs.
239 	 * @param monitor Progress monitor for reporting progress on how the
240 	 * wait is progressing, or <code>null</code> if no progress monitoring is required.
241 	 * @exception InterruptedException if this thread is interrupted while waiting
242 	 * @exception OperationCanceledException if the progress monitor is canceled while waiting
243 	 * @see Job#belongsTo(Object)
244 	 * @see #suspend()
245 	 */
join(Object family, IProgressMonitor monitor)246 	void join(Object family, IProgressMonitor monitor) throws InterruptedException, OperationCanceledException;
247 
248 	/**
249 	 * Creates a new lock object.  All lock objects supplied by the job manager
250 	 * know about each other and will always avoid circular deadlock amongst
251 	 * themselves.
252 	 *
253 	 * @return the new lock object
254 	 */
newLock()255 	ILock newLock();
256 
257 	/**
258 	 * Removes a job listener from the job manager.
259 	 * Has no effect if an identical listener is not already registered.
260 	 *
261 	 * @param listener the listener to be removed
262 	 * @see #addJobChangeListener(IJobChangeListener)
263 	 * @see IJobChangeListener
264 	 */
removeJobChangeListener(IJobChangeListener listener)265 	void removeJobChangeListener(IJobChangeListener listener);
266 
267 	/**
268 	 * Resumes execution of jobs after a previous <code>suspend</code>.  All
269 	 * jobs that were sleeping or waiting prior to the suspension, or that were
270 	 * scheduled while the job manager was suspended, will now be eligible
271 	 * for execution.
272 	 * <p>
273 	 * Calling this method on a rule that is not suspended  has no effect.  If another
274 	 * thread also owns the rule at the time this method is called, then the rule will
275 	 * not be resumed until all threads have released the rule.
276 	 *
277 	 * @deprecated This method is not safe and should not be used.
278 	 * Suspending a scheduling rule violates the thread safety
279 	 * of clients that use scheduling rules as a mutual exclusion mechanism,
280 	 * and can result in concurrency problems in all clients that use the suspended rule.
281 	 * @see #suspend(ISchedulingRule, IProgressMonitor)
282 	 */
resume(ISchedulingRule rule)283 	@Deprecated void resume(ISchedulingRule rule);
284 
285 	/**
286 	 * Resumes execution of jobs after a previous <code>suspend</code>.  All
287 	 * jobs that were sleeping or waiting prior to the suspension, or that were
288 	 * scheduled while the job manager was suspended, will now be eligible
289 	 * for execution.
290 	 * <p>
291 	 * Calling <code>resume</code> when the job manager is not suspended
292 	 * has no effect.
293 	 *
294 	 * @see #suspend()
295 	 * @see #isSuspended()
296 	 */
resume()297 	void resume();
298 
299 	/**
300 	 * Provides a hook that is notified whenever a thread is about to wait on a lock,
301 	 * or when a thread is about to release a lock.  This hook must only be set once.
302 	 * <p>
303 	 * This method is for internal use by the platform-related plug-ins.
304 	 * Clients should not call this method.
305 	 * </p>
306 	 * @see LockListener
307 	 */
setLockListener(LockListener listener)308 	void setLockListener(LockListener listener);
309 
310 	/**
311 	 * Registers a progress provider with the job manager.  If there was a
312 	 * provider already registered, it is replaced.
313 	 * <p>
314 	 * This method is intended for use by the currently executing Eclipse application.
315 	 * Plug-ins outside the currently running application should not call this method.
316 	 * </p>
317 	 *
318 	 * @param provider the new provider, or <code>null</code> if no progress
319 	 * is needed
320 	 */
setProgressProvider(ProgressProvider provider)321 	void setProgressProvider(ProgressProvider provider);
322 
323 	/**
324 	 * Suspends execution of all jobs.  Jobs that are already running
325 	 * when this method is invoked will complete as usual, but all sleeping and
326 	 * waiting jobs will not be executed until the job manager is resumed.
327 	 * <p>
328 	 * The job manager will remain suspended until a subsequent call to
329 	 * <code>resume</code>.  Further calls to <code>suspend</code>
330 	 * when the job manager is already suspended are ignored.
331 	 * <p>
332 	 * All attempts to join sleeping and waiting jobs while the job manager is
333 	 * suspended will return immediately.
334 	 * <p>
335 	 * Note that this very powerful function should be used with extreme caution.
336 	 * Suspending the job manager will prevent all jobs in the system from executing,
337 	 * which may have adverse affects on components that are relying on
338 	 * execution of jobs. The job manager should never be suspended without intent
339 	 * to resume execution soon afterwards.
340 	 *
341 	 * @see #resume()
342 	 * @see #join(Object, IProgressMonitor)
343 	 * @see #isSuspended()
344 	 */
suspend()345 	void suspend();
346 
347 	/**
348 	 * Defers execution of all jobs with scheduling rules that conflict with the
349 	 * given rule. The caller will be blocked until all currently executing jobs with
350 	 * conflicting rules are completed.  Conflicting jobs that are sleeping or waiting at
351 	 * the time this method is called will not be executed until the rule is resumed.
352 	 * <p>
353 	 * While a rule is suspended, all calls to <code>beginRule</code> and
354 	 * <code>endRule</code> on a suspended rule will not block the caller.
355 	 * The rule remains suspended until a subsequent call to
356 	 * <code>resume(ISchedulingRule)</code> with the identical rule instance.
357 	 * Further calls to <code>suspend</code> with an identical rule prior to calling
358 	 * <code>resume</code> are ignored.
359 	 * </p>
360 	 * <p>
361 	 * This method is long-running; progress and cancelation are provided by
362 	 * the given progress monitor. In the case of cancelation, the rule will
363 	 * not be suspended.
364 	 * </p>
365 	 * Note: this very powerful function should be used with extreme caution.
366 	 * Suspending rules will prevent jobs in the system from executing, which may
367 	 * have adverse effects on components that are relying on execution of jobs.
368 	 * The job manager should never be suspended without intent to resume
369 	 * execution soon afterwards. Deadlock will result if the thread responsible
370 	 * for resuming the rule attempts to join a suspended job.
371 	 *
372 	 * @deprecated This method is not safe and should not be used.
373 	 * Suspending a scheduling rule violates the thread safety
374 	 * of clients that use scheduling rules as a mutual exclusion mechanism,
375 	 * and can result in concurrency problems in all clients that use the suspended rule.
376 	 * @param rule The scheduling rule to suspend. Must not be <code>null</code>.
377 	 * @param monitor a progress monitor, or <code>null</code> if progress
378 	 * reporting is not desired
379 	 * @exception OperationCanceledException if the operation is canceled.
380 	 * Cancelation can occur even if no progress monitor is provided.
381 	 * @see #resume(ISchedulingRule)
382 	 */
suspend(ISchedulingRule rule, IProgressMonitor monitor)383 	@Deprecated void suspend(ISchedulingRule rule, IProgressMonitor monitor);
384 
385 	/**
386 	 * Requests that all jobs in the given job family be suspended.  Jobs currently
387 	 * waiting to be run will be removed from the queue and moved into the
388 	 * <code>SLEEPING</code> state.  Jobs that have been put to sleep
389 	 * will remain in that state until either resumed or canceled.  This method has
390 	 * no effect on jobs that are not currently waiting to be run.
391 	 * <p>
392 	 * Sleeping jobs can be resumed using <code>wakeUp</code>.
393 	 *
394 	 * @param family the job family to sleep, or <code>null</code> to sleep all jobs.
395 	 * @see Job#belongsTo(Object)
396 	 */
sleep(Object family)397 	void sleep(Object family);
398 
399 	/**
400 	 * Transfers ownership of a scheduling rule to another thread.  The identical
401 	 * scheduling rule must currently be owned by the calling thread as a result of
402 	 * a previous call to <code>beginRule</code>.  The destination thread must
403 	 * not already own a scheduling rule.
404 	 * <p>
405 	 * Calling this method is equivalent to atomically calling <code>endRule</code>
406 	 * in the calling thread followed by an immediate <code>beginRule</code> in
407 	 * the destination thread.  The destination thread is responsible for subsequently
408 	 * calling <code>endRule</code> when it is finished using the rule.
409 	 * <p>
410 	 * This method has no effect when the destination thread is the same as the
411 	 * calling thread.
412 	 *
413 	 * @param rule The scheduling rule to transfer
414 	 * @param destinationThread The new owner for the transferred rule.
415 	 * @since 3.1
416 	 */
transferRule(ISchedulingRule rule, Thread destinationThread)417 	void transferRule(ISchedulingRule rule, Thread destinationThread);
418 
419 	/**
420 	 * Resumes scheduling of all sleeping jobs in the given family.  This method
421 	 * has no effect on jobs in the family that are not currently sleeping.
422 	 *
423 	 * @param family the job family to wake up, or <code>null</code> to wake up all jobs
424 	 * @see Job#belongsTo(Object)
425 	 */
wakeUp(Object family)426 	void wakeUp(Object family);
427 }
428