Home | History | Annotate | Download | only in source
      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 {
     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 
     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 
     66 uint32_t ThreadWrapper::GetThreadId() {
     67   return GetCurrentThreadId();
     68 }
     69 
     70 unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter)
     71 {
     72     static_cast<ThreadWindows*>(lpParameter)->Run();
     73     return 0;
     74 }
     75 
     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 
    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 
    128 void ThreadWindows::SetNotAlive()
    129 {
    130     _alive = false;
    131 }
    132 
    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 
    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 
    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