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

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

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

Powered by Google App Engine
This is Rietveld 408576698