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"
21
22Thread *Thread::_main_thread;
23Thread *Thread::_external_thread;
24TypeHandle 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 */
38Thread::
39Thread(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 */
62Thread::
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 */
89PT(Thread) Thread::
90bind_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 */
114void Thread::
115set_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 */
131void Thread::
132output(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 */
142output_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 */
157void Thread::
158write_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 */
184start(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 */
207void Thread::
208init_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 */
223void Thread::
224init_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}
The special "external thread" class.
The special "main thread" class.
Definition: mainThread.h:24
A base class for all things which can have a name.
Definition: namable.h:26
void ref() const
Explicitly increments the reference count.
virtual ~PStatsCallback()
Since this class is just an interface definition, there is no need to have a destructor.
Definition: thread.cxx:238
virtual void deactivate_hook(Thread *thread)
Called when the thread is deactivated (swapped for another running thread).
Definition: thread.cxx:247
virtual void activate_hook(Thread *thread)
Called when the thread is activated (resumes execution).
Definition: thread.cxx:256
A thread; that is, a lightweight process.
Definition: thread.h:46
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
get_sync_name
Returns the sync name of the thread.
Definition: thread.h:101
set_pipeline_stage
Specifies the Pipeline stage number associated with this thread.
Definition: thread.h:105
get_external_thread
Returns a pointer to the "external" Thread object–this is a special Thread object that corresponds to...
Definition: thread.h:108
bool start(ThreadPriority priority, bool joinable)
Starts the thread executing.
Definition: thread.cxx:184
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.