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
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
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
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.