blob: 39495ab967176aef01c18d59c59885394e8f87c9 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for Linux goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include <pthread.h>
32#include <semaphore.h>
33#include <signal.h>
34#include <sys/time.h>
35#include <sys/resource.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000036#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include <stdlib.h>
38
39// Ubuntu Dapper requires memory pages to be marked as
40// executable. Otherwise, OS raises an exception when executing code
41// in that page.
42#include <sys/types.h> // mmap & munmap
ager@chromium.org236ad962008-09-25 09:45:57 +000043#include <sys/mman.h> // mmap & munmap
44#include <sys/stat.h> // open
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000045#include <fcntl.h> // open
46#include <unistd.h> // sysconf
47#ifdef __GLIBC__
ager@chromium.org236ad962008-09-25 09:45:57 +000048#include <execinfo.h> // backtrace, backtrace_symbols
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000049#endif // def __GLIBC__
ager@chromium.org236ad962008-09-25 09:45:57 +000050#include <strings.h> // index
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include <errno.h>
52#include <stdarg.h>
53
54#undef MAP_TYPE
55
56#include "v8.h"
57
58#include "platform.h"
59
60
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// 0 is never a valid thread id on Linux since tids and pids share a
65// name space and pid 0 is reserved (see man 2 kill).
66static const pthread_t kNoThread = (pthread_t) 0;
67
68
69double ceiling(double x) {
70 return ceil(x);
71}
72
73
74void OS::Setup() {
75 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000076 // Convert the current time to a 64-bit integer first, before converting it
77 // to an unsigned. Going directly can cause an overflow and the seed to be
78 // set to all ones. The seed will be identical for different instances that
79 // call this setup code within the same millisecond.
80 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
81 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082}
83
84
ager@chromium.org236ad962008-09-25 09:45:57 +000085double OS::nan_value() {
86 return NAN;
87}
88
89
90int OS::ActivationFrameAlignment() {
ager@chromium.orge2902be2009-06-08 12:21:35 +000091#ifdef V8_TARGET_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000092 // On EABI ARM targets this is required for fp correctness in the
93 // runtime system.
ager@chromium.org3a6061e2009-03-12 14:24:36 +000094 return 8;
ager@chromium.orge2902be2009-06-08 12:21:35 +000095#else
96 // With gcc 4.4 the tree vectorization optimiser can generate code
97 // that requires 16 byte alignment such as movdqa on x86.
98 return 16;
99#endif
ager@chromium.org236ad962008-09-25 09:45:57 +0000100}
101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102
103// We keep the lowest and highest addresses mapped as a quick way of
104// determining that pointers are outside the heap (used mostly in assertions
105// and verification). The estimate is conservative, ie, not all addresses in
106// 'allocated' space are actually allocated to our heap. The range is
107// [lowest, highest), inclusive on the low and and exclusive on the high end.
108static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
109static void* highest_ever_allocated = reinterpret_cast<void*>(0);
110
111
112static void UpdateAllocatedSpaceLimits(void* address, int size) {
113 lowest_ever_allocated = Min(lowest_ever_allocated, address);
114 highest_ever_allocated =
115 Max(highest_ever_allocated,
116 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
117}
118
119
120bool OS::IsOutsideAllocatedSpace(void* address) {
121 return address < lowest_ever_allocated || address >= highest_ever_allocated;
122}
123
124
125size_t OS::AllocateAlignment() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 return sysconf(_SC_PAGESIZE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127}
128
129
kasper.lund7276f142008-07-30 08:49:36 +0000130void* OS::Allocate(const size_t requested,
131 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000132 bool is_executable) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000134 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000135 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 if (mbase == MAP_FAILED) {
137 LOG(StringEvent("OS::Allocate", "mmap failed"));
138 return NULL;
139 }
140 *allocated = msize;
141 UpdateAllocatedSpaceLimits(mbase, msize);
142 return mbase;
143}
144
145
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000146void OS::Free(void* address, const size_t size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147 // TODO(1240712): munmap has a return value which is ignored here.
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000148 munmap(address, size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149}
150
151
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000152#ifdef ENABLE_HEAP_PROTECTION
153
154void OS::Protect(void* address, size_t size) {
155 // TODO(1240712): mprotect has a return value which is ignored here.
156 mprotect(address, size, PROT_READ);
157}
158
159
160void OS::Unprotect(void* address, size_t size, bool is_executable) {
161 // TODO(1240712): mprotect has a return value which is ignored here.
162 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
163 mprotect(address, size, prot);
164}
165
166#endif
167
168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169void OS::Sleep(int milliseconds) {
170 unsigned int ms = static_cast<unsigned int>(milliseconds);
171 usleep(1000 * ms);
172}
173
174
175void OS::Abort() {
176 // Redirect to std abort to signal abnormal program termination.
177 abort();
178}
179
180
kasper.lund7276f142008-07-30 08:49:36 +0000181void OS::DebugBreak() {
ager@chromium.org5ec48922009-05-05 07:25:34 +0000182// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
183// which is the architecture of generated code).
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000184#if defined(__arm__) || defined(__thumb__)
kasper.lund7276f142008-07-30 08:49:36 +0000185 asm("bkpt 0");
186#else
187 asm("int $3");
188#endif
189}
190
191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192class PosixMemoryMappedFile : public OS::MemoryMappedFile {
193 public:
194 PosixMemoryMappedFile(FILE* file, void* memory, int size)
195 : file_(file), memory_(memory), size_(size) { }
196 virtual ~PosixMemoryMappedFile();
197 virtual void* memory() { return memory_; }
198 private:
199 FILE* file_;
200 void* memory_;
201 int size_;
202};
203
204
205OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
206 void* initial) {
207 FILE* file = fopen(name, "w+");
208 if (file == NULL) return NULL;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000209 int result = fwrite(initial, size, 1, file);
210 if (result < 1) {
211 fclose(file);
212 return NULL;
213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 void* memory =
215 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
216 return new PosixMemoryMappedFile(file, memory, size);
217}
218
219
220PosixMemoryMappedFile::~PosixMemoryMappedFile() {
221 if (memory_) munmap(memory_, size_);
222 fclose(file_);
223}
224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000226#ifdef ENABLE_LOGGING_AND_PROFILING
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000227static uintptr_t StringToULong(char* buffer) {
228 return strtoul(buffer, NULL, 16); // NOLINT
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000229}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230#endif
231
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233void OS::LogSharedLibraryAddresses() {
234#ifdef ENABLE_LOGGING_AND_PROFILING
235 static const int MAP_LENGTH = 1024;
236 int fd = open("/proc/self/maps", O_RDONLY);
237 if (fd < 0) return;
238 while (true) {
239 char addr_buffer[11];
240 addr_buffer[0] = '0';
241 addr_buffer[1] = 'x';
242 addr_buffer[10] = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000243 int result = read(fd, addr_buffer + 2, 8);
244 if (result < 8) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000245 uintptr_t start = StringToULong(addr_buffer);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000246 result = read(fd, addr_buffer + 2, 1);
247 if (result < 1) break;
248 if (addr_buffer[2] != '-') break;
249 result = read(fd, addr_buffer + 2, 8);
250 if (result < 8) break;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000251 uintptr_t end = StringToULong(addr_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 char buffer[MAP_LENGTH];
253 int bytes_read = -1;
254 do {
255 bytes_read++;
ager@chromium.orgc27e4e72008-09-04 13:52:27 +0000256 if (bytes_read >= MAP_LENGTH - 1)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000258 result = read(fd, buffer + bytes_read, 1);
259 if (result < 1) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260 } while (buffer[bytes_read] != '\n');
261 buffer[bytes_read] = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262 // Ignore mappings that are not executable.
263 if (buffer[3] != 'x') continue;
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 char* start_of_path = index(buffer, '/');
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000265 // If there is no filename for this line then log it as an anonymous
266 // mapping and use the address as its name.
267 if (start_of_path == NULL) {
268 // 40 is enough to print a 64 bit address range.
269 ASSERT(sizeof(buffer) > 40);
270 snprintf(buffer,
271 sizeof(buffer),
272 "%08" V8PRIxPTR "-%08" V8PRIxPTR,
273 start,
274 end);
275 LOG(SharedLibraryEvent(buffer, start, end));
276 } else {
277 buffer[bytes_read] = 0;
278 LOG(SharedLibraryEvent(start_of_path, start, end));
279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000281 close(fd);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282#endif
283}
284
285
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000286int OS::StackWalk(Vector<OS::StackFrame> frames) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287 // backtrace is a glibc extension.
288#ifdef __GLIBC__
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000289 int frames_size = frames.length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290 void** addresses = NewArray<void*>(frames_size);
291
292 int frames_count = backtrace(addresses, frames_size);
293
294 char** symbols;
295 symbols = backtrace_symbols(addresses, frames_count);
296 if (symbols == NULL) {
297 DeleteArray(addresses);
298 return kStackWalkError;
299 }
300
301 for (int i = 0; i < frames_count; i++) {
302 frames[i].address = addresses[i];
303 // Format a text representation of the frame based on the information
304 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000305 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
306 "%s",
307 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 // Make sure line termination is in place.
309 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
310 }
311
312 DeleteArray(addresses);
313 free(symbols);
314
315 return frames_count;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316#else // ndef __GLIBC__
317 return 0;
318#endif // ndef __GLIBC__
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319}
320
321
322// Constants used for mmap.
323static const int kMmapFd = -1;
324static const int kMmapFdOffset = 0;
325
326
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000327VirtualMemory::VirtualMemory(size_t size) {
328 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
330 kMmapFd, kMmapFdOffset);
331 size_ = size;
332}
333
334
335VirtualMemory::~VirtualMemory() {
336 if (IsReserved()) {
337 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
338 }
339}
340
341
342bool VirtualMemory::IsReserved() {
343 return address_ != MAP_FAILED;
344}
345
346
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000347bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
348 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000349 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
351 kMmapFd, kMmapFdOffset)) {
352 return false;
353 }
354
355 UpdateAllocatedSpaceLimits(address, size);
356 return true;
357}
358
359
360bool VirtualMemory::Uncommit(void* address, size_t size) {
361 return mmap(address, size, PROT_NONE,
362 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
363 kMmapFd, kMmapFdOffset) != MAP_FAILED;
364}
365
366
367class ThreadHandle::PlatformData : public Malloced {
368 public:
369 explicit PlatformData(ThreadHandle::Kind kind) {
370 Initialize(kind);
371 }
372
373 void Initialize(ThreadHandle::Kind kind) {
374 switch (kind) {
375 case ThreadHandle::SELF: thread_ = pthread_self(); break;
376 case ThreadHandle::INVALID: thread_ = kNoThread; break;
377 }
378 }
ager@chromium.org41826e72009-03-30 13:30:57 +0000379
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 pthread_t thread_; // Thread handle for pthread.
381};
382
383
384ThreadHandle::ThreadHandle(Kind kind) {
385 data_ = new PlatformData(kind);
386}
387
388
389void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
390 data_->Initialize(kind);
391}
392
393
394ThreadHandle::~ThreadHandle() {
395 delete data_;
396}
397
398
399bool ThreadHandle::IsSelf() const {
400 return pthread_equal(data_->thread_, pthread_self());
401}
402
403
404bool ThreadHandle::IsValid() const {
405 return data_->thread_ != kNoThread;
406}
407
408
409Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
410}
411
412
413Thread::~Thread() {
414}
415
416
417static void* ThreadEntry(void* arg) {
418 Thread* thread = reinterpret_cast<Thread*>(arg);
419 // This is also initialized by the first argument to pthread_create() but we
420 // don't know which thread will run first (the original thread or the new
421 // one) so we initialize it here too.
422 thread->thread_handle_data()->thread_ = pthread_self();
423 ASSERT(thread->IsValid());
424 thread->Run();
425 return NULL;
426}
427
428
429void Thread::Start() {
430 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
431 ASSERT(IsValid());
432}
433
434
435void Thread::Join() {
436 pthread_join(thread_handle_data()->thread_, NULL);
437}
438
439
440Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
441 pthread_key_t key;
442 int result = pthread_key_create(&key, NULL);
443 USE(result);
444 ASSERT(result == 0);
445 return static_cast<LocalStorageKey>(key);
446}
447
448
449void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
450 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
451 int result = pthread_key_delete(pthread_key);
452 USE(result);
453 ASSERT(result == 0);
454}
455
456
457void* Thread::GetThreadLocal(LocalStorageKey key) {
458 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
459 return pthread_getspecific(pthread_key);
460}
461
462
463void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
464 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
465 pthread_setspecific(pthread_key, value);
466}
467
468
469void Thread::YieldCPU() {
470 sched_yield();
471}
472
473
474class LinuxMutex : public Mutex {
475 public:
476
477 LinuxMutex() {
478 pthread_mutexattr_t attrs;
479 int result = pthread_mutexattr_init(&attrs);
480 ASSERT(result == 0);
481 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
482 ASSERT(result == 0);
483 result = pthread_mutex_init(&mutex_, &attrs);
484 ASSERT(result == 0);
485 }
486
487 virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
488
489 virtual int Lock() {
490 int result = pthread_mutex_lock(&mutex_);
491 return result;
492 }
493
494 virtual int Unlock() {
495 int result = pthread_mutex_unlock(&mutex_);
496 return result;
497 }
498
499 private:
500 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
501};
502
503
504Mutex* OS::CreateMutex() {
505 return new LinuxMutex();
506}
507
508
509class LinuxSemaphore : public Semaphore {
510 public:
511 explicit LinuxSemaphore(int count) { sem_init(&sem_, 0, count); }
512 virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
513
kasper.lund7276f142008-07-30 08:49:36 +0000514 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000515 virtual bool Wait(int timeout);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516 virtual void Signal() { sem_post(&sem_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517 private:
518 sem_t sem_;
519};
520
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000521
kasper.lund7276f142008-07-30 08:49:36 +0000522void LinuxSemaphore::Wait() {
523 while (true) {
524 int result = sem_wait(&sem_);
525 if (result == 0) return; // Successfully got semaphore.
526 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
527 }
528}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000530
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000531#ifndef TIMEVAL_TO_TIMESPEC
532#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
533 (ts)->tv_sec = (tv)->tv_sec; \
534 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
535} while (false)
536#endif
537
538
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539bool LinuxSemaphore::Wait(int timeout) {
540 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541
542 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000543 struct timeval delta;
544 delta.tv_usec = timeout % kOneSecondMicros;
545 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000546
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000547 struct timeval current_time;
548 // Get the current time.
549 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000550 return false;
551 }
552
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000553 // Calculate time for end of timeout.
554 struct timeval end_time;
555 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000557 struct timespec ts;
558 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 // Wait for semaphore signalled or timeout.
560 while (true) {
561 int result = sem_timedwait(&sem_, &ts);
562 if (result == 0) return true; // Successfully got semaphore.
563 if (result > 0) {
564 // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
565 errno = result;
566 result = -1;
567 }
568 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
569 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
570 }
571}
572
573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574Semaphore* OS::CreateSemaphore(int count) {
575 return new LinuxSemaphore(count);
576}
577
ager@chromium.org381abbb2009-02-25 13:23:22 +0000578
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579#ifdef ENABLE_LOGGING_AND_PROFILING
580
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000581static Sampler* active_sampler_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582
kasperl@chromium.orgacae3782009-04-11 09:17:08 +0000583
584#if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
585// Android runs a fairly new Linux kernel, so signal info is there,
586// but the C library doesn't have the structs defined.
587
588struct sigcontext {
589 uint32_t trap_no;
590 uint32_t error_code;
591 uint32_t oldmask;
592 uint32_t gregs[16];
593 uint32_t arm_cpsr;
594 uint32_t fault_address;
595};
596typedef uint32_t __sigset_t;
597typedef struct sigcontext mcontext_t;
598typedef struct ucontext {
599 uint32_t uc_flags;
600 struct ucontext *uc_link;
601 stack_t uc_stack;
602 mcontext_t uc_mcontext;
603 __sigset_t uc_sigmask;
604} ucontext_t;
605enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
606
607#endif
608
609
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
611 USE(info);
612 if (signal != SIGPROF) return;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613 if (active_sampler_ == NULL) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 TickSample sample;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000616
617 // If profiling, we extract the current pc and sp.
618 if (active_sampler_->IsProfiling()) {
619 // Extracting the sample from the context is extremely machine dependent.
620 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
621 mcontext_t& mcontext = ucontext->uc_mcontext;
ager@chromium.org9085a012009-05-11 19:22:57 +0000622#if V8_HOST_ARCH_IA32
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000623 sample.pc = mcontext.gregs[REG_EIP];
624 sample.sp = mcontext.gregs[REG_ESP];
ager@chromium.org381abbb2009-02-25 13:23:22 +0000625 sample.fp = mcontext.gregs[REG_EBP];
ager@chromium.org9085a012009-05-11 19:22:57 +0000626#elif V8_HOST_ARCH_X64
627 sample.pc = mcontext.gregs[REG_RIP];
628 sample.sp = mcontext.gregs[REG_RSP];
629 sample.fp = mcontext.gregs[REG_RBP];
630#elif V8_HOST_ARCH_ARM
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000631// An undefined macro evaluates to 0, so this applies to Android's Bionic also.
632#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
ager@chromium.org9085a012009-05-11 19:22:57 +0000633 sample.pc = mcontext.gregs[R15];
634 sample.sp = mcontext.gregs[R13];
635 sample.fp = mcontext.gregs[R11];
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000636#else
637 sample.pc = mcontext.arm_pc;
638 sample.sp = mcontext.arm_sp;
639 sample.fp = mcontext.arm_fp;
640#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000642 }
643
644 // We always sample the VM state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 sample.state = Logger::state();
646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 active_sampler_->Tick(&sample);
648}
649
650
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000651class Sampler::PlatformData : public Malloced {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 public:
653 PlatformData() {
654 signal_handler_installed_ = false;
655 }
656
657 bool signal_handler_installed_;
658 struct sigaction old_signal_handler_;
659 struct itimerval old_timer_value_;
660};
661
662
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000663Sampler::Sampler(int interval, bool profiling)
664 : interval_(interval), profiling_(profiling), active_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 data_ = new PlatformData();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666}
667
668
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000669Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 delete data_;
671}
672
673
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674void Sampler::Start() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 // There can only be one active sampler at the time on POSIX
676 // platforms.
677 if (active_sampler_ != NULL) return;
678
679 // Request profiling signals.
680 struct sigaction sa;
681 sa.sa_sigaction = ProfilerSignalHandler;
682 sigemptyset(&sa.sa_mask);
683 sa.sa_flags = SA_SIGINFO;
684 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
685 data_->signal_handler_installed_ = true;
686
687 // Set the itimer to generate a tick for each interval.
688 itimerval itimer;
689 itimer.it_interval.tv_sec = interval_ / 1000;
690 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
691 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
692 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
693 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
694
695 // Set this sampler as the active sampler.
696 active_sampler_ = this;
697 active_ = true;
698}
699
700
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000701void Sampler::Stop() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702 // Restore old signal handler
703 if (data_->signal_handler_installed_) {
704 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
705 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
706 data_->signal_handler_installed_ = false;
707 }
708
709 // This sampler is no longer the active sampler.
710 active_sampler_ = NULL;
711 active_ = false;
712}
713
714#endif // ENABLE_LOGGING_AND_PROFILING
715
716} } // namespace v8::internal