Panda3D
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 
22 ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
23 
24 int ThreadSimpleImpl::_next_unique_id = 1;
25 
26 /**
27  *
28  */
29 ThreadSimpleImpl::
30 ThreadSimpleImpl(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  */
63 ThreadSimpleImpl::
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  */
83 void ThreadSimpleImpl::
84 setup_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  */
102 bool ThreadSimpleImpl::
103 start(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  */
158 void ThreadSimpleImpl::
159 join() {
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  */
173 void ThreadSimpleImpl::
174 preempt() {
175  _manager->preempt(this);
176 }
177 
178 /**
179  *
180  */
181 std::string ThreadSimpleImpl::
182 get_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  */
198 void ThreadSimpleImpl::
199 prepare_for_exit() {
200  ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
201  manager->prepare_for_exit();
202 }
203 
204 /**
205  *
206  */
207 bool ThreadSimpleImpl::
208 is_true_threads() {
209  return (is_os_threads != 0);
210 }
211 
212 /**
213  *
214  */
215 void ThreadSimpleImpl::
216 sleep_this(double seconds) {
217  _manager->enqueue_sleep(this, seconds);
218  _manager->next_context();
219 }
220 
221 /**
222  *
223  */
224 void ThreadSimpleImpl::
225 yield_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  */
237 void ThreadSimpleImpl::
238 st_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  */
246 void ThreadSimpleImpl::
247 begin_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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void mmap_free(void *ptr, size_t size)
Frees a block of memory previously allocated via mmap_alloc().
Definition: memoryHook.cxx:566
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
virtual void * mmap_alloc(size_t size, bool allow_exec)
Allocates a raw page or pages of memory directly from the OS.
Definition: memoryHook.cxx:512
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.