Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: runtime/platform/thread_macos.cc

Issue 463993002: - Separate the thread implementation used in bin/ and vm/ (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "platform/globals.h"
6 #if defined(TARGET_OS_MACOS)
7
8 #include "platform/thread.h"
9
10 #include <sys/errno.h> // NOLINT
11 #include <sys/types.h> // NOLINT
12 #include <sys/sysctl.h> // NOLINT
13 #include <mach/mach_init.h> // NOLINT
14 #include <mach/mach_host.h> // NOLINT
15 #include <mach/mach_port.h> // NOLINT
16 #include <mach/mach_traps.h> // NOLINT
17 #include <mach/task_info.h> // NOLINT
18 #include <mach/thread_info.h> // NOLINT
19 #include <mach/thread_act.h> // NOLINT
20
21 #include "platform/assert.h"
22
23 namespace dart {
24
25 #define VALIDATE_PTHREAD_RESULT(result) \
26 if (result != 0) { \
27 const int kBufferSize = 1024; \
28 char error_message[kBufferSize]; \
29 strerror_r(result, error_message, kBufferSize); \
30 FATAL2("pthread error: %d (%s)", result, error_message); \
31 }
32
33
34 #ifdef DEBUG
35 #define RETURN_ON_PTHREAD_FAILURE(result) \
36 if (result != 0) { \
37 const int kBufferSize = 1024; \
38 char error_message[kBufferSize]; \
39 strerror_r(result, error_message, kBufferSize); \
40 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
41 __FILE__, __LINE__, result, error_message); \
42 return result; \
43 }
44 #else
45 #define RETURN_ON_PTHREAD_FAILURE(result) \
46 if (result != 0) return result;
47 #endif
48
49
50 class ThreadStartData {
51 public:
52 ThreadStartData(Thread::ThreadStartFunction function,
53 uword parameter)
54 : function_(function), parameter_(parameter) {}
55
56 Thread::ThreadStartFunction function() const { return function_; }
57 uword parameter() const { return parameter_; }
58
59 private:
60 Thread::ThreadStartFunction function_;
61 uword parameter_;
62
63 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
64 };
65
66
67 // Dispatch to the thread start function provided by the caller. This trampoline
68 // is used to ensure that the thread is properly destroyed if the thread just
69 // exits.
70 static void* ThreadStart(void* data_ptr) {
71 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
72
73 Thread::ThreadStartFunction function = data->function();
74 uword parameter = data->parameter();
75 delete data;
76
77 // Call the supplied thread start function handing it its parameters.
78 function(parameter);
79
80 return NULL;
81 }
82
83
84 int Thread::Start(ThreadStartFunction function, uword parameter) {
85 pthread_attr_t attr;
86 int result = pthread_attr_init(&attr);
87 RETURN_ON_PTHREAD_FAILURE(result);
88
89 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
90 RETURN_ON_PTHREAD_FAILURE(result);
91
92 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
93 RETURN_ON_PTHREAD_FAILURE(result);
94
95 ThreadStartData* data = new ThreadStartData(function, parameter);
96
97 pthread_t tid;
98 result = pthread_create(&tid, &attr, ThreadStart, data);
99 RETURN_ON_PTHREAD_FAILURE(result);
100
101 result = pthread_attr_destroy(&attr);
102 RETURN_ON_PTHREAD_FAILURE(result);
103
104 return 0;
105 }
106
107
108 ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
109 ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
110
111 ThreadLocalKey Thread::CreateThreadLocal() {
112 pthread_key_t key = kUnsetThreadLocalKey;
113 int result = pthread_key_create(&key, NULL);
114 VALIDATE_PTHREAD_RESULT(result);
115 ASSERT(key != kUnsetThreadLocalKey);
116 return key;
117 }
118
119
120 void Thread::DeleteThreadLocal(ThreadLocalKey key) {
121 ASSERT(key != kUnsetThreadLocalKey);
122 int result = pthread_key_delete(key);
123 VALIDATE_PTHREAD_RESULT(result);
124 }
125
126
127 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
128 ASSERT(key != kUnsetThreadLocalKey);
129 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
130 VALIDATE_PTHREAD_RESULT(result);
131 }
132
133
134 intptr_t Thread::GetMaxStackSize() {
135 const int kStackSize = (128 * kWordSize * KB);
136 return kStackSize;
137 }
138
139
140 ThreadId Thread::GetCurrentThreadId() {
141 return pthread_self();
142 }
143
144
145 bool Thread::Join(ThreadId id) {
146 return false;
147 }
148
149
150 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
151 ASSERT(sizeof(id) == sizeof(intptr_t));
152 return reinterpret_cast<intptr_t>(id);
153 }
154
155
156 bool Thread::Compare(ThreadId a, ThreadId b) {
157 return pthread_equal(a, b) != 0;
158 }
159
160
161 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) {
162 ASSERT(thread_id == GetCurrentThreadId());
163 ASSERT(cpu_usage != NULL);
164 // TODO(johnmccutchan): Enable this after fixing issue with macos directory
165 // watcher.
166 const bool get_cpu_usage = false;
167 if (get_cpu_usage) {
168 mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
169 thread_basic_info_data_t info_data;
170 thread_basic_info_t info = &info_data;
171 mach_port_t thread_port = mach_thread_self();
172 kern_return_t r = thread_info(thread_port, THREAD_BASIC_INFO,
173 (thread_info_t)info, &count);
174 mach_port_deallocate(mach_task_self(), thread_port);
175 if (r == KERN_SUCCESS) {
176 *cpu_usage = (info->user_time.seconds * kMicrosecondsPerSecond) +
177 info->user_time.microseconds;
178 return;
179 }
180 }
181 *cpu_usage = 0;
182 }
183
184
185 Mutex::Mutex() {
186 pthread_mutexattr_t attr;
187 int result = pthread_mutexattr_init(&attr);
188 VALIDATE_PTHREAD_RESULT(result);
189
190 #if defined(DEBUG)
191 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
192 VALIDATE_PTHREAD_RESULT(result);
193 #endif // defined(DEBUG)
194
195 result = pthread_mutex_init(data_.mutex(), &attr);
196 // Verify that creating a pthread_mutex succeeded.
197 VALIDATE_PTHREAD_RESULT(result);
198
199 result = pthread_mutexattr_destroy(&attr);
200 VALIDATE_PTHREAD_RESULT(result);
201 }
202
203
204 Mutex::~Mutex() {
205 int result = pthread_mutex_destroy(data_.mutex());
206 // Verify that the pthread_mutex was destroyed.
207 VALIDATE_PTHREAD_RESULT(result);
208 }
209
210
211 void Mutex::Lock() {
212 int result = pthread_mutex_lock(data_.mutex());
213 // Specifically check for dead lock to help debugging.
214 ASSERT(result != EDEADLK);
215 ASSERT(result == 0); // Verify no other errors.
216 // TODO(iposva): Do we need to track lock owners?
217 }
218
219
220 bool Mutex::TryLock() {
221 int result = pthread_mutex_trylock(data_.mutex());
222 // Return false if the lock is busy and locking failed.
223 if ((result == EBUSY) || (result == EDEADLK)) {
224 return false;
225 }
226 ASSERT(result == 0); // Verify no other errors.
227 // TODO(iposva): Do we need to track lock owners?
228 return true;
229 }
230
231
232 void Mutex::Unlock() {
233 // TODO(iposva): Do we need to track lock owners?
234 int result = pthread_mutex_unlock(data_.mutex());
235 // Specifically check for wrong thread unlocking to aid debugging.
236 ASSERT(result != EPERM);
237 ASSERT(result == 0); // Verify no other errors.
238 }
239
240
241 Monitor::Monitor() {
242 pthread_mutexattr_t attr;
243 int result = pthread_mutexattr_init(&attr);
244 VALIDATE_PTHREAD_RESULT(result);
245
246 #if defined(DEBUG)
247 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
248 VALIDATE_PTHREAD_RESULT(result);
249 #endif // defined(DEBUG)
250
251 result = pthread_mutex_init(data_.mutex(), &attr);
252 VALIDATE_PTHREAD_RESULT(result);
253
254 result = pthread_mutexattr_destroy(&attr);
255 VALIDATE_PTHREAD_RESULT(result);
256
257 result = pthread_cond_init(data_.cond(), NULL);
258 VALIDATE_PTHREAD_RESULT(result);
259 }
260
261
262 Monitor::~Monitor() {
263 int result = pthread_mutex_destroy(data_.mutex());
264 VALIDATE_PTHREAD_RESULT(result);
265
266 result = pthread_cond_destroy(data_.cond());
267 VALIDATE_PTHREAD_RESULT(result);
268 }
269
270
271 void Monitor::Enter() {
272 int result = pthread_mutex_lock(data_.mutex());
273 VALIDATE_PTHREAD_RESULT(result);
274 // TODO(iposva): Do we need to track lock owners?
275 }
276
277
278 void Monitor::Exit() {
279 // TODO(iposva): Do we need to track lock owners?
280 int result = pthread_mutex_unlock(data_.mutex());
281 VALIDATE_PTHREAD_RESULT(result);
282 }
283
284
285 Monitor::WaitResult Monitor::Wait(int64_t millis) {
286 return WaitMicros(millis * kMicrosecondsPerMillisecond);
287 }
288
289
290 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
291 // TODO(iposva): Do we need to track lock owners?
292 Monitor::WaitResult retval = kNotified;
293 if (micros == kNoTimeout) {
294 // Wait forever.
295 int result = pthread_cond_wait(data_.cond(), data_.mutex());
296 VALIDATE_PTHREAD_RESULT(result);
297 } else {
298 struct timespec ts;
299 int64_t secs = micros / kMicrosecondsPerSecond;
300 if (secs > kMaxInt32) {
301 // Avoid truncation of overly large timeout values.
302 secs = kMaxInt32;
303 }
304 int64_t nanos =
305 (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
306 ts.tv_sec = static_cast<int32_t>(secs);
307 ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
308 int result = pthread_cond_timedwait_relative_np(data_.cond(),
309 data_.mutex(),
310 &ts);
311 ASSERT((result == 0) || (result == ETIMEDOUT));
312 if (result == ETIMEDOUT) {
313 retval = kTimedOut;
314 }
315 }
316 return retval;
317 }
318
319
320 void Monitor::Notify() {
321 // TODO(iposva): Do we need to track lock owners?
322 int result = pthread_cond_signal(data_.cond());
323 VALIDATE_PTHREAD_RESULT(result);
324 }
325
326
327 void Monitor::NotifyAll() {
328 // TODO(iposva): Do we need to track lock owners?
329 int result = pthread_cond_broadcast(data_.cond());
330 VALIDATE_PTHREAD_RESULT(result);
331 }
332
333 } // namespace dart
334
335 #endif // defined(TARGET_OS_MACOS)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698