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

Side by Side Diff: runtime/platform/thread_linux.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_LINUX)
7
8 #include "platform/thread.h"
9
10 #include <errno.h> // NOLINT
11 #include <sys/resource.h> // NOLINT
12 #include <sys/time.h> // NOLINT
13
14 #include "platform/assert.h"
15
16 namespace dart {
17
18 #define VALIDATE_PTHREAD_RESULT(result) \
19 if (result != 0) { \
20 const int kBufferSize = 1024; \
21 char error_buf[kBufferSize]; \
22 FATAL2("pthread error: %d (%s)", result, \
23 strerror_r(result, error_buf, kBufferSize)); \
24 }
25
26
27 #ifdef DEBUG
28 #define RETURN_ON_PTHREAD_FAILURE(result) \
29 if (result != 0) { \
30 const int kBufferSize = 1024; \
31 char error_buf[kBufferSize]; \
32 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
33 __FILE__, __LINE__, result, \
34 strerror_r(result, error_buf, kBufferSize)); \
35 return result; \
36 }
37 #else
38 #define RETURN_ON_PTHREAD_FAILURE(result) \
39 if (result != 0) return result;
40 #endif
41
42
43 static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
44 int64_t secs = micros / kMicrosecondsPerSecond;
45 int64_t nanos =
46 (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
47 int result = clock_gettime(CLOCK_MONOTONIC, ts);
48 ASSERT(result == 0);
49 ts->tv_sec += secs;
50 ts->tv_nsec += nanos;
51 if (ts->tv_nsec >= kNanosecondsPerSecond) {
52 ts->tv_sec += 1;
53 ts->tv_nsec -= kNanosecondsPerSecond;
54 }
55 }
56
57
58 class ThreadStartData {
59 public:
60 ThreadStartData(Thread::ThreadStartFunction function,
61 uword parameter)
62 : function_(function), parameter_(parameter) {}
63
64 Thread::ThreadStartFunction function() const { return function_; }
65 uword parameter() const { return parameter_; }
66
67 private:
68 Thread::ThreadStartFunction function_;
69 uword parameter_;
70
71 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
72 };
73
74
75 // Dispatch to the thread start function provided by the caller. This trampoline
76 // is used to ensure that the thread is properly destroyed if the thread just
77 // exits.
78 static void* ThreadStart(void* data_ptr) {
79 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
80
81 Thread::ThreadStartFunction function = data->function();
82 uword parameter = data->parameter();
83 delete data;
84
85 // Call the supplied thread start function handing it its parameters.
86 function(parameter);
87
88 return NULL;
89 }
90
91
92 int Thread::Start(ThreadStartFunction function, uword parameter) {
93 pthread_attr_t attr;
94 int result = pthread_attr_init(&attr);
95 RETURN_ON_PTHREAD_FAILURE(result);
96
97 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
98 RETURN_ON_PTHREAD_FAILURE(result);
99
100 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
101 RETURN_ON_PTHREAD_FAILURE(result);
102
103 ThreadStartData* data = new ThreadStartData(function, parameter);
104
105 pthread_t tid;
106 result = pthread_create(&tid, &attr, ThreadStart, data);
107 RETURN_ON_PTHREAD_FAILURE(result);
108
109 result = pthread_attr_destroy(&attr);
110 RETURN_ON_PTHREAD_FAILURE(result);
111
112 return 0;
113 }
114
115
116 ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
117 ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
118
119 ThreadLocalKey Thread::CreateThreadLocal() {
120 pthread_key_t key = kUnsetThreadLocalKey;
121 int result = pthread_key_create(&key, NULL);
122 VALIDATE_PTHREAD_RESULT(result);
123 ASSERT(key != kUnsetThreadLocalKey);
124 return key;
125 }
126
127
128 void Thread::DeleteThreadLocal(ThreadLocalKey key) {
129 ASSERT(key != kUnsetThreadLocalKey);
130 int result = pthread_key_delete(key);
131 VALIDATE_PTHREAD_RESULT(result);
132 }
133
134
135 void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
136 ASSERT(key != kUnsetThreadLocalKey);
137 int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
138 VALIDATE_PTHREAD_RESULT(result);
139 }
140
141
142 intptr_t Thread::GetMaxStackSize() {
143 const int kStackSize = (128 * kWordSize * KB);
144 return kStackSize;
145 }
146
147
148 ThreadId Thread::GetCurrentThreadId() {
149 return pthread_self();
150 }
151
152
153 bool Thread::Join(ThreadId id) {
154 return false;
155 }
156
157
158 intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
159 ASSERT(sizeof(id) == sizeof(intptr_t));
160 return static_cast<intptr_t>(id);
161 }
162
163
164 bool Thread::Compare(ThreadId a, ThreadId b) {
165 return pthread_equal(a, b) != 0;
166 }
167
168
169 void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) {
170 ASSERT(thread_id == GetCurrentThreadId());
171 ASSERT(cpu_usage != NULL);
172 struct timespec ts;
173 int r = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
174 ASSERT(r == 0);
175 *cpu_usage = (ts.tv_sec * kNanosecondsPerSecond + ts.tv_nsec) /
176 kNanosecondsPerMicrosecond;
177 }
178
179
180 Mutex::Mutex() {
181 pthread_mutexattr_t attr;
182 int result = pthread_mutexattr_init(&attr);
183 VALIDATE_PTHREAD_RESULT(result);
184
185 #if defined(DEBUG)
186 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
187 VALIDATE_PTHREAD_RESULT(result);
188 #endif // defined(DEBUG)
189
190 result = pthread_mutex_init(data_.mutex(), &attr);
191 // Verify that creating a pthread_mutex succeeded.
192 VALIDATE_PTHREAD_RESULT(result);
193
194 result = pthread_mutexattr_destroy(&attr);
195 VALIDATE_PTHREAD_RESULT(result);
196 }
197
198
199 Mutex::~Mutex() {
200 int result = pthread_mutex_destroy(data_.mutex());
201 // Verify that the pthread_mutex was destroyed.
202 VALIDATE_PTHREAD_RESULT(result);
203 }
204
205
206 void Mutex::Lock() {
207 int result = pthread_mutex_lock(data_.mutex());
208 // Specifically check for dead lock to help debugging.
209 ASSERT(result != EDEADLK);
210 ASSERT(result == 0); // Verify no other errors.
211 // TODO(iposva): Do we need to track lock owners?
212 }
213
214
215 bool Mutex::TryLock() {
216 int result = pthread_mutex_trylock(data_.mutex());
217 // Return false if the lock is busy and locking failed.
218 if (result == EBUSY) {
219 return false;
220 }
221 ASSERT(result == 0); // Verify no other errors.
222 // TODO(iposva): Do we need to track lock owners?
223 return true;
224 }
225
226
227 void Mutex::Unlock() {
228 // TODO(iposva): Do we need to track lock owners?
229 int result = pthread_mutex_unlock(data_.mutex());
230 // Specifically check for wrong thread unlocking to aid debugging.
231 ASSERT(result != EPERM);
232 ASSERT(result == 0); // Verify no other errors.
233 }
234
235
236 Monitor::Monitor() {
237 pthread_mutexattr_t mutex_attr;
238 int result = pthread_mutexattr_init(&mutex_attr);
239 VALIDATE_PTHREAD_RESULT(result);
240
241 #if defined(DEBUG)
242 result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
243 VALIDATE_PTHREAD_RESULT(result);
244 #endif // defined(DEBUG)
245
246 result = pthread_mutex_init(data_.mutex(), &mutex_attr);
247 VALIDATE_PTHREAD_RESULT(result);
248
249 result = pthread_mutexattr_destroy(&mutex_attr);
250 VALIDATE_PTHREAD_RESULT(result);
251
252 pthread_condattr_t cond_attr;
253 result = pthread_condattr_init(&cond_attr);
254 VALIDATE_PTHREAD_RESULT(result);
255
256 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
257 VALIDATE_PTHREAD_RESULT(result);
258
259 result = pthread_cond_init(data_.cond(), &cond_attr);
260 VALIDATE_PTHREAD_RESULT(result);
261
262 result = pthread_condattr_destroy(&cond_attr);
263 VALIDATE_PTHREAD_RESULT(result);
264 }
265
266
267 Monitor::~Monitor() {
268 int result = pthread_mutex_destroy(data_.mutex());
269 VALIDATE_PTHREAD_RESULT(result);
270
271 result = pthread_cond_destroy(data_.cond());
272 VALIDATE_PTHREAD_RESULT(result);
273 }
274
275
276 void Monitor::Enter() {
277 int result = pthread_mutex_lock(data_.mutex());
278 VALIDATE_PTHREAD_RESULT(result);
279 // TODO(iposva): Do we need to track lock owners?
280 }
281
282
283 void Monitor::Exit() {
284 // TODO(iposva): Do we need to track lock owners?
285 int result = pthread_mutex_unlock(data_.mutex());
286 VALIDATE_PTHREAD_RESULT(result);
287 }
288
289
290 Monitor::WaitResult Monitor::Wait(int64_t millis) {
291 return WaitMicros(millis * kMicrosecondsPerMillisecond);
292 }
293
294
295 Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
296 // TODO(iposva): Do we need to track lock owners?
297 Monitor::WaitResult retval = kNotified;
298 if (micros == kNoTimeout) {
299 // Wait forever.
300 int result = pthread_cond_wait(data_.cond(), data_.mutex());
301 VALIDATE_PTHREAD_RESULT(result);
302 } else {
303 struct timespec ts;
304 ComputeTimeSpecMicros(&ts, micros);
305 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
306 ASSERT((result == 0) || (result == ETIMEDOUT));
307 if (result == ETIMEDOUT) {
308 retval = kTimedOut;
309 }
310 }
311 return retval;
312 }
313
314
315 void Monitor::Notify() {
316 // TODO(iposva): Do we need to track lock owners?
317 int result = pthread_cond_signal(data_.cond());
318 VALIDATE_PTHREAD_RESULT(result);
319 }
320
321
322 void Monitor::NotifyAll() {
323 // TODO(iposva): Do we need to track lock owners?
324 int result = pthread_cond_broadcast(data_.cond());
325 VALIDATE_PTHREAD_RESULT(result);
326 }
327
328 } // namespace dart
329
330 #endif // defined(TARGET_OS_LINUX)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698