LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/base - platform_thread.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 77 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2015 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 "webrtc/base/platform_thread.h"
      12             : 
      13             : #include "webrtc/base/checks.h"
      14             : 
      15             : #if defined(WEBRTC_LINUX)
      16             : #include <sys/prctl.h>
      17             : #include <sys/syscall.h>
      18             : #endif
      19             : 
      20             : #if defined(__NetBSD__)
      21             : #include <lwp.h>
      22             : #elif defined(__FreeBSD__)
      23             : #include <pthread_np.h>
      24             : #endif
      25             : 
      26             : namespace rtc {
      27             : 
      28             : #if defined(WEBRTC_WIN)
      29             : // For use in ThreadWindowsUI callbacks
      30             : static UINT static_reg_windows_msg = RegisterWindowMessageW(L"WebrtcWindowsUIThreadEvent");
      31             : // timer id used in delayed callbacks
      32             : static const UINT_PTR kTimerId = 1;
      33             : static const wchar_t kThisProperty[] = L"ThreadWindowsUIPtr";
      34             : static const wchar_t kThreadWindow[] = L"WebrtcWindowsUIThread";
      35             : #endif
      36             : 
      37           0 : PlatformThreadId CurrentThreadId() {
      38             :   PlatformThreadId ret;
      39             : #if defined(WEBRTC_WIN)
      40             :   ret = GetCurrentThreadId();
      41             : #elif defined(WEBRTC_POSIX)
      42             : #if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
      43             :   ret = pthread_mach_thread_np(pthread_self());
      44             : #elif defined(WEBRTC_LINUX)
      45           0 :   ret =  syscall(__NR_gettid);
      46             : #elif defined(WEBRTC_ANDROID)
      47             :   ret = gettid();
      48             : #elif defined(__NetBSD__)
      49             :   ret = _lwp_self();
      50             : #elif defined(__DragonFly__)
      51             :   ret = lwp_gettid();
      52             : #elif defined(__OpenBSD__)
      53             :   ret = reinterpret_cast<uintptr_t> (pthread_self());
      54             : #elif defined(__FreeBSD__)
      55             :   ret = pthread_getthreadid_np();
      56             : #else
      57             :   // Default implementation for nacl and solaris.
      58             :   ret = reinterpret_cast<pid_t>(pthread_self());
      59             : #endif
      60             : #endif  // defined(WEBRTC_POSIX)
      61           0 :   RTC_DCHECK(ret);
      62           0 :   return ret;
      63             : }
      64             : 
      65           0 : PlatformThreadRef CurrentThreadRef() {
      66             : #if defined(WEBRTC_WIN)
      67             :   return GetCurrentThreadId();
      68             : #elif defined(WEBRTC_POSIX)
      69           0 :   return pthread_self();
      70             : #endif
      71             : }
      72             : 
      73           0 : bool IsThreadRefEqual(const PlatformThreadRef& a, const PlatformThreadRef& b) {
      74             : #if defined(WEBRTC_WIN)
      75             :   return a == b;
      76             : #elif defined(WEBRTC_POSIX)
      77           0 :   return pthread_equal(a, b);
      78             : #endif
      79             : }
      80             : 
      81           0 : void SetCurrentThreadName(const char* name) {
      82             : #if defined(WEBRTC_WIN)
      83             :   struct {
      84             :     DWORD dwType;
      85             :     LPCSTR szName;
      86             :     DWORD dwThreadID;
      87             :     DWORD dwFlags;
      88             :   } threadname_info = {0x1000, name, static_cast<DWORD>(-1), 0};
      89             : 
      90             :   __try {
      91             :     ::RaiseException(0x406D1388, 0, sizeof(threadname_info) / sizeof(DWORD),
      92             :                      reinterpret_cast<ULONG_PTR*>(&threadname_info));
      93             :   } __except (EXCEPTION_EXECUTE_HANDLER) {
      94             :   }
      95             : #elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
      96           0 :   prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name));
      97             : #elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
      98             :   pthread_setname_np(name);
      99             : #endif
     100           0 : }
     101             : 
     102             : namespace {
     103             : #if defined(WEBRTC_WIN)
     104             : void CALLBACK RaiseFlag(ULONG_PTR param) {
     105             :   *reinterpret_cast<bool*>(param) = true;
     106             : }
     107             : #else
     108             : struct ThreadAttributes {
     109           0 :   ThreadAttributes() { pthread_attr_init(&attr); }
     110           0 :   ~ThreadAttributes() { pthread_attr_destroy(&attr); }
     111           0 :   pthread_attr_t* operator&() { return &attr; }
     112             :   pthread_attr_t attr;
     113             : };
     114             : #endif  // defined(WEBRTC_WIN)
     115             : }
     116             : 
     117           0 : PlatformThread::PlatformThread(ThreadRunFunction func,
     118             :                                void* obj,
     119           0 :                                const char* thread_name)
     120             :     : run_function_(func),
     121             :       obj_(obj),
     122             :       name_(thread_name ? thread_name : "webrtc"),
     123             : #if defined(WEBRTC_WIN)
     124             :       stop_(false),
     125             :       thread_(NULL),
     126             :       thread_id_(0) {
     127             : #else
     128             :       stop_event_(false, false),
     129           0 :       thread_(0) {
     130             : #endif  // defined(WEBRTC_WIN)
     131           0 :   RTC_DCHECK(func);
     132           0 :   RTC_DCHECK(name_.length() < 64);
     133           0 : }
     134             : 
     135           0 : PlatformThread::~PlatformThread() {
     136           0 :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     137             : #if defined(WEBRTC_WIN)
     138             :   RTC_DCHECK(!thread_);
     139             :   RTC_DCHECK(!thread_id_);
     140             : #endif  // defined(WEBRTC_WIN)
     141           0 : }
     142             : 
     143             : #if defined(WEBRTC_WIN)
     144             : bool PlatformUIThread::InternalInit() {
     145             :   // Create an event window for use in generating callbacks to capture
     146             :   // objects.
     147             :   if (hwnd_ == NULL) {
     148             :     WNDCLASSW wc;
     149             :     HMODULE hModule = GetModuleHandle(NULL);
     150             :     if (!GetClassInfoW(hModule, kThreadWindow, &wc)) {
     151             :       ZeroMemory(&wc, sizeof(WNDCLASSW));
     152             :       wc.hInstance = hModule;
     153             :       wc.lpfnWndProc = EventWindowProc;
     154             :       wc.lpszClassName = kThreadWindow;
     155             :       RegisterClassW(&wc);
     156             :     }
     157             :     hwnd_ = CreateWindowW(kThreadWindow, L"",
     158             :                           0, 0, 0, 0, 0,
     159             :                           NULL, NULL, hModule, NULL);
     160             :     RTC_DCHECK(hwnd_);
     161             :     SetPropW(hwnd_, kThisProperty, this);
     162             : 
     163             :     if (timeout_) {
     164             :       // if someone set the timer before we started
     165             :       RequestCallbackTimer(timeout_);
     166             :     }
     167             :   }
     168             :   return !!hwnd_;
     169             : }
     170             : 
     171             : void PlatformUIThread::RequestCallback() {
     172             :   RTC_DCHECK(hwnd_);
     173             :   RTC_DCHECK(static_reg_windows_msg);
     174             :   PostMessage(hwnd_, static_reg_windows_msg, 0, 0);
     175             : }
     176             : 
     177             : bool PlatformUIThread::RequestCallbackTimer(unsigned int milliseconds) {
     178             :   if (!hwnd_) {
     179             :     RTC_DCHECK(!thread_);
     180             :     // set timer once thread starts
     181             :   } else {
     182             :     if (timerid_) {
     183             :       KillTimer(hwnd_, timerid_);
     184             :     }
     185             :     timerid_ = SetTimer(hwnd_, kTimerId, milliseconds, NULL);
     186             :   }
     187             :   timeout_ = milliseconds;
     188             :   return !!timerid_;
     189             : }
     190             : 
     191             : DWORD WINAPI PlatformThread::StartThread(void* param) {
     192             :   // The GetLastError() function only returns valid results when it is called
     193             :   // after a Win32 API function that returns a "failed" result. A crash dump
     194             :   // contains the result from GetLastError() and to make sure it does not
     195             :   // falsely report a Windows error we call SetLastError here.
     196             :   ::SetLastError(ERROR_SUCCESS);
     197             :   static_cast<PlatformThread*>(param)->Run();
     198             :   return 0;
     199             : }
     200             : #else
     201           0 : void* PlatformThread::StartThread(void* param) {
     202           0 :   static_cast<PlatformThread*>(param)->Run();
     203           0 :   return 0;
     204             : }
     205             : #endif  // defined(WEBRTC_WIN)
     206             : 
     207           0 : void PlatformThread::Start() {
     208           0 :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     209           0 :   RTC_DCHECK(!thread_) << "Thread already started?";
     210             : #if defined(WEBRTC_WIN)
     211             :   stop_ = false;
     212             : 
     213             :   // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
     214             :   // Set the reserved stack stack size to 1M, which is the default on Windows
     215             :   // and Linux.
     216             :   thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
     217             :                            STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id_);
     218             :   RTC_CHECK(thread_) << "CreateThread failed";
     219             :   RTC_DCHECK(thread_id_);
     220             : #else
     221           0 :   ThreadAttributes attr;
     222             :   // Set the stack stack size to 1M.
     223           0 :   pthread_attr_setstacksize(&attr, 1024 * 1024);
     224           0 :   RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
     225             : #endif  // defined(WEBRTC_WIN)
     226           0 : }
     227             : 
     228           0 : bool PlatformThread::IsRunning() const {
     229           0 :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     230             : #if defined(WEBRTC_WIN)
     231             :   return thread_ != nullptr;
     232             : #else
     233           0 :   return thread_ != 0;
     234             : #endif  // defined(WEBRTC_WIN)
     235             : }
     236             : 
     237           0 : PlatformThreadRef PlatformThread::GetThreadRef() const {
     238             : #if defined(WEBRTC_WIN)
     239             :   return thread_id_;
     240             : #else
     241           0 :   return thread_;
     242             : #endif  // defined(WEBRTC_WIN)
     243             : }
     244             : 
     245           0 : void PlatformThread::Stop() {
     246           0 :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     247           0 :   if (!IsRunning())
     248           0 :     return;
     249             : 
     250             : #if defined(WEBRTC_WIN)
     251             :   // Set stop_ to |true| on the worker thread.
     252             :   bool queued = QueueAPC(&RaiseFlag, reinterpret_cast<ULONG_PTR>(&stop_));
     253             :   // Queuing the APC can fail if the thread is being terminated.
     254             :   RTC_CHECK(queued || GetLastError() == ERROR_GEN_FAILURE);
     255             :   WaitForSingleObject(thread_, INFINITE);
     256             :   CloseHandle(thread_);
     257             :   thread_ = nullptr;
     258             :   thread_id_ = 0;
     259             : #else
     260           0 :   stop_event_.Set();
     261           0 :   RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
     262           0 :   thread_ = 0;
     263             : #endif  // defined(WEBRTC_WIN)
     264             : }
     265             : 
     266             : #ifdef WEBRTC_WIN
     267             : void PlatformUIThread::Stop() {
     268             :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     269             :   // Shut down the dispatch loop and let the background thread exit.
     270             :   if (timerid_) {
     271             :     KillTimer(hwnd_, timerid_);
     272             :     timerid_ = 0;
     273             :   }
     274             : 
     275             :   PostMessage(hwnd_, WM_CLOSE, 0, 0);
     276             : 
     277             :   PlatformThread::Stop();
     278             : }
     279             : #endif
     280             : 
     281           0 : void PlatformThread::Run() {
     282           0 :   if (!name_.empty())
     283           0 :     rtc::SetCurrentThreadName(name_.c_str());
     284           0 :   do {
     285             :     // The interface contract of Start/Stop is that for a successful call to
     286             :     // Start, there should be at least one call to the run function.  So we
     287             :     // call the function before checking |stop_|.
     288           0 :     if (!run_function_(obj_))
     289           0 :       break;
     290             : #if defined(WEBRTC_WIN)
     291             :     // Alertable sleep to permit RaiseFlag to run and update |stop_|.
     292             :     SleepEx(0, true);
     293             :   } while (!stop_);
     294             : #else
     295           0 :   } while (!stop_event_.Wait(0));
     296             : #endif  // defined(WEBRTC_WIN)
     297           0 : }
     298             : 
     299             : #if defined(WEBRTC_WIN)
     300             : void PlatformUIThread::Run() {
     301             :   RTC_CHECK(InternalInit()); // always evaluates
     302             :   PlatformThread::Run();
     303             :   // Don't need to DestroyWindow(hwnd_) due to WM_CLOSE->WM_DESTROY handling
     304             : }
     305             : 
     306             : void PlatformUIThread::NativeEventCallback() {
     307             :   if (!run_function_) {
     308             :     stop_ = true;
     309             :     return;
     310             :   }
     311             :   stop_ = !run_function_(obj_);
     312             : }
     313             : 
     314             : /* static */
     315             : LRESULT CALLBACK
     316             : PlatformUIThread::EventWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
     317             :   if (uMsg == WM_DESTROY) {
     318             :     RemovePropW(hwnd, kThisProperty);
     319             :     PostQuitMessage(0);
     320             :     return 0;
     321             :   }
     322             : 
     323             :   PlatformUIThread *twui = static_cast<PlatformUIThread*>(GetPropW(hwnd, kThisProperty));
     324             :   if (!twui) {
     325             :     return DefWindowProc(hwnd, uMsg, wParam, lParam);
     326             :   }
     327             : 
     328             :   if ((uMsg == static_reg_windows_msg && uMsg != WM_NULL) ||
     329             :       (uMsg == WM_TIMER && wParam == kTimerId)) {
     330             :     twui->NativeEventCallback();
     331             :     return 0;
     332             :   }
     333             : 
     334             :   return DefWindowProc(hwnd, uMsg, wParam, lParam);
     335             : }
     336             : #endif
     337             : 
     338           0 : bool PlatformThread::SetPriority(ThreadPriority priority) {
     339           0 :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     340           0 :   RTC_DCHECK(IsRunning());
     341             : #if defined(WEBRTC_WIN)
     342             :   return SetThreadPriority(thread_, priority) != FALSE;
     343             : #elif defined(__native_client__)
     344             :   // Setting thread priorities is not supported in NaCl.
     345             :   return true;
     346             : #elif defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
     347             :   // TODO(tommi): Switch to the same mechanism as Chromium uses for changing
     348             :   // thread priorities.
     349             :   return true;
     350             : #else
     351             : #ifdef WEBRTC_THREAD_RR
     352             :   const int policy = SCHED_RR;
     353             : #else
     354           0 :   const int policy = SCHED_FIFO;
     355             : #endif
     356           0 :   const int min_prio = sched_get_priority_min(policy);
     357           0 :   const int max_prio = sched_get_priority_max(policy);
     358           0 :   if (min_prio == -1 || max_prio == -1) {
     359           0 :     return false;
     360             :   }
     361             : 
     362           0 :   if (max_prio - min_prio <= 2)
     363           0 :     return false;
     364             : 
     365             :   // Convert webrtc priority to system priorities:
     366             :   sched_param param;
     367           0 :   const int top_prio = max_prio - 1;
     368           0 :   const int low_prio = min_prio + 1;
     369           0 :   switch (priority) {
     370             :     case kLowPriority:
     371           0 :       param.sched_priority = low_prio;
     372           0 :       break;
     373             :     case kNormalPriority:
     374             :       // The -1 ensures that the kHighPriority is always greater or equal to
     375             :       // kNormalPriority.
     376           0 :       param.sched_priority = (low_prio + top_prio - 1) / 2;
     377           0 :       break;
     378             :     case kHighPriority:
     379           0 :       param.sched_priority = std::max(top_prio - 2, low_prio);
     380           0 :       break;
     381             :     case kHighestPriority:
     382           0 :       param.sched_priority = std::max(top_prio - 1, low_prio);
     383           0 :       break;
     384             :     case kRealtimePriority:
     385           0 :       param.sched_priority = top_prio;
     386           0 :       break;
     387             :   }
     388           0 :   return pthread_setschedparam(thread_, policy, &param) == 0;
     389             : #endif  // defined(WEBRTC_WIN)
     390             : }
     391             : 
     392             : #if defined(WEBRTC_WIN)
     393             : bool PlatformThread::QueueAPC(PAPCFUNC function, ULONG_PTR data) {
     394             :   RTC_DCHECK(thread_checker_.CalledOnValidThread());
     395             :   RTC_DCHECK(IsRunning());
     396             : 
     397             :   return QueueUserAPC(function, thread_, data) != FALSE;
     398             : }
     399             : #endif
     400             : 
     401             : }  // namespace rtc

Generated by: LCOV version 1.13