1 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "base/platform_thread.h"
6 :
7 : #include <errno.h>
8 : #include <sched.h>
9 :
10 : #if defined(OS_MACOSX)
11 : #include <mach/mach.h>
12 : #elif defined(OS_LINUX)
13 : #include <sys/syscall.h>
14 : #include <unistd.h>
15 : #endif
16 :
17 : #if defined(OS_MACOSX)
18 : namespace base {
19 : void InitThreading();
20 : } // namespace
21 : #endif
22 :
23 1420 : static void* ThreadFunc(void* closure) {
24 : PlatformThread::Delegate* delegate =
25 1420 : static_cast<PlatformThread::Delegate*>(closure);
26 1420 : delegate->ThreadMain();
27 1419 : return NULL;
28 : }
29 :
30 : // static
31 2839 : PlatformThreadId PlatformThread::CurrentId() {
32 : // Pthreads doesn't have the concept of a thread ID, so we have to reach down
33 : // into the kernel.
34 : #if defined(OS_MACOSX)
35 : return mach_thread_self();
36 : #elif defined (__OpenBSD__)
37 : // TODO(BSD): find a better thread ID
38 : return (intptr_t)(pthread_self());
39 : #elif defined(OS_LINUX)
40 2839 : return syscall(__NR_gettid);
41 : #endif
42 : }
43 :
44 : // static
45 0 : void PlatformThread::YieldCurrentThread() {
46 0 : sched_yield();
47 0 : }
48 :
49 : // static
50 0 : void PlatformThread::Sleep(int duration_ms) {
51 : struct timespec sleep_time, remaining;
52 :
53 : // Contains the portion of duration_ms >= 1 sec.
54 0 : sleep_time.tv_sec = duration_ms / 1000;
55 0 : duration_ms -= sleep_time.tv_sec * 1000;
56 :
57 : // Contains the portion of duration_ms < 1 sec.
58 0 : sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds.
59 :
60 0 : while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
61 0 : sleep_time = remaining;
62 0 : }
63 :
64 : // static
65 1420 : void PlatformThread::SetName(const char* name) {
66 : // The POSIX standard does not provide for naming threads, and neither Linux
67 : // nor Mac OS X (our two POSIX targets) provide any non-portable way of doing
68 : // it either. (Some BSDs provide pthread_set_name_np but that isn't much of a
69 : // consolation prize.)
70 : // TODO(darin): decide whether stuffing the name in TLS or other in-memory
71 : // structure would be useful for debugging or not.
72 1420 : }
73 :
74 : namespace {
75 :
76 1420 : bool CreateThread(size_t stack_size, bool joinable,
77 : PlatformThread::Delegate* delegate,
78 : PlatformThreadHandle* thread_handle) {
79 : #if defined(OS_MACOSX)
80 : base::InitThreading();
81 : #endif // OS_MACOSX
82 :
83 1420 : bool success = false;
84 : pthread_attr_t attributes;
85 1420 : pthread_attr_init(&attributes);
86 :
87 : // Pthreads are joinable by default, so only specify the detached attribute if
88 : // the thread should be non-joinable.
89 1420 : if (!joinable) {
90 0 : pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
91 : }
92 :
93 1420 : if (stack_size > 0)
94 0 : pthread_attr_setstacksize(&attributes, stack_size);
95 :
96 1420 : success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
97 :
98 1420 : pthread_attr_destroy(&attributes);
99 1420 : return success;
100 : }
101 :
102 : } // anonymous namespace
103 :
104 : // static
105 1420 : bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
106 : PlatformThreadHandle* thread_handle) {
107 : return CreateThread(stack_size, true /* joinable thread */,
108 1420 : delegate, thread_handle);
109 : }
110 :
111 : // static
112 0 : bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
113 : PlatformThreadHandle unused;
114 :
115 : bool result = CreateThread(stack_size, false /* non-joinable thread */,
116 0 : delegate, &unused);
117 0 : return result;
118 : }
119 :
120 : // static
121 1419 : void PlatformThread::Join(PlatformThreadHandle thread_handle) {
122 1419 : pthread_join(thread_handle, NULL);
123 1419 : }
|