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
A thread; that is, a lightweight process.
Definition: thread.h:46
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.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.