00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <pthread.h>
00031 #include <semaphore.h>
00032 #include <signal.h>
00033 #include <sys/time.h>
00034 #include <sys/resource.h>
00035 #include <stdlib.h>
00036
00037
00038
00039
00040 #include <sys/types.h>
00041 #include <sys/mman.h>
00042 #include <sys/stat.h>
00043 #include <sys/fcntl.h>
00044 #include <unistd.h>
00045 #include <execinfo.h>
00046 #include <strings.h>
00047 #include <errno.h>
00048 #include <stdarg.h>
00049
00050 #undef MAP_TYPE
00051
00052 #include "v8.h"
00053
00054 #include "platform.h"
00055
00056
00057 namespace v8 { namespace internal {
00058
00059
00060
00061 static const pthread_t kNoThread = (pthread_t) 0;
00062
00063
00064 double ceiling(double x) {
00065 return ceil(x);
00066 }
00067
00068
00069 void OS::Setup() {
00070
00071
00072
00073
00074
00075 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
00076 srandom(static_cast<unsigned int>(seed));
00077 }
00078
00079
00080 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
00081 struct rusage usage;
00082
00083 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
00084 *secs = usage.ru_utime.tv_sec;
00085 *usecs = usage.ru_utime.tv_usec;
00086 return 0;
00087 }
00088
00089
00090 double OS::TimeCurrentMillis() {
00091 struct timeval tv;
00092 if (gettimeofday(&tv, NULL) < 0) return 0.0;
00093 return (static_cast<double>(tv.tv_sec) * 1000) +
00094 (static_cast<double>(tv.tv_usec) / 1000);
00095 }
00096
00097
00098 int64_t OS::Ticks() {
00099
00100 struct timeval tv;
00101 if (gettimeofday(&tv, NULL) < 0)
00102 return 0;
00103 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
00104 }
00105
00106
00107 char* OS::LocalTimezone(double time) {
00108 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
00109 struct tm* t = localtime(&tv);
00110 return const_cast<char*>(t->tm_zone);
00111 }
00112
00113
00114 double OS::DaylightSavingsOffset(double time) {
00115 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
00116 struct tm* t = localtime(&tv);
00117 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
00118 }
00119
00120
00121 double OS::LocalTimeOffset() {
00122 time_t tv = time(NULL);
00123 struct tm* t = localtime(&tv);
00124
00125 return static_cast<double>(t->tm_gmtoff * msPerSecond -
00126 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
00127 }
00128
00129
00130 FILE* OS::FOpen(const char* path, const char* mode) {
00131 return fopen(path, mode);
00132 }
00133
00134
00135 void OS::Print(const char* format, ...) {
00136 va_list args;
00137 va_start(args, format);
00138 VPrint(format, args);
00139 va_end(args);
00140 }
00141
00142
00143 void OS::VPrint(const char* format, va_list args) {
00144 vprintf(format, args);
00145 }
00146
00147
00148 void OS::PrintError(const char* format, ...) {
00149 va_list args;
00150 va_start(args, format);
00151 VPrintError(format, args);
00152 va_end(args);
00153 }
00154
00155
00156 void OS::VPrintError(const char* format, va_list args) {
00157 vfprintf(stderr, format, args);
00158 }
00159
00160
00161 int OS::SNPrintF(Vector<char> str, const char* format, ...) {
00162 va_list args;
00163 va_start(args, format);
00164 int result = VSNPrintF(str, format, args);
00165 va_end(args);
00166 return result;
00167 }
00168
00169
00170 int OS::VSNPrintF(Vector<char> str,
00171 const char* format,
00172 va_list args) {
00173 int n = vsnprintf(str.start(), str.length(), format, args);
00174 if (n < 0 || n >= str.length()) {
00175 str[str.length() - 1] = '\0';
00176 return -1;
00177 } else {
00178 return n;
00179 }
00180 }
00181
00182
00183 void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
00184 strncpy(dest.start(), src, n);
00185 }
00186
00187
00188 void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
00189 wcscpy(dest.start(), src);
00190 }
00191
00192
00193 char *OS::StrDup(const char* str) {
00194 return strdup(str);
00195 }
00196
00197
00198 double OS::nan_value() {
00199 return NAN;
00200 }
00201
00202
00203 int OS::ActivationFrameAlignment() {
00204
00205 return 0;
00206 }
00207
00208
00209
00210
00211
00212
00213
00214 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
00215 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
00216
00217
00218 static void UpdateAllocatedSpaceLimits(void* address, int size) {
00219 lowest_ever_allocated = Min(lowest_ever_allocated, address);
00220 highest_ever_allocated =
00221 Max(highest_ever_allocated,
00222 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
00223 }
00224
00225
00226 bool OS::IsOutsideAllocatedSpace(void* address) {
00227 return address < lowest_ever_allocated || address >= highest_ever_allocated;
00228 }
00229
00230
00231 size_t OS::AllocateAlignment() {
00232 return getpagesize();
00233 }
00234
00235
00236 void* OS::Allocate(const size_t requested,
00237 size_t* allocated,
00238 bool executable) {
00239 const size_t msize = RoundUp(requested, getpagesize());
00240 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
00241 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
00242 if (mbase == MAP_FAILED) {
00243 LOG(StringEvent("OS::Allocate", "mmap failed"));
00244 return NULL;
00245 }
00246 *allocated = msize;
00247 UpdateAllocatedSpaceLimits(mbase, msize);
00248 return mbase;
00249 }
00250
00251
00252 void OS::Free(void* buf, const size_t length) {
00253
00254 munmap(buf, length);
00255 }
00256
00257
00258 void OS::Sleep(int milliseconds) {
00259 unsigned int ms = static_cast<unsigned int>(milliseconds);
00260 usleep(1000 * ms);
00261 }
00262
00263
00264 void OS::Abort() {
00265
00266 abort();
00267 }
00268
00269
00270 void OS::DebugBreak() {
00271 #if defined (__arm__) || defined(__thumb__)
00272 asm("bkpt 0");
00273 #else
00274 asm("int $3");
00275 #endif
00276 }
00277
00278
00279 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
00280 public:
00281 PosixMemoryMappedFile(FILE* file, void* memory, int size)
00282 : file_(file), memory_(memory), size_(size) { }
00283 virtual ~PosixMemoryMappedFile();
00284 virtual void* memory() { return memory_; }
00285 private:
00286 FILE* file_;
00287 void* memory_;
00288 int size_;
00289 };
00290
00291
00292 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
00293 void* initial) {
00294 FILE* file = fopen(name, "w+");
00295 if (file == NULL) return NULL;
00296 int result = fwrite(initial, size, 1, file);
00297 if (result < 1) {
00298 fclose(file);
00299 return NULL;
00300 }
00301 void* memory =
00302 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
00303 return new PosixMemoryMappedFile(file, memory, size);
00304 }
00305
00306
00307 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
00308 if (memory_) munmap(memory_, size_);
00309 fclose(file_);
00310 }
00311
00312 #ifdef ENABLE_LOGGING_AND_PROFILING
00313 static unsigned StringToLongLong(char* buffer) {
00314 return static_cast<unsigned>(strtoll(buffer, NULL, 16));
00315 }
00316
00317 #endif
00318
00319 void OS::LogSharedLibraryAddresses() {
00320 #ifdef ENABLE_LOGGING_AND_PROFILING
00321 static const int MAP_LENGTH = 1024;
00322 int fd = open("/proc/self/maps", O_RDONLY);
00323 if (fd < 0) return;
00324 while (true) {
00325 char addr_buffer[11];
00326 addr_buffer[0] = '0';
00327 addr_buffer[1] = 'x';
00328 addr_buffer[10] = 0;
00329 int result = read(fd, addr_buffer + 2, 8);
00330 if (result < 8) break;
00331 unsigned start = StringToLongLong(addr_buffer);
00332 result = read(fd, addr_buffer + 2, 1);
00333 if (result < 1) break;
00334 if (addr_buffer[2] != '-') break;
00335 result = read(fd, addr_buffer + 2, 8);
00336 if (result < 8) break;
00337 unsigned end = StringToLongLong(addr_buffer);
00338 char buffer[MAP_LENGTH];
00339 int bytes_read = -1;
00340 do {
00341 bytes_read++;
00342 if (bytes_read >= MAP_LENGTH - 1)
00343 break;
00344 result = read(fd, buffer + bytes_read, 1);
00345 if (result < 1) break;
00346 } while (buffer[bytes_read] != '\n');
00347 buffer[bytes_read] = 0;
00348
00349 if (buffer[3] != 'x') continue;
00350 char* start_of_path = index(buffer, '/');
00351
00352 if (start_of_path == NULL) continue;
00353 buffer[bytes_read] = 0;
00354 LOG(SharedLibraryEvent(start_of_path, start, end));
00355 }
00356 close(fd);
00357 #endif
00358 }
00359
00360
00361 int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
00362 void** addresses = NewArray<void*>(frames_size);
00363
00364 int frames_count = backtrace(addresses, frames_size);
00365
00366 char** symbols;
00367 symbols = backtrace_symbols(addresses, frames_count);
00368 if (symbols == NULL) {
00369 DeleteArray(addresses);
00370 return kStackWalkError;
00371 }
00372
00373 for (int i = 0; i < frames_count; i++) {
00374 frames[i].address = addresses[i];
00375
00376
00377 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
00378 "%s",
00379 symbols[i]);
00380
00381 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
00382 }
00383
00384 DeleteArray(addresses);
00385 free(symbols);
00386
00387 return frames_count;
00388 }
00389
00390
00391
00392 static const int kMmapFd = -1;
00393 static const int kMmapFdOffset = 0;
00394
00395
00396 VirtualMemory::VirtualMemory(size_t size) {
00397 address_ = mmap(NULL, size, PROT_NONE,
00398 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
00399 kMmapFd, kMmapFdOffset);
00400 size_ = size;
00401 }
00402
00403
00404 VirtualMemory::~VirtualMemory() {
00405 if (IsReserved()) {
00406 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
00407 }
00408 }
00409
00410
00411 bool VirtualMemory::IsReserved() {
00412 return address_ != MAP_FAILED;
00413 }
00414
00415
00416 bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
00417 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
00418 if (MAP_FAILED == mmap(address, size, prot,
00419 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
00420 kMmapFd, kMmapFdOffset)) {
00421 return false;
00422 }
00423
00424 UpdateAllocatedSpaceLimits(address, size);
00425 return true;
00426 }
00427
00428
00429 bool VirtualMemory::Uncommit(void* address, size_t size) {
00430 return mmap(address, size, PROT_NONE,
00431 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
00432 kMmapFd, kMmapFdOffset) != MAP_FAILED;
00433 }
00434
00435
00436 class ThreadHandle::PlatformData : public Malloced {
00437 public:
00438 explicit PlatformData(ThreadHandle::Kind kind) {
00439 Initialize(kind);
00440 }
00441
00442 void Initialize(ThreadHandle::Kind kind) {
00443 switch (kind) {
00444 case ThreadHandle::SELF: thread_ = pthread_self(); break;
00445 case ThreadHandle::INVALID: thread_ = kNoThread; break;
00446 }
00447 }
00448 pthread_t thread_;
00449 };
00450
00451
00452 ThreadHandle::ThreadHandle(Kind kind) {
00453 data_ = new PlatformData(kind);
00454 }
00455
00456
00457 void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
00458 data_->Initialize(kind);
00459 }
00460
00461
00462 ThreadHandle::~ThreadHandle() {
00463 delete data_;
00464 }
00465
00466
00467 bool ThreadHandle::IsSelf() const {
00468 return pthread_equal(data_->thread_, pthread_self());
00469 }
00470
00471
00472 bool ThreadHandle::IsValid() const {
00473 return data_->thread_ != kNoThread;
00474 }
00475
00476
00477 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
00478 }
00479
00480
00481 Thread::~Thread() {
00482 }
00483
00484
00485 static void* ThreadEntry(void* arg) {
00486 Thread* thread = reinterpret_cast<Thread*>(arg);
00487
00488
00489
00490 thread->thread_handle_data()->thread_ = pthread_self();
00491 ASSERT(thread->IsValid());
00492 thread->Run();
00493 return NULL;
00494 }
00495
00496
00497 void Thread::Start() {
00498 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
00499 ASSERT(IsValid());
00500 }
00501
00502
00503 void Thread::Join() {
00504 pthread_join(thread_handle_data()->thread_, NULL);
00505 }
00506
00507
00508 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
00509 pthread_key_t key;
00510 int result = pthread_key_create(&key, NULL);
00511 USE(result);
00512 ASSERT(result == 0);
00513 return static_cast<LocalStorageKey>(key);
00514 }
00515
00516
00517 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
00518 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00519 int result = pthread_key_delete(pthread_key);
00520 USE(result);
00521 ASSERT(result == 0);
00522 }
00523
00524
00525 void* Thread::GetThreadLocal(LocalStorageKey key) {
00526 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00527 return pthread_getspecific(pthread_key);
00528 }
00529
00530
00531 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
00532 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
00533 pthread_setspecific(pthread_key, value);
00534 }
00535
00536
00537 void Thread::YieldCPU() {
00538 sched_yield();
00539 }
00540
00541
00542 class LinuxMutex : public Mutex {
00543 public:
00544
00545 LinuxMutex() {
00546 pthread_mutexattr_t attrs;
00547 int result = pthread_mutexattr_init(&attrs);
00548 ASSERT(result == 0);
00549 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
00550 ASSERT(result == 0);
00551 result = pthread_mutex_init(&mutex_, &attrs);
00552 ASSERT(result == 0);
00553 }
00554
00555 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
00556
00557 virtual int Lock() {
00558 int result = pthread_mutex_lock(&mutex_);
00559 return result;
00560 }
00561
00562 virtual int Unlock() {
00563 int result = pthread_mutex_unlock(&mutex_);
00564 return result;
00565 }
00566
00567 private:
00568 pthread_mutex_t mutex_;
00569 };
00570
00571
00572 Mutex* OS::CreateMutex() {
00573 return new LinuxMutex();
00574 }
00575
00576
00577 class LinuxSemaphore : public Semaphore {
00578 public:
00579 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
00580 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
00581
00582 virtual void Wait();
00583 virtual void Signal() { sem_post(&sem_); }
00584 private:
00585 sem_t sem_;
00586 };
00587
00588 void LinuxSemaphore::Wait() {
00589 while (true) {
00590 int result = sem_wait(&sem_);
00591 if (result == 0) return;
00592 CHECK(result == -1 && errno == EINTR);
00593 }
00594 }
00595
00596 Semaphore* OS::CreateSemaphore(int count) {
00597 return new LinuxSemaphore(count);
00598 }
00599
00600 #ifdef ENABLE_LOGGING_AND_PROFILING
00601
00602 static Sampler* active_sampler_ = NULL;
00603
00604 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
00605 USE(info);
00606 if (signal != SIGPROF) return;
00607 if (active_sampler_ == NULL) return;
00608
00609 TickSample sample;
00610
00611
00612 if (active_sampler_->IsProfiling()) {
00613
00614 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
00615 mcontext_t& mcontext = ucontext->uc_mcontext;
00616 #if defined (__arm__) || defined(__thumb__)
00617 sample.pc = mcontext.gregs[R15];
00618 sample.sp = mcontext.gregs[R13];
00619 #else
00620 sample.pc = mcontext.gregs[REG_EIP];
00621 sample.sp = mcontext.gregs[REG_ESP];
00622 #endif
00623 }
00624
00625
00626 sample.state = Logger::state();
00627
00628 active_sampler_->Tick(&sample);
00629 }
00630
00631
00632 class Sampler::PlatformData : public Malloced {
00633 public:
00634 PlatformData() {
00635 signal_handler_installed_ = false;
00636 }
00637
00638 bool signal_handler_installed_;
00639 struct sigaction old_signal_handler_;
00640 struct itimerval old_timer_value_;
00641 };
00642
00643
00644 Sampler::Sampler(int interval, bool profiling)
00645 : interval_(interval), profiling_(profiling), active_(false) {
00646 data_ = new PlatformData();
00647 }
00648
00649
00650 Sampler::~Sampler() {
00651 delete data_;
00652 }
00653
00654
00655 void Sampler::Start() {
00656
00657
00658 if (active_sampler_ != NULL) return;
00659
00660
00661 struct sigaction sa;
00662 sa.sa_sigaction = ProfilerSignalHandler;
00663 sigemptyset(&sa.sa_mask);
00664 sa.sa_flags = SA_SIGINFO;
00665 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
00666 data_->signal_handler_installed_ = true;
00667
00668
00669 itimerval itimer;
00670 itimer.it_interval.tv_sec = interval_ / 1000;
00671 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
00672 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
00673 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
00674 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
00675
00676
00677 active_sampler_ = this;
00678 active_ = true;
00679 }
00680
00681
00682 void Sampler::Stop() {
00683
00684 if (data_->signal_handler_installed_) {
00685 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
00686 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
00687 data_->signal_handler_installed_ = false;
00688 }
00689
00690
00691 active_sampler_ = NULL;
00692 active_ = false;
00693 }
00694
00695 #endif // ENABLE_LOGGING_AND_PROFILING
00696
00697 } }