blob: ea35c1b130e7d6fbb03da518d868f0be0d706cb7 [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 MacOS goes here. For the POSIX comaptible parts
29// the implementation is in platform-posix.cc.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
lrn@chromium.org5d00b602011-01-05 09:51:43 +000031#include <dlfcn.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include <unistd.h>
33#include <sys/mman.h>
34#include <mach/mach_init.h>
kasperl@chromium.orge959c182009-07-27 08:59:04 +000035#include <mach-o/dyld.h>
36#include <mach-o/getsect.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
38#include <AvailabilityMacros.h>
39
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include <pthread.h>
41#include <semaphore.h>
42#include <signal.h>
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000043#include <libkern/OSAtomic.h>
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000044#include <mach/mach.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include <mach/semaphore.h>
46#include <mach/task.h>
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000047#include <mach/vm_statistics.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include <sys/time.h>
49#include <sys/resource.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000050#include <sys/types.h>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include <stdarg.h>
52#include <stdlib.h>
ager@chromium.org381abbb2009-02-25 13:23:22 +000053#include <errno.h>
54
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#undef MAP_TYPE
56
57#include "v8.h"
58
59#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
ager@chromium.org5aa501c2009-06-23 07:57:28 +000062// Manually define these here as weak imports, rather than including execinfo.h.
63// This lets us launch on 10.4 which does not have these calls.
64extern "C" {
65 extern int backtrace(void**, int) __attribute__((weak_import));
66 extern char** backtrace_symbols(void* const*, int)
67 __attribute__((weak_import));
68 extern void backtrace_symbols_fd(void* const*, int, int)
69 __attribute__((weak_import));
70}
71
72
kasperl@chromium.org71affb52009-05-26 05:44:31 +000073namespace v8 {
74namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075
76// 0 is never a valid thread id on MacOSX since a ptread_t is
77// a pointer.
78static const pthread_t kNoThread = (pthread_t) 0;
79
80
81double ceiling(double x) {
82 // Correct Mac OS X Leopard 'ceil' behavior.
83 if (-1.0 < x && x < 0.0) {
84 return -0.0;
85 } else {
86 return ceil(x);
87 }
88}
89
90
91void OS::Setup() {
92 // Seed the random number generator.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000093 // Convert the current time to a 64-bit integer first, before converting it
94 // to an unsigned. Going directly will cause an overflow and the seed to be
95 // set to all ones. The seed will be identical for different instances that
96 // call this setup code within the same millisecond.
97 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
98 srandom(static_cast<unsigned int>(seed));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099}
100
101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000102// We keep the lowest and highest addresses mapped as a quick way of
103// determining that pointers are outside the heap (used mostly in assertions
104// and verification). The estimate is conservative, ie, not all addresses in
105// 'allocated' space are actually allocated to our heap. The range is
106// [lowest, highest), inclusive on the low and and exclusive on the high end.
107static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
108static void* highest_ever_allocated = reinterpret_cast<void*>(0);
109
110
111static void UpdateAllocatedSpaceLimits(void* address, int size) {
112 lowest_ever_allocated = Min(lowest_ever_allocated, address);
113 highest_ever_allocated =
114 Max(highest_ever_allocated,
115 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
116}
117
118
119bool OS::IsOutsideAllocatedSpace(void* address) {
120 return address < lowest_ever_allocated || address >= highest_ever_allocated;
121}
122
123
124size_t OS::AllocateAlignment() {
kasper.lund7276f142008-07-30 08:49:36 +0000125 return getpagesize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126}
127
128
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000129// Constants used for mmap.
130// kMmapFd is used to pass vm_alloc flags to tag the region with the user
131// defined tag 255 This helps identify V8-allocated regions in memory analysis
132// tools like vmmap(1).
133static const int kMmapFd = VM_MAKE_TAG(255);
134static const off_t kMmapFdOffset = 0;
135
136
kasper.lund7276f142008-07-30 08:49:36 +0000137void* OS::Allocate(const size_t requested,
138 size_t* allocated,
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000139 bool is_executable) {
kasper.lund7276f142008-07-30 08:49:36 +0000140 const size_t msize = RoundUp(requested, getpagesize());
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000141 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000142 void* mbase = mmap(NULL, msize, prot,
143 MAP_PRIVATE | MAP_ANON,
144 kMmapFd, kMmapFdOffset);
kasper.lund7276f142008-07-30 08:49:36 +0000145 if (mbase == MAP_FAILED) {
146 LOG(StringEvent("OS::Allocate", "mmap failed"));
147 return NULL;
148 }
149 *allocated = msize;
150 UpdateAllocatedSpaceLimits(mbase, msize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 return mbase;
152}
153
154
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000155void OS::Free(void* address, const size_t size) {
kasper.lund7276f142008-07-30 08:49:36 +0000156 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000157 int result = munmap(address, size);
158 USE(result);
159 ASSERT(result == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000160}
161
162
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000163#ifdef ENABLE_HEAP_PROTECTION
164
165void OS::Protect(void* address, size_t size) {
166 UNIMPLEMENTED();
167}
168
169
170void OS::Unprotect(void* address, size_t size, bool is_executable) {
171 UNIMPLEMENTED();
172}
173
174#endif
175
176
ager@chromium.org32912102009-01-16 10:38:43 +0000177void OS::Sleep(int milliseconds) {
178 usleep(1000 * milliseconds);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179}
180
181
182void OS::Abort() {
183 // Redirect to std abort to signal abnormal program termination
184 abort();
185}
186
187
kasper.lund7276f142008-07-30 08:49:36 +0000188void OS::DebugBreak() {
189 asm("int $3");
190}
191
192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193class PosixMemoryMappedFile : public OS::MemoryMappedFile {
194 public:
195 PosixMemoryMappedFile(FILE* file, void* memory, int size)
196 : file_(file), memory_(memory), size_(size) { }
197 virtual ~PosixMemoryMappedFile();
198 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000199 virtual int size() { return size_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200 private:
201 FILE* file_;
202 void* memory_;
203 int size_;
204};
205
206
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000207OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
208 FILE* file = fopen(name, "w+");
209 if (file == NULL) return NULL;
210
211 fseek(file, 0, SEEK_END);
212 int size = ftell(file);
213
214 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
221 void* initial) {
222 FILE* file = fopen(name, "w+");
223 if (file == NULL) return NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000224 int result = fwrite(initial, size, 1, file);
225 if (result < 1) {
226 fclose(file);
227 return NULL;
228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229 void* memory =
230 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
231 return new PosixMemoryMappedFile(file, memory, size);
232}
233
234
235PosixMemoryMappedFile::~PosixMemoryMappedFile() {
236 if (memory_) munmap(memory_, size_);
237 fclose(file_);
238}
239
240
241void OS::LogSharedLibraryAddresses() {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000242#ifdef ENABLE_LOGGING_AND_PROFILING
243 unsigned int images_count = _dyld_image_count();
244 for (unsigned int i = 0; i < images_count; ++i) {
245 const mach_header* header = _dyld_get_image_header(i);
246 if (header == NULL) continue;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000247#if V8_HOST_ARCH_X64
248 uint64_t size;
249 char* code_ptr = getsectdatafromheader_64(
250 reinterpret_cast<const mach_header_64*>(header),
251 SEG_TEXT,
252 SECT_TEXT,
253 &size);
254#else
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000255 unsigned int size;
256 char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000257#endif
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000258 if (code_ptr == NULL) continue;
259 const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
260 const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
261 LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
262 }
263#endif // ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264}
265
266
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000267void OS::SignalCodeMovingGC() {
268}
269
270
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000271uint64_t OS::CpuFeaturesImpliedByPlatform() {
272 // MacOSX requires all these to install so we can assume they are present.
273 // These constants are defined by the CPUid instructions.
274 const uint64_t one = 1;
275 return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID);
276}
277
278
ager@chromium.org236ad962008-09-25 09:45:57 +0000279int OS::ActivationFrameAlignment() {
280 // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI
281 // Function Call Guide".
282 return 16;
283}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284
285
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000286void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
287 OSMemoryBarrier();
288 *ptr = value;
289}
290
291
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000292const char* OS::LocalTimezone(double time) {
293 if (isnan(time)) return "";
294 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
295 struct tm* t = localtime(&tv);
296 if (NULL == t) return "";
297 return t->tm_zone;
298}
299
300
301double OS::LocalTimeOffset() {
302 time_t tv = time(NULL);
303 struct tm* t = localtime(&tv);
304 // tm_gmtoff includes any daylight savings offset, so subtract it.
305 return static_cast<double>(t->tm_gmtoff * msPerSecond -
306 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
307}
308
309
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000310int OS::StackWalk(Vector<StackFrame> frames) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000311 // If weak link to execinfo lib has failed, ie because we are on 10.4, abort.
312 if (backtrace == NULL)
313 return 0;
314
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000315 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000316 ScopedVector<void*> addresses(frames_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000318 int frames_count = backtrace(addresses.start(), frames_size);
319
320 char** symbols = backtrace_symbols(addresses.start(), frames_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321 if (symbols == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 return kStackWalkError;
323 }
324
325 for (int i = 0; i < frames_count; i++) {
326 frames[i].address = addresses[i];
327 // Format a text representation of the frame based on the information
328 // available.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000329 SNPrintF(MutableCStrVector(frames[i].text,
330 kStackWalkMaxTextLen),
331 "%s",
332 symbols[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000333 // Make sure line termination is in place.
334 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
335 }
336
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 free(symbols);
338
339 return frames_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340}
341
342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343
344
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000345VirtualMemory::VirtualMemory(size_t size) {
346 address_ = mmap(NULL, size, PROT_NONE,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
348 kMmapFd, kMmapFdOffset);
349 size_ = size;
350}
351
352
353VirtualMemory::~VirtualMemory() {
354 if (IsReserved()) {
355 if (0 == munmap(address(), size())) address_ = MAP_FAILED;
356 }
357}
358
359
360bool VirtualMemory::IsReserved() {
361 return address_ != MAP_FAILED;
362}
363
364
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000365bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
366 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
kasper.lund7276f142008-07-30 08:49:36 +0000367 if (MAP_FAILED == mmap(address, size, prot,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
369 kMmapFd, kMmapFdOffset)) {
370 return false;
371 }
372
373 UpdateAllocatedSpaceLimits(address, size);
374 return true;
375}
376
377
378bool VirtualMemory::Uncommit(void* address, size_t size) {
379 return mmap(address, size, PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000380 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 kMmapFd, kMmapFdOffset) != MAP_FAILED;
382}
383
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385class ThreadHandle::PlatformData : public Malloced {
386 public:
387 explicit PlatformData(ThreadHandle::Kind kind) {
388 Initialize(kind);
389 }
390
391 void Initialize(ThreadHandle::Kind kind) {
392 switch (kind) {
393 case ThreadHandle::SELF: thread_ = pthread_self(); break;
394 case ThreadHandle::INVALID: thread_ = kNoThread; break;
395 }
396 }
397 pthread_t thread_; // Thread handle for pthread.
398};
399
400
401
402ThreadHandle::ThreadHandle(Kind kind) {
403 data_ = new PlatformData(kind);
404}
405
406
407void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
408 data_->Initialize(kind);
409}
410
411
412ThreadHandle::~ThreadHandle() {
413 delete data_;
414}
415
416
417bool ThreadHandle::IsSelf() const {
418 return pthread_equal(data_->thread_, pthread_self());
419}
420
421
422bool ThreadHandle::IsValid() const {
423 return data_->thread_ != kNoThread;
424}
425
426
427Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000428 set_name("v8:<unknown>");
429}
430
431
432Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
433 set_name(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434}
435
436
437Thread::~Thread() {
438}
439
440
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000441
442static void SetThreadName(const char* name) {
443 // pthread_setname_np is only available in 10.6 or later, so test
444 // for it at runtime.
445 int (*dynamic_pthread_setname_np)(const char*);
446 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
447 dlsym(RTLD_DEFAULT, "pthread_setname_np");
448 if (!dynamic_pthread_setname_np)
449 return;
450
451 // Mac OS X does not expose the length limit of the name, so hardcode it.
452 static const int kMaxNameLength = 63;
453 USE(kMaxNameLength);
454 ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
455 dynamic_pthread_setname_np(name);
456}
457
458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459static void* ThreadEntry(void* arg) {
460 Thread* thread = reinterpret_cast<Thread*>(arg);
461 // This is also initialized by the first argument to pthread_create() but we
462 // don't know which thread will run first (the original thread or the new
463 // one) so we initialize it here too.
464 thread->thread_handle_data()->thread_ = pthread_self();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000465 SetThreadName(thread->name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466 ASSERT(thread->IsValid());
467 thread->Run();
468 return NULL;
469}
470
471
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000472void Thread::set_name(const char* name) {
473 strncpy(name_, name, sizeof(name_));
474 name_[sizeof(name_) - 1] = '\0';
475}
476
477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000478void Thread::Start() {
479 pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
480}
481
482
483void Thread::Join() {
484 pthread_join(thread_handle_data()->thread_, NULL);
485}
486
487
488Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
489 pthread_key_t key;
490 int result = pthread_key_create(&key, NULL);
491 USE(result);
492 ASSERT(result == 0);
493 return static_cast<LocalStorageKey>(key);
494}
495
496
497void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
498 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
499 int result = pthread_key_delete(pthread_key);
500 USE(result);
501 ASSERT(result == 0);
502}
503
504
505void* Thread::GetThreadLocal(LocalStorageKey key) {
506 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
507 return pthread_getspecific(pthread_key);
508}
509
510
511void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
512 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
513 pthread_setspecific(pthread_key, value);
514}
515
516
517void Thread::YieldCPU() {
518 sched_yield();
519}
520
521
522class MacOSMutex : public Mutex {
523 public:
524
525 MacOSMutex() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 pthread_mutexattr_t attr;
527 pthread_mutexattr_init(&attr);
528 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000529 pthread_mutex_init(&mutex_, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530 }
531
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000532 virtual ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534 virtual int Lock() { return pthread_mutex_lock(&mutex_); }
535 virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000537 virtual bool TryLock() {
538 int result = pthread_mutex_trylock(&mutex_);
539 // Return false if the lock is busy and locking failed.
540 if (result == EBUSY) {
541 return false;
542 }
543 ASSERT(result == 0); // Verify no other errors.
544 return true;
545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546
547 private:
548 pthread_mutex_t mutex_;
549};
550
551
552Mutex* OS::CreateMutex() {
553 return new MacOSMutex();
554}
555
556
557class MacOSSemaphore : public Semaphore {
558 public:
559 explicit MacOSSemaphore(int count) {
560 semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count);
561 }
562
563 ~MacOSSemaphore() {
564 semaphore_destroy(mach_task_self(), semaphore_);
565 }
566
kasper.lund7276f142008-07-30 08:49:36 +0000567 // The MacOS mach semaphore documentation claims it does not have spurious
568 // wakeups, the way pthreads semaphores do. So the code from the linux
569 // platform is not needed here.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 void Wait() { semaphore_wait(semaphore_); }
571
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000572 bool Wait(int timeout);
573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 void Signal() { semaphore_signal(semaphore_); }
575
576 private:
577 semaphore_t semaphore_;
578};
579
580
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000581bool MacOSSemaphore::Wait(int timeout) {
582 mach_timespec_t ts;
583 ts.tv_sec = timeout / 1000000;
584 ts.tv_nsec = (timeout % 1000000) * 1000;
585 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
586}
587
588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589Semaphore* OS::CreateSemaphore(int count) {
590 return new MacOSSemaphore(count);
591}
592
ager@chromium.org381abbb2009-02-25 13:23:22 +0000593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594#ifdef ENABLE_LOGGING_AND_PROFILING
595
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000596class Sampler::PlatformData : public Malloced {
597 public:
598 explicit PlatformData(Sampler* sampler)
599 : sampler_(sampler),
600 task_self_(mach_task_self()),
601 profiled_thread_(0),
602 sampler_thread_(0) {
603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000605 Sampler* sampler_;
606 // Note: for profiled_thread_ Mach primitives are used instead of PThread's
607 // because the latter doesn't provide thread manipulation primitives required.
608 // For details, consult "Mac OS X Internals" book, Section 7.3.
609 mach_port_t task_self_;
610 thread_act_t profiled_thread_;
611 pthread_t sampler_thread_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 RuntimeProfilerRateLimiter rate_limiter_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000614 // Sampler thread handler.
615 void Runner() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 while (sampler_->IsActive()) {
617 if (rate_limiter_.SuspendIfNecessary()) continue;
618 Sample();
619 OS::Sleep(sampler_->interval_);
620 }
621 }
622
623 void Sample() {
624 if (sampler_->IsProfiling()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000625 TickSample sample_obj;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000626 TickSample* sample = CpuProfiler::TickSampleEvent();
ager@chromium.org357bf652010-04-12 11:30:10 +0000627 if (sample == NULL) sample = &sample_obj;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000628
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000629 if (KERN_SUCCESS != thread_suspend(profiled_thread_)) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000630
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000631#if V8_HOST_ARCH_X64
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632 thread_state_flavor_t flavor = x86_THREAD_STATE64;
633 x86_thread_state64_t state;
634 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000635#if __DARWIN_UNIX03
636#define REGISTER_FIELD(name) __r ## name
637#else
638#define REGISTER_FIELD(name) r ## name
639#endif // __DARWIN_UNIX03
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000640#elif V8_HOST_ARCH_IA32
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641 thread_state_flavor_t flavor = i386_THREAD_STATE;
642 i386_thread_state_t state;
643 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000644#if __DARWIN_UNIX03
645#define REGISTER_FIELD(name) __e ## name
646#else
647#define REGISTER_FIELD(name) e ## name
648#endif // __DARWIN_UNIX03
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000649#else
650#error Unsupported Mac OS X host architecture.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000651#endif // V8_HOST_ARCH
652
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000653 if (thread_get_state(profiled_thread_,
654 flavor,
655 reinterpret_cast<natural_t*>(&state),
656 &count) == KERN_SUCCESS) {
657 sample->state = Top::current_vm_state();
658 sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
659 sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
660 sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
661 sampler_->SampleStack(sample);
662 sampler_->Tick(sample);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000663 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664 thread_resume(profiled_thread_);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000665 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000666 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000667 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668};
669
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000670#undef REGISTER_FIELD
671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000673// Entry point for sampler thread.
674static void* SamplerEntry(void* arg) {
675 Sampler::PlatformData* data =
676 reinterpret_cast<Sampler::PlatformData*>(arg);
677 data->Runner();
678 return 0;
679}
680
681
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000682Sampler::Sampler(int interval)
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000683 : interval_(interval),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 profiling_(false),
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000685 active_(false),
686 samples_taken_(0) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000687 data_ = new PlatformData(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688}
689
690
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000691Sampler::~Sampler() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692 delete data_;
693}
694
695
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000696void Sampler::Start() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000697 // Do not start multiple threads for the same sampler.
698 ASSERT(!IsActive());
699 data_->profiled_thread_ = mach_thread_self();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000701 // Create sampler thread with high priority.
702 // According to POSIX spec, when SCHED_FIFO policy is used, a thread
703 // runs until it exits or blocks.
704 pthread_attr_t sched_attr;
705 sched_param fifo_param;
706 pthread_attr_init(&sched_attr);
707 pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED);
708 pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO);
709 fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
710 pthread_attr_setschedparam(&sched_attr, &fifo_param);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712 SetActive(true);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000713 pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry, data_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000714}
715
716
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000717void Sampler::Stop() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000718 // Seting active to false triggers termination of the sampler
719 // thread.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000720 SetActive(false);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000721
722 // Wait for sampler thread to terminate.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000723 Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000724 pthread_join(data_->sampler_thread_, NULL);
725
726 // Deallocate Mach port for thread.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000727 mach_port_deallocate(data_->task_self_, data_->profiled_thread_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000728}
729
730#endif // ENABLE_LOGGING_AND_PROFILING
731
732} } // namespace v8::internal