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
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
Thread::get_main_thread
get_main_thread
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process.
Definition: thread.h:107
config_pipeline.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pointerTo.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
unref_delete
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
Definition: referenceCount.I:344
selectThreadImpl.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
threadWin32Impl.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
thread.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.