Panda3D
thread.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file thread.cxx
10  * @author drose
11  * @date 2002-08-08
12  */
13 
14 #include "thread.h"
15 #include "mainThread.h"
16 #include "externalThread.h"
17 #include "config_pipeline.h"
18 #include "mutexDebug.h"
19 #include "conditionVarDebug.h"
20 #include "conditionVarFullDebug.h"
21 
22 Thread *Thread::_main_thread;
23 Thread *Thread::_external_thread;
24 TypeHandle Thread::_type_handle;
25 
26 /**
27  * Creates a new Thread object, but does not immediately start executing it.
28  * This gives the caller a chance to store it in a PT(Thread) object, if
29  * desired, before the thread gets a chance to terminate and destruct itself.
30  *
31  * Call start() to begin thread execution.
32  *
33  * The name should be unique for each thread (though this is not enforced, and
34  * not strictly required). The sync_name can be shared between multiple
35  * different threads; threads that run synchronously with each other should be
36  * given the same sync_name, for the benefit of PStats.
37  */
38 Thread::
39 Thread(const std::string &name, const std::string &sync_name) :
40  Namable(name),
41  _sync_name(sync_name),
42  _impl(this)
43 {
44  _started = false;
45  _pstats_index = -1;
46  _python_index = -1;
47  _pstats_callback = nullptr;
48  _pipeline_stage = 0;
49  _joinable = false;
50  _current_task = nullptr;
51 
52 #ifdef DEBUG_THREADS
53  _blocked_on_mutex = nullptr;
54  _waiting_on_cvar = nullptr;
55  _waiting_on_cvar_full = nullptr;
56 #endif
57 }
58 
59 /**
60  *
61  */
62 Thread::
63 ~Thread() {
64 #ifdef DEBUG_THREADS
65  nassertv(_blocked_on_mutex == nullptr &&
66  _waiting_on_cvar == nullptr &&
67  _waiting_on_cvar_full == nullptr);
68 #endif
69 }
70 
71 /**
72  * Returns a new Panda Thread object associated with the current thread (which
73  * has been created externally). This can be used to bind a unique Panda
74  * Thread object with an external thread, such as a new Python thread.
75  *
76  * It is particularly useful to bind a Panda Thread object to an external
77  * thread for the purposes of PStats monitoring. Without this call, each
78  * external thread will be assigned the same global ExternalThread object,
79  * which means they will all appear in the same PStats graph.
80  *
81  * It is the caller's responsibility to save the returned Thread pointer for
82  * the lifetime of the external thread. It is an error for the Thread pointer
83  * to destruct while the external thread is still in the system.
84  *
85  * It is also an error to call this method from the main thread, or twice
86  * within a given thread, unless it is given the same name each time (in which
87  * case the same pointer will be returned each time).
88  */
89 PT(Thread) Thread::
90 bind_thread(const std::string &name, const std::string &sync_name) {
91  Thread *current_thread = get_current_thread();
92  if (current_thread != get_external_thread()) {
93  // This thread already has an associated thread.
94  nassertr(current_thread->get_name() == name &&
95  current_thread->get_sync_name() == sync_name, current_thread);
96  return current_thread;
97  }
98 
99  PT(Thread) thread = new ExternalThread(name, sync_name);
100  ThreadImpl::bind_thread(thread);
101  return thread;
102 }
103 
104 /**
105  * Specifies the Pipeline stage number associated with this thread. The
106  * default stage is 0 if no stage is specified otherwise.
107  *
108  * This must be a value in the range [0 .. pipeline->get_num_stages() - 1].
109  * It specifies the values that this thread observes for all pipelined data.
110  * Typically, an application thread will leave this at 0, but a render thread
111  * may set it to 1 or 2 (to operate on the previous frame's data, or the
112  * second previous frame's data).
113  */
114 void Thread::
115 set_pipeline_stage(int pipeline_stage) {
116 #ifdef THREADED_PIPELINE
117  _pipeline_stage = pipeline_stage;
118 #else
119  if (pipeline_stage != 0) {
120  pipeline_cat.warning()
121  << "Requested pipeline stage " << pipeline_stage
122  << " but multithreaded render pipelines not enabled in build.\n";
123  }
124  _pipeline_stage = 0;
125 #endif
126 }
127 
128 /**
129  *
130  */
131 void Thread::
132 output(std::ostream &out) const {
133  out << get_type() << " " << get_name();
134 }
135 
136 /**
137  * Writes a description of the mutex or condition variable that this thread is
138  * blocked on. Writes nothing if there is no blocker, or if we are not in
139  * DEBUG_THREADS mode.
140  */
141 void Thread::
142 output_blocker(std::ostream &out) const {
143 #ifdef DEBUG_THREADS
144  if (_blocked_on_mutex != nullptr) {
145  _blocked_on_mutex->output_with_holder(out);
146  } else if (_waiting_on_cvar != nullptr) {
147  out << *_waiting_on_cvar;
148  } else if (_waiting_on_cvar_full != nullptr) {
149  out << *_waiting_on_cvar_full;
150  }
151 #endif // DEBUG_THREADS
152 }
153 
154 /**
155  *
156  */
157 void Thread::
158 write_status(std::ostream &out) {
159 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
160  ThreadImpl::write_status(out);
161 #endif
162 }
163 
164 /**
165  * Starts the thread executing. It is only valid to call this once.
166  *
167  * The thread will begin executing its thread_main() function, and will
168  * terminate when thread_main() returns.
169  *
170  * priority is intended as a hint to the relative importance of this thread.
171  * This may be ignored by the thread implementation.
172  *
173  * joinable should be set true if you intend to call join() to wait for the
174  * thread to terminate, or false if you don't care and you will never call
175  * join(). Note that the reference count on the Thread object is incremented
176  * while the thread itself is running, so if you just want to fire and forget
177  * a thread, you may pass joinable = false, and never store the Thread object.
178  * It will automatically destruct itself when it finishes.
179  *
180  * The return value is true if the thread is successfully started, false
181  * otherwise.
182  */
183 bool Thread::
184 start(ThreadPriority priority, bool joinable) {
185  nassertr(!_started, false);
186 
187  if (!support_threads) {
188  thread_cat->warning()
189  << *this << " could not be started: support-threads is false.\n";
190  return false;
191  }
192 
193  _joinable = joinable;
194  _started = _impl.start(priority, joinable);
195 
196  if (!_started) {
197  thread_cat->warning()
198  << *this << " could not be started!\n";
199  }
200 
201  return _started;
202 }
203 
204 /**
205  * Creates the Thread object that represents the main thread.
206  */
207 void Thread::
208 init_main_thread() {
209  // There is a chance of mutual recursion at startup. The count variable
210  // here attempts to protect against that.
211  static int count = 0;
212  ++count;
213  if (count == 1 && _main_thread == nullptr) {
215  _main_thread = new MainThread;
216  _main_thread->ref();
217  }
218 }
219 
220 /**
221  * Creates the Thread object that represents all of the external threads.
222  */
223 void Thread::
224 init_external_thread() {
225  if (_external_thread == nullptr) {
227  _external_thread = new ExternalThread;
228  _external_thread->ref();
229  }
230 }
231 
232 /**
233  * Since this class is just an interface definition, there is no need to have
234  * a destructor. However, we must have one anyway to stop gcc's annoying
235  * warning.
236  */
239 }
240 
241 /**
242  * Called when the thread is deactivated (swapped for another running thread).
243  * This is intended to provide a callback hook for PStats to assign time to
244  * individual threads properly, particularly in the SIMPLE_THREADS case.
245  */
248 }
249 
250 /**
251  * Called when the thread is activated (resumes execution). This is intended
252  * to provide a callback hook for PStats to assign time to individual threads
253  * properly, particularly in the SIMPLE_THREADS case.
254  */
257 }
virtual ~PStatsCallback()
Since this class is just an interface definition, there is no need to have a destructor.
Definition: thread.cxx:238
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void output_blocker(std::ostream &out) const
Writes a description of the mutex or condition variable that this thread is blocked on.
Definition: thread.cxx:142
void init_memory_hook()
Any code that might need to use PANDA_MALLOC or PANDA_FREE, or any methods of the global memory_hook ...
Definition: dtoolbase.cxx:38
PT(Thread) Thread
Returns a new Panda Thread object associated with the current thread (which has been created external...
Definition: thread.cxx:89
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void activate_hook(Thread *thread)
Called when the thread is activated (resumes execution).
Definition: thread.cxx:256
The special "external thread" class.
A base class for all things which can have a name.
Definition: namable.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The special "main thread" class.
Definition: mainThread.h:24
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void ref() const
Explicitly increments the reference count.
set_pipeline_stage
Specifies the Pipeline stage number associated with this thread.
Definition: thread.h:105
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual void deactivate_hook(Thread *thread)
Called when the thread is deactivated (swapped for another running thread).
Definition: thread.cxx:247
get_sync_name
Returns the sync name of the thread.
Definition: thread.h:101
bool start(ThreadPriority priority, bool joinable)
Starts the thread executing.
Definition: thread.cxx:184