1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "talk/base/thread.h"
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(WIN32)
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <comdef.h>
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(POSIX)
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <time.h>
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h"
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h"
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "talk/base/stringutils.h"
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/time.h"
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#ifdef OSX_USE_COCOA
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifndef OSX
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#error OSX_USE_COCOA is defined but not OSX
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/maccocoathreadhelper.h"
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/scoped_autorelease_pool.h"
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base {
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThreadManager g_thmgr;
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef POSIX
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochpthread_key_t ThreadManager::key_;
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThreadManager::ThreadManager() {
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pthread_key_create(&key_, NULL);
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  main_thread_ = WrapCurrentThread();
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(OSX_USE_COCOA)
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  InitCocoaMultiThreading();
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThreadManager::~ThreadManager() {
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef OSX_USE_COCOA
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // This is called during exit, at which point apparently no NSAutoreleasePools
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // are available; but we might still need them to do cleanup (or we get the
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // "no autoreleasepool in place, just leaking" warning when exiting).
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ScopedAutoreleasePool pool;
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  UnwrapCurrentThread();
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Unwrap deletes main_thread_ automatically.
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pthread_key_delete(key_);
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThread *ThreadManager::CurrentThread() {
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return static_cast<Thread *>(pthread_getspecific(key_));
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::SetCurrent(Thread *thread) {
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pthread_setspecific(key_, thread);
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochDWORD ThreadManager::key_;
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThreadManager::ThreadManager() {
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  key_ = TlsAlloc();
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  main_thread_ = WrapCurrentThread();
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThreadManager::~ThreadManager() {
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  UnwrapCurrentThread();
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TlsFree(key_);
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThread *ThreadManager::CurrentThread() {
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return static_cast<Thread *>(TlsGetValue(key_));
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::SetCurrent(Thread *thread) {
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TlsSetValue(key_, thread);
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// static
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThread *ThreadManager::WrapCurrentThread() {
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Thread* result = CurrentThread();
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (NULL == result) {
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result = new Thread();
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(WIN32)
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // We explicitly ask for no rights other than synchronization.
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // This gives us the best chance of succeeding.
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!result->thread_)
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#elif defined(POSIX)
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->thread_ = pthread_self();
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->owned_ = false;
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result->started_ = true;
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SetCurrent(result);
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return result;
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// static
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::UnwrapCurrentThread() {
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Thread* t = CurrentThread();
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (t && !(t->IsOwned())) {
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Clears the platform-specific thread-specific storage.
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SetCurrent(NULL);
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!CloseHandle(t->thread_)) {
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    t->started_ = false;
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete t;
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::Add(Thread *thread) {
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CritScope cs(&crit_);
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  threads_.push_back(thread);
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::Remove(Thread *thread) {
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CritScope cs(&crit_);
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  threads_.erase(std::remove(threads_.begin(), threads_.end(), thread),
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 threads_.end());
154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid ThreadManager::StopAllThreads_() {
157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: In order to properly implement, Threads need to be ref-counted.
158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CritScope cs(&g_thmgr.crit_);
1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (size_t i = 0; i < g_thmgr.threads_.size(); ++i) {
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    g_thmgr.threads_[i]->Stop();
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstruct ThreadInit {
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Thread* thread;
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Runnable* runnable;
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThread::Thread(SocketServer* ss)
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    : MessageQueue(ss),
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      priority_(PRIORITY_NORMAL),
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      started_(false),
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      has_sends_(false),
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(WIN32)
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      thread_(NULL),
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      owned_(true) {
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  g_thmgr.Add(this);
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SetName("Thread", this);  // default name
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochThread::~Thread() {
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Stop();
184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (active_)
185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Clear(NULL);
186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  g_thmgr.Remove(this);
187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Thread::SleepMs(int milliseconds) {
190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ::Sleep(milliseconds);
192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#else
194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // POSIX has both a usleep() and a nanosleep(), but the former is deprecated,
195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // so we use nanosleep() even though it has greater precision than necessary.
196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  struct timespec ts;
197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ts.tv_sec = milliseconds / 1000;
198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ts.tv_nsec = (milliseconds % 1000) * 1000000;
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int ret = nanosleep(&ts, NULL);
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (ret != 0) {
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG_ERR(LS_WARNING) << "nanosleep() returning early";
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool Thread::SetName(const std::string& name, const void* obj) {
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (started_) return false;
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  name_ = name;
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (obj) {
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    char buf[16];
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    sprintfn(buf, sizeof(buf), " 0x%p", obj);
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    name_ += buf;
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool Thread::SetPriority(ThreadPriority priority) {
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (started_) return false;
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  priority_ = priority;
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Thread::Start(Runnable* runnable) {
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT(owned_);
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!owned_) return false;
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT(!started_);
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (started_) return false;
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ThreadInit* init = new ThreadInit;
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  init->thread = this;
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  init->runnable = runnable;
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(WIN32)
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD flags = 0;
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (priority_ != PRIORITY_NORMAL) {
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    flags = CREATE_SUSPENDED;
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, flags,
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         NULL);
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (thread_) {
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (priority_ != PRIORITY_NORMAL) {
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (priority_ == PRIORITY_HIGH) {
244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ::SetThreadPriority(thread_, THREAD_PRIORITY_HIGHEST);
245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else if (priority_ == PRIORITY_ABOVE_NORMAL) {
246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else if (priority_ == PRIORITY_IDLE) {
248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ::SetThreadPriority(thread_, THREAD_PRIORITY_IDLE);
249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ::ResumeThread(thread_);
251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#elif defined(POSIX)
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pthread_attr_t attr;
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pthread_attr_init(&attr);
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (priority_ != PRIORITY_NORMAL) {
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (priority_ == PRIORITY_IDLE) {
260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // There is no POSIX-standard way to set a below-normal priority for an
261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // individual thread (only whole process), so let's not support it.
262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG(LS_WARNING) << "PRIORITY_IDLE not supported";
263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Set real-time round-robin policy.
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (pthread_attr_setschedpolicy(&attr, SCHED_RR) != 0) {
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_ERROR) << "pthread_attr_setschedpolicy";
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      struct sched_param param;
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (pthread_attr_getschedparam(&attr, &param) != 0) {
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_ERROR) << "pthread_attr_getschedparam";
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // The numbers here are arbitrary.
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (priority_ == PRIORITY_HIGH) {
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          param.sched_priority = 6;           // 6 = HIGH
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        } else {
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          ASSERT(priority_ == PRIORITY_ABOVE_NORMAL);
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          param.sched_priority = 4;           // 4 = ABOVE_NORMAL
278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (pthread_attr_setschedparam(&attr, &param) != 0) {
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          LOG(LS_ERROR) << "pthread_attr_setschedparam";
281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int error_code = pthread_create(&thread_, &attr, PreRun, init);
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (0 != error_code) {
287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  started_ = true;
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::Join() {
296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (started_) {
297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ASSERT(!IsCurrent());
298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if defined(WIN32)
299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    WaitForSingleObject(thread_, INFINITE);
300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    CloseHandle(thread_);
301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    thread_ = NULL;
302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#elif defined(POSIX)
303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    void *pv;
304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pthread_join(thread_, &pv);
305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    started_ = false;
307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// As seen on MSDN.
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx
3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#define MSDEV_SET_THREAD_NAME  0x406D1388
3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricktypedef struct tagTHREADNAME_INFO {
315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD dwType;
316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  LPCSTR szName;
317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD dwThreadID;
318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DWORD dwFlags;
319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} THREADNAME_INFO;
320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) {
322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  THREADNAME_INFO info;
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  info.dwType = 0x1000;
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  info.szName = szThreadName;
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  info.dwThreadID = dwThreadID;
3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  info.dwFlags = 0;
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  __try {
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    RaiseException(MSDEV_SET_THREAD_NAME, 0, sizeof(info) / sizeof(DWORD),
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   reinterpret_cast<DWORD*>(&info));
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  __except(EXCEPTION_CONTINUE_EXECUTION) {
333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif  // WIN32
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid* Thread::PreRun(void* pv) {
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ThreadInit* init = static_cast<ThreadInit*>(pv);
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ThreadManager::SetCurrent(init->thread);
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#if defined(WIN32)
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SetThreadName(GetCurrentThreadId(), init->thread->name_.c_str());
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#elif defined(POSIX)
343731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: See if naming exists for pthreads.
344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef OSX_USE_COCOA
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Make sure the new thread has an autoreleasepool
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ScopedAutoreleasePool pool;
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (init->runnable) {
350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    init->runnable->Run(init->thread);
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    init->thread->Run();
353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  delete init;
355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return NULL;
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::Run() {
359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ProcessMessages(kForever);
360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Thread::IsOwned() {
363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return owned_;
364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::Stop() {
367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  MessageQueue::Quit();
368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Join();
369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::Send(MessageHandler *phandler, uint32 id, MessageData *pdata) {
372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (fStop_)
373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Sent messages are sent to the MessageHandler directly, in the context
376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // of "thread", like Win32 SendMessage. If in the right context,
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // call the handler directly.
378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Message msg;
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg.phandler = phandler;
381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg.message_id = id;
382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg.pdata = pdata;
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (IsCurrent()) {
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    phandler->OnMessage(&msg);
385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AutoThread thread;
389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Thread *current_thread = Thread::Current();
390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(current_thread != NULL);  // AutoThread ensures this
391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool ready = false;
393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  {
394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    CritScope cs(&crit_);
395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    EnsureActive();
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    _SendMessage smsg;
397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    smsg.thread = current_thread;
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    smsg.msg = msg;
399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    smsg.ready = &ready;
400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sendlist_.push_back(smsg);
401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    has_sends_ = true;
402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Wait for a reply
405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ss_->WakeUp();
407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool waited = false;
409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (!ready) {
410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_thread->ReceiveSends();
411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_thread->socketserver()->Wait(kForever, false);
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    waited = true;
413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Our Wait loop above may have consumed some WakeUp events for this
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // MessageQueue, that weren't relevant to this Send.  Losing these WakeUps can
417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // cause problems for some SocketServers.
418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  //
419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Concrete example:
420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Win32SocketServer on thread A calls Send on thread B.  While processing the
421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // message, thread B Posts a message to A.  We consume the wakeup for that
422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Post while waiting for the Send to complete, which means that when we exit
423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // this loop, we need to issue another WakeUp, or else the Posted message
424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // won't be processed in a timely manner.
425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (waited) {
427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    current_thread->socketserver()->WakeUp();
428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::ReceiveSends() {
432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Before entering critical section, check boolean.
433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!has_sends_)
435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return;
436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Receive a sent message. Cleanup scenarios:
438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // - thread sending exits: We don't allow this, since thread can exit
439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  //   only via Join, so Send must complete.
440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // - thread receiving exits: Wakeup/set ready in Thread::Clear()
441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // - object target cleared: Wakeup/set ready in Thread::Clear()
442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  crit_.Enter();
443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (!sendlist_.empty()) {
444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    _SendMessage smsg = sendlist_.front();
445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sendlist_.pop_front();
446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    crit_.Leave();
447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    smsg.msg.phandler->OnMessage(&smsg.msg);
448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    crit_.Enter();
449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *smsg.ready = true;
450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    smsg.thread->socketserver()->WakeUp();
451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  has_sends_ = false;
453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  crit_.Leave();
454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid Thread::Clear(MessageHandler *phandler, uint32 id,
457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                   MessageList* removed) {
458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CritScope cs(&crit_);
459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Remove messages on sendlist_ with phandler
461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Object target cleared: remove from send list, wakeup/set ready
462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // if sender not NULL.
463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::list<_SendMessage>::iterator iter = sendlist_.begin();
465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (iter != sendlist_.end()) {
466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    _SendMessage smsg = *iter;
467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (smsg.msg.Match(phandler, id)) {
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (removed) {
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        removed->push_back(smsg.msg);
470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        delete smsg.msg.pdata;
472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      iter = sendlist_.erase(iter);
474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      *smsg.ready = true;
475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      smsg.thread->socketserver()->WakeUp();
476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      continue;
477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ++iter;
479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  MessageQueue::Clear(phandler, id, removed);
482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool Thread::ProcessMessages(int cmsLoop) {
485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  uint32 msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int cmsNext = cmsLoop;
487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (true) {
489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Message msg;
490f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!Get(&msg, cmsNext))
491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return !IsQuitting();
492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Dispatch(&msg);
493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (cmsLoop != kForever) {
495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      cmsNext = TimeUntil(msEnd);
496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (cmsNext < 0)
497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return true;
498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochAutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!ThreadManager::CurrentThread()) {
504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ThreadManager::SetCurrent(this);
505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochAutoThread::~AutoThread() {
509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (ThreadManager::CurrentThread() == this) {
510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ThreadManager::SetCurrent(NULL);
511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#ifdef WIN32
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ComThread::Run() {
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT(SUCCEEDED(hr));
5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (SUCCEEDED(hr)) {
5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Thread::Run();
5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CoUninitialize();
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#endif
5263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace talk_base
528