Panda3D
Loading...
Searching...
No Matches
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 */
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 */
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 */
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.