blob: 1af928e169da3af5cf0a9036eabc376423714540 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.orga74f0da2008-12-03 16:05:52 +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 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
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +000045// If you don't have execinfo.h then you need devel/libexecinfo from ports.
ager@chromium.orga74f0da2008-12-03 16:05:52 +000046#include <execinfo.h> // backtrace, backtrace_symbols
47#include <strings.h> // index
48#include <errno.h>
49#include <stdarg.h>
50#include <limits.h>
51
52#undef MAP_TYPE
53
54#include "v8.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000055#include "v8threads.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000056
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000057#include "platform-posix.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000058#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000059#include "vm-state-inl.h"
ager@chromium.orga74f0da2008-12-03 16:05:52 +000060
61
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
ager@chromium.orga74f0da2008-12-03 16:05:52 +000064
65// 0 is never a valid thread id on FreeBSD since tids and pids share a
66// name space and pid 0 is used to kill the group (see man 2 kill).
67static const pthread_t kNoThread = (pthread_t) 0;
68
69
70double ceiling(double x) {
71 // Correct as on OS X
72 if (-1.0 < x && x < 0.0) {
73 return -0.0;
74 } else {
75 return ceil(x);
76 }
77}
78
79
lrn@chromium.org7516f052011-03-30 08:52:27 +000080static Mutex* limit_mutex = NULL;
81
82
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000083void OS::PostSetUp() {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000084 POSIXPostSetUp();
danno@chromium.org8c0a43f2012-04-03 08:37:53 +000085}
86
87
ricow@chromium.org30ce4112010-05-31 10:38:25 +000088void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
89 __asm__ __volatile__("" : : : "memory");
90 *ptr = value;
91}
92
93
ager@chromium.orgc4c92722009-11-18 14:12:51 +000094uint64_t OS::CpuFeaturesImpliedByPlatform() {
95 return 0; // FreeBSD runs on anything.
96}
97
98
ager@chromium.orga74f0da2008-12-03 16:05:52 +000099int OS::ActivationFrameAlignment() {
100 // 16 byte alignment on FreeBSD
101 return 16;
102}
103
104
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000105const char* OS::LocalTimezone(double time) {
106 if (isnan(time)) return "";
107 time_t tv = static_cast<time_t>(floor(time/msPerSecond));
108 struct tm* t = localtime(&tv);
109 if (NULL == t) return "";
110 return t->tm_zone;
111}
112
113
114double OS::LocalTimeOffset() {
115 time_t tv = time(NULL);
116 struct tm* t = localtime(&tv);
117 // tm_gmtoff includes any daylight savings offset, so subtract it.
118 return static_cast<double>(t->tm_gmtoff * msPerSecond -
119 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
120}
121
122
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000123// We keep the lowest and highest addresses mapped as a quick way of
124// determining that pointers are outside the heap (used mostly in assertions
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000125// and verification). The estimate is conservative, i.e., not all addresses in
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000126// 'allocated' space are actually allocated to our heap. The range is
127// [lowest, highest), inclusive on the low and and exclusive on the high end.
128static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
129static void* highest_ever_allocated = reinterpret_cast<void*>(0);
130
131
132static void UpdateAllocatedSpaceLimits(void* address, int size) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000133 ASSERT(limit_mutex != NULL);
134 ScopedLock lock(limit_mutex);
135
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000136 lowest_ever_allocated = Min(lowest_ever_allocated, address);
137 highest_ever_allocated =
138 Max(highest_ever_allocated,
139 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
140}
141
142
143bool OS::IsOutsideAllocatedSpace(void* address) {
144 return address < lowest_ever_allocated || address >= highest_ever_allocated;
145}
146
147
148size_t OS::AllocateAlignment() {
149 return getpagesize();
150}
151
152
153void* OS::Allocate(const size_t requested,
154 size_t* allocated,
155 bool executable) {
156 const size_t msize = RoundUp(requested, getpagesize());
157 int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
158 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
159
160 if (mbase == MAP_FAILED) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000162 return NULL;
163 }
164 *allocated = msize;
165 UpdateAllocatedSpaceLimits(mbase, msize);
166 return mbase;
167}
168
169
170void OS::Free(void* buf, const size_t length) {
171 // TODO(1240712): munmap has a return value which is ignored here.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000172 int result = munmap(buf, length);
173 USE(result);
174 ASSERT(result == 0);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000175}
176
177
178void OS::Sleep(int milliseconds) {
179 unsigned int ms = static_cast<unsigned int>(milliseconds);
180 usleep(1000 * ms);
181}
182
183
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000184int OS::NumberOfCores() {
185 return sysconf(_SC_NPROCESSORS_ONLN);
186}
187
188
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000189void OS::Abort() {
190 // Redirect to std abort to signal abnormal program termination.
191 abort();
192}
193
194
195void OS::DebugBreak() {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#if (defined(__arm__) || defined(__thumb__))
197# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000198 asm("bkpt 0");
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000199# endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000200#else
201 asm("int $3");
202#endif
203}
204
205
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000206void OS::DumpBacktrace() {
207 void* trace[100];
208 int size = backtrace(trace, ARRAY_SIZE(trace));
209 char** symbols = backtrace_symbols(trace, size);
210 fprintf(stderr, "\n==== C stack trace ===============================\n\n");
211 if (size == 0) {
212 fprintf(stderr, "(empty)\n");
213 } else if (symbols == NULL) {
214 fprintf(stderr, "(no symbols)\n");
215 } else {
216 for (int i = 1; i < size; ++i) {
217 fprintf(stderr, "%2d: ", i);
218 char mangled[201];
219 if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) { // NOLINT
220 fprintf(stderr, "%s\n", mangled);
221 } else {
222 fprintf(stderr, "??\n");
223 }
224 }
225 }
226 fflush(stderr);
227 free(symbols);
228}
229
230
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000231class PosixMemoryMappedFile : public OS::MemoryMappedFile {
232 public:
233 PosixMemoryMappedFile(FILE* file, void* memory, int size)
234 : file_(file), memory_(memory), size_(size) { }
235 virtual ~PosixMemoryMappedFile();
236 virtual void* memory() { return memory_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000237 virtual int size() { return size_; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000238 private:
239 FILE* file_;
240 void* memory_;
241 int size_;
242};
243
244
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000245OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000246 FILE* file = fopen(name, "r+");
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000247 if (file == NULL) return NULL;
248
249 fseek(file, 0, SEEK_END);
250 int size = ftell(file);
251
252 void* memory =
253 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
254 return new PosixMemoryMappedFile(file, memory, size);
255}
256
257
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000258OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
259 void* initial) {
260 FILE* file = fopen(name, "w+");
261 if (file == NULL) return NULL;
262 int result = fwrite(initial, size, 1, file);
263 if (result < 1) {
264 fclose(file);
265 return NULL;
266 }
267 void* memory =
268 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
269 return new PosixMemoryMappedFile(file, memory, size);
270}
271
272
273PosixMemoryMappedFile::~PosixMemoryMappedFile() {
274 if (memory_) munmap(memory_, size_);
275 fclose(file_);
276}
277
278
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000279static unsigned StringToLong(char* buffer) {
280 return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
281}
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000282
283
284void OS::LogSharedLibraryAddresses() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000285 static const int MAP_LENGTH = 1024;
286 int fd = open("/proc/self/maps", O_RDONLY);
287 if (fd < 0) return;
288 while (true) {
289 char addr_buffer[11];
290 addr_buffer[0] = '0';
291 addr_buffer[1] = 'x';
292 addr_buffer[10] = 0;
293 int result = read(fd, addr_buffer + 2, 8);
294 if (result < 8) break;
295 unsigned start = StringToLong(addr_buffer);
296 result = read(fd, addr_buffer + 2, 1);
297 if (result < 1) break;
298 if (addr_buffer[2] != '-') break;
299 result = read(fd, addr_buffer + 2, 8);
300 if (result < 8) break;
301 unsigned end = StringToLong(addr_buffer);
302 char buffer[MAP_LENGTH];
303 int bytes_read = -1;
304 do {
305 bytes_read++;
306 if (bytes_read >= MAP_LENGTH - 1)
307 break;
308 result = read(fd, buffer + bytes_read, 1);
309 if (result < 1) break;
310 } while (buffer[bytes_read] != '\n');
311 buffer[bytes_read] = 0;
312 // Ignore mappings that are not executable.
313 if (buffer[3] != 'x') continue;
314 char* start_of_path = index(buffer, '/');
315 // There may be no filename in this line. Skip to next.
316 if (start_of_path == NULL) continue;
317 buffer[bytes_read] = 0;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000318 LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000319 }
320 close(fd);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000321}
322
323
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000324void OS::SignalCodeMovingGC() {
325}
326
327
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000328int OS::StackWalk(Vector<OS::StackFrame> frames) {
329 int frames_size = frames.length();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000330 ScopedVector<void*> addresses(frames_size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000331
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000332 int frames_count = backtrace(addresses.start(), frames_size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000333
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000334 char** symbols = backtrace_symbols(addresses.start(), frames_count);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000335 if (symbols == NULL) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000336 return kStackWalkError;
337 }
338
339 for (int i = 0; i < frames_count; i++) {
340 frames[i].address = addresses[i];
341 // Format a text representation of the frame based on the information
342 // available.
343 SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
344 "%s",
345 symbols[i]);
346 // Make sure line termination is in place.
347 frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
348 }
349
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000350 free(symbols);
351
352 return frames_count;
353}
354
355
356// Constants used for mmap.
357static const int kMmapFd = -1;
358static const int kMmapFdOffset = 0;
359
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000360VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000361
362VirtualMemory::VirtualMemory(size_t size) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000363 address_ = ReserveRegion(size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000364 size_ = size;
365}
366
367
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000368VirtualMemory::VirtualMemory(size_t size, size_t alignment)
369 : address_(NULL), size_(0) {
370 ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
371 size_t request_size = RoundUp(size + alignment,
372 static_cast<intptr_t>(OS::AllocateAlignment()));
373 void* reservation = mmap(OS::GetRandomMmapAddr(),
374 request_size,
375 PROT_NONE,
376 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
377 kMmapFd,
378 kMmapFdOffset);
379 if (reservation == MAP_FAILED) return;
380
381 Address base = static_cast<Address>(reservation);
382 Address aligned_base = RoundUp(base, alignment);
383 ASSERT_LE(base, aligned_base);
384
385 // Unmap extra memory reserved before and after the desired block.
386 if (aligned_base != base) {
387 size_t prefix_size = static_cast<size_t>(aligned_base - base);
388 OS::Free(base, prefix_size);
389 request_size -= prefix_size;
390 }
391
392 size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
393 ASSERT_LE(aligned_size, request_size);
394
395 if (aligned_size != request_size) {
396 size_t suffix_size = request_size - aligned_size;
397 OS::Free(aligned_base + aligned_size, suffix_size);
398 request_size -= suffix_size;
399 }
400
401 ASSERT(aligned_size == request_size);
402
403 address_ = static_cast<void*>(aligned_base);
404 size_ = aligned_size;
405}
406
407
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000408VirtualMemory::~VirtualMemory() {
409 if (IsReserved()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000410 bool result = ReleaseRegion(address(), size());
411 ASSERT(result);
412 USE(result);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000413 }
414}
415
416
417bool VirtualMemory::IsReserved() {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000418 return address_ != NULL;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000419}
420
421
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000422void VirtualMemory::Reset() {
423 address_ = NULL;
424 size_ = 0;
425}
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000426
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000427
428bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
429 return CommitRegion(address, size, is_executable);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000430}
431
432
433bool VirtualMemory::Uncommit(void* address, size_t size) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000434 return UncommitRegion(address, size);
435}
436
437
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000438bool VirtualMemory::Guard(void* address) {
439 OS::Guard(address, OS::CommitPageSize());
440 return true;
441}
442
443
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000444void* VirtualMemory::ReserveRegion(size_t size) {
445 void* result = mmap(OS::GetRandomMmapAddr(),
446 size,
447 PROT_NONE,
448 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
449 kMmapFd,
450 kMmapFdOffset);
451
452 if (result == MAP_FAILED) return NULL;
453
454 return result;
455}
456
457
458bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
459 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
460 if (MAP_FAILED == mmap(base,
461 size,
462 prot,
463 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
464 kMmapFd,
465 kMmapFdOffset)) {
466 return false;
467 }
468
469 UpdateAllocatedSpaceLimits(base, size);
470 return true;
471}
472
473
474bool VirtualMemory::UncommitRegion(void* base, size_t size) {
475 return mmap(base,
476 size,
477 PROT_NONE,
ager@chromium.orga1645e22009-09-09 19:27:10 +0000478 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000479 kMmapFd,
480 kMmapFdOffset) != MAP_FAILED;
481}
482
483
484bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
485 return munmap(base, size) == 0;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000486}
487
488
danno@chromium.org72204d52012-10-31 10:02:10 +0000489bool VirtualMemory::HasLazyCommits() {
490 // TODO(alph): implement for the platform.
491 return false;
492}
493
494
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000495class Thread::PlatformData : public Malloced {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000496 public:
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000497 pthread_t thread_; // Thread handle for pthread.
498};
499
500
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000501Thread::Thread(const Options& options)
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000502 : data_(new PlatformData),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000503 stack_size_(options.stack_size()) {
504 set_name(options.name());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000505}
506
507
508Thread::~Thread() {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000509 delete data_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000510}
511
512
513static void* ThreadEntry(void* arg) {
514 Thread* thread = reinterpret_cast<Thread*>(arg);
515 // This is also initialized by the first argument to pthread_create() but we
516 // don't know which thread will run first (the original thread or the new
517 // one) so we initialize it here too.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000518 thread->data()->thread_ = pthread_self();
519 ASSERT(thread->data()->thread_ != kNoThread);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000520 thread->Run();
521 return NULL;
522}
523
524
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000525void Thread::set_name(const char* name) {
526 strncpy(name_, name, sizeof(name_));
527 name_[sizeof(name_) - 1] = '\0';
528}
529
530
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000531void Thread::Start() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 pthread_attr_t* attr_ptr = NULL;
533 pthread_attr_t attr;
534 if (stack_size_ > 0) {
535 pthread_attr_init(&attr);
536 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
537 attr_ptr = &attr;
538 }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000539 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
540 ASSERT(data_->thread_ != kNoThread);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000541}
542
543
544void Thread::Join() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000545 pthread_join(data_->thread_, NULL);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000546}
547
548
549Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
550 pthread_key_t key;
551 int result = pthread_key_create(&key, NULL);
552 USE(result);
553 ASSERT(result == 0);
554 return static_cast<LocalStorageKey>(key);
555}
556
557
558void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
559 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
560 int result = pthread_key_delete(pthread_key);
561 USE(result);
562 ASSERT(result == 0);
563}
564
565
566void* Thread::GetThreadLocal(LocalStorageKey key) {
567 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
568 return pthread_getspecific(pthread_key);
569}
570
571
572void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
573 pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
574 pthread_setspecific(pthread_key, value);
575}
576
577
578void Thread::YieldCPU() {
579 sched_yield();
580}
581
582
583class FreeBSDMutex : public Mutex {
584 public:
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000585 FreeBSDMutex() {
586 pthread_mutexattr_t attrs;
587 int result = pthread_mutexattr_init(&attrs);
588 ASSERT(result == 0);
589 result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
590 ASSERT(result == 0);
591 result = pthread_mutex_init(&mutex_, &attrs);
592 ASSERT(result == 0);
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000593 USE(result);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000594 }
595
596 virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
597
598 virtual int Lock() {
599 int result = pthread_mutex_lock(&mutex_);
600 return result;
601 }
602
603 virtual int Unlock() {
604 int result = pthread_mutex_unlock(&mutex_);
605 return result;
606 }
607
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000608 virtual bool TryLock() {
609 int result = pthread_mutex_trylock(&mutex_);
610 // Return false if the lock is busy and locking failed.
611 if (result == EBUSY) {
612 return false;
613 }
614 ASSERT(result == 0); // Verify no other errors.
615 return true;
616 }
617
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000618 private:
619 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
620};
621
622
623Mutex* OS::CreateMutex() {
624 return new FreeBSDMutex();
625}
626
627
628class FreeBSDSemaphore : public Semaphore {
629 public:
630 explicit FreeBSDSemaphore(int count) { sem_init(&sem_, 0, count); }
631 virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
632
633 virtual void Wait();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000634 virtual bool Wait(int timeout);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000635 virtual void Signal() { sem_post(&sem_); }
636 private:
637 sem_t sem_;
638};
639
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000640
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000641void FreeBSDSemaphore::Wait() {
642 while (true) {
643 int result = sem_wait(&sem_);
644 if (result == 0) return; // Successfully got semaphore.
645 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
646 }
647}
648
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000649
650bool FreeBSDSemaphore::Wait(int timeout) {
651 const long kOneSecondMicros = 1000000; // NOLINT
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000652
653 // Split timeout into second and nanosecond parts.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000654 struct timeval delta;
655 delta.tv_usec = timeout % kOneSecondMicros;
656 delta.tv_sec = timeout / kOneSecondMicros;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000657
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000658 struct timeval current_time;
659 // Get the current time.
660 if (gettimeofday(&current_time, NULL) == -1) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000661 return false;
662 }
663
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000664 // Calculate time for end of timeout.
665 struct timeval end_time;
666 timeradd(&current_time, &delta, &end_time);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000667
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000668 struct timespec ts;
669 TIMEVAL_TO_TIMESPEC(&end_time, &ts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000670 while (true) {
671 int result = sem_timedwait(&sem_, &ts);
672 if (result == 0) return true; // Successfully got semaphore.
673 if (result == -1 && errno == ETIMEDOUT) return false; // Timeout.
674 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
675 }
676}
677
678
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000679Semaphore* OS::CreateSemaphore(int count) {
680 return new FreeBSDSemaphore(count);
681}
682
ager@chromium.org381abbb2009-02-25 13:23:22 +0000683
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000684static pthread_t GetThreadID() {
685 pthread_t thread_id = pthread_self();
686 return thread_id;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000687}
688
689
690class Sampler::PlatformData : public Malloced {
691 public:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000692 PlatformData() : vm_tid_(GetThreadID()) {}
693
694 pthread_t vm_tid() const { return vm_tid_; }
695
696 private:
697 pthread_t vm_tid_;
698};
699
700
701static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
702 USE(info);
703 if (signal != SIGPROF) return;
704 Isolate* isolate = Isolate::UncheckedCurrent();
705 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
706 // We require a fully initialized and entered isolate.
707 return;
708 }
vitalyr@chromium.org0ec56d62011-04-15 22:22:08 +0000709 if (v8::Locker::IsActive() &&
710 !isolate->thread_manager()->IsLockedByCurrentThread()) {
711 return;
712 }
713
lrn@chromium.org7516f052011-03-30 08:52:27 +0000714 Sampler* sampler = isolate->logger()->sampler();
715 if (sampler == NULL || !sampler->IsActive()) return;
716
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000717 TickSample sample_obj;
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000718 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +0000719 if (sample == NULL) sample = &sample_obj;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000720
721 // Extracting the sample from the context is extremely machine dependent.
722 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
723 mcontext_t& mcontext = ucontext->uc_mcontext;
724 sample->state = isolate->current_vm_state();
725#if V8_HOST_ARCH_IA32
726 sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
727 sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
728 sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
729#elif V8_HOST_ARCH_X64
730 sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
731 sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
732 sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
733#elif V8_HOST_ARCH_ARM
734 sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
735 sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
736 sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
737#endif
738 sampler->SampleStack(sample);
739 sampler->Tick(sample);
740}
741
742
743class SignalSender : public Thread {
744 public:
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000745 static const int kSignalSenderStackSize = 64 * KB;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000746
lrn@chromium.org7516f052011-03-30 08:52:27 +0000747 explicit SignalSender(int interval)
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000748 : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
lrn@chromium.org7516f052011-03-30 08:52:27 +0000749 interval_(interval) {}
750
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000751 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
752 static void TearDown() { delete mutex_; }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000753
lrn@chromium.org7516f052011-03-30 08:52:27 +0000754 static void AddActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000755 ScopedLock lock(mutex_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000756 SamplerRegistry::AddActiveSampler(sampler);
757 if (instance_ == NULL) {
758 // Install a signal handler.
759 struct sigaction sa;
760 sa.sa_sigaction = ProfilerSignalHandler;
761 sigemptyset(&sa.sa_mask);
762 sa.sa_flags = SA_RESTART | SA_SIGINFO;
763 signal_handler_installed_ =
764 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
765
766 // Start a thread that sends SIGPROF signal to VM threads.
767 instance_ = new SignalSender(sampler->interval());
768 instance_->Start();
769 } else {
770 ASSERT(instance_->interval_ == sampler->interval());
771 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000772 }
773
lrn@chromium.org7516f052011-03-30 08:52:27 +0000774 static void RemoveActiveSampler(Sampler* sampler) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000775 ScopedLock lock(mutex_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000776 SamplerRegistry::RemoveActiveSampler(sampler);
777 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000778 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000779 delete instance_;
780 instance_ = NULL;
781
782 // Restore the old signal handler.
783 if (signal_handler_installed_) {
784 sigaction(SIGPROF, &old_signal_handler_, 0);
785 signal_handler_installed_ = false;
786 }
787 }
788 }
789
790 // Implement Thread::Run().
791 virtual void Run() {
792 SamplerRegistry::State state;
793 while ((state = SamplerRegistry::GetState()) !=
794 SamplerRegistry::HAS_NO_SAMPLERS) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000795 // When CPU profiling is enabled both JavaScript and C++ code is
796 // profiled. We must not suspend.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000797 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
798 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
799 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000800 if (RuntimeProfiler::WaitForSomeIsolateToEnterJS()) continue;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000801 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000802 Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000803 }
804 }
805
lrn@chromium.org7516f052011-03-30 08:52:27 +0000806 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
807 if (!sampler->IsProfiling()) return;
808 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
809 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
810 }
811
lrn@chromium.org7516f052011-03-30 08:52:27 +0000812 void SendProfilingSignal(pthread_t tid) {
813 if (!signal_handler_installed_) return;
814 pthread_kill(tid, SIGPROF);
815 }
816
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000817 void Sleep() {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000818 // Convert ms to us and subtract 100 us to compensate delays
819 // occuring during signal delivery.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000820 useconds_t interval = interval_ * 1000 - 100;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000821 int result = usleep(interval);
822#ifdef DEBUG
823 if (result != 0 && errno != EINTR) {
824 fprintf(stderr,
825 "SignalSender usleep error; interval = %u, errno = %d\n",
826 interval,
827 errno);
828 ASSERT(result == 0 || errno == EINTR);
829 }
830#endif
831 USE(result);
832 }
833
lrn@chromium.org7516f052011-03-30 08:52:27 +0000834 const int interval_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000835
836 // Protects the process wide state below.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000837 static Mutex* mutex_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000838 static SignalSender* instance_;
839 static bool signal_handler_installed_;
840 static struct sigaction old_signal_handler_;
841
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000842 private:
lrn@chromium.org7516f052011-03-30 08:52:27 +0000843 DISALLOW_COPY_AND_ASSIGN(SignalSender);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000844};
845
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000846Mutex* SignalSender::mutex_ = NULL;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000847SignalSender* SignalSender::instance_ = NULL;
848struct sigaction SignalSender::old_signal_handler_;
849bool SignalSender::signal_handler_installed_ = false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000850
851
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000852void OS::SetUp() {
853 // Seed the random number generator.
854 // Convert the current time to a 64-bit integer first, before converting it
855 // to an unsigned. Going directly can cause an overflow and the seed to be
856 // set to all ones. The seed will be identical for different instances that
857 // call this setup code within the same millisecond.
858 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
859 srandom(static_cast<unsigned int>(seed));
860 limit_mutex = CreateMutex();
861 SignalSender::SetUp();
862}
863
864
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000865void OS::TearDown() {
866 SignalSender::TearDown();
867 delete limit_mutex;
868}
869
870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871Sampler::Sampler(Isolate* isolate, int interval)
872 : isolate_(isolate),
873 interval_(interval),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000874 profiling_(false),
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000875 active_(false),
876 samples_taken_(0) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000877 data_ = new PlatformData;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000878}
879
880
881Sampler::~Sampler() {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000882 ASSERT(!IsActive());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000883 delete data_;
884}
885
886
887void Sampler::Start() {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000888 ASSERT(!IsActive());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000889 SetActive(true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000890 SignalSender::AddActiveSampler(this);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000891}
892
893
894void Sampler::Stop() {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000895 ASSERT(IsActive());
896 SignalSender::RemoveActiveSampler(this);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000897 SetActive(false);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000898}
899
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000900
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +0000901bool Sampler::CanSampleOnProfilerEventsProcessorThread() {
902 return false;
903}
904
905
906void Sampler::DoSample() {
907}
908
909
910void Sampler::StartProfiling() {
911}
912
913
914void Sampler::StopProfiling() {
915}
916
917
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000918} } // namespace v8::internal