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

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

Issue 6525028: Cygwin support (Closed)
Patch Set: Address issues Created 9 years, 10 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
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | tools/utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2006-2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 // Platform specific code for Cygwin goes here. For the POSIX comaptible parts
29 // the implementation is in platform-posix.cc.
30
31 #include <errno.h>
32 #include <pthread.h>
33 #include <semaphore.h>
34 #include <stdarg.h>
35 #include <strings.h> // index
36 #include <sys/time.h>
37 #include <sys/mman.h> // mmap & munmap
38 #include <unistd.h> // sysconf
39
40 #undef MAP_TYPE
41
42 #include "v8.h"
43
44 #include "platform.h"
45 #include "top.h"
46 #include "v8threads.h"
47 #include "vm-state-inl.h"
48 #include "win32-headers.h"
49
50 namespace v8 {
51 namespace internal {
52
53 // 0 is never a valid thread id
54 static const pthread_t kNoThread = (pthread_t) 0;
55
56
57 double ceiling(double x) {
58 return ceil(x);
59 }
60
61
62 void OS::Setup() {
63 // Seed the random number generator.
64 // Convert the current time to a 64-bit integer first, before converting it
65 // to an unsigned. Going directly can cause an overflow and the seed to be
66 // set to all ones. The seed will be identical for different instances that
67 // call this setup code within the same millisecond.
68 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
69 srandom(static_cast<unsigned int>(seed));
70 }
71
72
73 uint64_t OS::CpuFeaturesImpliedByPlatform() {
74 return 0; // Nothing special about Cygwin.
75 }
76
77
78 int OS::ActivationFrameAlignment() {
79 // With gcc 4.4 the tree vectorization optimizer can generate code
80 // that requires 16 byte alignment such as movdqa on x86.
81 return 16;
82 }
83
84
85 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
86 __asm__ __volatile__("" : : : "memory");
87 // An x86 store acts as a release barrier.
88 *ptr = value;
89 }
90
91 const char* OS::LocalTimezone(double time) {
92 if (isnan(time)) return "";
93 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
94 struct tm* t = localtime(&tv);
95 if (NULL == t) return "";
96 return tzname[0]; // The location of the timezone string on Cygwin.
97 }
98
99
100 double OS::LocalTimeOffset() {
101 // On Cygwin, struct tm does not contain a tm_gmtoff field.
102 time_t utc = time(NULL);
103 ASSERT(utc != -1);
104 struct tm* loc = localtime(&utc);
105 ASSERT(loc != NULL);
106 // time - localtime includes any daylight savings offset, so subtract it.
107 return static_cast<double>((mktime(loc) - utc) * msPerSecond -
108 (loc->tm_isdst > 0 ? 3600 * msPerSecond : 0));
109 }
110
111
112 // We keep the lowest and highest addresses mapped as a quick way of
113 // determining that pointers are outside the heap (used mostly in assertions
114 // and verification). The estimate is conservative, ie, not all addresses in
115 // 'allocated' space are actually allocated to our heap. The range is
116 // [lowest, highest), inclusive on the low and and exclusive on the high end.
117 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
118 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
119
120
121 static void UpdateAllocatedSpaceLimits(void* address, int size) {
122 lowest_ever_allocated = Min(lowest_ever_allocated, address);
123 highest_ever_allocated =
124 Max(highest_ever_allocated,
125 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
126 }
127
128
129 bool OS::IsOutsideAllocatedSpace(void* address) {
130 return address < lowest_ever_allocated || address >= highest_ever_allocated;
131 }
132
133
134 size_t OS::AllocateAlignment() {
135 return sysconf(_SC_PAGESIZE);
136 }
137
138
139 void* OS::Allocate(const size_t requested,
140 size_t* allocated,
141 bool is_executable) {
142 const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE));
143 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
144 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
145 if (mbase == MAP_FAILED) {
146 LOG(StringEvent("OS::Allocate", "mmap failed"));
147 return NULL;
148 }
149 *allocated = msize;
150 UpdateAllocatedSpaceLimits(mbase, msize);
151 return mbase;
152 }
153
154
155 void OS::Free(void* address, const size_t size) {
156 // TODO(1240712): munmap has a return value which is ignored here.
157 int result = munmap(address, size);
158 USE(result);
159 ASSERT(result == 0);
160 }
161
162
163 #ifdef ENABLE_HEAP_PROTECTION
164
165 void OS::Protect(void* address, size_t size) {
166 // TODO(1240712): mprotect has a return value which is ignored here.
167 mprotect(address, size, PROT_READ);
168 }
169
170
171 void OS::Unprotect(void* address, size_t size, bool is_executable) {
172 // TODO(1240712): mprotect has a return value which is ignored here.
173 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
174 mprotect(address, size, prot);
175 }
176
177 #endif
178
179
180 void OS::Sleep(int milliseconds) {
181 unsigned int ms = static_cast<unsigned int>(milliseconds);
182 usleep(1000 * ms);
183 }
184
185
186 void OS::Abort() {
187 // Redirect to std abort to signal abnormal program termination.
188 abort();
189 }
190
191
192 void OS::DebugBreak() {
193 asm("int $3");
194 }
195
196
197 class PosixMemoryMappedFile : public OS::MemoryMappedFile {
198 public:
199 PosixMemoryMappedFile(FILE* file, void* memory, int size)
200 : file_(file), memory_(memory), size_(size) { }
201 virtual ~PosixMemoryMappedFile();
202 virtual void* memory() { return memory_; }
203 virtual int size() { return size_; }
204 private:
205 FILE* file_;
206 void* memory_;
207 int size_;
208 };
209
210
211 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
212 FILE* file = fopen(name, "w+");
213 if (file == NULL) return NULL;
214
215 fseek(file, 0, SEEK_END);
216 int size = ftell(file);
217
218 void* memory =
219 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
220 return new PosixMemoryMappedFile(file, memory, size);
221 }
222
223
224 OS::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
239 PosixMemoryMappedFile::~PosixMemoryMappedFile() {
240 if (memory_) munmap(memory_, size_);
241 fclose(file_);
242 }
243
244
245 void OS::LogSharedLibraryAddresses() {
246 #ifdef ENABLE_LOGGING_AND_PROFILING
247 // This function assumes that the layout of the file is as follows:
248 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
249 // If we encounter an unexpected situation we abort scanning further entries.
250 FILE* fp = fopen("/proc/self/maps", "r");
251 if (fp == NULL) return;
252
253 // Allocate enough room to be able to store a full file name.
254 const int kLibNameLen = FILENAME_MAX + 1;
255 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
256
257 // This loop will terminate once the scanning hits an EOF.
258 while (true) {
259 uintptr_t start, end;
260 char attr_r, attr_w, attr_x, attr_p;
261 // Parse the addresses and permission bits at the beginning of the line.
262 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
263 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
264
265 int c;
266 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
267 // Found a read-only executable entry. Skip characters until we reach
268 // the beginning of the filename or the end of the line.
269 do {
270 c = getc(fp);
271 } while ((c != EOF) && (c != '\n') && (c != '/'));
272 if (c == EOF) break; // EOF: Was unexpected, just exit.
273
274 // Process the filename if found.
275 if (c == '/') {
276 ungetc(c, fp); // Push the '/' back into the stream to be read below.
277
278 // Read to the end of the line. Exit if the read fails.
279 if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
280
281 // Drop the newline character read by fgets. We do not need to check
282 // for a zero-length string because we know that we at least read the
283 // '/' character.
284 lib_name[strlen(lib_name) - 1] = '\0';
285 } else {
286 // No library name found, just record the raw address range.
287 snprintf(lib_name, kLibNameLen,
288 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
289 }
290 LOG(SharedLibraryEvent(lib_name, start, end));
291 } else {
292 // Entry not describing executable data. Skip to end of line to setup
293 // reading the next entry.
294 do {
295 c = getc(fp);
296 } while ((c != EOF) && (c != '\n'));
297 if (c == EOF) break;
298 }
299 }
300 free(lib_name);
301 fclose(fp);
302 #endif
303 }
304
305
306 void OS::SignalCodeMovingGC() {
307 // Nothing to do on Cygwin.
308 }
309
310
311 int OS::StackWalk(Vector<OS::StackFrame> frames) {
312 // Not supported on Cygwin.
313 return 0;
314 }
315
316
317 // Constants used for mmap.
318 static const int kMmapFd = -1;
319 static const int kMmapFdOffset = 0;
320
321
322 VirtualMemory::VirtualMemory(size_t size) {
323 address_ = mmap(NULL, size, PROT_NONE,
324 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
325 kMmapFd, kMmapFdOffset);
326 size_ = size;
327 }
328
329
330 VirtualMemory::~VirtualMemory() {
331 if (IsReserved()) {
332 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
333 }
334 }
335
336
337 bool VirtualMemory::IsReserved() {
338 return address_ != MAP_FAILED;
339 }
340
341
342 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
343 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
344
345 if (mprotect(address, size, prot) != 0) {
346 return false;
347 }
348
349 UpdateAllocatedSpaceLimits(address, size);
350 return true;
351 }
352
353
354 bool VirtualMemory::Uncommit(void* address, size_t size) {
355 return mmap(address, size, PROT_NONE,
356 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
357 kMmapFd, kMmapFdOffset) != MAP_FAILED;
358 }
359
360
361 class ThreadHandle::PlatformData : public Malloced {
362 public:
363 explicit PlatformData(ThreadHandle::Kind kind) {
364 Initialize(kind);
365 }
366
367 void Initialize(ThreadHandle::Kind kind) {
368 switch (kind) {
369 case ThreadHandle::SELF: thread_ = pthread_self(); break;
370 case ThreadHandle::INVALID: thread_ = kNoThread; break;
371 }
372 }
373
374 pthread_t thread_; // Thread handle for pthread.
375 };
376
377
378 ThreadHandle::ThreadHandle(Kind kind) {
379 data_ = new PlatformData(kind);
380 }
381
382
383 void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
384 data_->Initialize(kind);
385 }
386
387
388 ThreadHandle::~ThreadHandle() {
389 delete data_;
390 }
391
392
393 bool ThreadHandle::IsSelf() const {
394 return pthread_equal(data_->thread_, pthread_self());
395 }
396
397
398 bool ThreadHandle::IsValid() const {
399 return data_->thread_ != kNoThread;
400 }
401
402
403 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
404 set_name("v8:<unknown>");
405 }
406
407
408 Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
409 set_name(name);
410 }
411
412
413 Thread::~Thread() {
414 }
415
416
417 static 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
429 void Thread::set_name(const char* name) {
430 strncpy(name_, name, sizeof(name_));
431 name_[sizeof(name_) - 1] = '\0';
432 }
433
434
435 void Thread::Start() {
436 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
437 ASSERT(IsValid());
438 }
439
440
441 void Thread::Join() {
442 pthread_join(thread_handle_data()->thread_, NULL);
443 }
444
445
446 static inline Thread::LocalStorageKey PthreadKeyToLocalKey(
447 pthread_key_t pthread_key) {
448 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps
449 // because pthread_key_t is a pointer type on Cygwin. This will probably not
450 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway.
451 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
452 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key);
453 return static_cast<Thread::LocalStorageKey>(ptr_key);
454 }
455
456
457 static inline pthread_key_t LocalKeyToPthreadKey(
458 Thread::LocalStorageKey local_key) {
459 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t));
460 intptr_t ptr_key = static_cast<intptr_t>(local_key);
461 return reinterpret_cast<pthread_key_t>(ptr_key);
462 }
463
464
465 Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
466 pthread_key_t key;
467 int result = pthread_key_create(&key, NULL);
468 USE(result);
469 ASSERT(result == 0);
470 return PthreadKeyToLocalKey(key);
471 }
472
473
474 void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
475 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
476 int result = pthread_key_delete(pthread_key);
477 USE(result);
478 ASSERT(result == 0);
479 }
480
481
482 void* Thread::GetThreadLocal(LocalStorageKey key) {
483 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
484 return pthread_getspecific(pthread_key);
485 }
486
487
488 void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
489 pthread_key_t pthread_key = LocalKeyToPthreadKey(key);
490 pthread_setspecific(pthread_key, value);
491 }
492
493
494 void Thread::YieldCPU() {
495 sched_yield();
496 }
497
498
499 class CygwinMutex : public Mutex {
500 public:
501
502 CygwinMutex() {
503 pthread_mutexattr_t attrs;
504 memset(&attrs, 0, sizeof(attrs));
505
506 int result = pthread_mutexattr_init(&attrs);
507 ASSERT(result == 0);
508 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
509 ASSERT(result == 0);
510 result = pthread_mutex_init(&mutex_, &attrs);
511 ASSERT(result == 0);
512 }
513
514 virtual ~CygwinMutex() { pthread_mutex_destroy(&mutex_); }
515
516 virtual int Lock() {
517 int result = pthread_mutex_lock(&mutex_);
518 return result;
519 }
520
521 virtual int Unlock() {
522 int result = pthread_mutex_unlock(&mutex_);
523 return result;
524 }
525
526 virtual bool TryLock() {
527 int result = pthread_mutex_trylock(&mutex_);
528 // Return false if the lock is busy and locking failed.
529 if (result == EBUSY) {
530 return false;
531 }
532 ASSERT(result == 0); // Verify no other errors.
533 return true;
534 }
535
536 private:
537 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
538 };
539
540
541 Mutex* OS::CreateMutex() {
542 return new CygwinMutex();
543 }
544
545
546 class CygwinSemaphore : public Semaphore {
547 public:
548 explicit CygwinSemaphore(int count) { sem_init(&sem_, 0, count); }
549 virtual ~CygwinSemaphore() { sem_destroy(&sem_); }
550
551 virtual void Wait();
552 virtual bool Wait(int timeout);
553 virtual void Signal() { sem_post(&sem_); }
554 private:
555 sem_t sem_;
556 };
557
558
559 void CygwinSemaphore::Wait() {
560 while (true) {
561 int result = sem_wait(&sem_);
562 if (result == 0) return; // Successfully got semaphore.
563 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
564 }
565 }
566
567
568 #ifndef TIMEVAL_TO_TIMESPEC
569 #define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
570 (ts)->tv_sec = (tv)->tv_sec; \
571 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
572 } while (false)
573 #endif
574
575
576 bool CygwinSemaphore::Wait(int timeout) {
577 const long kOneSecondMicros = 1000000; // NOLINT
578
579 // Split timeout into second and nanosecond parts.
580 struct timeval delta;
581 delta.tv_usec = timeout % kOneSecondMicros;
582 delta.tv_sec = timeout / kOneSecondMicros;
583
584 struct timeval current_time;
585 // Get the current time.
586 if (gettimeofday(&current_time, NULL) == -1) {
587 return false;
588 }
589
590 // Calculate time for end of timeout.
591 struct timeval end_time;
592 timeradd(&current_time, &delta, &end_time);
593
594 struct timespec ts;
595 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
596 // Wait for semaphore signalled or timeout.
597 while (true) {
598 int result = sem_timedwait(&sem_, &ts);
599 if (result == 0) return true; // Successfully got semaphore.
600 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
601 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
602 }
603 }
604
605
606 Semaphore* OS::CreateSemaphore(int count) {
607 return new CygwinSemaphore(count);
608 }
609
610
611 #ifdef ENABLE_LOGGING_AND_PROFILING
612
613 // ----------------------------------------------------------------------------
614 // Cygwin profiler support.
615 //
616 // On Cygwin we use the same sampler implementation as on win32.
617
618 class Sampler::PlatformData : public Malloced {
619 public:
620 explicit PlatformData(Sampler* sampler) {
621 sampler_ = sampler;
622 sampler_thread_ = INVALID_HANDLE_VALUE;
623 profiled_thread_ = INVALID_HANDLE_VALUE;
624 }
625
626 Sampler* sampler_;
627 HANDLE sampler_thread_;
628 HANDLE profiled_thread_;
629 RuntimeProfilerRateLimiter rate_limiter_;
630
631 // Sampler thread handler.
632 void Runner() {
633 while (sampler_->IsActive()) {
634 if (rate_limiter_.SuspendIfNecessary()) continue;
635 Sample();
636 Sleep(sampler_->interval_);
637 }
638 }
639
640 void Sample() {
641 if (sampler_->IsProfiling()) {
642 // Context used for sampling the register state of the profiled thread.
643 CONTEXT context;
644 memset(&context, 0, sizeof(context));
645
646 TickSample sample_obj;
647 TickSample* sample = CpuProfiler::TickSampleEvent();
648 if (sample == NULL) sample = &sample_obj;
649
650 static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
651 if (SuspendThread(profiled_thread_) == kSuspendFailed) return;
652 sample->state = Top::current_vm_state();
653
654 context.ContextFlags = CONTEXT_FULL;
655 if (GetThreadContext(profiled_thread_, &context) != 0) {
656 #if V8_HOST_ARCH_X64
657 sample->pc = reinterpret_cast<Address>(context.Rip);
658 sample->sp = reinterpret_cast<Address>(context.Rsp);
659 sample->fp = reinterpret_cast<Address>(context.Rbp);
660 #else
661 sample->pc = reinterpret_cast<Address>(context.Eip);
662 sample->sp = reinterpret_cast<Address>(context.Esp);
663 sample->fp = reinterpret_cast<Address>(context.Ebp);
664 #endif
665 sampler_->SampleStack(sample);
666 sampler_->Tick(sample);
667 }
668 ResumeThread(profiled_thread_);
669 }
670 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
671 }
672 };
673
674
675 // Entry point for sampler thread.
676 static DWORD __stdcall SamplerEntry(void* arg) {
677 Sampler::PlatformData* data =
678 reinterpret_cast<Sampler::PlatformData*>(arg);
679 data->Runner();
680 return 0;
681 }
682
683
684 // Initialize a profile sampler.
685 Sampler::Sampler(int interval)
686 : interval_(interval),
687 profiling_(false),
688 active_(false),
689 samples_taken_(0) {
690 data_ = new PlatformData(this);
691 }
692
693
694 Sampler::~Sampler() {
695 delete data_;
696 }
697
698
699 // Start profiling.
700 void Sampler::Start() {
701 // Do not start multiple threads for the same sampler.
702 ASSERT(!IsActive());
703
704 // Get a handle to the calling thread. This is the thread that we are
705 // going to profile. We need to make a copy of the handle because we are
706 // going to use it in the sampler thread. Using GetThreadHandle() will
707 // not work in this case. We're using OpenThread because DuplicateHandle
708 // for some reason doesn't work in Chrome's sandbox.
709 data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT |
710 THREAD_SUSPEND_RESUME |
711 THREAD_QUERY_INFORMATION,
712 false,
713 GetCurrentThreadId());
714 BOOL ok = data_->profiled_thread_ != NULL;
715 if (!ok) return;
716
717 // Start sampler thread.
718 DWORD tid;
719 SetActive(true);
720 data_->sampler_thread_ = CreateThread(NULL, 0, SamplerEntry, data_, 0, &tid);
721 // Set thread to high priority to increase sampling accuracy.
722 SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL);
723 }
724
725
726 // Stop profiling.
727 void Sampler::Stop() {
728 // Seting active to false triggers termination of the sampler
729 // thread.
730 SetActive(false);
731
732 // Wait for sampler thread to terminate.
733 Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
734 WaitForSingleObject(data_->sampler_thread_, INFINITE);
735
736 // Release the thread handles
737 CloseHandle(data_->sampler_thread_);
738 CloseHandle(data_->profiled_thread_);
739 }
740
741
742 #endif // ENABLE_LOGGING_AND_PROFILING
743
744 } } // namespace v8::internal
745
OLDNEW
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | tools/utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698