OLD | NEW |
| (Empty) |
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 #include "base/logging.h" | |
11 #include "base/safe_strerror_posix.h" | |
12 #include "base/scoped_ptr.h" | |
13 #include "base/thread_restrictions.h" | |
14 | |
15 #if defined(OS_MACOSX) | |
16 #include <mach/mach.h> | |
17 #include <sys/resource.h> | |
18 #include <algorithm> | |
19 #endif | |
20 | |
21 #if defined(OS_LINUX) | |
22 #include <dlfcn.h> | |
23 #include <sys/prctl.h> | |
24 #include <sys/syscall.h> | |
25 #include <unistd.h> | |
26 #endif | |
27 | |
28 #if defined(OS_NACL) | |
29 #include <sys/nacl_syscalls.h> | |
30 #endif | |
31 | |
32 #if defined(OS_MACOSX) | |
33 namespace base { | |
34 void InitThreading(); | |
35 } // namespace base | |
36 #endif | |
37 | |
38 namespace { | |
39 | |
40 struct ThreadParams { | |
41 PlatformThread::Delegate* delegate; | |
42 bool joinable; | |
43 }; | |
44 | |
45 } // namespace | |
46 | |
47 static void* ThreadFunc(void* params) { | |
48 ThreadParams* thread_params = static_cast<ThreadParams*>(params); | |
49 PlatformThread::Delegate* delegate = thread_params->delegate; | |
50 if (!thread_params->joinable) | |
51 base::ThreadRestrictions::SetSingletonAllowed(false); | |
52 delete thread_params; | |
53 delegate->ThreadMain(); | |
54 return NULL; | |
55 } | |
56 | |
57 // static | |
58 PlatformThreadId PlatformThread::CurrentId() { | |
59 // Pthreads doesn't have the concept of a thread ID, so we have to reach down | |
60 // into the kernel. | |
61 #if defined(OS_MACOSX) | |
62 return mach_thread_self(); | |
63 #elif defined(OS_LINUX) | |
64 return syscall(__NR_gettid); | |
65 #elif defined(OS_FREEBSD) | |
66 // TODO(BSD): find a better thread ID | |
67 return reinterpret_cast<int64>(pthread_self()); | |
68 #elif defined(OS_NACL) | |
69 return pthread_self(); | |
70 #endif | |
71 } | |
72 | |
73 // static | |
74 void PlatformThread::YieldCurrentThread() { | |
75 sched_yield(); | |
76 } | |
77 | |
78 // static | |
79 void PlatformThread::Sleep(int duration_ms) { | |
80 struct timespec sleep_time, remaining; | |
81 | |
82 // Contains the portion of duration_ms >= 1 sec. | |
83 sleep_time.tv_sec = duration_ms / 1000; | |
84 duration_ms -= sleep_time.tv_sec * 1000; | |
85 | |
86 // Contains the portion of duration_ms < 1 sec. | |
87 sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds. | |
88 | |
89 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) | |
90 sleep_time = remaining; | |
91 } | |
92 | |
93 // Linux SetName is currently disabled, as we need to distinguish between | |
94 // helper threads (where it's ok to make this call) and the main thread | |
95 // (where making this call renames our process, causing tools like killall | |
96 // to stop working). | |
97 #if 0 && defined(OS_LINUX) | |
98 // static | |
99 void PlatformThread::SetName(const char* name) { | |
100 // http://0pointer.de/blog/projects/name-your-threads.html | |
101 | |
102 // glibc recently added support for pthread_setname_np, but it's not | |
103 // commonly available yet. So test for it at runtime. | |
104 int (*dynamic_pthread_setname_np)(pthread_t, const char*); | |
105 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = | |
106 dlsym(RTLD_DEFAULT, "pthread_setname_np"); | |
107 | |
108 if (dynamic_pthread_setname_np) { | |
109 // This limit comes from glibc, which gets it from the kernel | |
110 // (TASK_COMM_LEN). | |
111 const int kMaxNameLength = 15; | |
112 std::string shortened_name = std::string(name).substr(0, kMaxNameLength); | |
113 int err = dynamic_pthread_setname_np(pthread_self(), | |
114 shortened_name.c_str()); | |
115 if (err < 0) | |
116 LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err); | |
117 } else { | |
118 // Implementing this function without glibc is simple enough. (We | |
119 // don't do the name length clipping as above because it will be | |
120 // truncated by the callee (see TASK_COMM_LEN above).) | |
121 int err = prctl(PR_SET_NAME, name); | |
122 if (err < 0) | |
123 PLOG(ERROR) << "prctl(PR_SET_NAME)"; | |
124 } | |
125 } | |
126 #elif defined(OS_MACOSX) | |
127 // Mac is implemented in platform_thread_mac.mm. | |
128 #else | |
129 // static | |
130 void PlatformThread::SetName(const char* name) { | |
131 // Leave it unimplemented. | |
132 | |
133 // (This should be relatively simple to implement for the BSDs; I | |
134 // just don't have one handy to test the code on.) | |
135 } | |
136 #endif // defined(OS_LINUX) | |
137 | |
138 namespace { | |
139 | |
140 bool CreateThread(size_t stack_size, bool joinable, | |
141 PlatformThread::Delegate* delegate, | |
142 PlatformThreadHandle* thread_handle) { | |
143 #if defined(OS_MACOSX) | |
144 base::InitThreading(); | |
145 #endif // OS_MACOSX | |
146 | |
147 bool success = false; | |
148 pthread_attr_t attributes; | |
149 pthread_attr_init(&attributes); | |
150 | |
151 // Pthreads are joinable by default, so only specify the detached attribute if | |
152 // the thread should be non-joinable. | |
153 if (!joinable) { | |
154 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); | |
155 } | |
156 | |
157 #if defined(OS_MACOSX) | |
158 // The Mac OS X default for a pthread stack size is 512kB. | |
159 // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses | |
160 // DEFAULT_STACK_SIZE for this purpose. | |
161 // | |
162 // 512kB isn't quite generous enough for some deeply recursive threads that | |
163 // otherwise request the default stack size by specifying 0. Here, adopt | |
164 // glibc's behavior as on Linux, which is to use the current stack size | |
165 // limit (ulimit -s) as the default stack size. See | |
166 // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To | |
167 // avoid setting the limit below the Mac OS X default or the minimum usable | |
168 // stack size, these values are also considered. If any of these values | |
169 // can't be determined, or if stack size is unlimited (ulimit -s unlimited), | |
170 // stack_size is left at 0 to get the system default. | |
171 // | |
172 // Mac OS X normally only applies ulimit -s to the main thread stack. On | |
173 // contemporary OS X and Linux systems alike, this value is generally 8MB | |
174 // or in that neighborhood. | |
175 if (stack_size == 0) { | |
176 size_t default_stack_size; | |
177 struct rlimit stack_rlimit; | |
178 if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 && | |
179 getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 && | |
180 stack_rlimit.rlim_cur != RLIM_INFINITY) { | |
181 stack_size = std::max(std::max(default_stack_size, | |
182 static_cast<size_t>(PTHREAD_STACK_MIN)), | |
183 static_cast<size_t>(stack_rlimit.rlim_cur)); | |
184 } | |
185 } | |
186 #endif // OS_MACOSX | |
187 | |
188 if (stack_size > 0) | |
189 pthread_attr_setstacksize(&attributes, stack_size); | |
190 | |
191 ThreadParams* params = new ThreadParams; | |
192 params->delegate = delegate; | |
193 params->joinable = joinable; | |
194 success = !pthread_create(thread_handle, &attributes, ThreadFunc, params); | |
195 | |
196 pthread_attr_destroy(&attributes); | |
197 if (!success) | |
198 delete params; | |
199 return success; | |
200 } | |
201 | |
202 } // anonymous namespace | |
203 | |
204 // static | |
205 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, | |
206 PlatformThreadHandle* thread_handle) { | |
207 return CreateThread(stack_size, true /* joinable thread */, | |
208 delegate, thread_handle); | |
209 } | |
210 | |
211 // static | |
212 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { | |
213 PlatformThreadHandle unused; | |
214 | |
215 bool result = CreateThread(stack_size, false /* non-joinable thread */, | |
216 delegate, &unused); | |
217 return result; | |
218 } | |
219 | |
220 // static | |
221 void PlatformThread::Join(PlatformThreadHandle thread_handle) { | |
222 // Joining another thread may block the current thread for a long time, since | |
223 // the thread referred to by |thread_handle| may still be running long-lived / | |
224 // blocking tasks. | |
225 base::ThreadRestrictions::AssertIOAllowed(); | |
226 pthread_join(thread_handle, NULL); | |
227 } | |
OLD | NEW |