Flutter Engine
The Flutter Engine
thread_macos.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_MACOS) && !defined(DART_USE_ABSL)
7
8#include "bin/thread.h"
9#include "bin/thread_macos.h"
10
11#include <mach/mach_host.h> // NOLINT
12#include <mach/mach_init.h> // NOLINT
13#include <mach/mach_port.h> // NOLINT
14#include <mach/mach_traps.h> // NOLINT
15#include <mach/task_info.h> // NOLINT
16#include <mach/thread_act.h> // NOLINT
17#include <mach/thread_info.h> // NOLINT
18#include <sys/errno.h> // NOLINT
19#include <sys/sysctl.h> // NOLINT
20#include <sys/types.h> // NOLINT
21
22#include "platform/assert.h"
23#include "platform/utils.h"
24
25namespace dart {
26namespace bin {
27
28#define VALIDATE_PTHREAD_RESULT(result) \
29 if (result != 0) { \
30 const int kBufferSize = 1024; \
31 char error_message[kBufferSize]; \
32 Utils::StrError(result, error_message, kBufferSize); \
33 FATAL("pthread error: %d (%s)", result, error_message); \
34 }
35
36#ifdef DEBUG
37#define RETURN_ON_PTHREAD_FAILURE(result) \
38 if (result != 0) { \
39 const int kBufferSize = 1024; \
40 char error_message[kBufferSize]; \
41 Utils::StrError(result, error_message, kBufferSize); \
42 fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", __FILE__, __LINE__, \
43 result, error_message); \
44 return result; \
45 }
46#else
47#define RETURN_ON_PTHREAD_FAILURE(result) \
48 if (result != 0) { \
49 return result; \
50 }
51#endif
52
53class ThreadStartData {
54 public:
55 ThreadStartData(const char* name,
57 uword parameter)
58 : name_(name), function_(function), parameter_(parameter) {}
59
60 const char* name() const { return name_; }
61 Thread::ThreadStartFunction function() const { return function_; }
62 uword parameter() const { return parameter_; }
63
64 private:
65 const char* name_;
67 uword parameter_;
68
69 DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
70};
71
72// Dispatch to the thread start function provided by the caller. This trampoline
73// is used to ensure that the thread is properly destroyed if the thread just
74// exits.
75static void* ThreadStart(void* data_ptr) {
76 ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
77
78 const char* name = data->name();
80 uword parameter = data->parameter();
81 delete data;
82
83 // Set the thread name. We need to impose a limit on the name length so that
84 // we can know how large of a buffer to use when retrieving the name. We
85 // truncate the name at 16 bytes to be consistent with Android and Linux.
86 char truncated_name[16];
87 snprintf(truncated_name, sizeof(truncated_name), "%s", name);
88 pthread_setname_np(name);
89
90 // Call the supplied thread start function handing it its parameters.
91 function(parameter);
92
93 return nullptr;
94}
95
96int Thread::Start(const char* name,
97 ThreadStartFunction function,
98 uword parameter) {
99 pthread_attr_t attr;
100 int result = pthread_attr_init(&attr);
101 RETURN_ON_PTHREAD_FAILURE(result);
102
103 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
104 RETURN_ON_PTHREAD_FAILURE(result);
105
106 result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
107 RETURN_ON_PTHREAD_FAILURE(result);
108
109 ThreadStartData* data = new ThreadStartData(name, function, parameter);
110
111 pthread_t tid;
112 result = pthread_create(&tid, &attr, ThreadStart, data);
113 RETURN_ON_PTHREAD_FAILURE(result);
114
115 result = pthread_attr_destroy(&attr);
116 RETURN_ON_PTHREAD_FAILURE(result);
117
118 return 0;
119}
120
121const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(nullptr);
122
123intptr_t Thread::GetMaxStackSize() {
124 const int kStackSize = (128 * kWordSize * KB);
125 return kStackSize;
126}
127
129 return pthread_self();
130}
131
133 return (pthread_equal(a, b) != 0);
134}
135
136Mutex::Mutex() {
137 pthread_mutexattr_t attr;
138 int result = pthread_mutexattr_init(&attr);
139 VALIDATE_PTHREAD_RESULT(result);
140
141#if defined(DEBUG)
142 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
143 VALIDATE_PTHREAD_RESULT(result);
144#endif // defined(DEBUG)
145
146 result = pthread_mutex_init(data_.mutex(), &attr);
147 // Verify that creating a pthread_mutex succeeded.
148 VALIDATE_PTHREAD_RESULT(result);
149
150 result = pthread_mutexattr_destroy(&attr);
151 VALIDATE_PTHREAD_RESULT(result);
152}
153
155 int result = pthread_mutex_destroy(data_.mutex());
156 // Verify that the pthread_mutex was destroyed.
157 VALIDATE_PTHREAD_RESULT(result);
158}
159
160void Mutex::Lock() {
161 int result = pthread_mutex_lock(data_.mutex());
162 // Specifically check for dead lock to help debugging.
163 ASSERT(result != EDEADLK);
164 ASSERT(result == 0); // Verify no other errors.
165 // TODO(iposva): Do we need to track lock owners?
166}
167
168bool Mutex::TryLock() {
169 int result = pthread_mutex_trylock(data_.mutex());
170 // Return false if the lock is busy and locking failed.
171 if ((result == EBUSY) || (result == EDEADLK)) {
172 return false;
173 }
174 ASSERT(result == 0); // Verify no other errors.
175 // TODO(iposva): Do we need to track lock owners?
176 return true;
177}
178
179void Mutex::Unlock() {
180 // TODO(iposva): Do we need to track lock owners?
181 int result = pthread_mutex_unlock(data_.mutex());
182 // Specifically check for wrong thread unlocking to aid debugging.
183 ASSERT(result != EPERM);
184 ASSERT(result == 0); // Verify no other errors.
185}
186
188 pthread_mutexattr_t attr;
189 int result = pthread_mutexattr_init(&attr);
190 VALIDATE_PTHREAD_RESULT(result);
191
192#if defined(DEBUG)
193 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
194 VALIDATE_PTHREAD_RESULT(result);
195#endif // defined(DEBUG)
196
197 result = pthread_mutex_init(data_.mutex(), &attr);
198 VALIDATE_PTHREAD_RESULT(result);
199
200 result = pthread_mutexattr_destroy(&attr);
201 VALIDATE_PTHREAD_RESULT(result);
202
203 result = pthread_cond_init(data_.cond(), nullptr);
204 VALIDATE_PTHREAD_RESULT(result);
205}
206
208 int result = pthread_mutex_destroy(data_.mutex());
209 VALIDATE_PTHREAD_RESULT(result);
210
211 result = pthread_cond_destroy(data_.cond());
212 VALIDATE_PTHREAD_RESULT(result);
213}
214
215void Monitor::Enter() {
216 int result = pthread_mutex_lock(data_.mutex());
217 VALIDATE_PTHREAD_RESULT(result);
218 // TODO(iposva): Do we need to track lock owners?
219}
220
221void Monitor::Exit() {
222 // TODO(iposva): Do we need to track lock owners?
223 int result = pthread_mutex_unlock(data_.mutex());
224 VALIDATE_PTHREAD_RESULT(result);
225}
226
227Monitor::WaitResult Monitor::Wait(int64_t millis) {
229}
230
232 // TODO(iposva): Do we need to track lock owners?
234 if (micros == kNoTimeout) {
235 // Wait forever.
236 int result = pthread_cond_wait(data_.cond(), data_.mutex());
237 VALIDATE_PTHREAD_RESULT(result);
238 } else {
239 struct timespec ts;
240 int64_t secs = micros / kMicrosecondsPerSecond;
241 if (secs > kMaxInt32) {
242 // Avoid truncation of overly large timeout values.
243 secs = kMaxInt32;
244 }
245 int64_t nanos =
247 ts.tv_sec = static_cast<int32_t>(secs);
248 ts.tv_nsec = static_cast<long>(nanos); // NOLINT (long used in timespec).
249 int result =
250 pthread_cond_timedwait_relative_np(data_.cond(), data_.mutex(), &ts);
251 ASSERT((result == 0) || (result == ETIMEDOUT));
252 if (result == ETIMEDOUT) {
253 retval = kTimedOut;
254 }
255 }
256 return retval;
257}
258
259void Monitor::Notify() {
260 // TODO(iposva): Do we need to track lock owners?
261 int result = pthread_cond_signal(data_.cond());
262 VALIDATE_PTHREAD_RESULT(result);
263}
264
265void Monitor::NotifyAll() {
266 // TODO(iposva): Do we need to track lock owners?
267 int result = pthread_cond_broadcast(data_.cond());
268 VALIDATE_PTHREAD_RESULT(result);
269}
270
271} // namespace bin
272} // namespace dart
273
274#endif // defined(DART_HOST_OS_MACOS) && !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 int32_t kMaxInt32
Definition: globals.h:483
constexpr intptr_t kWordSize
Definition: globals.h:509
static int8_t data[kExtLength]
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581