1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Platform specific code for POSIX goes here. This is not a platform on its
29// own but contains the parts which are the same across POSIX platforms Linux,
30// Mac OS, FreeBSD and OpenBSD.
31
32#include "platform-posix.h"
33
34#include <dlfcn.h>
35#include <pthread.h>
36#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
37#include <pthread_np.h>  // for pthread_set_name_np
38#endif
39#include <sched.h>  // for sched_yield
40#include <unistd.h>
41#include <errno.h>
42#include <time.h>
43
44#include <sys/mman.h>
45#include <sys/socket.h>
46#include <sys/resource.h>
47#include <sys/time.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#if defined(__linux__)
51#include <sys/prctl.h>  // for prctl
52#endif
53#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
54    defined(__NetBSD__) || defined(__OpenBSD__)
55#include <sys/sysctl.h>  // for sysctl
56#endif
57
58#include <arpa/inet.h>
59#include <netinet/in.h>
60#include <netdb.h>
61
62#undef MAP_TYPE
63
64#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
65#define LOG_TAG "v8"
66#include <android/log.h>
67#endif
68
69#include "v8.h"
70
71#include "codegen.h"
72#include "platform.h"
73
74namespace v8 {
75namespace internal {
76
77// 0 is never a valid thread id.
78static const pthread_t kNoThread = (pthread_t) 0;
79
80
81uint64_t OS::CpuFeaturesImpliedByPlatform() {
82#if defined(__APPLE__)
83  // Mac OS X requires all these to install so we can assume they are present.
84  // These constants are defined by the CPUid instructions.
85  const uint64_t one = 1;
86  return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID);
87#else
88  return 0;  // Nothing special about the other systems.
89#endif
90}
91
92
93// Maximum size of the virtual memory.  0 means there is no artificial
94// limit.
95
96intptr_t OS::MaxVirtualMemory() {
97  struct rlimit limit;
98  int result = getrlimit(RLIMIT_DATA, &limit);
99  if (result != 0) return 0;
100  return limit.rlim_cur;
101}
102
103
104int OS::ActivationFrameAlignment() {
105#if V8_TARGET_ARCH_ARM
106  // On EABI ARM targets this is required for fp correctness in the
107  // runtime system.
108  return 8;
109#elif V8_TARGET_ARCH_MIPS
110  return 8;
111#else
112  // Otherwise we just assume 16 byte alignment, i.e.:
113  // - With gcc 4.4 the tree vectorization optimizer can generate code
114  //   that requires 16 byte alignment such as movdqa on x86.
115  // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned;
116  //   see "Mac OS X ABI Function Call Guide"
117  return 16;
118#endif
119}
120
121
122intptr_t OS::CommitPageSize() {
123  static intptr_t page_size = getpagesize();
124  return page_size;
125}
126
127
128void OS::Free(void* address, const size_t size) {
129  // TODO(1240712): munmap has a return value which is ignored here.
130  int result = munmap(address, size);
131  USE(result);
132  ASSERT(result == 0);
133}
134
135
136// Get rid of writable permission on code allocations.
137void OS::ProtectCode(void* address, const size_t size) {
138#if defined(__CYGWIN__)
139  DWORD old_protect;
140  VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect);
141#elif defined(__native_client__)
142  // The Native Client port of V8 uses an interpreter, so
143  // code pages don't need PROT_EXEC.
144  mprotect(address, size, PROT_READ);
145#else
146  mprotect(address, size, PROT_READ | PROT_EXEC);
147#endif
148}
149
150
151// Create guard pages.
152void OS::Guard(void* address, const size_t size) {
153#if defined(__CYGWIN__)
154  DWORD oldprotect;
155  VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
156#else
157  mprotect(address, size, PROT_NONE);
158#endif
159}
160
161
162void* OS::GetRandomMmapAddr() {
163#if defined(__native_client__)
164  // TODO(bradchen): restore randomization once Native Client gets
165  // smarter about using mmap address hints.
166  // See http://code.google.com/p/nativeclient/issues/3341
167  return NULL;
168#endif
169  Isolate* isolate = Isolate::UncheckedCurrent();
170  // Note that the current isolate isn't set up in a call path via
171  // CpuFeatures::Probe. We don't care about randomization in this case because
172  // the code page is immediately freed.
173  if (isolate != NULL) {
174#if V8_TARGET_ARCH_X64
175    uint64_t rnd1 = V8::RandomPrivate(isolate);
176    uint64_t rnd2 = V8::RandomPrivate(isolate);
177    uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
178    // Currently available CPUs have 48 bits of virtual addressing.  Truncate
179    // the hint address to 46 bits to give the kernel a fighting chance of
180    // fulfilling our placement request.
181    raw_addr &= V8_UINT64_C(0x3ffffffff000);
182#else
183    uint32_t raw_addr = V8::RandomPrivate(isolate);
184
185    raw_addr &= 0x3ffff000;
186
187# ifdef __sun
188    // For our Solaris/illumos mmap hint, we pick a random address in the bottom
189    // half of the top half of the address space (that is, the third quarter).
190    // Because we do not MAP_FIXED, this will be treated only as a hint -- the
191    // system will not fail to mmap() because something else happens to already
192    // be mapped at our random address. We deliberately set the hint high enough
193    // to get well above the system's break (that is, the heap); Solaris and
194    // illumos will try the hint and if that fails allocate as if there were
195    // no hint at all. The high hint prevents the break from getting hemmed in
196    // at low values, ceding half of the address space to the system heap.
197    raw_addr += 0x80000000;
198# else
199    // The range 0x20000000 - 0x60000000 is relatively unpopulated across a
200    // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos
201    // 10.6 and 10.7.
202    raw_addr += 0x20000000;
203# endif
204#endif
205    return reinterpret_cast<void*>(raw_addr);
206  }
207  return NULL;
208}
209
210
211size_t OS::AllocateAlignment() {
212  return getpagesize();
213}
214
215
216void OS::Sleep(int milliseconds) {
217  useconds_t ms = static_cast<useconds_t>(milliseconds);
218  usleep(1000 * ms);
219}
220
221
222int OS::NumberOfCores() {
223  return sysconf(_SC_NPROCESSORS_ONLN);
224}
225
226
227void OS::Abort() {
228  // Redirect to std abort to signal abnormal program termination.
229  if (FLAG_break_on_abort) {
230    DebugBreak();
231  }
232  abort();
233}
234
235
236void OS::DebugBreak() {
237#if V8_HOST_ARCH_ARM
238  asm("bkpt 0");
239#elif V8_HOST_ARCH_MIPS
240  asm("break");
241#elif V8_HOST_ARCH_IA32
242#if defined(__native_client__)
243  asm("hlt");
244#else
245  asm("int $3");
246#endif  // __native_client__
247#elif V8_HOST_ARCH_X64
248  asm("int $3");
249#else
250#error Unsupported host architecture.
251#endif
252}
253
254
255// ----------------------------------------------------------------------------
256// Math functions
257
258double ceiling(double x) {
259  // Correct buggy 'ceil' on some systems (i.e. FreeBSD, OS X 10.5)
260  return (-1.0 < x && x < 0.0) ? -0.0 : ceil(x);
261}
262
263
264double modulo(double x, double y) {
265  return fmod(x, y);
266}
267
268
269#define UNARY_MATH_FUNCTION(name, generator)             \
270static UnaryMathFunction fast_##name##_function = NULL;  \
271void init_fast_##name##_function() {                     \
272  fast_##name##_function = generator;                    \
273}                                                        \
274double fast_##name(double x) {                           \
275  return (*fast_##name##_function)(x);                   \
276}
277
278UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN))
279UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS))
280UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN))
281UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG))
282UNARY_MATH_FUNCTION(exp, CreateExpFunction())
283UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
284
285#undef UNARY_MATH_FUNCTION
286
287
288void lazily_initialize_fast_exp() {
289  if (fast_exp_function == NULL) {
290    init_fast_exp_function();
291  }
292}
293
294
295double OS::nan_value() {
296  // NAN from math.h is defined in C99 and not in POSIX.
297  return NAN;
298}
299
300
301int OS::GetCurrentProcessId() {
302  return static_cast<int>(getpid());
303}
304
305
306// ----------------------------------------------------------------------------
307// POSIX date/time support.
308//
309
310int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
311  struct rusage usage;
312
313  if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
314  *secs = usage.ru_utime.tv_sec;
315  *usecs = usage.ru_utime.tv_usec;
316  return 0;
317}
318
319
320double OS::TimeCurrentMillis() {
321  struct timeval tv;
322  if (gettimeofday(&tv, NULL) < 0) return 0.0;
323  return (static_cast<double>(tv.tv_sec) * 1000) +
324         (static_cast<double>(tv.tv_usec) / 1000);
325}
326
327
328int64_t OS::Ticks() {
329  // gettimeofday has microsecond resolution.
330  struct timeval tv;
331  if (gettimeofday(&tv, NULL) < 0)
332    return 0;
333  return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
334}
335
336
337double OS::DaylightSavingsOffset(double time) {
338  if (std::isnan(time)) return nan_value();
339  time_t tv = static_cast<time_t>(floor(time/msPerSecond));
340  struct tm* t = localtime(&tv);
341  if (NULL == t) return nan_value();
342  return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
343}
344
345
346int OS::GetLastError() {
347  return errno;
348}
349
350
351// ----------------------------------------------------------------------------
352// POSIX stdio support.
353//
354
355FILE* OS::FOpen(const char* path, const char* mode) {
356  FILE* file = fopen(path, mode);
357  if (file == NULL) return NULL;
358  struct stat file_stat;
359  if (fstat(fileno(file), &file_stat) != 0) return NULL;
360  bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
361  if (is_regular_file) return file;
362  fclose(file);
363  return NULL;
364}
365
366
367bool OS::Remove(const char* path) {
368  return (remove(path) == 0);
369}
370
371
372FILE* OS::OpenTemporaryFile() {
373  return tmpfile();
374}
375
376
377const char* const OS::LogFileOpenMode = "w";
378
379
380void OS::Print(const char* format, ...) {
381  va_list args;
382  va_start(args, format);
383  VPrint(format, args);
384  va_end(args);
385}
386
387
388void OS::VPrint(const char* format, va_list args) {
389#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
390  __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
391#else
392  vprintf(format, args);
393#endif
394}
395
396
397void OS::FPrint(FILE* out, const char* format, ...) {
398  va_list args;
399  va_start(args, format);
400  VFPrint(out, format, args);
401  va_end(args);
402}
403
404
405void OS::VFPrint(FILE* out, const char* format, va_list args) {
406#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
407  __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args);
408#else
409  vfprintf(out, format, args);
410#endif
411}
412
413
414void OS::PrintError(const char* format, ...) {
415  va_list args;
416  va_start(args, format);
417  VPrintError(format, args);
418  va_end(args);
419}
420
421
422void OS::VPrintError(const char* format, va_list args) {
423#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT)
424  __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
425#else
426  vfprintf(stderr, format, args);
427#endif
428}
429
430
431int OS::SNPrintF(Vector<char> str, const char* format, ...) {
432  va_list args;
433  va_start(args, format);
434  int result = VSNPrintF(str, format, args);
435  va_end(args);
436  return result;
437}
438
439
440int OS::VSNPrintF(Vector<char> str,
441                  const char* format,
442                  va_list args) {
443  int n = vsnprintf(str.start(), str.length(), format, args);
444  if (n < 0 || n >= str.length()) {
445    // If the length is zero, the assignment fails.
446    if (str.length() > 0)
447      str[str.length() - 1] = '\0';
448    return -1;
449  } else {
450    return n;
451  }
452}
453
454
455#if V8_TARGET_ARCH_IA32
456static void MemMoveWrapper(void* dest, const void* src, size_t size) {
457  memmove(dest, src, size);
458}
459
460
461// Initialize to library version so we can call this at any time during startup.
462static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
463
464// Defined in codegen-ia32.cc.
465OS::MemMoveFunction CreateMemMoveFunction();
466
467// Copy memory area. No restrictions.
468void OS::MemMove(void* dest, const void* src, size_t size) {
469  if (size == 0) return;
470  // Note: here we rely on dependent reads being ordered. This is true
471  // on all architectures we currently support.
472  (*memmove_function)(dest, src, size);
473}
474
475#elif defined(V8_HOST_ARCH_ARM)
476void OS::MemCopyUint16Uint8Wrapper(uint16_t* dest,
477                               const uint8_t* src,
478                               size_t chars) {
479  uint16_t *limit = dest + chars;
480  while (dest < limit) {
481    *dest++ = static_cast<uint16_t>(*src++);
482  }
483}
484
485
486OS::MemCopyUint8Function OS::memcopy_uint8_function = &OS::MemCopyUint8Wrapper;
487OS::MemCopyUint16Uint8Function OS::memcopy_uint16_uint8_function =
488    &OS::MemCopyUint16Uint8Wrapper;
489// Defined in codegen-arm.cc.
490OS::MemCopyUint8Function CreateMemCopyUint8Function(
491    OS::MemCopyUint8Function stub);
492OS::MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
493    OS::MemCopyUint16Uint8Function stub);
494#endif
495
496
497void OS::PostSetUp() {
498#if V8_TARGET_ARCH_IA32
499  OS::MemMoveFunction generated_memmove = CreateMemMoveFunction();
500  if (generated_memmove != NULL) {
501    memmove_function = generated_memmove;
502  }
503#elif defined(V8_HOST_ARCH_ARM)
504  OS::memcopy_uint8_function =
505      CreateMemCopyUint8Function(&OS::MemCopyUint8Wrapper);
506  OS::memcopy_uint16_uint8_function =
507      CreateMemCopyUint16Uint8Function(&OS::MemCopyUint16Uint8Wrapper);
508#endif
509  init_fast_sin_function();
510  init_fast_cos_function();
511  init_fast_tan_function();
512  init_fast_log_function();
513  // fast_exp is initialized lazily.
514  init_fast_sqrt_function();
515}
516
517
518// ----------------------------------------------------------------------------
519// POSIX string support.
520//
521
522char* OS::StrChr(char* str, int c) {
523  return strchr(str, c);
524}
525
526
527void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
528  strncpy(dest.start(), src, n);
529}
530
531
532// ----------------------------------------------------------------------------
533// POSIX thread support.
534//
535
536class Thread::PlatformData : public Malloced {
537 public:
538  PlatformData() : thread_(kNoThread) {}
539  pthread_t thread_;  // Thread handle for pthread.
540};
541
542Thread::Thread(const Options& options)
543    : data_(new PlatformData),
544      stack_size_(options.stack_size()),
545      start_semaphore_(NULL) {
546  set_name(options.name());
547}
548
549
550Thread::~Thread() {
551  delete data_;
552}
553
554
555static void SetThreadName(const char* name) {
556#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
557  pthread_set_name_np(pthread_self(), name);
558#elif defined(__NetBSD__)
559  STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP);
560  pthread_setname_np(pthread_self(), "%s", name);
561#elif defined(__APPLE__)
562  // pthread_setname_np is only available in 10.6 or later, so test
563  // for it at runtime.
564  int (*dynamic_pthread_setname_np)(const char*);
565  *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
566    dlsym(RTLD_DEFAULT, "pthread_setname_np");
567  if (dynamic_pthread_setname_np == NULL)
568    return;
569
570  // Mac OS X does not expose the length limit of the name, so hardcode it.
571  static const int kMaxNameLength = 63;
572  STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
573  dynamic_pthread_setname_np(name);
574#elif defined(PR_SET_NAME)
575  prctl(PR_SET_NAME,
576        reinterpret_cast<unsigned long>(name),  // NOLINT
577        0, 0, 0);
578#endif
579}
580
581
582static void* ThreadEntry(void* arg) {
583  Thread* thread = reinterpret_cast<Thread*>(arg);
584  // This is also initialized by the first argument to pthread_create() but we
585  // don't know which thread will run first (the original thread or the new
586  // one) so we initialize it here too.
587  thread->data()->thread_ = pthread_self();
588  SetThreadName(thread->name());
589  ASSERT(thread->data()->thread_ != kNoThread);
590  thread->NotifyStartedAndRun();
591  return NULL;
592}
593
594
595void Thread::set_name(const char* name) {
596  strncpy(name_, name, sizeof(name_));
597  name_[sizeof(name_) - 1] = '\0';
598}
599
600
601void Thread::Start() {
602  int result;
603  pthread_attr_t attr;
604  memset(&attr, 0, sizeof(attr));
605  result = pthread_attr_init(&attr);
606  ASSERT_EQ(0, result);
607  // Native client uses default stack size.
608#if !defined(__native_client__)
609  if (stack_size_ > 0) {
610    result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
611    ASSERT_EQ(0, result);
612  }
613#endif
614  result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
615  ASSERT_EQ(0, result);
616  result = pthread_attr_destroy(&attr);
617  ASSERT_EQ(0, result);
618  ASSERT(data_->thread_ != kNoThread);
619  USE(result);
620}
621
622
623void Thread::Join() {
624  pthread_join(data_->thread_, NULL);
625}
626
627
628void Thread::YieldCPU() {
629  int result = sched_yield();
630  ASSERT_EQ(0, result);
631  USE(result);
632}
633
634
635static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) {
636#if defined(__CYGWIN__)
637  // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
638  // because pthread_key_t is a pointer type on Cygwin. This will probably not
639  // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
640  STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
641  intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
642  return static_cast<Thread::LocalStorageKey>(ptr_key);
643#else
644  return static_cast<Thread::LocalStorageKey>(pthread_key);
645#endif
646}
647
648
649static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) {
650#if defined(__CYGWIN__)
651  STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
652  intptr_t ptr_key = static_cast<intptr_t>(local_key);
653  return reinterpret_cast<pthread_key_t>(ptr_key);
654#else
655  return static_cast<pthread_key_t>(local_key);
656#endif
657}
658
659
660#ifdef V8_FAST_TLS_SUPPORTED
661
662static Atomic32 tls_base_offset_initialized = 0;
663intptr_t kMacTlsBaseOffset = 0;
664
665// It's safe to do the initialization more that once, but it has to be
666// done at least once.
667static void InitializeTlsBaseOffset() {
668  const size_t kBufferSize = 128;
669  char buffer[kBufferSize];
670  size_t buffer_size = kBufferSize;
671  int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
672  if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) {
673    V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
674  }
675  // The buffer now contains a string of the form XX.YY.ZZ, where
676  // XX is the major kernel version component.
677  // Make sure the buffer is 0-terminated.
678  buffer[kBufferSize - 1] = '\0';
679  char* period_pos = strchr(buffer, '.');
680  *period_pos = '\0';
681  int kernel_version_major =
682      static_cast<int>(strtol(buffer, NULL, 10));  // NOLINT
683  // The constants below are taken from pthreads.s from the XNU kernel
684  // sources archive at www.opensource.apple.com.
685  if (kernel_version_major < 11) {
686    // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the
687    // same offsets.
688#if V8_HOST_ARCH_IA32
689    kMacTlsBaseOffset = 0x48;
690#else
691    kMacTlsBaseOffset = 0x60;
692#endif
693  } else {
694    // 11.x.x (Lion) changed the offset.
695    kMacTlsBaseOffset = 0;
696  }
697
698  Release_Store(&tls_base_offset_initialized, 1);
699}
700
701
702static void CheckFastTls(Thread::LocalStorageKey key) {
703  void* expected = reinterpret_cast<void*>(0x1234CAFE);
704  Thread::SetThreadLocal(key, expected);
705  void* actual = Thread::GetExistingThreadLocal(key);
706  if (expected != actual) {
707    V8_Fatal(__FILE__, __LINE__,
708             "V8 failed to initialize fast TLS on current kernel");
709  }
710  Thread::SetThreadLocal(key, NULL);
711}
712
713#endif  // V8_FAST_TLS_SUPPORTED
714
715
716Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
717#ifdef V8_FAST_TLS_SUPPORTED
718  bool check_fast_tls = false;
719  if (tls_base_offset_initialized == 0) {
720    check_fast_tls = true;
721    InitializeTlsBaseOffset();
722  }
723#endif
724  pthread_key_t key;
725  int result = pthread_key_create(&key, NULL);
726  ASSERT_EQ(0, result);
727  USE(result);
728  LocalStorageKey local_key = PthreadKeyToLocalKey(key);
729#ifdef V8_FAST_TLS_SUPPORTED
730  // If we just initialized fast TLS support, make sure it works.
731  if (check_fast_tls) CheckFastTls(local_key);
732#endif
733  return local_key;
734}
735
736
737void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
738  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
739  int result = pthread_key_delete(pthread_key);
740  ASSERT_EQ(0, result);
741  USE(result);
742}
743
744
745void* Thread::GetThreadLocal(LocalStorageKey key) {
746  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
747  return pthread_getspecific(pthread_key);
748}
749
750
751void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
752  pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
753  int result = pthread_setspecific(pthread_key, value);
754  ASSERT_EQ(0, result);
755  USE(result);
756}
757
758
759class POSIXMutex : public Mutex {
760 public:
761  POSIXMutex() {
762    pthread_mutexattr_t attr;
763    memset(&attr, 0, sizeof(attr));
764    int result = pthread_mutexattr_init(&attr);
765    ASSERT(result == 0);
766    result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
767    ASSERT(result == 0);
768    result = pthread_mutex_init(&mutex_, &attr);
769    ASSERT(result == 0);
770    result = pthread_mutexattr_destroy(&attr);
771    ASSERT(result == 0);
772    USE(result);
773  }
774
775  virtual ~POSIXMutex() { pthread_mutex_destroy(&mutex_); }
776
777  virtual int Lock() { return pthread_mutex_lock(&mutex_); }
778
779  virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
780
781  virtual bool TryLock() {
782    int result = pthread_mutex_trylock(&mutex_);
783    // Return false if the lock is busy and locking failed.
784    if (result == EBUSY) {
785      return false;
786    }
787    ASSERT(result == 0);  // Verify no other errors.
788    return true;
789  }
790
791 private:
792  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
793};
794
795
796Mutex* OS::CreateMutex() {
797  return new POSIXMutex();
798}
799
800
801// ----------------------------------------------------------------------------
802// POSIX socket support.
803//
804
805class POSIXSocket : public Socket {
806 public:
807  explicit POSIXSocket() {
808    // Create the socket.
809    socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
810    if (IsValid()) {
811      // Allow rapid reuse.
812      static const int kOn = 1;
813      int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
814                           &kOn, sizeof(kOn));
815      ASSERT(ret == 0);
816      USE(ret);
817    }
818  }
819  explicit POSIXSocket(int socket): socket_(socket) { }
820  virtual ~POSIXSocket() { Shutdown(); }
821
822  // Server initialization.
823  bool Bind(const int port);
824  bool Listen(int backlog) const;
825  Socket* Accept() const;
826
827  // Client initialization.
828  bool Connect(const char* host, const char* port);
829
830  // Shutdown socket for both read and write.
831  bool Shutdown();
832
833  // Data Transimission
834  int Send(const char* data, int len) const;
835  int Receive(char* data, int len) const;
836
837  bool SetReuseAddress(bool reuse_address);
838
839  bool IsValid() const { return socket_ != -1; }
840
841 private:
842  int socket_;
843};
844
845
846bool POSIXSocket::Bind(const int port) {
847  if (!IsValid())  {
848    return false;
849  }
850
851  sockaddr_in addr;
852  memset(&addr, 0, sizeof(addr));
853  addr.sin_family = AF_INET;
854  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
855  addr.sin_port = htons(port);
856  int status = bind(socket_,
857                    BitCast<struct sockaddr *>(&addr),
858                    sizeof(addr));
859  return status == 0;
860}
861
862
863bool POSIXSocket::Listen(int backlog) const {
864  if (!IsValid()) {
865    return false;
866  }
867
868  int status = listen(socket_, backlog);
869  return status == 0;
870}
871
872
873Socket* POSIXSocket::Accept() const {
874  if (!IsValid()) {
875    return NULL;
876  }
877
878  int socket;
879  do {
880    socket = accept(socket_, NULL, NULL);
881  } while (socket == -1 && errno == EINTR);
882
883  if (socket == -1) {
884    return NULL;
885  } else {
886    return new POSIXSocket(socket);
887  }
888}
889
890
891bool POSIXSocket::Connect(const char* host, const char* port) {
892  if (!IsValid()) {
893    return false;
894  }
895
896  // Lookup host and port.
897  struct addrinfo *result = NULL;
898  struct addrinfo hints;
899  memset(&hints, 0, sizeof(addrinfo));
900  hints.ai_family = AF_INET;
901  hints.ai_socktype = SOCK_STREAM;
902  hints.ai_protocol = IPPROTO_TCP;
903  int status = getaddrinfo(host, port, &hints, &result);
904  if (status != 0) {
905    return false;
906  }
907
908  // Connect.
909  do {
910    status = connect(socket_, result->ai_addr, result->ai_addrlen);
911  } while (status == -1 && errno == EINTR);
912  freeaddrinfo(result);
913  return status == 0;
914}
915
916
917bool POSIXSocket::Shutdown() {
918  if (IsValid()) {
919    // Shutdown socket for both read and write.
920    int status = shutdown(socket_, SHUT_RDWR);
921    close(socket_);
922    socket_ = -1;
923    return status == 0;
924  }
925  return true;
926}
927
928
929int POSIXSocket::Send(const char* data, int len) const {
930  if (len <= 0) return 0;
931  int written = 0;
932  while (written < len) {
933    int status = send(socket_, data + written, len - written, 0);
934    if (status == 0) {
935      break;
936    } else if (status > 0) {
937      written += status;
938    } else if (errno != EINTR) {
939      return 0;
940    }
941  }
942  return written;
943}
944
945
946int POSIXSocket::Receive(char* data, int len) const {
947  if (len <= 0) return 0;
948  int status;
949  do {
950    status = recv(socket_, data, len, 0);
951  } while (status == -1 && errno == EINTR);
952  return (status < 0) ? 0 : status;
953}
954
955
956bool POSIXSocket::SetReuseAddress(bool reuse_address) {
957  int on = reuse_address ? 1 : 0;
958  int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
959  return status == 0;
960}
961
962
963bool Socket::SetUp() {
964  // Nothing to do on POSIX.
965  return true;
966}
967
968
969int Socket::LastError() {
970  return errno;
971}
972
973
974uint16_t Socket::HToN(uint16_t value) {
975  return htons(value);
976}
977
978
979uint16_t Socket::NToH(uint16_t value) {
980  return ntohs(value);
981}
982
983
984uint32_t Socket::HToN(uint32_t value) {
985  return htonl(value);
986}
987
988
989uint32_t Socket::NToH(uint32_t value) {
990  return ntohl(value);
991}
992
993
994Socket* OS::CreateSocket() {
995  return new POSIXSocket();
996}
997
998
999} }  // namespace v8::internal
1000