blob: 6b8f2c048a7d6805cd00095ef44ab8e54a3c90f8 [file] [log] [blame]
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001// Copyright 2006-2008 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
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000028// Platform specific code for FreeBSD goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
ager@chromium.orga74f0da2008-12-03 16:05:52 +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>
ager@chromium.orga74f0da2008-12-03 16:05:52 +000037#include <sys/ucontext.h>
38#include <stdlib.h>
39
40#include <sys/types.h> // mmap & munmap
41#include <sys/mman.h> // mmap & munmap
42#include <sys/stat.h> // open
43#include <sys/fcntl.h> // open
44#include <unistd.h> // getpagesize
45#include <execinfo.h> // backtrace, backtrace_symbols
46#include <strings.h> // index
47#include <errno.h>
48#include <stdarg.h>
49#include <limits.h>
50
51#undef MAP_TYPE
52
53#include "v8.h"
54
55#include "platform.h"
56
57
kasperl@chromium.org71affb52009-05-26 05:44:31 +000058namespace v8 {
59namespace internal {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000060
61// 0 is never a valid thread id on FreeBSD since tids and pids share a
62// name space and pid 0 is used to kill the group (see man 2 kill).
63static const pthread_t kNoThread = (pthread_t) 0;
64
65
66double ceiling(double x) {
67 // Correct as on OS X
68 if (-1.0 < x && x < 0.0) {
69 return -0.0;
70 } else {
71 return ceil(x);
72 }
73}
74
75
76void OS::Setup() {
77 // Seed the random number generator.
78 // Convert the current time to a 64-bit integer first, before converting it
79 // to an unsigned. Going directly can cause an overflow and the seed to be
80 // set to all ones. The seed will be identical for different instances that
81 // call this setup code within the same millisecond.
82 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
83 srandom(static_cast<unsigned int>(seed));
84}
85
86
ricow@chromium.org30ce4112010-05-31 10:38:25 +000087void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
88 __asm__ __volatile__("" : : : "memory");
89 *ptr = value;
90}
91
92
ager@chromium.orgc4c92722009-11-18 14:12:51 +000093uint64_t OS::CpuFeaturesImpliedByPlatform() {
94 return 0; // FreeBSD runs on anything.
95}
96
97
ager@chromium.orga74f0da2008-12-03 16:05:52 +000098int OS::ActivationFrameAlignment() {
99 // 16 byte alignment on FreeBSD
100 return 16;
101}
102
103
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000104const char* OS::LocalTimezone(double time) {
105 if (isnan(time)) return "";
106 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
107 struct tm* t = localtime(&tv);
108 if (NULL == t) return "";
109 return t->tm_zone;
110}
111
112
113double OS::LocalTimeOffset() {
114 time_t tv = time(NULL);
115 struct tm* t = localtime(&tv);
116 // tm_gmtoff includes any daylight savings offset, so subtract it.
117 return static_cast<double>(t->tm_gmtoff * msPerSecond -
118 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
119}
120
121
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000122// We keep the lowest and highest addresses mapped as a quick way of
123// determining that pointers are outside the heap (used mostly in assertions
124// and verification). The estimate is conservative, ie, not all addresses in
125// 'allocated' space are actually allocated to our heap. The range is
126// [lowest, highest), inclusive on the low and and exclusive on the high end.
127static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
128static void* highest_ever_allocated = reinterpret_cast<void*>(0);
129
130
131static void UpdateAllocatedSpaceLimits(void* address, int size) {
132 lowest_ever_allocated = Min(lowest_ever_allocated, address);
133 highest_ever_allocated =
134 Max(highest_ever_allocated,
135 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
136}
137
138
139bool OS::IsOutsideAllocatedSpace(void* address) {
140 return address < lowest_ever_allocated || address >= highest_ever_allocated;
141}
142
143
144size_t OS::AllocateAlignment() {
145 return getpagesize();
146}
147
148
149void* OS::Allocate(const size_t requested,
150 size_t* allocated,
151 bool executable) {
152 const size_t msize = RoundUp(requested, getpagesize());
153 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
154 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
155
156 if (mbase == MAP_FAILED) {
157 LOG(StringEvent("OS::Allocate", "mmap failed"));
158 return NULL;
159 }
160 *allocated = msize;
161 UpdateAllocatedSpaceLimits(mbase, msize);
162 return mbase;
163}
164
165
166void OS::Free(void* buf, const size_t length) {
167 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000168 int result = munmap(buf, length);
169 USE(result);
170 ASSERT(result == 0);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000171}
172
173
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000174#ifdef ENABLE_HEAP_PROTECTION
175
176void OS::Protect(void* address, size_t size) {
177 UNIMPLEMENTED();
178}
179
180
181void OS::Unprotect(void* address, size_t size, bool is_executable) {
182 UNIMPLEMENTED();
183}
184
185#endif
186
187
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000188void OS::Sleep(int milliseconds) {
189 unsigned int ms = static_cast<unsigned int>(milliseconds);
190 usleep(1000 * ms);
191}
192
193
194void OS::Abort() {
195 // Redirect to std abort to signal abnormal program termination.
196 abort();
197}
198
199
200void OS::DebugBreak() {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000201#if (defined(__arm__) || defined(__thumb__))
202# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000203 asm("bkpt 0");
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000204# endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000205#else
206 asm("int $3");
207#endif
208}
209
210
211class PosixMemoryMappedFile : public OS::MemoryMappedFile {
212 public:
213 PosixMemoryMappedFile(FILE* file, void* memory, int size)
214 : file_(file), memory_(memory), size_(size) { }
215 virtual ~PosixMemoryMappedFile();
216 virtual void* memory() { return memory_; }
217 private:
218 FILE* file_;
219 void* memory_;
220 int size_;
221};
222
223
224OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
225 void* initial) {
226 FILE* file = fopen(name, "w+");
227 if (file == NULL) return NULL;
228 int result = fwrite(initial, size, 1, file);
229 if (result < 1) {
230 fclose(file);
231 return NULL;
232 }
233 void* memory =
234 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
235 return new PosixMemoryMappedFile(file, memory, size);
236}
237
238
239PosixMemoryMappedFile::~PosixMemoryMappedFile() {
240 if (memory_) munmap(memory_, size_);
241 fclose(file_);
242}
243
244
245#ifdef ENABLE_LOGGING_AND_PROFILING
246static unsigned StringToLong(char* buffer) {
247 return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
248}
249#endif
250
251
252void OS::LogSharedLibraryAddresses() {
253#ifdef ENABLE_LOGGING_AND_PROFILING
254 static const int MAP_LENGTH = 1024;
255 int fd = open("/proc/self/maps", O_RDONLY);
256 if (fd < 0) return;
257 while (true) {
258 char addr_buffer[11];
259 addr_buffer[0] = '0';
260 addr_buffer[1] = 'x';
261 addr_buffer[10] = 0;
262 int result = read(fd, addr_buffer + 2, 8);
263 if (result < 8) break;
264 unsigned start = StringToLong(addr_buffer);
265 result = read(fd, addr_buffer + 2, 1);
266 if (result < 1) break;
267 if (addr_buffer[2] != '-') break;
268 result = read(fd, addr_buffer + 2, 8);
269 if (result < 8) break;
270 unsigned end = StringToLong(addr_buffer);
271 char buffer[MAP_LENGTH];
272 int bytes_read = -1;
273 do {
274 bytes_read++;
275 if (bytes_read >= MAP_LENGTH - 1)
276 break;
277 result = read(fd, buffer + bytes_read, 1);
278 if (result < 1) break;
279 } while (buffer[bytes_read] != '\n');
280 buffer[bytes_read] = 0;
281 // Ignore mappings that are not executable.
282 if (buffer[3] != 'x') continue;
283 char* start_of_path = index(buffer, '/');
284 // There may be no filename in this line. Skip to next.
285 if (start_of_path == NULL) continue;
286 buffer[bytes_read] = 0;
287 LOG(SharedLibraryEvent(start_of_path, start, end));
288 }
289 close(fd);
290#endif
291}
292
293
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000294void OS::SignalCodeMovingGC() {
295}
296
297
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000298int OS::StackWalk(Vector<OS::StackFrame> frames) {
299 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000300 ScopedVector<void*> addresses(frames_size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000301
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000302 int frames_count = backtrace(addresses.start(), frames_size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000303
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000304 char** symbols = backtrace_symbols(addresses.start(), frames_count);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000305 if (symbols == NULL) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000306 return kStackWalkError;
307 }
308
309 for (int i = 0; i < frames_count; i++) {
310 frames[i].address = addresses[i];
311 // Format a text representation of the frame based on the information
312 // available.
313 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
314 "%s",
315 symbols[i]);
316 // Make sure line termination is in place.
317 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
318 }
319
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000320 free(symbols);
321
322 return frames_count;
323}
324
325
326// Constants used for mmap.
327static const int kMmapFd = -1;
328static const int kMmapFdOffset = 0;
329
330
331VirtualMemory::VirtualMemory(size_t size) {
332 address_ = mmap(NULL, size, PROT_NONE,
333 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
334 kMmapFd, kMmapFdOffset);
335 size_ = size;
336}
337
338
339VirtualMemory::~VirtualMemory() {
340 if (IsReserved()) {
341 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
342 }
343}
344
345
346bool VirtualMemory::IsReserved() {
347 return address_ != MAP_FAILED;
348}
349
350
351bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
352 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
353 if (MAP_FAILED == mmap(address, size, prot,
354 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
355 kMmapFd, kMmapFdOffset)) {
356 return false;
357 }
358
359 UpdateAllocatedSpaceLimits(address, size);
360 return true;
361}
362
363
364bool VirtualMemory::Uncommit(void* address, size_t size) {
365 return mmap(address, size, PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000366 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000367 kMmapFd, kMmapFdOffset) != MAP_FAILED;
368}
369
370
371class ThreadHandle::PlatformData : public Malloced {
372 public:
373 explicit PlatformData(ThreadHandle::Kind kind) {
374 Initialize(kind);
375 }
376
377 void Initialize(ThreadHandle::Kind kind) {
378 switch (kind) {
379 case ThreadHandle::SELF: thread_ = pthread_self(); break;
380 case ThreadHandle::INVALID: thread_ = kNoThread; break;
381 }
382 }
383 pthread_t thread_; // Thread handle for pthread.
384};
385
386
387ThreadHandle::ThreadHandle(Kind kind) {
388 data_ = new PlatformData(kind);
389}
390
391
392void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
393 data_->Initialize(kind);
394}
395
396
397ThreadHandle::~ThreadHandle() {
398 delete data_;
399}
400
401
402bool ThreadHandle::IsSelf() const {
403 return pthread_equal(data_->thread_, pthread_self());
404}
405
406
407bool ThreadHandle::IsValid() const {
408 return data_->thread_ != kNoThread;
409}
410
411
412Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
413}
414
415
416Thread::~Thread() {
417}
418
419
420static void* ThreadEntry(void* arg) {
421 Thread* thread = reinterpret_cast<Thread*>(arg);
422 // This is also initialized by the first argument to pthread_create() but we
423 // don't know which thread will run first (the original thread or the new
424 // one) so we initialize it here too.
425 thread->thread_handle_data()->thread_ = pthread_self();
426 ASSERT(thread->IsValid());
427 thread->Run();
428 return NULL;
429}
430
431
432void Thread::Start() {
433 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
434 ASSERT(IsValid());
435}
436
437
438void Thread::Join() {
439 pthread_join(thread_handle_data()->thread_, NULL);
440}
441
442
443Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
444 pthread_key_t key;
445 int result = pthread_key_create(&key, NULL);
446 USE(result);
447 ASSERT(result == 0);
448 return static_cast<LocalStorageKey>(key);
449}
450
451
452void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
453 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
454 int result = pthread_key_delete(pthread_key);
455 USE(result);
456 ASSERT(result == 0);
457}
458
459
460void* Thread::GetThreadLocal(LocalStorageKey key) {
461 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
462 return pthread_getspecific(pthread_key);
463}
464
465
466void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
467 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
468 pthread_setspecific(pthread_key, value);
469}
470
471
472void Thread::YieldCPU() {
473 sched_yield();
474}
475
476
477class FreeBSDMutex : public Mutex {
478 public:
479
480 FreeBSDMutex() {
481 pthread_mutexattr_t attrs;
482 int result = pthread_mutexattr_init(&attrs);
483 ASSERT(result == 0);
484 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
485 ASSERT(result == 0);
486 result = pthread_mutex_init(&mutex_, &attrs);
487 ASSERT(result == 0);
488 }
489
490 virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
491
492 virtual int Lock() {
493 int result = pthread_mutex_lock(&mutex_);
494 return result;
495 }
496
497 virtual int Unlock() {
498 int result = pthread_mutex_unlock(&mutex_);
499 return result;
500 }
501
502 private:
503 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
504};
505
506
507Mutex* OS::CreateMutex() {
508 return new FreeBSDMutex();
509}
510
511
512class FreeBSDSemaphore : public Semaphore {
513 public:
514 explicit FreeBSDSemaphore(int count) { sem_init(&sem_, 0, count); }
515 virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
516
517 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 virtual bool Wait(int timeout);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000519 virtual void Signal() { sem_post(&sem_); }
520 private:
521 sem_t sem_;
522};
523
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000524
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000525void FreeBSDSemaphore::Wait() {
526 while (true) {
527 int result = sem_wait(&sem_);
528 if (result == 0) return; // Successfully got semaphore.
529 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
530 }
531}
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533
534bool FreeBSDSemaphore::Wait(int timeout) {
535 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000536
537 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000538 struct timeval delta;
539 delta.tv_usec = timeout % kOneSecondMicros;
540 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000542 struct timeval current_time;
543 // Get the current time.
544 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000545 return false;
546 }
547
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000548 // Calculate time for end of timeout.
549 struct timeval end_time;
550 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000551
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000552 struct timespec ts;
553 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000554 while (true) {
555 int result = sem_timedwait(&sem_, &ts);
556 if (result == 0) return true; // Successfully got semaphore.
557 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
558 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
559 }
560}
561
562
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000563Semaphore* OS::CreateSemaphore(int count) {
564 return new FreeBSDSemaphore(count);
565}
566
ager@chromium.org381abbb2009-02-25 13:23:22 +0000567
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000568#ifdef ENABLE_LOGGING_AND_PROFILING
569
570static Sampler* active_sampler_ = NULL;
571
572static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
573 USE(info);
574 if (signal != SIGPROF) return;
575 if (active_sampler_ == NULL) return;
576
577 TickSample sample;
578
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000579 // We always sample the VM state.
ager@chromium.org357bf652010-04-12 11:30:10 +0000580 sample.state = VMState::current_state();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000581
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000582 // If profiling, we extract the current pc and sp.
583 if (active_sampler_->IsProfiling()) {
584 // Extracting the sample from the context is extremely machine dependent.
585 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
586 mcontext_t& mcontext = ucontext->uc_mcontext;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000587#if V8_HOST_ARCH_IA32
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000588 sample.pc = reinterpret_cast<Address>(mcontext.mc_eip);
589 sample.sp = reinterpret_cast<Address>(mcontext.mc_esp);
590 sample.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000591#elif V8_HOST_ARCH_X64
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000592 sample.pc = reinterpret_cast<Address>(mcontext.mc_rip);
593 sample.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
594 sample.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000595#elif V8_HOST_ARCH_ARM
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000596 sample.pc = reinterpret_cast<Address>(mcontext.mc_r15);
597 sample.sp = reinterpret_cast<Address>(mcontext.mc_r13);
598 sample.fp = reinterpret_cast<Address>(mcontext.mc_r11);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000599#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000600 active_sampler_->SampleStack(&sample);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000601 }
602
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000603 active_sampler_->Tick(&sample);
604}
605
606
607class Sampler::PlatformData : public Malloced {
608 public:
609 PlatformData() {
610 signal_handler_installed_ = false;
611 }
612
613 bool signal_handler_installed_;
614 struct sigaction old_signal_handler_;
615 struct itimerval old_timer_value_;
616};
617
618
619Sampler::Sampler(int interval, bool profiling)
lrn@chromium.org303ada72010-10-27 09:33:13 +0000620 : interval_(interval),
621 profiling_(profiling),
622 synchronous_(profiling),
623 active_(false) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000624 data_ = new PlatformData();
625}
626
627
628Sampler::~Sampler() {
629 delete data_;
630}
631
632
633void Sampler::Start() {
634 // There can only be one active sampler at the time on POSIX
635 // platforms.
636 if (active_sampler_ != NULL) return;
637
638 // Request profiling signals.
639 struct sigaction sa;
640 sa.sa_sigaction = ProfilerSignalHandler;
641 sigemptyset(&sa.sa_mask);
642 sa.sa_flags = SA_SIGINFO;
643 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
644 data_->signal_handler_installed_ = true;
645
646 // Set the itimer to generate a tick for each interval.
647 itimerval itimer;
648 itimer.it_interval.tv_sec = interval_ / 1000;
649 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
650 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
651 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
652 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
653
654 // Set this sampler as the active sampler.
655 active_sampler_ = this;
656 active_ = true;
657}
658
659
660void Sampler::Stop() {
661 // Restore old signal handler
662 if (data_->signal_handler_installed_) {
663 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
664 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
665 data_->signal_handler_installed_ = false;
666 }
667
668 // This sampler is no longer the active sampler.
669 active_sampler_ = NULL;
670 active_ = false;
671}
672
673#endif // ENABLE_LOGGING_AND_PROFILING
674
675} } // namespace v8::internal