Panda3D
threadWin32Impl.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 threadWin32Impl.cxx
10  * @author drose
11  * @date 2006-02-07
12  */
13 
14 #include "threadWin32Impl.h"
15 #include "selectThreadImpl.h"
16 
17 #ifdef THREAD_WIN32_IMPL
18 
19 #include "thread.h"
20 #include "pointerTo.h"
21 #include "config_pipeline.h"
22 
23 DWORD ThreadWin32Impl::_pt_ptr_index = 0;
24 bool ThreadWin32Impl::_got_pt_ptr_index = false;
25 
26 /**
27  *
28  */
29 ThreadWin32Impl::
30 ~ThreadWin32Impl() {
31  if (thread_cat->is_debug()) {
32  thread_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n";
33  }
34 
35  CloseHandle(_thread);
36 }
37 
38 /**
39  * Called for the main thread only, which has been already started, to fill in
40  * the values appropriate to that thread.
41  */
42 void ThreadWin32Impl::
43 setup_main_thread() {
44  _status = S_running;
45 }
46 
47 /**
48  *
49  */
50 bool ThreadWin32Impl::
51 start(ThreadPriority priority, bool joinable) {
52  _mutex.lock();
53  if (thread_cat->is_debug()) {
54  thread_cat.debug() << "Starting " << *_parent_obj << "\n";
55  }
56 
57  nassertd(_status == S_new && _thread == 0) {
58  _mutex.unlock();
59  return false;
60  }
61 
62  _joinable = joinable;
63  _status = S_start_called;
64 
65  if (!_got_pt_ptr_index) {
66  init_pt_ptr_index();
67  }
68 
69  // Increment the parent object's reference count first. The thread will
70  // eventually decrement it when it terminates.
71  _parent_obj->ref();
72  _thread =
73  CreateThread(nullptr, 0, &root_func, (void *)this, 0, &_thread_id);
74 
75  if (_thread_id == 0) {
76  // Oops, we couldn't start the thread. Be sure to decrement the reference
77  // count we incremented above, and return false to indicate failure.
78  unref_delete(_parent_obj);
79  _mutex.unlock();
80  return false;
81  }
82 
83  // Thread was successfully started. Set the priority as specified.
84  switch (priority) {
85  case TP_low:
86  SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
87  break;
88 
89  case TP_high:
90  SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
91  break;
92 
93  case TP_urgent:
94  SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
95  break;
96 
97  case TP_normal:
98  default:
99  SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
100  break;
101  }
102 
103  _mutex.unlock();
104  return true;
105 }
106 
107 /**
108  * Blocks the calling process until the thread terminates. If the thread has
109  * already terminated, this returns immediately.
110  */
111 void ThreadWin32Impl::
112 join() {
113  _mutex.lock();
114  nassertd(_joinable && _status != S_new) {
115  _mutex.unlock();
116  return;
117  }
118 
119  while (_status != S_finished) {
120  _cv.wait();
121  }
122  _mutex.unlock();
123 }
124 
125 /**
126  *
127  */
128 std::string ThreadWin32Impl::
129 get_unique_id() const {
130  std::ostringstream strm;
131  strm << GetCurrentProcessId() << "." << _thread_id;
132 
133  return strm.str();
134 }
135 
136 /**
137  * The entry point of each thread.
138  */
139 DWORD ThreadWin32Impl::
140 root_func(LPVOID data) {
141  TAU_REGISTER_THREAD();
142  {
143  // TAU_PROFILE("void ThreadWin32Impl::root_func()", " ", TAU_USER);
144 
145  ThreadWin32Impl *self = (ThreadWin32Impl *)data;
146  BOOL result = TlsSetValue(_pt_ptr_index, self->_parent_obj);
147  nassertr(result, 1);
148 
149  {
150  self->_mutex.lock();
151  nassertd(self->_status == S_start_called) {
152  self->_mutex.unlock();
153  return 1;
154  }
155  self->_status = S_running;
156  self->_cv.notify();
157  self->_mutex.unlock();
158  }
159 
160  self->_parent_obj->thread_main();
161 
162  if (thread_cat->is_debug()) {
163  thread_cat.debug()
164  << "Terminating thread " << self->_parent_obj->get_name()
165  << ", count = " << self->_parent_obj->get_ref_count() << "\n";
166  }
167 
168  {
169  self->_mutex.lock();
170  nassertd(self->_status == S_running) {
171  self->_mutex.unlock();
172  return 1;
173  }
174  self->_status = S_finished;
175  self->_cv.notify();
176  self->_mutex.unlock();
177  }
178 
179  // Now drop the parent object reference that we grabbed in start(). This
180  // might delete the parent object, and in turn, delete the ThreadWin32Impl
181  // object.
182  unref_delete(self->_parent_obj);
183  }
184 
185  return 0;
186 }
187 
188 /**
189  * Allocate a new index to store the Thread parent pointer as a piece of per-
190  * thread private data.
191  */
192 void ThreadWin32Impl::
193 init_pt_ptr_index() {
194  nassertv(!_got_pt_ptr_index);
195 
196  _pt_ptr_index = TlsAlloc();
197  if (_pt_ptr_index == TLS_OUT_OF_INDEXES) {
198  thread_cat->error()
199  << "Unable to associate Thread pointers with threads.\n";
200  return;
201  }
202 
203  _got_pt_ptr_index = true;
204 
205  // Assume that we must be in the main thread, since this method must be
206  // called before the first thread is spawned.
207  Thread *main_thread_obj = Thread::get_main_thread();
208  BOOL result = TlsSetValue(_pt_ptr_index, main_thread_obj);
209  nassertv(result);
210 }
211 
212 #endif // THREAD_WIN32_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.
get_main_thread
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process.
Definition: thread.h:107
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...