platform-posix.cc revision 5d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0b
1// Copyright 2011 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 <unistd.h> 33#include <errno.h> 34#include <time.h> 35 36#include <sys/mman.h> 37#include <sys/socket.h> 38#include <sys/resource.h> 39#include <sys/time.h> 40#include <sys/types.h> 41#include <sys/stat.h> 42 43#include <arpa/inet.h> 44#include <netinet/in.h> 45#include <netdb.h> 46 47#undef MAP_TYPE 48 49#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 50#define LOG_TAG "v8" 51#include <android/log.h> 52#endif 53 54#include "v8.h" 55 56#include "codegen.h" 57#include "platform.h" 58 59namespace v8 { 60namespace internal { 61 62 63// Maximum size of the virtual memory. 0 means there is no artificial 64// limit. 65 66intptr_t OS::MaxVirtualMemory() { 67 struct rlimit limit; 68 int result = getrlimit(RLIMIT_DATA, &limit); 69 if (result != 0) return 0; 70 return limit.rlim_cur; 71} 72 73 74intptr_t OS::CommitPageSize() { 75 static intptr_t page_size = getpagesize(); 76 return page_size; 77} 78 79 80#ifndef __CYGWIN__ 81// Get rid of writable permission on code allocations. 82void OS::ProtectCode(void* address, const size_t size) { 83 mprotect(address, size, PROT_READ | PROT_EXEC); 84} 85 86 87// Create guard pages. 88void OS::Guard(void* address, const size_t size) { 89 mprotect(address, size, PROT_NONE); 90} 91#endif // __CYGWIN__ 92 93 94void* OS::GetRandomMmapAddr() { 95 Isolate* isolate = Isolate::UncheckedCurrent(); 96 // Note that the current isolate isn't set up in a call path via 97 // CpuFeatures::Probe. We don't care about randomization in this case because 98 // the code page is immediately freed. 99 if (isolate != NULL) { 100#ifdef V8_TARGET_ARCH_X64 101 uint64_t rnd1 = V8::RandomPrivate(isolate); 102 uint64_t rnd2 = V8::RandomPrivate(isolate); 103 uint64_t raw_addr = (rnd1 << 32) ^ rnd2; 104 // Currently available CPUs have 48 bits of virtual addressing. Truncate 105 // the hint address to 46 bits to give the kernel a fighting chance of 106 // fulfilling our placement request. 107 raw_addr &= V8_UINT64_C(0x3ffffffff000); 108#else 109 uint32_t raw_addr = V8::RandomPrivate(isolate); 110 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 111 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 112 // 10.6 and 10.7. 113 raw_addr &= 0x3ffff000; 114 raw_addr += 0x20000000; 115#endif 116 return reinterpret_cast<void*>(raw_addr); 117 } 118 return NULL; 119} 120 121 122// ---------------------------------------------------------------------------- 123// Math functions 124 125double modulo(double x, double y) { 126 return fmod(x, y); 127} 128 129 130#define UNARY_MATH_FUNCTION(name, generator) \ 131static UnaryMathFunction fast_##name##_function = NULL; \ 132V8_DECLARE_ONCE(fast_##name##_init_once); \ 133void init_fast_##name##_function() { \ 134 fast_##name##_function = generator; \ 135} \ 136double fast_##name(double x) { \ 137 CallOnce(&fast_##name##_init_once, \ 138 &init_fast_##name##_function); \ 139 return (*fast_##name##_function)(x); \ 140} 141 142UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 143UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 144UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 145UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 146UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 147 148#undef MATH_FUNCTION 149 150 151double OS::nan_value() { 152 // NAN from math.h is defined in C99 and not in POSIX. 153 return NAN; 154} 155 156 157// ---------------------------------------------------------------------------- 158// POSIX date/time support. 159// 160 161int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 162 struct rusage usage; 163 164 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 165 *secs = usage.ru_utime.tv_sec; 166 *usecs = usage.ru_utime.tv_usec; 167 return 0; 168} 169 170 171double OS::TimeCurrentMillis() { 172 struct timeval tv; 173 if (gettimeofday(&tv, NULL) < 0) return 0.0; 174 return (static_cast<double>(tv.tv_sec) * 1000) + 175 (static_cast<double>(tv.tv_usec) / 1000); 176} 177 178 179int64_t OS::Ticks() { 180 // gettimeofday has microsecond resolution. 181 struct timeval tv; 182 if (gettimeofday(&tv, NULL) < 0) 183 return 0; 184 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec; 185} 186 187 188double OS::DaylightSavingsOffset(double time) { 189 if (isnan(time)) return nan_value(); 190 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 191 struct tm* t = localtime(&tv); 192 if (NULL == t) return nan_value(); 193 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 194} 195 196 197int OS::GetLastError() { 198 return errno; 199} 200 201 202// ---------------------------------------------------------------------------- 203// POSIX stdio support. 204// 205 206FILE* OS::FOpen(const char* path, const char* mode) { 207 FILE* file = fopen(path, mode); 208 if (file == NULL) return NULL; 209 struct stat file_stat; 210 if (fstat(fileno(file), &file_stat) != 0) return NULL; 211 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 212 if (is_regular_file) return file; 213 fclose(file); 214 return NULL; 215} 216 217 218bool OS::Remove(const char* path) { 219 return (remove(path) == 0); 220} 221 222 223FILE* OS::OpenTemporaryFile() { 224 return tmpfile(); 225} 226 227 228const char* const OS::LogFileOpenMode = "w"; 229 230 231void OS::Print(const char* format, ...) { 232 va_list args; 233 va_start(args, format); 234 VPrint(format, args); 235 va_end(args); 236} 237 238 239void OS::VPrint(const char* format, va_list args) { 240#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 241 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 242#else 243 vprintf(format, args); 244#endif 245} 246 247 248void OS::FPrint(FILE* out, const char* format, ...) { 249 va_list args; 250 va_start(args, format); 251 VFPrint(out, format, args); 252 va_end(args); 253} 254 255 256void OS::VFPrint(FILE* out, const char* format, va_list args) { 257#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 258 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 259#else 260 vfprintf(out, format, args); 261#endif 262} 263 264 265void OS::PrintError(const char* format, ...) { 266 va_list args; 267 va_start(args, format); 268 VPrintError(format, args); 269 va_end(args); 270} 271 272 273void OS::VPrintError(const char* format, va_list args) { 274#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 275 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 276#else 277 vfprintf(stderr, format, args); 278#endif 279} 280 281 282int OS::SNPrintF(Vector<char> str, const char* format, ...) { 283 va_list args; 284 va_start(args, format); 285 int result = VSNPrintF(str, format, args); 286 va_end(args); 287 return result; 288} 289 290 291int OS::VSNPrintF(Vector<char> str, 292 const char* format, 293 va_list args) { 294 int n = vsnprintf(str.start(), str.length(), format, args); 295 if (n < 0 || n >= str.length()) { 296 // If the length is zero, the assignment fails. 297 if (str.length() > 0) 298 str[str.length() - 1] = '\0'; 299 return -1; 300 } else { 301 return n; 302 } 303} 304 305 306#if defined(V8_TARGET_ARCH_IA32) 307static OS::MemCopyFunction memcopy_function = NULL; 308static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER; 309// Defined in codegen-ia32.cc. 310OS::MemCopyFunction CreateMemCopyFunction(); 311 312// Copy memory area to disjoint memory area. 313void OS::MemCopy(void* dest, const void* src, size_t size) { 314 if (memcopy_function == NULL) { 315 ScopedLock lock(memcopy_function_mutex.Pointer()); 316 if (memcopy_function == NULL) { 317 OS::MemCopyFunction temp = CreateMemCopyFunction(); 318 MemoryBarrier(); 319 memcopy_function = temp; 320 } 321 } 322 // Note: here we rely on dependent reads being ordered. This is true 323 // on all architectures we currently support. 324 (*memcopy_function)(dest, src, size); 325#ifdef DEBUG 326 CHECK_EQ(0, memcmp(dest, src, size)); 327#endif 328} 329#endif // V8_TARGET_ARCH_IA32 330 331// ---------------------------------------------------------------------------- 332// POSIX string support. 333// 334 335char* OS::StrChr(char* str, int c) { 336 return strchr(str, c); 337} 338 339 340void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 341 strncpy(dest.start(), src, n); 342} 343 344 345// ---------------------------------------------------------------------------- 346// POSIX socket support. 347// 348 349class POSIXSocket : public Socket { 350 public: 351 explicit POSIXSocket() { 352 // Create the socket. 353 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 354 if (IsValid()) { 355 // Allow rapid reuse. 356 static const int kOn = 1; 357 int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, 358 &kOn, sizeof(kOn)); 359 ASSERT(ret == 0); 360 USE(ret); 361 } 362 } 363 explicit POSIXSocket(int socket): socket_(socket) { } 364 virtual ~POSIXSocket() { Shutdown(); } 365 366 // Server initialization. 367 bool Bind(const int port); 368 bool Listen(int backlog) const; 369 Socket* Accept() const; 370 371 // Client initialization. 372 bool Connect(const char* host, const char* port); 373 374 // Shutdown socket for both read and write. 375 bool Shutdown(); 376 377 // Data Transimission 378 int Send(const char* data, int len) const; 379 int Receive(char* data, int len) const; 380 381 bool SetReuseAddress(bool reuse_address); 382 383 bool IsValid() const { return socket_ != -1; } 384 385 private: 386 int socket_; 387}; 388 389 390bool POSIXSocket::Bind(const int port) { 391 if (!IsValid()) { 392 return false; 393 } 394 395 sockaddr_in addr; 396 memset(&addr, 0, sizeof(addr)); 397 addr.sin_family = AF_INET; 398 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 399 addr.sin_port = htons(port); 400 int status = bind(socket_, 401 BitCast<struct sockaddr *>(&addr), 402 sizeof(addr)); 403 return status == 0; 404} 405 406 407bool POSIXSocket::Listen(int backlog) const { 408 if (!IsValid()) { 409 return false; 410 } 411 412 int status = listen(socket_, backlog); 413 return status == 0; 414} 415 416 417Socket* POSIXSocket::Accept() const { 418 if (!IsValid()) { 419 return NULL; 420 } 421 422 int socket = accept(socket_, NULL, NULL); 423 if (socket == -1) { 424 return NULL; 425 } else { 426 return new POSIXSocket(socket); 427 } 428} 429 430 431bool POSIXSocket::Connect(const char* host, const char* port) { 432 if (!IsValid()) { 433 return false; 434 } 435 436 // Lookup host and port. 437 struct addrinfo *result = NULL; 438 struct addrinfo hints; 439 memset(&hints, 0, sizeof(addrinfo)); 440 hints.ai_family = AF_INET; 441 hints.ai_socktype = SOCK_STREAM; 442 hints.ai_protocol = IPPROTO_TCP; 443 int status = getaddrinfo(host, port, &hints, &result); 444 if (status != 0) { 445 return false; 446 } 447 448 // Connect. 449 status = connect(socket_, result->ai_addr, result->ai_addrlen); 450 freeaddrinfo(result); 451 return status == 0; 452} 453 454 455bool POSIXSocket::Shutdown() { 456 if (IsValid()) { 457 // Shutdown socket for both read and write. 458 int status = shutdown(socket_, SHUT_RDWR); 459 close(socket_); 460 socket_ = -1; 461 return status == 0; 462 } 463 return true; 464} 465 466 467int POSIXSocket::Send(const char* data, int len) const { 468 int status = send(socket_, data, len, 0); 469 return status; 470} 471 472 473int POSIXSocket::Receive(char* data, int len) const { 474 int status = recv(socket_, data, len, 0); 475 return status; 476} 477 478 479bool POSIXSocket::SetReuseAddress(bool reuse_address) { 480 int on = reuse_address ? 1 : 0; 481 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 482 return status == 0; 483} 484 485 486bool Socket::SetUp() { 487 // Nothing to do on POSIX. 488 return true; 489} 490 491 492int Socket::LastError() { 493 return errno; 494} 495 496 497uint16_t Socket::HToN(uint16_t value) { 498 return htons(value); 499} 500 501 502uint16_t Socket::NToH(uint16_t value) { 503 return ntohs(value); 504} 505 506 507uint32_t Socket::HToN(uint32_t value) { 508 return htonl(value); 509} 510 511 512uint32_t Socket::NToH(uint32_t value) { 513 return ntohl(value); 514} 515 516 517Socket* OS::CreateSocket() { 518 return new POSIXSocket(); 519} 520 521 522} } // namespace v8::internal 523