Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/platform-openbsd.cc

Issue 7348008: Merge up to 8597 to experimental/gc from the bleeding edge. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/platform-nullos.cc ('k') | src/platform-posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 #include <unistd.h> // getpagesize 43 #include <unistd.h> // getpagesize
44 #include <execinfo.h> // backtrace, backtrace_symbols 44 #include <execinfo.h> // backtrace, backtrace_symbols
45 #include <strings.h> // index 45 #include <strings.h> // index
46 #include <errno.h> 46 #include <errno.h>
47 #include <stdarg.h> 47 #include <stdarg.h>
48 #include <limits.h> 48 #include <limits.h>
49 49
50 #undef MAP_TYPE 50 #undef MAP_TYPE
51 51
52 #include "v8.h" 52 #include "v8.h"
53 #include "v8threads.h"
53 54
54 #include "platform.h" 55 #include "platform.h"
55 #include "vm-state-inl.h" 56 #include "vm-state-inl.h"
56 57
57 58
58 namespace v8 { 59 namespace v8 {
59 namespace internal { 60 namespace internal {
60 61
61 // 0 is never a valid thread id on OpenBSD since tids and pids share a 62 // 0 is never a valid thread id on OpenBSD since tids and pids share a
62 // name space and pid 0 is used to kill the group (see man 2 kill). 63 // name space and pid 0 is used to kill the group (see man 2 kill).
63 static const pthread_t kNoThread = (pthread_t) 0; 64 static const pthread_t kNoThread = (pthread_t) 0;
64 65
65 66
66 double ceiling(double x) { 67 double ceiling(double x) {
67 // Correct as on OS X 68 // Correct as on OS X
68 if (-1.0 < x && x < 0.0) { 69 if (-1.0 < x && x < 0.0) {
69 return -0.0; 70 return -0.0;
70 } else { 71 } else {
71 return ceil(x); 72 return ceil(x);
72 } 73 }
73 } 74 }
74 75
75 76
77 static Mutex* limit_mutex = NULL;
78
79
76 void OS::Setup() { 80 void OS::Setup() {
77 // Seed the random number generator. 81 // Seed the random number generator.
78 // Convert the current time to a 64-bit integer first, before converting it 82 // 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 83 // 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 84 // set to all ones. The seed will be identical for different instances that
81 // call this setup code within the same millisecond. 85 // call this setup code within the same millisecond.
82 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); 86 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
83 srandom(static_cast<unsigned int>(seed)); 87 srandom(static_cast<unsigned int>(seed));
88 limit_mutex = CreateMutex();
84 } 89 }
85 90
86 91
87 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { 92 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
88 __asm__ __volatile__("" : : : "memory"); 93 __asm__ __volatile__("" : : : "memory");
89 *ptr = value; 94 *ptr = value;
90 } 95 }
91 96
92 97
93 uint64_t OS::CpuFeaturesImpliedByPlatform() { 98 uint64_t OS::CpuFeaturesImpliedByPlatform() {
(...skipping 28 matching lines...) Expand all
122 // We keep the lowest and highest addresses mapped as a quick way of 127 // 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 128 // determining that pointers are outside the heap (used mostly in assertions
124 // and verification). The estimate is conservative, ie, not all addresses in 129 // and verification). The estimate is conservative, ie, not all addresses in
125 // 'allocated' space are actually allocated to our heap. The range is 130 // '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. 131 // [lowest, highest), inclusive on the low and and exclusive on the high end.
127 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 132 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
128 static void* highest_ever_allocated = reinterpret_cast<void*>(0); 133 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
129 134
130 135
131 static void UpdateAllocatedSpaceLimits(void* address, int size) { 136 static void UpdateAllocatedSpaceLimits(void* address, int size) {
137 ASSERT(limit_mutex != NULL);
138 ScopedLock lock(limit_mutex);
139
132 lowest_ever_allocated = Min(lowest_ever_allocated, address); 140 lowest_ever_allocated = Min(lowest_ever_allocated, address);
133 highest_ever_allocated = 141 highest_ever_allocated =
134 Max(highest_ever_allocated, 142 Max(highest_ever_allocated,
135 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 143 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
136 } 144 }
137 145
138 146
139 bool OS::IsOutsideAllocatedSpace(void* address) { 147 bool OS::IsOutsideAllocatedSpace(void* address) {
140 return address < lowest_ever_allocated || address >= highest_ever_allocated; 148 return address < lowest_ever_allocated || address >= highest_ever_allocated;
141 } 149 }
(...skipping 15 matching lines...) Expand all
157 LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed")); 165 LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
158 return NULL; 166 return NULL;
159 } 167 }
160 *allocated = msize; 168 *allocated = msize;
161 UpdateAllocatedSpaceLimits(mbase, msize); 169 UpdateAllocatedSpaceLimits(mbase, msize);
162 return mbase; 170 return mbase;
163 } 171 }
164 172
165 173
166 void OS::Free(void* buf, const size_t length) { 174 void OS::Free(void* buf, const size_t length) {
175 // TODO(1240712): munmap has a return value which is ignored here.
167 int result = munmap(buf, length); 176 int result = munmap(buf, length);
168 USE(result); 177 USE(result);
169 ASSERT(result == 0); 178 ASSERT(result == 0);
170 } 179 }
171 180
172 181
173 #ifdef ENABLE_HEAP_PROTECTION 182 #ifdef ENABLE_HEAP_PROTECTION
174 183
175 void OS::Protect(void* address, size_t size) { 184 void OS::Protect(void* address, size_t size) {
176 UNIMPLEMENTED(); 185 UNIMPLEMENTED();
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 result = read(fd, buffer + bytes_read, 1); 299 result = read(fd, buffer + bytes_read, 1);
291 if (result < 1) break; 300 if (result < 1) break;
292 } while (buffer[bytes_read] != '\n'); 301 } while (buffer[bytes_read] != '\n');
293 buffer[bytes_read] = 0; 302 buffer[bytes_read] = 0;
294 // Ignore mappings that are not executable. 303 // Ignore mappings that are not executable.
295 if (buffer[3] != 'x') continue; 304 if (buffer[3] != 'x') continue;
296 char* start_of_path = index(buffer, '/'); 305 char* start_of_path = index(buffer, '/');
297 // There may be no filename in this line. Skip to next. 306 // There may be no filename in this line. Skip to next.
298 if (start_of_path == NULL) continue; 307 if (start_of_path == NULL) continue;
299 buffer[bytes_read] = 0; 308 buffer[bytes_read] = 0;
300 LOG(SharedLibraryEvent(start_of_path, start, end)); 309 LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
301 } 310 }
302 close(fd); 311 close(fd);
303 #endif 312 #endif
304 } 313 }
305 314
306 315
307 void OS::SignalCodeMovingGC() { 316 void OS::SignalCodeMovingGC() {
308 } 317 }
309 318
310 319
311 int OS::StackWalk(Vector<OS::StackFrame> frames) { 320 int OS::StackWalk(Vector<OS::StackFrame> frames) {
312 UNIMPLEMENTED(); 321 int frames_size = frames.length();
313 return 1; 322 ScopedVector<void*> addresses(frames_size);
323
324 int frames_count = backtrace(addresses.start(), frames_size);
325
326 char** symbols = backtrace_symbols(addresses.start(), frames_count);
327 if (symbols == NULL) {
328 return kStackWalkError;
329 }
330
331 for (int i = 0; i < frames_count; i++) {
332 frames[i].address = addresses[i];
333 // Format a text representation of the frame based on the information
334 // available.
335 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
336 "%s",
337 symbols[i]);
338 // Make sure line termination is in place.
339 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
340 }
341
342 free(symbols);
343
344 return frames_count;
314 } 345 }
315 346
316 347
317 // Constants used for mmap. 348 // Constants used for mmap.
318 static const int kMmapFd = -1; 349 static const int kMmapFd = -1;
319 static const int kMmapFdOffset = 0; 350 static const int kMmapFdOffset = 0;
320 351
321 352
322 VirtualMemory::VirtualMemory(size_t size) { 353 VirtualMemory::VirtualMemory(size_t size) {
323 address_ = mmap(NULL, size, PROT_NONE, 354 address_ = mmap(NULL, size, PROT_NONE,
(...skipping 23 matching lines...) Expand all
347 return false; 378 return false;
348 } 379 }
349 380
350 UpdateAllocatedSpaceLimits(address, size); 381 UpdateAllocatedSpaceLimits(address, size);
351 return true; 382 return true;
352 } 383 }
353 384
354 385
355 bool VirtualMemory::Uncommit(void* address, size_t size) { 386 bool VirtualMemory::Uncommit(void* address, size_t size) {
356 return mmap(address, size, PROT_NONE, 387 return mmap(address, size, PROT_NONE,
357 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 388 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
358 kMmapFd, kMmapFdOffset) != MAP_FAILED; 389 kMmapFd, kMmapFdOffset) != MAP_FAILED;
359 } 390 }
360 391
361 392
362 class Thread::PlatformData : public Malloced { 393 class Thread::PlatformData : public Malloced {
363 public: 394 public:
364 PlatformData() : thread_(kNoThread) {}
365
366 pthread_t thread_; // Thread handle for pthread. 395 pthread_t thread_; // Thread handle for pthread.
367 }; 396 };
368 397
369 398
370 Thread::Thread(Isolate* isolate, const Options& options) 399 Thread::Thread(const Options& options)
371 : data_(new PlatformData()), 400 : data_(new PlatformData),
372 isolate_(isolate),
373 stack_size_(options.stack_size) { 401 stack_size_(options.stack_size) {
374 set_name(options.name); 402 set_name(options.name);
375 } 403 }
376 404
377 405
378 Thread::Thread(Isolate* isolate, const char* name) 406 Thread::Thread(const char* name)
379 : data_(new PlatfromData()), 407 : data_(new PlatformData),
380 isolate_(isolate),
381 stack_size_(0) { 408 stack_size_(0) {
382 set_name(name); 409 set_name(name);
383 } 410 }
384 411
385 412
386 Thread::~Thread() { 413 Thread::~Thread() {
387 delete data_; 414 delete data_;
388 } 415 }
389 416
390 417
391 static void* ThreadEntry(void* arg) { 418 static void* ThreadEntry(void* arg) {
392 Thread* thread = reinterpret_cast<Thread*>(arg); 419 Thread* thread = reinterpret_cast<Thread*>(arg);
393 // This is also initialized by the first argument to pthread_create() but we 420 // This is also initialized by the first argument to pthread_create() but we
394 // don't know which thread will run first (the original thread or the new 421 // don't know which thread will run first (the original thread or the new
395 // one) so we initialize it here too. 422 // one) so we initialize it here too.
396 thread->data()->thread_ = pthread_self(); 423 thread->data()->thread_ = pthread_self();
397 ASSERT(thread->data()->thread_ != kNoThread); 424 ASSERT(thread->data()->thread_ != kNoThread);
398 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
399 thread->Run(); 425 thread->Run();
400 return NULL; 426 return NULL;
401 } 427 }
402 428
403 429
404 void Thread::set_name(const char* name) { 430 void Thread::set_name(const char* name) {
405 strncpy(name_, name, sizeof(name_)); 431 strncpy(name_, name, sizeof(name_));
406 name_[sizeof(name_) - 1] = '\0'; 432 name_[sizeof(name_) - 1] = '\0';
407 } 433 }
408 434
409 435
410 void Thread::Start() { 436 void Thread::Start() {
411 pthread_attr_t* attr_ptr = NULL; 437 pthread_attr_t* attr_ptr = NULL;
412 pthread_attr_t attr; 438 pthread_attr_t attr;
413 if (stack_size_ > 0) { 439 if (stack_size_ > 0) {
414 pthread_attr_init(&attr); 440 pthread_attr_init(&attr);
415 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 441 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
416 attr_ptr = &attr; 442 attr_ptr = &attr;
417 } 443 }
418 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this); 444 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
419 ASSERT(IsValid()); 445 ASSERT(data_->thread_ != kNoThread);
420 } 446 }
421 447
422 448
423 void Thread::Join() { 449 void Thread::Join() {
424 pthread_join(data_->thread_, NULL); 450 pthread_join(data_->thread_, NULL);
425 } 451 }
426 452
427 453
428 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 454 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
429 pthread_key_t key; 455 pthread_key_t key;
(...skipping 24 matching lines...) Expand all
454 } 480 }
455 481
456 482
457 void Thread::YieldCPU() { 483 void Thread::YieldCPU() {
458 sched_yield(); 484 sched_yield();
459 } 485 }
460 486
461 487
462 class OpenBSDMutex : public Mutex { 488 class OpenBSDMutex : public Mutex {
463 public: 489 public:
464
465 OpenBSDMutex() { 490 OpenBSDMutex() {
466 pthread_mutexattr_t attrs; 491 pthread_mutexattr_t attrs;
467 int result = pthread_mutexattr_init(&attrs); 492 int result = pthread_mutexattr_init(&attrs);
468 ASSERT(result == 0); 493 ASSERT(result == 0);
469 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE); 494 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
470 ASSERT(result == 0); 495 ASSERT(result == 0);
471 result = pthread_mutex_init(&mutex_, &attrs); 496 result = pthread_mutex_init(&mutex_, &attrs);
472 ASSERT(result == 0); 497 ASSERT(result == 0);
473 } 498 }
474 499
475 virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); } 500 virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
476 501
477 virtual int Lock() { 502 virtual int Lock() {
478 int result = pthread_mutex_lock(&mutex_); 503 int result = pthread_mutex_lock(&mutex_);
479 return result; 504 return result;
480 } 505 }
481 506
482 virtual int Unlock() { 507 virtual int Unlock() {
483 int result = pthread_mutex_unlock(&mutex_); 508 int result = pthread_mutex_unlock(&mutex_);
484 return result; 509 return result;
485 } 510 }
486 511
512 virtual bool TryLock() {
513 int result = pthread_mutex_trylock(&mutex_);
514 // Return false if the lock is busy and locking failed.
515 if (result == EBUSY) {
516 return false;
517 }
518 ASSERT(result == 0); // Verify no other errors.
519 return true;
520 }
521
487 private: 522 private:
488 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. 523 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
489 }; 524 };
490 525
491 526
492 Mutex* OS::CreateMutex() { 527 Mutex* OS::CreateMutex() {
493 return new OpenBSDMutex(); 528 return new OpenBSDMutex();
494 } 529 }
495 530
496 531
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 if (gettimeofday(&current_time, NULL) == -1) { 564 if (gettimeofday(&current_time, NULL) == -1) {
530 return false; 565 return false;
531 } 566 }
532 567
533 // Calculate time for end of timeout. 568 // Calculate time for end of timeout.
534 struct timeval end_time; 569 struct timeval end_time;
535 timeradd(&current_time, &delta, &end_time); 570 timeradd(&current_time, &delta, &end_time);
536 571
537 struct timespec ts; 572 struct timespec ts;
538 TIMEVAL_TO_TIMESPEC(&end_time, &ts); 573 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
574
575 int to = ts.tv_sec;
576
539 while (true) { 577 while (true) {
540 int result = sem_trywait(&sem_); 578 int result = sem_trywait(&sem_);
541 if (result == 0) return true; // Successfully got semaphore. 579 if (result == 0) return true; // Successfully got semaphore.
542 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout. 580 if (!to) return false; // Timeout.
543 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. 581 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
582 usleep(ts.tv_nsec / 1000);
583 to--;
544 } 584 }
545 } 585 }
546 586
547 587
548 Semaphore* OS::CreateSemaphore(int count) { 588 Semaphore* OS::CreateSemaphore(int count) {
549 return new OpenBSDSemaphore(count); 589 return new OpenBSDSemaphore(count);
550 } 590 }
551 591
552 592
553 #ifdef ENABLE_LOGGING_AND_PROFILING 593 #ifdef ENABLE_LOGGING_AND_PROFILING
554 594
555 static Sampler* active_sampler_ = NULL; 595 static pthread_t GetThreadID() {
596 pthread_t thread_id = pthread_self();
597 return thread_id;
598 }
599
600
601 class Sampler::PlatformData : public Malloced {
602 public:
603 PlatformData() : vm_tid_(GetThreadID()) {}
604
605 pthread_t vm_tid() const { return vm_tid_; }
606
607 private:
608 pthread_t vm_tid_;
609 };
610
556 611
557 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { 612 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
558 USE(info); 613 USE(info);
559 if (signal != SIGPROF) return; 614 if (signal != SIGPROF) return;
560 if (active_sampler_ == NULL) return; 615 Isolate* isolate = Isolate::UncheckedCurrent();
561 616 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
562 TickSample sample; 617 // We require a fully initialized and entered isolate.
563 618 return;
564 // We always sample the VM state. 619 }
565 sample.state = VMState::current_state(); 620 if (v8::Locker::IsActive() &&
566 621 !isolate->thread_manager()->IsLockedByCurrentThread()) {
567 active_sampler_->Tick(&sample); 622 return;
568 } 623 }
569 624
570 625 Sampler* sampler = isolate->logger()->sampler();
571 class Sampler::PlatformData : public Malloced { 626 if (sampler == NULL || !sampler->IsActive()) return;
627
628 TickSample sample_obj;
629 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
630 if (sample == NULL) sample = &sample_obj;
631
632 // Extracting the sample from the context is extremely machine dependent.
633 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
634 sample->state = isolate->current_vm_state();
635 #if V8_HOST_ARCH_IA32
636 sample->pc = reinterpret_cast<Address>(ucontext->sc_eip);
637 sample->sp = reinterpret_cast<Address>(ucontext->sc_esp);
638 sample->fp = reinterpret_cast<Address>(ucontext->sc_ebp);
639 #elif V8_HOST_ARCH_X64
640 sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
641 sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
642 sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
643 #elif V8_HOST_ARCH_ARM
644 sample->pc = reinterpret_cast<Address>(ucontext->sc_r15);
645 sample->sp = reinterpret_cast<Address>(ucontext->sc_r13);
646 sample->fp = reinterpret_cast<Address>(ucontext->sc_r11);
647 #endif
648 sampler->SampleStack(sample);
649 sampler->Tick(sample);
650 }
651
652
653 class SignalSender : public Thread {
572 public: 654 public:
573 PlatformData() { 655 enum SleepInterval {
574 signal_handler_installed_ = false; 656 HALF_INTERVAL,
575 } 657 FULL_INTERVAL
576 658 };
577 bool signal_handler_installed_; 659
578 struct sigaction old_signal_handler_; 660 explicit SignalSender(int interval)
579 struct itimerval old_timer_value_; 661 : Thread("SignalSender"),
662 interval_(interval) {}
663
664 static void AddActiveSampler(Sampler* sampler) {
665 ScopedLock lock(mutex_);
666 SamplerRegistry::AddActiveSampler(sampler);
667 if (instance_ == NULL) {
668 // Install a signal handler.
669 struct sigaction sa;
670 sa.sa_sigaction = ProfilerSignalHandler;
671 sigemptyset(&sa.sa_mask);
672 sa.sa_flags = SA_RESTART | SA_SIGINFO;
673 signal_handler_installed_ =
674 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
675
676 // Start a thread that sends SIGPROF signal to VM threads.
677 instance_ = new SignalSender(sampler->interval());
678 instance_->Start();
679 } else {
680 ASSERT(instance_->interval_ == sampler->interval());
681 }
682 }
683
684 static void RemoveActiveSampler(Sampler* sampler) {
685 ScopedLock lock(mutex_);
686 SamplerRegistry::RemoveActiveSampler(sampler);
687 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
688 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
689 delete instance_;
690 instance_ = NULL;
691
692 // Restore the old signal handler.
693 if (signal_handler_installed_) {
694 sigaction(SIGPROF, &old_signal_handler_, 0);
695 signal_handler_installed_ = false;
696 }
697 }
698 }
699
700 // Implement Thread::Run().
701 virtual void Run() {
702 SamplerRegistry::State state;
703 while ((state = SamplerRegistry::GetState()) !=
704 SamplerRegistry::HAS_NO_SAMPLERS) {
705 bool cpu_profiling_enabled =
706 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
707 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
708 // When CPU profiling is enabled both JavaScript and C++ code is
709 // profiled. We must not suspend.
710 if (!cpu_profiling_enabled) {
711 if (rate_limiter_.SuspendIfNecessary()) continue;
712 }
713 if (cpu_profiling_enabled && runtime_profiler_enabled) {
714 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
715 return;
716 }
717 Sleep(HALF_INTERVAL);
718 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
719 return;
720 }
721 Sleep(HALF_INTERVAL);
722 } else {
723 if (cpu_profiling_enabled) {
724 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
725 this)) {
726 return;
727 }
728 }
729 if (runtime_profiler_enabled) {
730 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
731 NULL)) {
732 return;
733 }
734 }
735 Sleep(FULL_INTERVAL);
736 }
737 }
738 }
739
740 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
741 if (!sampler->IsProfiling()) return;
742 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
743 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
744 }
745
746 static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
747 if (!sampler->isolate()->IsInitialized()) return;
748 sampler->isolate()->runtime_profiler()->NotifyTick();
749 }
750
751 void SendProfilingSignal(pthread_t tid) {
752 if (!signal_handler_installed_) return;
753 pthread_kill(tid, SIGPROF);
754 }
755
756 void Sleep(SleepInterval full_or_half) {
757 // Convert ms to us and subtract 100 us to compensate delays
758 // occuring during signal delivery.
759 useconds_t interval = interval_ * 1000 - 100;
760 if (full_or_half == HALF_INTERVAL) interval /= 2;
761 int result = usleep(interval);
762 #ifdef DEBUG
763 if (result != 0 && errno != EINTR) {
764 fprintf(stderr,
765 "SignalSender usleep error; interval = %u, errno = %d\n",
766 interval,
767 errno);
768 ASSERT(result == 0 || errno == EINTR);
769 }
770 #endif
771 USE(result);
772 }
773
774 const int interval_;
775 RuntimeProfilerRateLimiter rate_limiter_;
776
777 // Protects the process wide state below.
778 static Mutex* mutex_;
779 static SignalSender* instance_;
780 static bool signal_handler_installed_;
781 static struct sigaction old_signal_handler_;
782
783 DISALLOW_COPY_AND_ASSIGN(SignalSender);
580 }; 784 };
581 785
786 Mutex* SignalSender::mutex_ = OS::CreateMutex();
787 SignalSender* SignalSender::instance_ = NULL;
788 struct sigaction SignalSender::old_signal_handler_;
789 bool SignalSender::signal_handler_installed_ = false;
790
582 791
583 Sampler::Sampler(Isolate* isolate, int interval) 792 Sampler::Sampler(Isolate* isolate, int interval)
584 : isolate_(isolate), 793 : isolate_(isolate),
585 interval_(interval), 794 interval_(interval),
586 profiling_(false), 795 profiling_(false),
587 active_(false), 796 active_(false),
588 samples_taken_(0) { 797 samples_taken_(0) {
589 data_ = new PlatformData(); 798 data_ = new PlatformData;
590 } 799 }
591 800
592 801
593 Sampler::~Sampler() { 802 Sampler::~Sampler() {
803 ASSERT(!IsActive());
594 delete data_; 804 delete data_;
595 } 805 }
596 806
597 807
598 void Sampler::Start() { 808 void Sampler::Start() {
599 // There can only be one active sampler at the time on POSIX 809 ASSERT(!IsActive());
600 // platforms. 810 SetActive(true);
601 if (active_sampler_ != NULL) return; 811 SignalSender::AddActiveSampler(this);
602
603 // Request profiling signals.
604 struct sigaction sa;
605 sa.sa_sigaction = ProfilerSignalHandler;
606 sigemptyset(&sa.sa_mask);
607 sa.sa_flags = SA_SIGINFO;
608 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
609 data_->signal_handler_installed_ = true;
610
611 // Set the itimer to generate a tick for each interval.
612 itimerval itimer;
613 itimer.it_interval.tv_sec = interval_ / 1000;
614 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
615 itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
616 itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
617 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
618
619 // Set this sampler as the active sampler.
620 active_sampler_ = this;
621 active_ = true;
622 } 812 }
623 813
624 814
625 void Sampler::Stop() { 815 void Sampler::Stop() {
626 // Restore old signal handler 816 ASSERT(IsActive());
627 if (data_->signal_handler_installed_) { 817 SignalSender::RemoveActiveSampler(this);
628 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); 818 SetActive(false);
629 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
630 data_->signal_handler_installed_ = false;
631 }
632
633 // This sampler is no longer the active sampler.
634 active_sampler_ = NULL;
635 active_ = false;
636 } 819 }
637 820
638 #endif // ENABLE_LOGGING_AND_PROFILING 821 #endif // ENABLE_LOGGING_AND_PROFILING
639 822
640 } } // namespace v8::internal 823 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/platform-nullos.cc ('k') | src/platform-posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698