Flutter Engine
The Flutter Engine
thread_linux.cc
Go to the documentation of this file.
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(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)) && \
7 !defined(DART_USE_ABSL)
8
9#include "bin/thread.h"
10#include "bin/thread_linux.h"
11
12#include <errno.h> // NOLINT
13#include <sys/resource.h> // NOLINT
14#include <sys/time.h> // NOLINT
15
16#include "platform/assert.h"
17#include "platform/utils.h"
18
19namespace dart {
20namespace bin {
21
22#define VALIDATE_PTHREAD_RESULT(result) \
23 if (result != 0) { \
24 const int kBufferSize = 1024; \
25 char error_buf[kBufferSize]; \
26 FATAL("pthread error: %d (%s)", result, \
27 Utils::StrError(result, error_buf, kBufferSize)); \
28 }
29
30#ifdef DEBUG
31#define RETURN_ON_PTHREAD_FAILURE(result) \
32 if (result != 0) { \
33 const int kBufferSize = 1024; \
34 char error_buf[kBufferSize]; \
35 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
36 result, Utils::StrError(result, error_buf, kBufferSize)); \
37 return result; \
38 }
39#else
40#define RETURN_ON_PTHREAD_FAILURE(result) \
41 if (result != 0) { \
42 return result; \
43 }
44#endif
45
46static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
47 int64_t secs = micros / kMicrosecondsPerSecond;
48 int64_t nanos =
50 int result = clock_gettime(CLOCK_MONOTONIC, ts);
51 ASSERT(result == 0);
52 ts->tv_sec += secs;
53 ts->tv_nsec += nanos;
54 if (ts->tv_nsec >= kNanosecondsPerSecond) {
55 ts->tv_sec += 1;
56 ts->tv_nsec -= kNanosecondsPerSecond;
57 }
58}
59
60class ThreadStartData {
61 public:
62 ThreadStartData(const char* name,
64 uword parameter)
65 : name_(name), function_(function), parameter_(parameter) {}
66
67 const char* name() const { return name_; }
68 Thread::ThreadStartFunction function() const { return function_; }
69 uword parameter() const { return parameter_; }
70
71 private:
72 const char* name_;
74 uword parameter_;
75
76 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
77};
78
79// Dispatch to the thread start function provided by the caller. This trampoline
80// is used to ensure that the thread is properly destroyed if the thread just
81// exits.
82static void* ThreadStart(void* data_ptr) {
83 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
84
85 const char* name = data->name();
87 uword parameter = data->parameter();
88 delete data;
89
90 // Set the thread name. There is 16 bytes limit on the name (including \0).
91 // pthread_setname_np ignores names that are too long rather than truncating.
92 char truncated_name[16];
93 snprintf(truncated_name, sizeof(truncated_name), "%s", name);
94 pthread_setname_np(pthread_self(), truncated_name);
95
96 // Call the supplied thread start function handing it its parameters.
97 function(parameter);
98
99 return nullptr;
100}
101
102int Thread::Start(const char* name,
103 ThreadStartFunction function,
104 uword parameter) {
105 pthread_attr_t attr;
106 int result = pthread_attr_init(&attr);
107 RETURN_ON_PTHREAD_FAILURE(result);
108
109 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
110 RETURN_ON_PTHREAD_FAILURE(result);
111
112 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
113 RETURN_ON_PTHREAD_FAILURE(result);
114
115 ThreadStartData* data = new ThreadStartData(name, function, parameter);
116
117 pthread_t tid;
118 result = pthread_create(&tid, &attr, ThreadStart, data);
119 RETURN_ON_PTHREAD_FAILURE(result);
120
121 result = pthread_attr_destroy(&attr);
122 RETURN_ON_PTHREAD_FAILURE(result);
123
124 return 0;
125}
126
127const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
128
129intptr_t Thread::GetMaxStackSize() {
130 const int kStackSize = (128 * kWordSize * KB);
131 return kStackSize;
132}
133
135 return pthread_self();
136}
137
139 return (pthread_equal(a, b) != 0);
140}
141
142Mutex::Mutex() {
143 pthread_mutexattr_t attr;
144 int result = pthread_mutexattr_init(&attr);
145 VALIDATE_PTHREAD_RESULT(result);
146
147#if defined(DEBUG)
148 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
149 VALIDATE_PTHREAD_RESULT(result);
150#endif // defined(DEBUG)
151
152 result = pthread_mutex_init(data_.mutex(), &attr);
153 // Verify that creating a pthread_mutex succeeded.
154 VALIDATE_PTHREAD_RESULT(result);
155
156 result = pthread_mutexattr_destroy(&attr);
157 VALIDATE_PTHREAD_RESULT(result);
158}
159
161 int result = pthread_mutex_destroy(data_.mutex());
162 // Verify that the pthread_mutex was destroyed.
163 VALIDATE_PTHREAD_RESULT(result);
164}
165
166void Mutex::Lock() {
167 int result = pthread_mutex_lock(data_.mutex());
168 // Specifically check for dead lock to help debugging.
169 ASSERT(result != EDEADLK);
170 ASSERT(result == 0); // Verify no other errors.
171 // TODO(iposva): Do we need to track lock owners?
172}
173
174bool Mutex::TryLock() {
175 int result = pthread_mutex_trylock(data_.mutex());
176 // Return false if the lock is busy and locking failed.
177 if (result == EBUSY) {
178 return false;
179 }
180 ASSERT(result == 0); // Verify no other errors.
181 // TODO(iposva): Do we need to track lock owners?
182 return true;
183}
184
185void Mutex::Unlock() {
186 // TODO(iposva): Do we need to track lock owners?
187 int result = pthread_mutex_unlock(data_.mutex());
188 // Specifically check for wrong thread unlocking to aid debugging.
189 ASSERT(result != EPERM);
190 ASSERT(result == 0); // Verify no other errors.
191}
192
194 pthread_mutexattr_t mutex_attr;
195 int result = pthread_mutexattr_init(&mutex_attr);
196 VALIDATE_PTHREAD_RESULT(result);
197
198#if defined(DEBUG)
199 result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
200 VALIDATE_PTHREAD_RESULT(result);
201#endif // defined(DEBUG)
202
203 result = pthread_mutex_init(data_.mutex(), &mutex_attr);
204 VALIDATE_PTHREAD_RESULT(result);
205
206 result = pthread_mutexattr_destroy(&mutex_attr);
207 VALIDATE_PTHREAD_RESULT(result);
208
209 pthread_condattr_t cond_attr;
210 result = pthread_condattr_init(&cond_attr);
211 VALIDATE_PTHREAD_RESULT(result);
212
213 result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
214 VALIDATE_PTHREAD_RESULT(result);
215
216 result = pthread_cond_init(data_.cond(), &cond_attr);
217 VALIDATE_PTHREAD_RESULT(result);
218
219 result = pthread_condattr_destroy(&cond_attr);
220 VALIDATE_PTHREAD_RESULT(result);
221}
222
224 int result = pthread_mutex_destroy(data_.mutex());
225 VALIDATE_PTHREAD_RESULT(result);
226
227 result = pthread_cond_destroy(data_.cond());
228 VALIDATE_PTHREAD_RESULT(result);
229}
230
231void Monitor::Enter() {
232 int result = pthread_mutex_lock(data_.mutex());
233 VALIDATE_PTHREAD_RESULT(result);
234 // TODO(iposva): Do we need to track lock owners?
235}
236
237void Monitor::Exit() {
238 // TODO(iposva): Do we need to track lock owners?
239 int result = pthread_mutex_unlock(data_.mutex());
240 VALIDATE_PTHREAD_RESULT(result);
241}
242
243Monitor::WaitResult Monitor::Wait(int64_t millis) {
245}
246
248 // TODO(iposva): Do we need to track lock owners?
250 if (micros == kNoTimeout) {
251 // Wait forever.
252 int result = pthread_cond_wait(data_.cond(), data_.mutex());
253 VALIDATE_PTHREAD_RESULT(result);
254 } else {
255 struct timespec ts;
256 ComputeTimeSpecMicros(&ts, micros);
257 int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
258 ASSERT((result == 0) || (result == ETIMEDOUT));
259 if (result == ETIMEDOUT) {
260 retval = kTimedOut;
261 }
262 }
263 return retval;
264}
265
266void Monitor::Notify() {
267 // TODO(iposva): Do we need to track lock owners?
268 int result = pthread_cond_signal(data_.cond());
269 VALIDATE_PTHREAD_RESULT(result);
270}
271
272void Monitor::NotifyAll() {
273 // TODO(iposva): Do we need to track lock owners?
274 int result = pthread_cond_broadcast(data_.cond());
275 VALIDATE_PTHREAD_RESULT(result);
276}
277
278} // namespace bin
279} // namespace dart
280
281#endif // (defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)) && \
282 // !defined(DART_USE_ABSL)
static constexpr int64_t kNoTimeout
Definition: thread.h:79
WaitResult Wait(int64_t millis)
WaitResult WaitMicros(int64_t micros)
static const ThreadId kInvalidThreadId
Definition: thread.h:38
void(* ThreadStartFunction)(uword parameter)
Definition: thread.h:40
static intptr_t GetMaxStackSize()
static int Start(const char *name, ThreadStartFunction function, uword parameters)
static bool Compare(ThreadId a, ThreadId b)
static ThreadId GetCurrentThreadId()
#define ASSERT(E)
static bool b
struct MyStruct a[10]
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
pthread_t ThreadId
Definition: thread_absl.h:21
Definition: dart_vm.cc:33
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
const char *const name
constexpr intptr_t kMicrosecondsPerSecond
Definition: globals.h:562
constexpr intptr_t kNanosecondsPerMicrosecond
Definition: globals.h:564
constexpr intptr_t KB
Definition: globals.h:528
uintptr_t uword
Definition: globals.h:501
constexpr intptr_t kNanosecondsPerSecond
Definition: globals.h:567
constexpr intptr_t kWordSize
Definition: globals.h:509
static int8_t data[kExtLength]
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581