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