Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : // Platform-specific code for POSIX goes here. This is not a platform on its
6 : // own, but contains the parts which are the same across the POSIX platforms
7 : // Linux, MacOS, FreeBSD, OpenBSD, NetBSD and QNX.
8 :
9 : #include <errno.h>
10 : #include <limits.h>
11 : #include <pthread.h>
12 : #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
13 : #include <pthread_np.h> // for pthread_set_name_np
14 : #endif
15 : #include <sched.h> // for sched_yield
16 : #include <stdio.h>
17 : #include <time.h>
18 : #include <unistd.h>
19 :
20 : #include <sys/mman.h>
21 : #include <sys/resource.h>
22 : #include <sys/stat.h>
23 : #include <sys/time.h>
24 : #include <sys/types.h>
25 : #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
26 : defined(__NetBSD__) || defined(__OpenBSD__)
27 : #include <sys/sysctl.h> // NOLINT, for sysctl
28 : #endif
29 :
30 : #undef MAP_TYPE
31 :
32 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
33 : #define LOG_TAG "v8"
34 : #include <android/log.h> // NOLINT
35 : #endif
36 :
37 : #include <cmath>
38 : #include <cstdlib>
39 :
40 : #include "src/base/platform/platform-posix.h"
41 :
42 : #include "src/base/lazy-instance.h"
43 : #include "src/base/macros.h"
44 : #include "src/base/platform/platform.h"
45 : #include "src/base/platform/time.h"
46 : #include "src/base/utils/random-number-generator.h"
47 :
48 : #ifdef V8_FAST_TLS_SUPPORTED
49 : #include "src/base/atomicops.h"
50 : #endif
51 :
52 : #if V8_OS_MACOSX
53 : #include <dlfcn.h>
54 : #endif
55 :
56 : #if V8_OS_LINUX
57 : #include <sys/prctl.h> // NOLINT, for prctl
58 : #endif
59 :
60 : #if !defined(_AIX) && !defined(V8_OS_FUCHSIA)
61 : #include <sys/syscall.h>
62 : #endif
63 :
64 : namespace v8 {
65 : namespace base {
66 :
67 : namespace {
68 :
69 : // 0 is never a valid thread id.
70 : const pthread_t kNoThread = (pthread_t) 0;
71 :
72 : bool g_hard_abort = false;
73 :
74 : const char* g_gc_fake_mmap = nullptr;
75 :
76 : } // namespace
77 :
78 :
79 467382 : int OS::ActivationFrameAlignment() {
80 : #if V8_TARGET_ARCH_ARM
81 : // On EABI ARM targets this is required for fp correctness in the
82 : // runtime system.
83 : return 8;
84 : #elif V8_TARGET_ARCH_MIPS
85 : return 8;
86 : #elif V8_TARGET_ARCH_S390
87 : return 8;
88 : #else
89 : // Otherwise we just assume 16 byte alignment, i.e.:
90 : // - With gcc 4.4 the tree vectorization optimizer can generate code
91 : // that requires 16 byte alignment such as movdqa on x86.
92 : // - Mac OS X, PPC and Solaris (64-bit) activation frames must
93 : // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide"
94 467382 : return 16;
95 : #endif
96 : }
97 :
98 :
99 9921249 : intptr_t OS::CommitPageSize() {
100 9921249 : static intptr_t page_size = getpagesize();
101 9921249 : return page_size;
102 : }
103 :
104 204 : void* OS::Allocate(const size_t requested, size_t* allocated,
105 : bool is_executable, void* hint) {
106 : return OS::Allocate(requested, allocated,
107 : is_executable ? OS::MemoryPermission::kReadWriteExecute
108 : : OS::MemoryPermission::kReadWrite,
109 204 : hint);
110 : }
111 :
112 494813 : void OS::Free(void* address, const size_t size) {
113 : // TODO(1240712): munmap has a return value which is ignored here.
114 494813 : int result = munmap(address, size);
115 : USE(result);
116 : DCHECK_EQ(result, 0);
117 494813 : }
118 :
119 0 : void OS::SetReadAndExecutable(void* address, const size_t size) {
120 : #if V8_OS_CYGWIN
121 : DWORD old_protect;
122 : CHECK_NOT_NULL(
123 : VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect));
124 : #else
125 0 : CHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_EXEC));
126 : #endif
127 0 : }
128 :
129 :
130 : // Create guard pages.
131 : #if !V8_OS_FUCHSIA
132 619866 : void OS::Guard(void* address, const size_t size) {
133 : #if V8_OS_CYGWIN
134 : DWORD oldprotect;
135 : VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect);
136 : #else
137 619866 : mprotect(address, size, PROT_NONE);
138 : #endif
139 619866 : }
140 : #endif // !V8_OS_FUCHSIA
141 :
142 : // Make a region of memory readable and writable.
143 861 : void OS::SetReadAndWritable(void* address, const size_t size, bool commit) {
144 : #if V8_OS_CYGWIN
145 : DWORD oldprotect;
146 : CHECK_NOT_NULL(VirtualProtect(address, size, PAGE_READWRITE, &oldprotect));
147 : #else
148 861 : CHECK_EQ(0, mprotect(address, size, PROT_READ | PROT_WRITE));
149 : #endif
150 861 : }
151 :
152 : static LazyInstance<RandomNumberGenerator>::type
153 : platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;
154 :
155 53977 : void OS::Initialize(int64_t random_seed, bool hard_abort,
156 : const char* const gc_fake_mmap) {
157 53977 : if (random_seed) {
158 53975 : platform_random_number_generator.Pointer()->SetSeed(random_seed);
159 : }
160 53977 : g_hard_abort = hard_abort;
161 53977 : g_gc_fake_mmap = gc_fake_mmap;
162 53977 : }
163 :
164 :
165 0 : const char* OS::GetGCFakeMMapFile() {
166 0 : return g_gc_fake_mmap;
167 : }
168 :
169 917672 : void* OS::GetRandomMmapAddr() {
170 : #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
171 : defined(THREAD_SANITIZER)
172 : // Dynamic tools do not support custom mmap addresses.
173 : return NULL;
174 : #endif
175 : uintptr_t raw_addr;
176 : platform_random_number_generator.Pointer()->NextBytes(&raw_addr,
177 917672 : sizeof(raw_addr));
178 : #if V8_TARGET_ARCH_X64
179 : // Currently available CPUs have 48 bits of virtual addressing. Truncate
180 : // the hint address to 46 bits to give the kernel a fighting chance of
181 : // fulfilling our placement request.
182 917675 : raw_addr &= V8_UINT64_C(0x3ffffffff000);
183 : #elif V8_TARGET_ARCH_PPC64
184 : #if V8_OS_AIX
185 : // AIX: 64 bits of virtual addressing, but we limit address range to:
186 : // a) minimize Segment Lookaside Buffer (SLB) misses and
187 : raw_addr &= V8_UINT64_C(0x3ffff000);
188 : // Use extra address space to isolate the mmap regions.
189 : raw_addr += V8_UINT64_C(0x400000000000);
190 : #elif V8_TARGET_BIG_ENDIAN
191 : // Big-endian Linux: 44 bits of virtual addressing.
192 : raw_addr &= V8_UINT64_C(0x03fffffff000);
193 : #else
194 : // Little-endian Linux: 48 bits of virtual addressing.
195 : raw_addr &= V8_UINT64_C(0x3ffffffff000);
196 : #endif
197 : #elif V8_TARGET_ARCH_S390X
198 : // Linux on Z uses bits 22-32 for Region Indexing, which translates to 42 bits
199 : // of virtual addressing. Truncate to 40 bits to allow kernel chance to
200 : // fulfill request.
201 : raw_addr &= V8_UINT64_C(0xfffffff000);
202 : #elif V8_TARGET_ARCH_S390
203 : // 31 bits of virtual addressing. Truncate to 29 bits to allow kernel chance
204 : // to fulfill request.
205 : raw_addr &= 0x1ffff000;
206 : #else
207 : raw_addr &= 0x3ffff000;
208 :
209 : #ifdef __sun
210 : // For our Solaris/illumos mmap hint, we pick a random address in the bottom
211 : // half of the top half of the address space (that is, the third quarter).
212 : // Because we do not MAP_FIXED, this will be treated only as a hint -- the
213 : // system will not fail to mmap() because something else happens to already
214 : // be mapped at our random address. We deliberately set the hint high enough
215 : // to get well above the system's break (that is, the heap); Solaris and
216 : // illumos will try the hint and if that fails allocate as if there were
217 : // no hint at all. The high hint prevents the break from getting hemmed in
218 : // at low values, ceding half of the address space to the system heap.
219 : raw_addr += 0x80000000;
220 : #elif V8_OS_AIX
221 : // The range 0x30000000 - 0xD0000000 is available on AIX;
222 : // choose the upper range.
223 : raw_addr += 0x90000000;
224 : #else
225 : // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
226 : // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
227 : // 10.6 and 10.7.
228 : raw_addr += 0x20000000;
229 : #endif
230 : #endif
231 917675 : return reinterpret_cast<void*>(raw_addr);
232 : }
233 :
234 1047886 : size_t OS::AllocateAlignment() {
235 1047886 : return static_cast<size_t>(sysconf(_SC_PAGESIZE));
236 : }
237 :
238 :
239 50925 : void OS::Sleep(TimeDelta interval) {
240 50925 : usleep(static_cast<useconds_t>(interval.InMicroseconds()));
241 50925 : }
242 :
243 :
244 0 : void OS::Abort() {
245 0 : if (g_hard_abort) {
246 0 : V8_IMMEDIATE_CRASH();
247 : }
248 : // Redirect to std abort to signal abnormal program termination.
249 0 : abort();
250 : }
251 :
252 :
253 0 : void OS::DebugBreak() {
254 : #if V8_HOST_ARCH_ARM
255 : asm("bkpt 0");
256 : #elif V8_HOST_ARCH_ARM64
257 : asm("brk 0");
258 : #elif V8_HOST_ARCH_MIPS
259 : asm("break");
260 : #elif V8_HOST_ARCH_MIPS64
261 : asm("break");
262 : #elif V8_HOST_ARCH_PPC
263 : asm("twge 2,2");
264 : #elif V8_HOST_ARCH_IA32
265 : asm("int $3");
266 : #elif V8_HOST_ARCH_X64
267 0 : asm("int $3");
268 : #elif V8_HOST_ARCH_S390
269 : // Software breakpoint instruction is 0x0001
270 : asm volatile(".word 0x0001");
271 : #else
272 : #error Unsupported host architecture.
273 : #endif
274 0 : }
275 :
276 :
277 : class PosixMemoryMappedFile final : public OS::MemoryMappedFile {
278 : public:
279 : PosixMemoryMappedFile(FILE* file, void* memory, size_t size)
280 0 : : file_(file), memory_(memory), size_(size) {}
281 : ~PosixMemoryMappedFile() final;
282 0 : void* memory() const final { return memory_; }
283 0 : size_t size() const final { return size_; }
284 :
285 : private:
286 : FILE* const file_;
287 : void* const memory_;
288 : size_t const size_;
289 : };
290 :
291 :
292 : // static
293 0 : OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
294 0 : if (FILE* file = fopen(name, "r+")) {
295 0 : if (fseek(file, 0, SEEK_END) == 0) {
296 0 : long size = ftell(file); // NOLINT(runtime/int)
297 0 : if (size >= 0) {
298 : void* const memory =
299 : mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_WRITE,
300 0 : MAP_SHARED, fileno(file), 0);
301 0 : if (memory != MAP_FAILED) {
302 0 : return new PosixMemoryMappedFile(file, memory, size);
303 : }
304 : }
305 : }
306 0 : fclose(file);
307 : }
308 : return nullptr;
309 : }
310 :
311 :
312 : // static
313 0 : OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name,
314 : size_t size, void* initial) {
315 0 : if (FILE* file = fopen(name, "w+")) {
316 0 : size_t result = fwrite(initial, 1, size, file);
317 0 : if (result == size && !ferror(file)) {
318 : void* memory = mmap(OS::GetRandomMmapAddr(), result,
319 0 : PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
320 0 : if (memory != MAP_FAILED) {
321 0 : return new PosixMemoryMappedFile(file, memory, result);
322 : }
323 : }
324 0 : fclose(file);
325 : }
326 : return nullptr;
327 : }
328 :
329 :
330 0 : PosixMemoryMappedFile::~PosixMemoryMappedFile() {
331 0 : if (memory_) OS::Free(memory_, size_);
332 0 : fclose(file_);
333 0 : }
334 :
335 :
336 87459 : int OS::GetCurrentProcessId() {
337 87459 : return static_cast<int>(getpid());
338 : }
339 :
340 :
341 941 : int OS::GetCurrentThreadId() {
342 : #if V8_OS_MACOSX || (V8_OS_ANDROID && defined(__APPLE__))
343 : return static_cast<int>(pthread_mach_thread_np(pthread_self()));
344 : #elif V8_OS_LINUX
345 941 : return static_cast<int>(syscall(__NR_gettid));
346 : #elif V8_OS_ANDROID
347 : return static_cast<int>(gettid());
348 : #elif V8_OS_AIX
349 : return static_cast<int>(thread_self());
350 : #elif V8_OS_FUCHSIA
351 : return static_cast<int>(pthread_self());
352 : #elif V8_OS_SOLARIS
353 : return static_cast<int>(pthread_self());
354 : #else
355 : return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self()));
356 : #endif
357 : }
358 :
359 :
360 : // ----------------------------------------------------------------------------
361 : // POSIX date/time support.
362 : //
363 :
364 2 : int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
365 : struct rusage usage;
366 :
367 2 : if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
368 2 : *secs = static_cast<uint32_t>(usage.ru_utime.tv_sec);
369 2 : *usecs = static_cast<uint32_t>(usage.ru_utime.tv_usec);
370 2 : return 0;
371 : }
372 :
373 :
374 184368 : double OS::TimeCurrentMillis() {
375 184368 : return Time::Now().ToJsTime();
376 : }
377 :
378 21793 : double PosixTimezoneCache::DaylightSavingsOffset(double time) {
379 21793 : if (std::isnan(time)) return std::numeric_limits<double>::quiet_NaN();
380 21793 : time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
381 : struct tm tm;
382 21793 : struct tm* t = localtime_r(&tv, &tm);
383 21793 : if (nullptr == t) return std::numeric_limits<double>::quiet_NaN();
384 21793 : return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
385 : }
386 :
387 :
388 18 : int OS::GetLastError() {
389 18 : return errno;
390 : }
391 :
392 :
393 : // ----------------------------------------------------------------------------
394 : // POSIX stdio support.
395 : //
396 :
397 1733 : FILE* OS::FOpen(const char* path, const char* mode) {
398 1733 : FILE* file = fopen(path, mode);
399 1733 : if (file == nullptr) return nullptr;
400 : struct stat file_stat;
401 3466 : if (fstat(fileno(file), &file_stat) != 0) {
402 0 : fclose(file);
403 0 : return nullptr;
404 : }
405 1733 : bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
406 1733 : if (is_regular_file) return file;
407 0 : fclose(file);
408 0 : return nullptr;
409 : }
410 :
411 :
412 0 : bool OS::Remove(const char* path) {
413 0 : return (remove(path) == 0);
414 : }
415 :
416 0 : char OS::DirectorySeparator() { return '/'; }
417 :
418 1491275 : bool OS::isDirectorySeparator(const char ch) {
419 1491275 : return ch == DirectorySeparator();
420 : }
421 :
422 :
423 21 : FILE* OS::OpenTemporaryFile() {
424 21 : return tmpfile();
425 : }
426 :
427 :
428 : const char* const OS::LogFileOpenMode = "w";
429 :
430 :
431 2412 : void OS::Print(const char* format, ...) {
432 : va_list args;
433 2412 : va_start(args, format);
434 : VPrint(format, args);
435 2412 : va_end(args);
436 2412 : }
437 :
438 :
439 9441 : void OS::VPrint(const char* format, va_list args) {
440 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
441 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
442 : #else
443 : vprintf(format, args);
444 : #endif
445 9441 : }
446 :
447 :
448 0 : void OS::FPrint(FILE* out, const char* format, ...) {
449 : va_list args;
450 0 : va_start(args, format);
451 : VFPrint(out, format, args);
452 0 : va_end(args);
453 0 : }
454 :
455 :
456 3182225 : void OS::VFPrint(FILE* out, const char* format, va_list args) {
457 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
458 : __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
459 : #else
460 : vfprintf(out, format, args);
461 : #endif
462 3182225 : }
463 :
464 :
465 2335 : void OS::PrintError(const char* format, ...) {
466 : va_list args;
467 2335 : va_start(args, format);
468 : VPrintError(format, args);
469 2335 : va_end(args);
470 2335 : }
471 :
472 :
473 0 : void OS::VPrintError(const char* format, va_list args) {
474 : #if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
475 : __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
476 : #else
477 2335 : vfprintf(stderr, format, args);
478 : #endif
479 0 : }
480 :
481 :
482 2392850 : int OS::SNPrintF(char* str, int length, const char* format, ...) {
483 : va_list args;
484 2392850 : va_start(args, format);
485 2392850 : int result = VSNPrintF(str, length, format, args);
486 2392850 : va_end(args);
487 2392850 : return result;
488 : }
489 :
490 :
491 6361281 : int OS::VSNPrintF(char* str,
492 : int length,
493 : const char* format,
494 : va_list args) {
495 6361281 : int n = vsnprintf(str, length, format, args);
496 6361281 : if (n < 0 || n >= length) {
497 : // If the length is zero, the assignment fails.
498 124625 : if (length > 0)
499 124625 : str[length - 1] = '\0';
500 : return -1;
501 : } else {
502 : return n;
503 : }
504 : }
505 :
506 :
507 : // ----------------------------------------------------------------------------
508 : // POSIX string support.
509 : //
510 :
511 0 : char* OS::StrChr(char* str, int c) {
512 0 : return strchr(str, c);
513 : }
514 :
515 :
516 7619 : void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
517 : strncpy(dest, src, n);
518 7619 : }
519 :
520 :
521 : // ----------------------------------------------------------------------------
522 : // POSIX thread support.
523 : //
524 :
525 434134 : class Thread::PlatformData {
526 : public:
527 442224 : PlatformData() : thread_(kNoThread) {}
528 : pthread_t thread_; // Thread handle for pthread.
529 : // Synchronizes thread creation
530 : Mutex thread_creation_mutex_;
531 : };
532 :
533 1326670 : Thread::Thread(const Options& options)
534 : : data_(new PlatformData),
535 : stack_size_(options.stack_size()),
536 1326670 : start_semaphore_(nullptr) {
537 442223 : if (stack_size_ > 0 && static_cast<size_t>(stack_size_) < PTHREAD_STACK_MIN) {
538 0 : stack_size_ = PTHREAD_STACK_MIN;
539 : }
540 : set_name(options.name());
541 442223 : }
542 :
543 :
544 434134 : Thread::~Thread() {
545 868268 : delete data_;
546 434134 : }
547 :
548 :
549 : static void SetThreadName(const char* name) {
550 : #if V8_OS_DRAGONFLYBSD || V8_OS_FREEBSD || V8_OS_OPENBSD
551 : pthread_set_name_np(pthread_self(), name);
552 : #elif V8_OS_NETBSD
553 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
554 : pthread_setname_np(pthread_self(), "%s", name);
555 : #elif V8_OS_MACOSX
556 : // pthread_setname_np is only available in 10.6 or later, so test
557 : // for it at runtime.
558 : int (*dynamic_pthread_setname_np)(const char*);
559 : *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
560 : dlsym(RTLD_DEFAULT, "pthread_setname_np");
561 : if (dynamic_pthread_setname_np == nullptr) return;
562 :
563 : // Mac OS X does not expose the length limit of the name, so hardcode it.
564 : static const int kMaxNameLength = 63;
565 : STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
566 : dynamic_pthread_setname_np(name);
567 : #elif defined(PR_SET_NAME)
568 : prctl(PR_SET_NAME,
569 : reinterpret_cast<unsigned long>(name), // NOLINT
570 386972 : 0, 0, 0);
571 : #endif
572 : }
573 :
574 :
575 386635 : static void* ThreadEntry(void* arg) {
576 386635 : Thread* thread = reinterpret_cast<Thread*>(arg);
577 : // We take the lock here to make sure that pthread_create finished first since
578 : // we don't know which thread will run first (the original thread or the new
579 : // one).
580 386635 : { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
581 386972 : SetThreadName(thread->name());
582 : DCHECK_NE(thread->data()->thread_, kNoThread);
583 386458 : thread->NotifyStartedAndRun();
584 381223 : return nullptr;
585 : }
586 :
587 :
588 0 : void Thread::set_name(const char* name) {
589 442223 : strncpy(name_, name, sizeof(name_));
590 442223 : name_[sizeof(name_) - 1] = '\0';
591 0 : }
592 :
593 :
594 387225 : void Thread::Start() {
595 : int result;
596 : pthread_attr_t attr;
597 : memset(&attr, 0, sizeof(attr));
598 387225 : result = pthread_attr_init(&attr);
599 : DCHECK_EQ(0, result);
600 387225 : size_t stack_size = stack_size_;
601 : if (stack_size == 0) {
602 : #if V8_OS_MACOSX
603 : // Default on Mac OS X is 512kB -- bump up to 1MB
604 : stack_size = 1 * 1024 * 1024;
605 : #elif V8_OS_AIX
606 : // Default on AIX is 96kB -- bump up to 2MB
607 : stack_size = 2 * 1024 * 1024;
608 : #endif
609 : }
610 387225 : if (stack_size > 0) {
611 275 : result = pthread_attr_setstacksize(&attr, stack_size);
612 : DCHECK_EQ(0, result);
613 : }
614 : {
615 387225 : LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
616 387225 : result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
617 : }
618 : DCHECK_EQ(0, result);
619 387225 : result = pthread_attr_destroy(&attr);
620 : DCHECK_EQ(0, result);
621 : DCHECK_NE(data_->thread_, kNoThread);
622 : USE(result);
623 387225 : }
624 :
625 383802 : void Thread::Join() { pthread_join(data_->thread_, nullptr); }
626 :
627 : static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
628 : #if V8_OS_CYGWIN
629 : // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
630 : // because pthread_key_t is a pointer type on Cygwin. This will probably not
631 : // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
632 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
633 : intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
634 : return static_cast<Thread::LocalStorageKey>(ptr_key);
635 : #else
636 161963 : return static_cast<Thread::LocalStorageKey>(pthread_key);
637 : #endif
638 : }
639 :
640 :
641 : static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
642 : #if V8_OS_CYGWIN
643 : STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
644 : intptr_t ptr_key = static_cast<intptr_t>(local_key);
645 : return reinterpret_cast<pthread_key_t>(ptr_key);
646 : #else
647 5650539 : return static_cast<pthread_key_t>(local_key);
648 : #endif
649 : }
650 :
651 :
652 : #ifdef V8_FAST_TLS_SUPPORTED
653 :
654 : static Atomic32 tls_base_offset_initialized = 0;
655 : intptr_t kMacTlsBaseOffset = 0;
656 :
657 : // It's safe to do the initialization more that once, but it has to be
658 : // done at least once.
659 : static void InitializeTlsBaseOffset() {
660 : const size_t kBufferSize = 128;
661 : char buffer[kBufferSize];
662 : size_t buffer_size = kBufferSize;
663 : int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
664 : if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
665 : V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
666 : }
667 : // The buffer now contains a string of the form XX.YY.ZZ, where
668 : // XX is the major kernel version component.
669 : // Make sure the buffer is 0-terminated.
670 : buffer[kBufferSize - 1] = '\0';
671 : char* period_pos = strchr(buffer, '.');
672 : *period_pos = '\0';
673 : int kernel_version_major =
674 : static_cast<int>(strtol(buffer, nullptr, 10)); // NOLINT
675 : // The constants below are taken from pthreads.s from the XNU kernel
676 : // sources archive at www.opensource.apple.com.
677 : if (kernel_version_major < 11) {
678 : // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
679 : // same offsets.
680 : #if V8_HOST_ARCH_IA32
681 : kMacTlsBaseOffset = 0x48;
682 : #else
683 : kMacTlsBaseOffset = 0x60;
684 : #endif
685 : } else {
686 : // 11.x.x (Lion) changed the offset.
687 : kMacTlsBaseOffset = 0;
688 : }
689 :
690 : Release_Store(&tls_base_offset_initialized, 1);
691 : }
692 :
693 :
694 : static void CheckFastTls(Thread::LocalStorageKey key) {
695 : void* expected = reinterpret_cast<void*>(0x1234CAFE);
696 : Thread::SetThreadLocal(key, expected);
697 : void* actual = Thread::GetExistingThreadLocal(key);
698 : if (expected != actual) {
699 : V8_Fatal(__FILE__, __LINE__,
700 : "V8 failed to initialize fast TLS on current kernel");
701 : }
702 : Thread::SetThreadLocal(key, nullptr);
703 : }
704 :
705 : #endif // V8_FAST_TLS_SUPPORTED
706 :
707 :
708 161963 : Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
709 : #ifdef V8_FAST_TLS_SUPPORTED
710 : bool check_fast_tls = false;
711 : if (tls_base_offset_initialized == 0) {
712 : check_fast_tls = true;
713 : InitializeTlsBaseOffset();
714 : }
715 : #endif
716 : pthread_key_t key;
717 161963 : int result = pthread_key_create(&key, nullptr);
718 : DCHECK_EQ(0, result);
719 : USE(result);
720 161963 : LocalStorageKey local_key = PthreadKeyToLocalKey(key);
721 : #ifdef V8_FAST_TLS_SUPPORTED
722 : // If we just initialized fast TLS support, make sure it works.
723 : if (check_fast_tls) CheckFastTls(local_key);
724 : #endif
725 161963 : return local_key;
726 : }
727 :
728 :
729 32 : void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
730 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
731 32 : int result = pthread_key_delete(pthread_key);
732 : DCHECK_EQ(0, result);
733 : USE(result);
734 32 : }
735 :
736 :
737 4660842 : void* Thread::GetThreadLocal(LocalStorageKey key) {
738 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
739 4660842 : return pthread_getspecific(pthread_key);
740 : }
741 :
742 :
743 989665 : void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
744 : pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
745 989665 : int result = pthread_setspecific(pthread_key, value);
746 : DCHECK_EQ(0, result);
747 : USE(result);
748 989618 : }
749 :
750 207 : int GetProtectionFromMemoryPermission(OS::MemoryPermission access) {
751 207 : switch (access) {
752 : case OS::MemoryPermission::kNoAccess:
753 : return PROT_NONE;
754 : case OS::MemoryPermission::kReadWrite:
755 1 : return PROT_READ | PROT_WRITE;
756 : case OS::MemoryPermission::kReadWriteExecute:
757 205 : return PROT_READ | PROT_WRITE | PROT_EXEC;
758 : }
759 0 : UNREACHABLE();
760 : }
761 :
762 : } // namespace base
763 : } // namespace v8
|