• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2004 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/thread.h"
12 
13 #ifndef __has_feature
14 #define __has_feature(x) 0  // Compatibility with non-clang or LLVM compilers.
15 #endif  // __has_feature
16 
17 #if defined(WEBRTC_WIN)
18 #include <comdef.h>
19 #elif defined(WEBRTC_POSIX)
20 #include <time.h>
21 #endif
22 
23 #include "webrtc/base/common.h"
24 #include "webrtc/base/logging.h"
25 #include "webrtc/base/platform_thread.h"
26 #include "webrtc/base/stringutils.h"
27 #include "webrtc/base/timeutils.h"
28 
29 #if !__has_feature(objc_arc) && (defined(WEBRTC_MAC))
30 #include "webrtc/base/maccocoathreadhelper.h"
31 #include "webrtc/base/scoped_autorelease_pool.h"
32 #endif
33 
34 #include "webrtc/base/trace_event.h"
35 
36 namespace rtc {
37 
Instance()38 ThreadManager* ThreadManager::Instance() {
39   RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ());
40   return &thread_manager;
41 }
42 
43 // static
Current()44 Thread* Thread::Current() {
45   return ThreadManager::Instance()->CurrentThread();
46 }
47 
48 #if defined(WEBRTC_POSIX)
ThreadManager()49 ThreadManager::ThreadManager() {
50   pthread_key_create(&key_, NULL);
51 #ifndef NO_MAIN_THREAD_WRAPPING
52   WrapCurrentThread();
53 #endif
54 #if !__has_feature(objc_arc) && (defined(WEBRTC_MAC))
55   // Under Automatic Reference Counting (ARC), you cannot use autorelease pools
56   // directly. Instead, you use @autoreleasepool blocks instead.  Also, we are
57   // maintaining thread safety using immutability within context of GCD dispatch
58   // queues in this case.
59   InitCocoaMultiThreading();
60 #endif
61 }
62 
~ThreadManager()63 ThreadManager::~ThreadManager() {
64 #if __has_feature(objc_arc)
65   @autoreleasepool
66 #elif defined(WEBRTC_MAC)
67   // This is called during exit, at which point apparently no NSAutoreleasePools
68   // are available; but we might still need them to do cleanup (or we get the
69   // "no autoreleasepool in place, just leaking" warning when exiting).
70   ScopedAutoreleasePool pool;
71 #endif
72   {
73     UnwrapCurrentThread();
74     pthread_key_delete(key_);
75   }
76 }
77 
CurrentThread()78 Thread *ThreadManager::CurrentThread() {
79   return static_cast<Thread *>(pthread_getspecific(key_));
80 }
81 
SetCurrentThread(Thread * thread)82 void ThreadManager::SetCurrentThread(Thread *thread) {
83   pthread_setspecific(key_, thread);
84 }
85 #endif
86 
87 #if defined(WEBRTC_WIN)
ThreadManager()88 ThreadManager::ThreadManager() {
89   key_ = TlsAlloc();
90 #ifndef NO_MAIN_THREAD_WRAPPING
91   WrapCurrentThread();
92 #endif
93 }
94 
~ThreadManager()95 ThreadManager::~ThreadManager() {
96   UnwrapCurrentThread();
97   TlsFree(key_);
98 }
99 
CurrentThread()100 Thread *ThreadManager::CurrentThread() {
101   return static_cast<Thread *>(TlsGetValue(key_));
102 }
103 
SetCurrentThread(Thread * thread)104 void ThreadManager::SetCurrentThread(Thread *thread) {
105   TlsSetValue(key_, thread);
106 }
107 #endif
108 
WrapCurrentThread()109 Thread *ThreadManager::WrapCurrentThread() {
110   Thread* result = CurrentThread();
111   if (NULL == result) {
112     result = new Thread();
113     result->WrapCurrentWithThreadManager(this, true);
114   }
115   return result;
116 }
117 
UnwrapCurrentThread()118 void ThreadManager::UnwrapCurrentThread() {
119   Thread* t = CurrentThread();
120   if (t && !(t->IsOwned())) {
121     t->UnwrapCurrent();
122     delete t;
123   }
124 }
125 
126 struct ThreadInit {
127   Thread* thread;
128   Runnable* runnable;
129 };
130 
ScopedDisallowBlockingCalls()131 Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
132   : thread_(Thread::Current()),
133     previous_state_(thread_->SetAllowBlockingCalls(false)) {
134 }
135 
~ScopedDisallowBlockingCalls()136 Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() {
137   ASSERT(thread_->IsCurrent());
138   thread_->SetAllowBlockingCalls(previous_state_);
139 }
140 
Thread(SocketServer * ss)141 Thread::Thread(SocketServer* ss)
142     : MessageQueue(ss),
143       running_(true, false),
144 #if defined(WEBRTC_WIN)
145       thread_(NULL),
146       thread_id_(0),
147 #endif
148       owned_(true),
149       blocking_calls_allowed_(true) {
150   SetName("Thread", this);  // default name
151 }
152 
~Thread()153 Thread::~Thread() {
154   Stop();
155   Clear(NULL);
156 }
157 
SleepMs(int milliseconds)158 bool Thread::SleepMs(int milliseconds) {
159   AssertBlockingIsAllowedOnCurrentThread();
160 
161 #if defined(WEBRTC_WIN)
162   ::Sleep(milliseconds);
163   return true;
164 #else
165   // POSIX has both a usleep() and a nanosleep(), but the former is deprecated,
166   // so we use nanosleep() even though it has greater precision than necessary.
167   struct timespec ts;
168   ts.tv_sec = milliseconds / 1000;
169   ts.tv_nsec = (milliseconds % 1000) * 1000000;
170   int ret = nanosleep(&ts, NULL);
171   if (ret != 0) {
172     LOG_ERR(LS_WARNING) << "nanosleep() returning early";
173     return false;
174   }
175   return true;
176 #endif
177 }
178 
SetName(const std::string & name,const void * obj)179 bool Thread::SetName(const std::string& name, const void* obj) {
180   if (running()) return false;
181   name_ = name;
182   if (obj) {
183     char buf[16];
184     sprintfn(buf, sizeof(buf), " 0x%p", obj);
185     name_ += buf;
186   }
187   return true;
188 }
189 
Start(Runnable * runnable)190 bool Thread::Start(Runnable* runnable) {
191   ASSERT(owned_);
192   if (!owned_) return false;
193   ASSERT(!running());
194   if (running()) return false;
195 
196   Restart();  // reset fStop_ if the thread is being restarted
197 
198   // Make sure that ThreadManager is created on the main thread before
199   // we start a new thread.
200   ThreadManager::Instance();
201 
202   ThreadInit* init = new ThreadInit;
203   init->thread = this;
204   init->runnable = runnable;
205 #if defined(WEBRTC_WIN)
206   thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, 0,
207                          &thread_id_);
208   if (thread_) {
209     running_.Set();
210   } else {
211     return false;
212   }
213 #elif defined(WEBRTC_POSIX)
214   pthread_attr_t attr;
215   pthread_attr_init(&attr);
216 
217   int error_code = pthread_create(&thread_, &attr, PreRun, init);
218   if (0 != error_code) {
219     LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
220     return false;
221   }
222   running_.Set();
223 #endif
224   return true;
225 }
226 
WrapCurrent()227 bool Thread::WrapCurrent() {
228   return WrapCurrentWithThreadManager(ThreadManager::Instance(), true);
229 }
230 
UnwrapCurrent()231 void Thread::UnwrapCurrent() {
232   // Clears the platform-specific thread-specific storage.
233   ThreadManager::Instance()->SetCurrentThread(NULL);
234 #if defined(WEBRTC_WIN)
235   if (thread_ != NULL) {
236     if (!CloseHandle(thread_)) {
237       LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
238     }
239     thread_ = NULL;
240   }
241 #endif
242   running_.Reset();
243 }
244 
SafeWrapCurrent()245 void Thread::SafeWrapCurrent() {
246   WrapCurrentWithThreadManager(ThreadManager::Instance(), false);
247 }
248 
Join()249 void Thread::Join() {
250   if (running()) {
251     ASSERT(!IsCurrent());
252     if (Current() && !Current()->blocking_calls_allowed_) {
253       LOG(LS_WARNING) << "Waiting for the thread to join, "
254                       << "but blocking calls have been disallowed";
255     }
256 
257 #if defined(WEBRTC_WIN)
258     ASSERT(thread_ != NULL);
259     WaitForSingleObject(thread_, INFINITE);
260     CloseHandle(thread_);
261     thread_ = NULL;
262     thread_id_ = 0;
263 #elif defined(WEBRTC_POSIX)
264     void *pv;
265     pthread_join(thread_, &pv);
266 #endif
267     running_.Reset();
268   }
269 }
270 
SetAllowBlockingCalls(bool allow)271 bool Thread::SetAllowBlockingCalls(bool allow) {
272   ASSERT(IsCurrent());
273   bool previous = blocking_calls_allowed_;
274   blocking_calls_allowed_ = allow;
275   return previous;
276 }
277 
278 // static
AssertBlockingIsAllowedOnCurrentThread()279 void Thread::AssertBlockingIsAllowedOnCurrentThread() {
280 #if !defined(NDEBUG)
281   Thread* current = Thread::Current();
282   ASSERT(!current || current->blocking_calls_allowed_);
283 #endif
284 }
285 
PreRun(void * pv)286 void* Thread::PreRun(void* pv) {
287   ThreadInit* init = static_cast<ThreadInit*>(pv);
288   ThreadManager::Instance()->SetCurrentThread(init->thread);
289   rtc::SetCurrentThreadName(init->thread->name_.c_str());
290 #if __has_feature(objc_arc)
291   @autoreleasepool
292 #elif defined(WEBRTC_MAC)
293   // Make sure the new thread has an autoreleasepool
294   ScopedAutoreleasePool pool;
295 #endif
296   {
297     if (init->runnable) {
298       init->runnable->Run(init->thread);
299     } else {
300       init->thread->Run();
301     }
302     delete init;
303     return NULL;
304   }
305 }
306 
Run()307 void Thread::Run() {
308   ProcessMessages(kForever);
309 }
310 
IsOwned()311 bool Thread::IsOwned() {
312   return owned_;
313 }
314 
Stop()315 void Thread::Stop() {
316   MessageQueue::Quit();
317   Join();
318 }
319 
Send(MessageHandler * phandler,uint32_t id,MessageData * pdata)320 void Thread::Send(MessageHandler* phandler, uint32_t id, MessageData* pdata) {
321   if (fStop_)
322     return;
323 
324   // Sent messages are sent to the MessageHandler directly, in the context
325   // of "thread", like Win32 SendMessage. If in the right context,
326   // call the handler directly.
327   Message msg;
328   msg.phandler = phandler;
329   msg.message_id = id;
330   msg.pdata = pdata;
331   if (IsCurrent()) {
332     phandler->OnMessage(&msg);
333     return;
334   }
335 
336   AssertBlockingIsAllowedOnCurrentThread();
337 
338   AutoThread thread;
339   Thread *current_thread = Thread::Current();
340   ASSERT(current_thread != NULL);  // AutoThread ensures this
341 
342   bool ready = false;
343   {
344     CritScope cs(&crit_);
345     _SendMessage smsg;
346     smsg.thread = current_thread;
347     smsg.msg = msg;
348     smsg.ready = &ready;
349     sendlist_.push_back(smsg);
350   }
351 
352   // Wait for a reply
353 
354   ss_->WakeUp();
355 
356   bool waited = false;
357   crit_.Enter();
358   while (!ready) {
359     crit_.Leave();
360     // We need to limit "ReceiveSends" to |this| thread to avoid an arbitrary
361     // thread invoking calls on the current thread.
362     current_thread->ReceiveSendsFromThread(this);
363     current_thread->socketserver()->Wait(kForever, false);
364     waited = true;
365     crit_.Enter();
366   }
367   crit_.Leave();
368 
369   // Our Wait loop above may have consumed some WakeUp events for this
370   // MessageQueue, that weren't relevant to this Send.  Losing these WakeUps can
371   // cause problems for some SocketServers.
372   //
373   // Concrete example:
374   // Win32SocketServer on thread A calls Send on thread B.  While processing the
375   // message, thread B Posts a message to A.  We consume the wakeup for that
376   // Post while waiting for the Send to complete, which means that when we exit
377   // this loop, we need to issue another WakeUp, or else the Posted message
378   // won't be processed in a timely manner.
379 
380   if (waited) {
381     current_thread->socketserver()->WakeUp();
382   }
383 }
384 
ReceiveSends()385 void Thread::ReceiveSends() {
386   ReceiveSendsFromThread(NULL);
387 }
388 
ReceiveSendsFromThread(const Thread * source)389 void Thread::ReceiveSendsFromThread(const Thread* source) {
390   // Receive a sent message. Cleanup scenarios:
391   // - thread sending exits: We don't allow this, since thread can exit
392   //   only via Join, so Send must complete.
393   // - thread receiving exits: Wakeup/set ready in Thread::Clear()
394   // - object target cleared: Wakeup/set ready in Thread::Clear()
395   _SendMessage smsg;
396 
397   crit_.Enter();
398   while (PopSendMessageFromThread(source, &smsg)) {
399     crit_.Leave();
400 
401     smsg.msg.phandler->OnMessage(&smsg.msg);
402 
403     crit_.Enter();
404     *smsg.ready = true;
405     smsg.thread->socketserver()->WakeUp();
406   }
407   crit_.Leave();
408 }
409 
PopSendMessageFromThread(const Thread * source,_SendMessage * msg)410 bool Thread::PopSendMessageFromThread(const Thread* source, _SendMessage* msg) {
411   for (std::list<_SendMessage>::iterator it = sendlist_.begin();
412        it != sendlist_.end(); ++it) {
413     if (it->thread == source || source == NULL) {
414       *msg = *it;
415       sendlist_.erase(it);
416       return true;
417     }
418   }
419   return false;
420 }
421 
InvokeBegin()422 void Thread::InvokeBegin() {
423   TRACE_EVENT_BEGIN0("webrtc", "Thread::Invoke");
424 }
425 
InvokeEnd()426 void Thread::InvokeEnd() {
427   TRACE_EVENT_END0("webrtc", "Thread::Invoke");
428 }
429 
Clear(MessageHandler * phandler,uint32_t id,MessageList * removed)430 void Thread::Clear(MessageHandler* phandler,
431                    uint32_t id,
432                    MessageList* removed) {
433   CritScope cs(&crit_);
434 
435   // Remove messages on sendlist_ with phandler
436   // Object target cleared: remove from send list, wakeup/set ready
437   // if sender not NULL.
438 
439   std::list<_SendMessage>::iterator iter = sendlist_.begin();
440   while (iter != sendlist_.end()) {
441     _SendMessage smsg = *iter;
442     if (smsg.msg.Match(phandler, id)) {
443       if (removed) {
444         removed->push_back(smsg.msg);
445       } else {
446         delete smsg.msg.pdata;
447       }
448       iter = sendlist_.erase(iter);
449       *smsg.ready = true;
450       smsg.thread->socketserver()->WakeUp();
451       continue;
452     }
453     ++iter;
454   }
455 
456   MessageQueue::Clear(phandler, id, removed);
457 }
458 
ProcessMessages(int cmsLoop)459 bool Thread::ProcessMessages(int cmsLoop) {
460   uint32_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
461   int cmsNext = cmsLoop;
462 
463   while (true) {
464 #if __has_feature(objc_arc)
465     @autoreleasepool
466 #elif defined(WEBRTC_MAC)
467     // see: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html
468     // Each thread is supposed to have an autorelease pool. Also for event loops
469     // like this, autorelease pool needs to be created and drained/released
470     // for each cycle.
471     ScopedAutoreleasePool pool;
472 #endif
473     {
474       Message msg;
475       if (!Get(&msg, cmsNext))
476         return !IsQuitting();
477       Dispatch(&msg);
478 
479       if (cmsLoop != kForever) {
480         cmsNext = TimeUntil(msEnd);
481         if (cmsNext < 0)
482           return true;
483       }
484     }
485   }
486 }
487 
WrapCurrentWithThreadManager(ThreadManager * thread_manager,bool need_synchronize_access)488 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager,
489                                           bool need_synchronize_access) {
490   if (running())
491     return false;
492 
493 #if defined(WEBRTC_WIN)
494   if (need_synchronize_access) {
495     // We explicitly ask for no rights other than synchronization.
496     // This gives us the best chance of succeeding.
497     thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
498     if (!thread_) {
499       LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
500       return false;
501     }
502     thread_id_ = GetCurrentThreadId();
503   }
504 #elif defined(WEBRTC_POSIX)
505   thread_ = pthread_self();
506 #endif
507 
508   owned_ = false;
509   running_.Set();
510   thread_manager->SetCurrentThread(this);
511   return true;
512 }
513 
AutoThread(SocketServer * ss)514 AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
515   if (!ThreadManager::Instance()->CurrentThread()) {
516     ThreadManager::Instance()->SetCurrentThread(this);
517   }
518 }
519 
~AutoThread()520 AutoThread::~AutoThread() {
521   Stop();
522   if (ThreadManager::Instance()->CurrentThread() == this) {
523     ThreadManager::Instance()->SetCurrentThread(NULL);
524   }
525 }
526 
527 #if defined(WEBRTC_WIN)
Run()528 void ComThread::Run() {
529   HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
530   ASSERT(SUCCEEDED(hr));
531   if (SUCCEEDED(hr)) {
532     Thread::Run();
533     CoUninitialize();
534   } else {
535     LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
536   }
537 }
538 #endif
539 
540 }  // namespace rtc
541