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