Panda3D
Loading...
Searching...
No Matches
threadSimpleImpl.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 threadSimpleImpl.cxx
10 * @author drose
11 * @date 2007-06-18
12 */
13
14#include "selectThreadImpl.h"
15
16#ifdef THREAD_SIMPLE_IMPL
17
18#include "threadSimpleImpl.h"
19#include "threadSimpleManager.h"
20#include "thread.h"
21
22ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
23
24int ThreadSimpleImpl::_next_unique_id = 1;
25
26/**
27 *
28 */
29ThreadSimpleImpl::
30ThreadSimpleImpl(Thread *parent_obj) :
31 _parent_obj(parent_obj)
32{
33 _unique_id = _next_unique_id;
34 ++_next_unique_id;
35
36 _status = TS_new;
37 _joinable = false;
38 _priority = TP_normal;
39 _priority_weight = 1.0;
40 _run_ticks = 0;
41 _start_time = 0.0;
42 _stop_time = 0.0;
43 _wake_time = 0.0;
44
45 _context = alloc_thread_context();
46 _stack = nullptr;
47 _stack_size = 0;
48
49 // Save this pointer for convenience.
50 _manager = ThreadSimpleManager::get_global_ptr();
51
52#ifdef HAVE_POSIX_THREADS
53 _posix_system_thread_id = (pthread_t)-1;
54#endif
55#ifdef WIN32
56 _win32_system_thread_id = 0;
57#endif
58}
59
60/**
61 *
62 */
63ThreadSimpleImpl::
64~ThreadSimpleImpl() {
65 if (thread_cat->is_debug()) {
66 thread_cat.debug()
67 << "Deleting thread " << _parent_obj->get_name() << "\n";
68 }
69 nassertv(_status != TS_running);
70
71 free_thread_context(_context);
72
73 if (_stack != nullptr) {
74 memory_hook->mmap_free(_stack, _stack_size);
75 }
76 _manager->remove_thread(this);
77}
78
79/**
80 * Called for the main thread only, which has been already started, to fill in
81 * the values appropriate to that thread.
82 */
83void ThreadSimpleImpl::
84setup_main_thread() {
85 _status = TS_running;
86 _priority = TP_normal;
87 _priority_weight = _manager->_simple_thread_normal_weight;
88
89#ifdef HAVE_POSIX_THREADS
90 _posix_system_thread_id = pthread_self();
91#endif
92#ifdef WIN32
93 _win32_system_thread_id = GetCurrentThreadId();
94#endif
95
96 _manager->set_current_thread(this);
97}
98
99/**
100 *
101 */
102bool ThreadSimpleImpl::
103start(ThreadPriority priority, bool joinable) {
104 if (thread_cat->is_debug()) {
105 thread_cat.debug() << "Starting " << *_parent_obj << "\n";
106 }
107
108 nassertr(_status == TS_new, false);
109
110 nassertr(_stack == nullptr, false);
111 _stack_size = memory_hook->round_up_to_page_size((size_t)thread_stack_size);
112 if (needs_stack_prealloc) {
113 _stack = (unsigned char *)memory_hook->mmap_alloc(_stack_size, true);
114 }
115
116 _joinable = joinable;
117 _status = TS_running;
118 _priority = priority;
119
120 switch (priority) {
121 case TP_low:
122 _priority_weight = _manager->_simple_thread_low_weight;
123 break;
124
125 case TP_normal:
126 _priority_weight = _manager->_simple_thread_normal_weight;
127 break;
128
129 case TP_high:
130 _priority_weight = _manager->_simple_thread_high_weight;
131 break;
132
133 case TP_urgent:
134 _priority_weight = _manager->_simple_thread_urgent_weight;
135 break;
136 }
137
138 // We'll keep the reference count upped while the thread is running. When
139 // the thread finishes, we'll drop the reference count.
140 _parent_obj->ref();
141
142#ifdef HAVE_PYTHON
143 // Query the current Python thread state.
144 _python_state = thread_state_swap(nullptr);
145 thread_state_swap(_python_state);
146#endif // HAVE_PYTHON
147
148 init_thread_context(_context, _stack, _stack_size, st_begin_thread, this);
149
150 _manager->enqueue_ready(this, false);
151 return true;
152}
153
154/**
155 * Blocks the calling process until the thread terminates. If the thread has
156 * already terminated, this returns immediately.
157 */
158void ThreadSimpleImpl::
159join() {
160 nassertv(_joinable);
161 if (_status == TS_running) {
162 ThreadSimpleImpl *thread = _manager->get_current_thread();
163 if (thread != this) {
164 _joining_threads.push_back(thread);
165 _manager->next_context();
166 }
167 }
168}
169
170/**
171 *
172 */
173void ThreadSimpleImpl::
174preempt() {
175 _manager->preempt(this);
176}
177
178/**
179 *
180 */
181std::string ThreadSimpleImpl::
182get_unique_id() const {
183 std::ostringstream strm;
184#ifdef WIN32
185 strm << GetCurrentProcessId();
186#else
187 strm << getpid();
188#endif
189 strm << "." << _unique_id;
190
191 return strm.str();
192}
193
194/**
195 * Waits for all threads to terminate. Normally this is called only from the
196 * main thread.
197 */
198void ThreadSimpleImpl::
199prepare_for_exit() {
200 ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
201 manager->prepare_for_exit();
202}
203
204/**
205 *
206 */
207bool ThreadSimpleImpl::
208is_true_threads() {
209 return (is_os_threads != 0);
210}
211
212/**
213 *
214 */
215void ThreadSimpleImpl::
216sleep_this(double seconds) {
217 _manager->enqueue_sleep(this, seconds);
218 _manager->next_context();
219}
220
221/**
222 *
223 */
224void ThreadSimpleImpl::
225yield_this(bool volunteer) {
226 if (thread_cat->is_debug() && volunteer) {
227 thread_cat.debug()
228 << "Force-yielding " << _parent_obj->get_name() << "\n";
229 }
230 _manager->enqueue_ready(this, true);
231 _manager->next_context();
232}
233
234/**
235 * This method is called as the first introduction to a new thread.
236 */
237void ThreadSimpleImpl::
238st_begin_thread(void *data) {
239 ThreadSimpleImpl *self = (ThreadSimpleImpl *)data;
240 self->begin_thread();
241}
242
243/**
244 * This method is called as the first introduction to a new thread.
245 */
246void ThreadSimpleImpl::
247begin_thread() {
248#ifdef HAVE_PYTHON
249 thread_state_swap(_python_state);
250#endif // HAVE_PYTHON
251
252#ifdef HAVE_POSIX_THREADS
253 _posix_system_thread_id = pthread_self();
254#endif
255#ifdef WIN32
256 _win32_system_thread_id = GetCurrentThreadId();
257#endif
258
259 // Here we are executing within the thread. Run the thread_main function
260 // defined for this thread.
261 _parent_obj->thread_main();
262
263 // Now we have completed the thread.
264 _status = TS_finished;
265
266 // Any threads that were waiting to join with this thread now become ready.
267 JoiningThreads::iterator jti;
268 for (jti = _joining_threads.begin(); jti != _joining_threads.end(); ++jti) {
269 _manager->enqueue_ready(*jti, false);
270 }
271 _joining_threads.clear();
272
273 _manager->enqueue_finished(this);
274 _manager->next_context();
275
276 // Shouldn't get here.
277 nassertv(false);
278 abort();
279}
280
281#endif // THREAD_SIMPLE_IMPL
virtual void * mmap_alloc(size_t size, bool allow_exec)
Allocates a raw page or pages of memory directly from the OS.
virtual void mmap_free(void *ptr, size_t size)
Frees a block of memory previously allocated via mmap_alloc().
size_t round_up_to_page_size(size_t size) const
Rounds the indicated size request up to the next larger multiple of page_size, to qualify it for a ca...
Definition memoryHook.I:51
A thread; that is, a lightweight process.
Definition thread.h:46
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.