001/* A subclass of Thread to be used for optimizing reader-writer mechanism in
002 Ptolemy II.
003
004 Copyright (c) 1997-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.kernel.util;
030
031import java.util.ArrayList;
032import java.util.Iterator;
033import java.util.LinkedList;
034import java.util.List;
035
036///////////////////////////////////////////////////////////////////
037////
038
039/** PtolemyThread
040 PtolemyThread extends Thread by adding rudimentary debugging capability.
041
042 @author Lukito Muliadi, contributor: Edward A. Lee
043 @version $Id$
044 @since Ptolemy II 0.2
045 @Pt.ProposedRating Green (lmuliadi)
046 @Pt.AcceptedRating Green (liuj)
047 */
048public class PtolemyThread extends Thread implements Debuggable {
049    /** Construct a new PtolemyThread object. This constructor has the
050     *  same effect as PtolemyThread(null, null, <i>generatedName</i>), where
051     *  <i>generatedName</i> is a newly generated name. Automatically generated
052     *  names are of the form "Thread-"+n, where n is an integer.
053     */
054    public PtolemyThread() {
055        super();
056    }
057
058    /** Construct a new PtolemyThread object. This constructor has the same
059     *  effect as PtolemyThread(null, target, <i>generatedName</i>), where
060     *  <i>generatedName</i> is a newly generated name. Automatically generated
061     *  names are of the form "Thread-"+n, where n is an integer.
062     *  @param target The object whose run method is called.
063     */
064    public PtolemyThread(Runnable target) {
065        super(target);
066    }
067
068    /** Construct a new PtolemyThread object. This constructor has the
069     *  same effect as PtolemyThread(null, target, name)
070     *  @param target The object whose run method is called.
071     *  @param name The name of the new thread.
072     *
073     */
074    public PtolemyThread(Runnable target, String name) {
075        super(target, name);
076    }
077
078    /** Construct a new PtolemyThread object. This constructor has the
079     *  same effect as PtolemyThread(null, null, name)
080     *  @param name The name of the new thread.
081     */
082    public PtolemyThread(String name) {
083        super(name);
084    }
085
086    /** Construct a new PtolemyThread object. This constructor has the
087     *  same effect as PtolemyThread(group, target, generatedName),
088     *  where generatedName is a newly generated name. Automatically
089     *  generated names are of the form "Thread-"+n, where n is an
090     *  integer.
091     *  @param group The thread group
092     *  @param target The object whose run method is called.
093     */
094    public PtolemyThread(ThreadGroup group, Runnable target) {
095        super(group, target);
096    }
097
098    /** Construct a new PtolemyThread object so that it has target as
099     *  its run object, has the specified name as its name, and belongs
100     *  to the thread group referred to by group.
101     *  @param group The thread group.
102     *  @param target The object whose run method is called.
103     *  @param name The name of the new thread.
104     *  @exception SecurityException If the superclass constructor throws it.
105     *
106     */
107    public PtolemyThread(ThreadGroup group, Runnable target, String name) {
108        super(group, target, name);
109    }
110
111    /** Construct a new PtolemyThread object. This constructor has the same
112     *  effect as PtolemyThread(group, null, name).
113     *  @param group The thread group.
114     *  @param name The name of the new thread.
115     */
116    public PtolemyThread(ThreadGroup group, String name) {
117        super(group, name);
118    }
119
120    ///////////////////////////////////////////////////////////////////
121    ////                         public methods                    ////
122
123    /** Append a listener to the current set of debug listeners.
124     *  If the listener is already in the set, do not add it again.
125     *  @param listener The listener to which to send debug messages.
126     *  @see #removeDebugListener(DebugListener)
127     *  @since Ptolemy II 2.3
128     */
129    @Override
130    public synchronized void addDebugListener(DebugListener listener) {
131        if (_debugListeners == null) {
132            _debugListeners = new LinkedList();
133        } else {
134            if (_debugListeners.contains(listener)) {
135                return;
136            }
137        }
138
139        _debugListeners.add(listener);
140        _debugging = true;
141    }
142
143    /** Unregister a debug listener.  If the specified listener has not
144     *  been previously registered, then do nothing.
145     *  @param listener The listener to remove from the list of listeners
146     *   to which debug messages are sent.
147     *  @see #addDebugListener(DebugListener)
148     *  @since Ptolemy II 2.3
149     */
150    @Override
151    public synchronized void removeDebugListener(DebugListener listener) {
152        if (_debugListeners == null) {
153            return;
154        }
155
156        _debugListeners.remove(listener);
157
158        if (_debugListeners.size() == 0) {
159            _debugging = false;
160        }
161
162        return;
163    }
164
165    ///////////////////////////////////////////////////////////////////
166    ////                         protected methods                 ////
167
168    /** Send a debug event to all debug listeners that have registered.
169     *  @param event The event.
170     *  @since Ptolemy II 2.3
171     */
172    protected final void _debug(DebugEvent event) {
173        if (_debugging) {
174            // We copy this list to that responding to the event may block.
175            // while the execution thread is blocked, we want to be able to
176            // add more debug listeners...
177            // Yes, this is slow, but hey, it's debug code.
178            List list;
179
180            synchronized (this) {
181                list = new ArrayList(_debugListeners);
182            }
183
184            Iterator listeners = list.iterator();
185
186            while (listeners.hasNext()) {
187                ((DebugListener) listeners.next()).event(event);
188            }
189        }
190    }
191
192    /** Send a debug message to all debug listeners that have registered.
193     *  By convention, messages should not include a newline at the end.
194     *  The newline will be added by the listener, if appropriate.
195     *  Note that using this method could be fairly expensive if the
196     *  message is constructed from parts, and that this expense will
197     *  be incurred regardless of whether there are actually any debug
198     *  listeners.  Thus, you should avoid, if possible, constructing
199     *  the message from parts.
200     *  @param message The message.
201     *  @since Ptolemy II 2.3
202     */
203    protected final void _debug(String message) {
204        if (_debugging) {
205            // We copy this list to that responding to the event may block.
206            // while the execution thread is blocked, we want to be able to
207            // add more debug listeners...
208            // Yes, this is slow, but hey, it's debug code.
209            List list;
210
211            synchronized (this) {
212                list = new ArrayList(_debugListeners);
213            }
214
215            Iterator listeners = list.iterator();
216
217            while (listeners.hasNext()) {
218                ((DebugListener) listeners.next()).message(message);
219            }
220        }
221    }
222
223    ///////////////////////////////////////////////////////////////////
224    ////                         protected variables               ////
225
226    /** Flag that is true if there are debug listeners.
227     *  @since Ptolemy II 2.3
228     */
229    protected volatile boolean _debugging = false;
230
231    /** The list of DebugListeners registered with this object.
232     *  @since Ptolemy II 2.3
233     */
234    protected LinkedList _debugListeners = null;
235}