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