• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "thread_win.h"
12 
13 #include <assert.h>
14 #include <process.h>
15 #include <stdio.h>
16 #include <windows.h>
17 
18 #include "set_thread_name_win.h"
19 #include "trace.h"
20 
21 namespace webrtc {
ThreadWindows(ThreadRunFunction func,ThreadObj obj,ThreadPriority prio,const char * threadName)22 ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
23                              ThreadPriority prio, const char* threadName)
24     : ThreadWrapper(),
25       _runFunction(func),
26       _obj(obj),
27       _alive(false),
28       _dead(true),
29       _doNotCloseHandle(false),
30       _prio(prio),
31       _event(NULL),
32       _thread(NULL),
33       _id(0),
34       _name(),
35       _setThreadName(false)
36 {
37     _event = EventWrapper::Create();
38     _critsectStop = CriticalSectionWrapper::CreateCriticalSection();
39     if (threadName != NULL)
40     {
41         // Set the thread name to appear in the VS debugger.
42         _setThreadName = true;
43         strncpy(_name, threadName, kThreadMaxNameLength);
44     }
45 }
46 
~ThreadWindows()47 ThreadWindows::~ThreadWindows()
48 {
49 #ifdef _DEBUG
50     assert(!_alive);
51 #endif
52     if (_thread)
53     {
54         CloseHandle(_thread);
55     }
56     if(_event)
57     {
58         delete _event;
59     }
60     if(_critsectStop)
61     {
62         delete _critsectStop;
63     }
64 }
65 
GetThreadId()66 uint32_t ThreadWrapper::GetThreadId() {
67   return GetCurrentThreadId();
68 }
69 
StartThread(LPVOID lpParameter)70 unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter)
71 {
72     static_cast<ThreadWindows*>(lpParameter)->Run();
73     return 0;
74 }
75 
Start(unsigned int & threadID)76 bool ThreadWindows::Start(unsigned int& threadID)
77 {
78     _doNotCloseHandle = false;
79 
80     // Set stack size to 1M
81     _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0,
82                                    &threadID);
83     if(_thread == NULL)
84     {
85         return false;
86     }
87     _id = threadID;
88     _event->Wait(INFINITE);
89 
90     switch(_prio)
91     {
92     case kLowPriority:
93         SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
94         break;
95     case kNormalPriority:
96         SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
97         break;
98     case kHighPriority:
99         SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
100         break;
101     case kHighestPriority:
102         SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
103         break;
104     case kRealtimePriority:
105         SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL);
106         break;
107     };
108     return true;
109 }
110 
SetAffinity(const int * processorNumbers,const unsigned int amountOfProcessors)111 bool ThreadWindows::SetAffinity(const int* processorNumbers,
112                                 const unsigned int amountOfProcessors)
113 {
114     DWORD_PTR processorBitMask = 0;
115     for(unsigned int processorIndex = 0;
116         processorIndex < amountOfProcessors;
117         processorIndex++)
118     {
119         // Convert from an array with processor numbers to a bitmask
120         // Processor numbers start at zero.
121         // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='?
122         // Or even better |=
123         processorBitMask = 1 << processorNumbers[processorIndex];
124     }
125     return SetThreadAffinityMask(_thread,processorBitMask) != 0;
126 }
127 
SetNotAlive()128 void ThreadWindows::SetNotAlive()
129 {
130     _alive = false;
131 }
132 
Shutdown()133 bool ThreadWindows::Shutdown()
134 {
135     DWORD exitCode = 0;
136     BOOL ret = TRUE;
137     if (_thread)
138     {
139         ret = TerminateThread(_thread, exitCode);
140         _alive = false;
141         _dead = true;
142         _thread = NULL;
143     }
144     return ret == TRUE;
145 }
146 
Stop()147 bool ThreadWindows::Stop()
148 {
149     _critsectStop->Enter();
150     // Prevents the handle from being closed in ThreadWindows::Run()
151     _doNotCloseHandle = true;
152     _alive = false;
153     bool signaled = false;
154     if (_thread && !_dead)
155     {
156         _critsectStop->Leave();
157         // Wait up to 2 seconds for the thread to complete.
158         if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000))
159         {
160             signaled = true;
161         }
162         _critsectStop->Enter();
163     }
164     if (_thread)
165     {
166         CloseHandle(_thread);
167         _thread = NULL;
168     }
169     _critsectStop->Leave();
170 
171     if (_dead || signaled)
172     {
173         return true;
174     }
175     else
176     {
177         return false;
178     }
179 }
180 
Run()181 void ThreadWindows::Run()
182 {
183     _alive = true;
184     _dead = false;
185     _event->Set();
186 
187     // All tracing must be after _event->Set to avoid deadlock in Trace.
188     if (_setThreadName)
189     {
190         WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
191                      "Thread with name:%s started ", _name);
192         SetThreadName(-1, _name); // -1, set thread name for the calling thread.
193     }else
194     {
195         WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
196                      "Thread without name started");
197     }
198 
199     do
200     {
201         if (_runFunction)
202         {
203             if (!_runFunction(_obj))
204             {
205                 _alive = false;
206             }
207         } else {
208             _alive = false;
209         }
210     } while(_alive);
211 
212     if (_setThreadName)
213     {
214         WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id,
215                      "Thread with name:%s stopped", _name);
216     } else {
217         WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id,
218                      "Thread without name stopped");
219     }
220 
221     _critsectStop->Enter();
222 
223     if (_thread && !_doNotCloseHandle)
224     {
225         HANDLE thread = _thread;
226         _thread = NULL;
227         CloseHandle(thread);
228     }
229     _dead = true;
230 
231     _critsectStop->Leave();
232 };
233 } // namespace webrtc
234