Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
threadutils.cc
Go to the documentation of this file.
1 
18 #include "ion/port/threadutils.h"
19 
20 #include <cstring> // NOLINT
21 #include <iostream> // NOLINT
22 
23 #if defined(ION_PLATFORM_WINDOWS)
24 # define API_DECL WINAPI
25 #else
26 # include <sched.h>
27 # include <stdio.h>
28 # define API_DECL
29 #endif
30 
31 #if defined(ION_PLATFORM_ASMJS) || defined(ION_PLATFORM_NACL)
32 # define THREAD_NAMING_SUPPORTED 0
33 #else
34 # define THREAD_NAMING_SUPPORTED 1
35 #endif
36 
37 namespace ion {
38 namespace port {
39 
40 namespace {
41 
43 
48 
49 
54 static ThreadId InitMainThreadId(ThreadId id) {
55  static ThreadId main_thread_id = kInvalidThreadId;
56  if (id == kInvalidThreadId) {
57  if (main_thread_id == kInvalidThreadId)
58  main_thread_id = GetCurrentThreadId();
59  } else {
60  main_thread_id = id;
61  }
62  return main_thread_id;
63 }
64 
69 template <typename ReturnType> static ReturnType CastSuccessCode(bool success) {
70  return static_cast<ReturnType>(success ? 0 : 1);
71 }
72 template <> void* CastSuccessCode(bool success) {
73  return reinterpret_cast<void*>(static_cast<size_t>(success ? 0 : 1));
74 }
75 
77 template <typename ReturnType>
78 static ReturnType API_DECL InvokeThreadFuncPtr(void* arg) {
79  ThreadFuncPtr func_ptr = reinterpret_cast<ThreadFuncPtr>(arg);
80 
82  const bool success = (*func_ptr)();
83  return CastSuccessCode<ReturnType>(success);
84 }
85 
87 template <typename ReturnType>
88 static ReturnType API_DECL InvokeThreadFuncStd(void* arg) {
89  ThreadStdFunc* func = reinterpret_cast<ThreadStdFunc*>(arg);
90 
92  const bool success = (*func)();
93  return CastSuccessCode<ReturnType>(success);
94 }
95 
97 
102 
103 #if defined(ION_PLATFORM_WINDOWS)
104 
106 struct ThreadNameInfo {
107  ThreadNameInfo() : type(0x1000), flags(0) {}
108  DWORD type; // Must be 0x1000.
109  LPCSTR name; // Pointer to name.
110  DWORD thread_id; // Thread ID, or -1 to indicate the calling thread.
111  DWORD flags; // Reserved for future use; must be zero.
112 };
113 
115 static void CreateThread(const ThreadFuncPtr func_ptr, void* arg,
116  ThreadId* id) {
117  if (!::CreateThread(NULL, 0, InvokeThreadFuncPtr<DWORD>, arg, 0, id))
118  std::cerr << "***ION error: Unable to create thread: " << GetLastError()
119  << "\n";
120 }
121 
123 static void CreateThreadStd(const ThreadStdFunc* func, void* arg,
124  ThreadId* id) {
125  if (!::CreateThread(NULL, 0, InvokeThreadFuncStd<DWORD>, arg, 0, id))
126  std::cerr << "***ION error: Unable to create thread: " << GetLastError()
127  << "\n";
128 }
129 
130 #endif
131 
133 
139 
140 #if !defined(ION_PLATFORM_WINDOWS)
141 
144 static bool CheckPthreadSuccess(const char* what, int result) {
145  if (result) {
146 #if !defined(ION_COVERAGE) // COV_NF_START
147  std::cerr << "Pthread error: " << what << " returned "
152  << result << ": " << strerror(result) << "\n";
153  return false;
154 #endif // COV_NF_END
155  }
156  return true;
157 }
158 
160 static void CreateThread(const ThreadFuncPtr func_ptr, void* arg,
161  ThreadId* id) {
162  CheckPthreadSuccess(
163  "Creating thread",
164  ::pthread_create(id, NULL, InvokeThreadFuncPtr<void*>, arg));
165 }
166 
168 static void CreateThreadStd(const ThreadStdFunc* func, void* arg,
169  ThreadId* id) {
170  CheckPthreadSuccess(
171  "Creating thread",
172  ::pthread_create(id, NULL, InvokeThreadFuncStd<void*>, arg));
173 }
174 
175 #endif
176 
177 } // anonymous namespace
178 
180 
185 
186 
190  InitMainThreadId(kInvalidThreadId);
191 
192  ThreadId id = kInvalidThreadId;
193  if (func_ptr) {
194  void* arg = const_cast<void*>(reinterpret_cast<const void*>(func_ptr));
195  CreateThread(func_ptr, arg, &id);
196  }
197  return id;
198 }
199 
203  InitMainThreadId(kInvalidThreadId);
204 
205  ThreadId id = kInvalidThreadId;
206  if (func && *func) {
207  void* arg = const_cast<void*>(reinterpret_cast<const void*>(func));
208  CreateThreadStd(func, arg, &id);
209  }
210  return id;
211 }
212 
215 }
216 
217 bool IsMainThread() {
218  return GetCurrentThreadId() == InitMainThreadId(kInvalidThreadId);
219 }
220 
222  InitMainThreadId(id);
223 }
224 
226 
231 
232 #if defined(ION_PLATFORM_WINDOWS)
233 
234 bool JoinThread(ThreadId id) {
235  if (id != kInvalidThreadId) {
236  if (const HANDLE handle = ::OpenThread(THREAD_ALL_ACCESS, 0, id)) {
237  ::WaitForSingleObject(handle, INFINITE);
238  ::CloseHandle(handle);
239  return true;
240  }
241  std::cerr << "***ION error: Could not join thread with ID " << id
242  << ": error " << GetLastError() << "\n";
243  }
244  return false;
245 }
246 
247 size_t GetMaxThreadNameLength() {
248  return 0;
249 }
250 
251 bool SetThreadName(const std::string& name) {
252  bool success = false;
255  ThreadNameInfo info;
256  info.name = name.c_str();
257  info.thread_id = GetCurrentThreadId();
258  __try {
259  static const DWORD kMsVcException = 0x406d1388;
260  ::RaiseException(kMsVcException, 0, sizeof(info) / sizeof(DWORD),
261  reinterpret_cast<ULONG_PTR*>(&info));
262  success = true;
263  } __except(EXCEPTION_CONTINUE_EXECUTION) {
264  std::cerr << "***ION error: Unable to name thread with ID "
265  << info.thread_id << "\n";
266  }
267  return success;
268 }
269 
270 void YieldThread() {
271  ::SwitchToThread();
272 }
273 
276 }
277 
279  ThreadLocalStorageKey key = ::TlsAlloc();
280  if (key == TLS_OUT_OF_INDEXES) {
281  std::cerr << "***ION error: Unable to create thread-local storage key: "
282  << GetLastError() << "\n";
283  key = kInvalidThreadLocalStorageKey;
284  }
285  return key;
286 }
287 
288 bool SetThreadLocalStorage(ThreadLocalStorageKey key, void* ptr) {
289  if (key != kInvalidThreadLocalStorageKey) {
290  if (::TlsSetValue(key, ptr))
291  return true;
292  std::cerr << "***ION error: Unable to set thread-local storage pointer: "
293  << GetLastError() << "\n";
294  }
295  return false;
296 }
297 
299  return key == kInvalidThreadLocalStorageKey ? NULL : ::TlsGetValue(key);
300 }
301 
303  if (key != kInvalidThreadLocalStorageKey) {
304  if (::TlsFree(key))
305  return true;
306  std::cerr << "***ION error: Unable to delete thread-local storage key: "
307  << GetLastError() << "\n";
308  }
309  return false;
310 }
311 #endif
312 
314 
319 
320 #if !defined(ION_PLATFORM_WINDOWS)
321 
323  if (id != kInvalidThreadId) {
324  return CheckPthreadSuccess("Joining thread", ::pthread_join(id, NULL));
325  }
326  return false;
327 }
328 
330 #if THREAD_NAMING_SUPPORTED
331  static const size_t kMaxThreadNameLength = 16;
334  return kMaxThreadNameLength - 1U;
335 #else
336  return 0;
337 #endif
338 }
339 
340 bool SetThreadName(const std::string& name) {
341 #if THREAD_NAMING_SUPPORTED
342  std::string truncated_name = name;
343  if (const size_t max_len = GetMaxThreadNameLength())
344  truncated_name = truncated_name.substr(0, max_len);
345 # if defined(ION_PLATFORM_IOS) || defined(ION_PLATFORM_MAC)
346  return CheckPthreadSuccess(
348  "Naming thread", ::pthread_setname_np(truncated_name.c_str()));
349 # else
350  return CheckPthreadSuccess(
351  "Naming thread",
352  ::pthread_setname_np(GetCurrentThreadId(), truncated_name.c_str()));
353 # endif
354 #else
355  return false;
356 #endif
357 }
358 
359 void YieldThread() {
360  CheckPthreadSuccess("Yielding thread", sched_yield());
361 }
362 
364  return ::pthread_self();
365 }
366 
368  ThreadLocalStorageKey key = kInvalidThreadLocalStorageKey;
369  CheckPthreadSuccess("Creating thread-local storage key",
370  ::pthread_key_create(&key, NULL));
371  return key;
372 }
373 
375  if (key != kInvalidThreadLocalStorageKey) {
376  return CheckPthreadSuccess("Setting thread-local storage area",
377  ::pthread_setspecific(key, ptr));
378  }
379  return false;
380 }
381 
383  return key == kInvalidThreadLocalStorageKey ? NULL :
384  ::pthread_getspecific(key);
385 }
386 
388  if (key != kInvalidThreadLocalStorageKey) {
389  return CheckPthreadSuccess("Deleting thread-local storage key",
390  ::pthread_key_delete(key));
391  }
392  return false;
393 }
394 
395 #endif
396 
397 #undef API_DECL
398 #undef THREAD_NAMING_SUPPORTED
399 
400 } // namespace port
401 } // namespace ion
size_t GetMaxThreadNameLength()
Returns the maximum length of a thread name if restricted by the platform.
Definition: threadutils.cc:329
bool(* ThreadFuncPtr)()
Thread types and constants.
Definition: threadutils.h:58
std::string type
Definition: printer.cc:353
ThreadLocalStorageKey CreateThreadLocalStorageKey()
Thread-local storage functions.
Definition: threadutils.cc:367
unzFile handle
bool IsMainThread()
Returns true if the current thread is the main thread.
Definition: threadutils.cc:217
#define THREAD_NAMING_SUPPORTED
Definition: threadutils.cc:34
int pthread_join(pthread_t thread, void **retval)
Definition: asmjsfixes.cc:55
void YieldThread()
Causes the calling thread to relinquish the CPU if there are other threads waiting to execute...
Definition: threadutils.cc:359
bool JoinThread(ThreadId id)
Windows-specific public functions.
Definition: threadutils.cc:322
uint32 id
#define API_DECL
Copyright 2016 Google Inc.
Definition: threadutils.cc:28
bool SetThreadLocalStorage(ThreadLocalStorageKey key, void *ptr)
Associates ptr with the thread-local storage area indicated by key.
Definition: threadutils.cc:374
ThreadId SpawnThreadStd(const ThreadStdFunc *func)
Definition: threadutils.cc:200
pthread_key_t ThreadLocalStorageKey
Defines a type that is used to access thread-local storage.
Definition: threadutils.h:42
std::string name
Definition: printer.cc:324
ThreadId SpawnThread(const ThreadFuncPtr func_ptr)
Platform-independent public functions.
Definition: threadutils.cc:187
std::function< bool()> ThreadStdFunc
Definition: threadutils.h:59
bool IsThreadNamingSupported()
Thread naming functions.
Definition: threadutils.cc:213
pthread_t ThreadId
Defines a type that can be used to identify a thread.
Definition: threadutils.h:40
bool SetThreadName(const std::string &name)
Sets the name of the current thread.
Definition: threadutils.cc:340
void * GetThreadLocalStorage(ThreadLocalStorageKey key)
Returns the pointer to the thread-local storage area indicated by key.
Definition: threadutils.cc:382
bool DeleteThreadLocalStorageKey(ThreadLocalStorageKey key)
Deletes a key returned by CreateThreadLocalStorageKey().
Definition: threadutils.cc:387
void SetMainThreadId(ThreadId id)
Sets the given thread ID to be considered the main thread; IsMainThread() will return true only for t...
Definition: threadutils.cc:221
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *arg), void *arg)
Definition: asmjsfixes.cc:45
ThreadId GetCurrentThreadId()
Thread ID functions.
Definition: threadutils.cc:363