001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.thread;
028:
029: import java.util.TimerTask;
030:
031: import org.cougaar.util.log.Logger;
032: import org.cougaar.util.log.Logging;
033:
034: /**
035: * This implementation of {@link Schedulable} is used by the trivial
036: * {@link ThreadService}, which has no queueing and always runs threads
037: * immediately.
038: */
039: class TrivialSchedulable implements Schedulable {
040: private final Object consumer;
041: private final Runnable runnable;
042: private Thread thread;
043: private String name;
044: private int start_count;
045: private boolean cancelled;
046: private TimerTask task;
047: private long start_time;
048: private int state;
049: private boolean suspending; // suspend requested but not yet achieved
050: private boolean suspended; // truly suspended
051: private SuspendCallback suspendCallback;
052:
053: TrivialSchedulable(Runnable runnable, String name, Object consumer) {
054: this .runnable = runnable;
055: if (name == null) {
056: this .name = TrivialThreadPool.pool().generateName();
057: } else {
058: this .name = name;
059: }
060: this .consumer = consumer;
061: this .start_count = 0;
062: }
063:
064: // should only be used by the SerialThreadRunner/Queue
065: void setState(int state) {
066: this .state = state;
067: }
068:
069: Runnable getRunnable() {
070: return runnable;
071: }
072:
073: public int getLane() {
074: return org.cougaar.core.service.ThreadService.BEST_EFFORT_LANE;
075: }
076:
077: public String getName() {
078: return name;
079: }
080:
081: public int getBlockingType() {
082: return SchedulableStatus.NOT_BLOCKING;
083: }
084:
085: public String getBlockingExcuse() {
086: return "";
087: }
088:
089: public long getTimestamp() {
090: return start_time;
091: }
092:
093: public String toString() {
094: return "<Schedulable " + (name == null ? "anonymous" : name)
095: + ">";
096: }
097:
098: public Object getConsumer() {
099: return consumer;
100: }
101:
102: // caller synchronizes
103: private void thread_start() {
104: start_count = 1; // forget any extra intervening start() calls
105: start_time = System.currentTimeMillis();
106: state = CougaarThread.THREAD_RUNNING;
107: thread = runThread();
108: }
109:
110: Thread runThread() {
111: return TrivialThreadPool.pool().getThread(this , runnable, name);
112: }
113:
114: void thread_stop() {
115: SuspendCallback cb = null;
116: boolean restart = false;
117: synchronized (this ) {
118: if (suspending) {
119: cb = suspendCallback;
120: suspendCallback = null;
121: suspended = true;
122: suspending = false;
123: }
124: state = CougaarThread.THREAD_DORMANT;
125: // If start_count > 1, start() was called while the
126: // Schedulable was running. Now that it's finished, start it
127: // again.
128: restart = !suspended && --start_count > 0;
129: thread = null;
130: }
131: if (cb != null) {
132: cb.suspended(this );
133: }
134: if (restart) {
135: thread_start();
136: }
137: }
138:
139: public void suspend(SuspendCallback cb) {
140: boolean runCallback = false;
141: synchronized (this ) {
142: if (thread == null) {
143: // Already suspended, run the callback immediately
144: runCallback = suspended = true;
145:
146: } else if (suspendCallback != null) {
147: throw new RuntimeException(
148: "More than one SuspendCallback!");
149: } else {
150: suspendCallback = cb;
151: suspending = true;
152: }
153: }
154: if (runCallback) {
155: cb.suspended(this );
156: }
157: }
158:
159: public void resume() {
160: boolean restart = false;
161: synchronized (this ) {
162: if (!suspended) {
163: Logger logger = Logging.getLogger(getClass());
164: logger.warn("Resuming " + this
165: + ", which was not suspended");
166: return;
167: }
168: suspended = false;
169: restart = start_count > 0;
170: }
171: if (restart) {
172: thread_start();
173: }
174: }
175:
176: public void start() {
177: synchronized (this ) {
178: // If the Schedulable has been cancelled, or has already
179: // been asked to start, there's nothing further to do.
180: if (cancelled) {
181: return;
182: }
183: if (++start_count > 1 || suspended || suspending) {
184: return;
185: }
186: thread_start();
187: }
188: }
189:
190: private TimerTask task() {
191: cancelTimer();
192: task = new TimerTask() {
193: public void run() {
194: start();
195: }
196: };
197: return task;
198: }
199:
200: public synchronized void schedule(long delay) {
201: TreeNode.timer().schedule(task(), delay);
202: }
203:
204: public synchronized void schedule(long delay, long interval) {
205: TreeNode.timer().schedule(task(), delay, interval);
206: }
207:
208: public synchronized void scheduleAtFixedRate(long delay,
209: long interval) {
210: TreeNode.timer().scheduleAtFixedRate(task(), delay, interval);
211: }
212:
213: public synchronized void cancelTimer() {
214: if (task != null) {
215: task.cancel();
216: }
217: task = null;
218: }
219:
220: public synchronized int getState() {
221: return state;
222: }
223:
224: public boolean cancel() {
225: synchronized (this ) {
226: cancelTimer();
227: cancelled = true;
228: start_count = 0;
229: if (thread != null) {
230: // Currently running.
231: return false;
232: }
233: return true;
234: }
235: }
236: }
|