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