33
33
#include <signal.h>
34
34
#include <sys/time.h>
35
35
#include <sys/resource.h>
36
#include <sys/syscall.h>
36
37
#include <sys/types.h>
37
38
#include <stdlib.h>
39
40
#include <sys/types.h> // mmap & munmap
40
41
#include <sys/mman.h> // mmap & munmap
41
42
#include <sys/stat.h> // open
42
#include <sys/fcntl.h> // open
43
#include <unistd.h> // getpagesize
43
#include <fcntl.h> // open
44
#include <unistd.h> // sysconf
44
45
#include <execinfo.h> // backtrace, backtrace_symbols
45
46
#include <strings.h> // index
47
48
#include <stdarg.h>
53
55
#include "v8threads.h"
56
56
#include "vm-state-inl.h"
60
60
namespace internal {
62
// 0 is never a valid thread id on OpenBSD since tids and pids share a
63
// name space and pid 0 is used to kill the group (see man 2 kill).
62
// 0 is never a valid thread id on Linux and OpenBSD since tids and pids share a
63
// name space and pid 0 is reserved (see man 2 kill).
64
64
static const pthread_t kNoThread = (pthread_t) 0;
67
67
double ceiling(double x) {
69
if (-1.0 < x && x < 0.0) {
77
72
static Mutex* limit_mutex = NULL;
75
static void* GetRandomMmapAddr() {
76
Isolate* isolate = Isolate::UncheckedCurrent();
77
// Note that the current isolate isn't set up in a call path via
78
// CpuFeatures::Probe. We don't care about randomization in this case because
79
// the code page is immediately freed.
80
if (isolate != NULL) {
81
#ifdef V8_TARGET_ARCH_X64
82
uint64_t rnd1 = V8::RandomPrivate(isolate);
83
uint64_t rnd2 = V8::RandomPrivate(isolate);
84
uint64_t raw_addr = (rnd1 << 32) ^ rnd2;
85
// Currently available CPUs have 48 bits of virtual addressing. Truncate
86
// the hint address to 46 bits to give the kernel a fighting chance of
87
// fulfilling our placement request.
88
raw_addr &= V8_UINT64_C(0x3ffffffff000);
90
uint32_t raw_addr = V8::RandomPrivate(isolate);
91
// The range 0x20000000 - 0x60000000 is relatively unpopulated across a
92
// variety of ASLR modes (PAE kernel, NX compat mode, etc).
93
raw_addr &= 0x3ffff000;
94
raw_addr += 0x20000000;
96
return reinterpret_cast<void*>(raw_addr);
80
102
void OS::Setup() {
81
// Seed the random number generator.
82
// Convert the current time to a 64-bit integer first, before converting it
83
// to an unsigned. Going directly can cause an overflow and the seed to be
84
// set to all ones. The seed will be identical for different instances that
85
// call this setup code within the same millisecond.
86
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
103
// Seed the random number generator. We preserve microsecond resolution.
104
uint64_t seed = Ticks() ^ (getpid() << 16);
87
105
srandom(static_cast<unsigned int>(seed));
88
106
limit_mutex = CreateMutex();
110
uint64_t OS::CpuFeaturesImpliedByPlatform() {
115
int OS::ActivationFrameAlignment() {
116
// With gcc 4.4 the tree vectorization optimizer can generate code
117
// that requires 16 byte alignment such as movdqa on x86.
92
122
void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
93
123
__asm__ __volatile__("" : : : "memory");
124
// An x86 store acts as a release barrier.
98
uint64_t OS::CpuFeaturesImpliedByPlatform() {
99
return 0; // OpenBSD runs on anything.
103
int OS::ActivationFrameAlignment() {
104
// 16 byte alignment on OpenBSD
109
129
const char* OS::LocalTimezone(double time) {
110
130
if (isnan(time)) return "";
111
131
time_t tv = static_cast<time_t>(floor(time/msPerSecond));
152
172
size_t OS::AllocateAlignment() {
153
return getpagesize();
173
return sysconf(_SC_PAGESIZE);
157
177
void* OS::Allocate(const size_t requested,
158
178
size_t* allocated,
160
const size_t msize = RoundUp(requested, getpagesize());
161
int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
162
void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
179
bool is_executable) {
180
const size_t msize = RoundUp(requested, AllocateAlignment());
181
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
182
void* addr = GetRandomMmapAddr();
183
void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
164
184
if (mbase == MAP_FAILED) {
165
LOG(ISOLATE, StringEvent("OS::Allocate", "mmap failed"));
185
LOG(i::Isolate::Current(),
186
StringEvent("OS::Allocate", "mmap failed"));
168
189
*allocated = msize;
247
262
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
248
if (memory_) munmap(memory_, size_);
263
if (memory_) OS::Free(memory_, size_);
253
static unsigned StringToLong(char* buffer) {
254
return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
258
268
void OS::LogSharedLibraryAddresses() {
259
static const int MAP_LENGTH = 1024;
260
int fd = open("/proc/self/maps", O_RDONLY);
269
// This function assumes that the layout of the file is as follows:
270
// hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
271
// If we encounter an unexpected situation we abort scanning further entries.
272
FILE* fp = fopen("/proc/self/maps", "r");
273
if (fp == NULL) return;
275
// Allocate enough room to be able to store a full file name.
276
const int kLibNameLen = FILENAME_MAX + 1;
277
char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
279
i::Isolate* isolate = ISOLATE;
280
// This loop will terminate once the scanning hits an EOF.
263
char addr_buffer[11];
264
addr_buffer[0] = '0';
265
addr_buffer[1] = 'x';
267
int result = read(fd, addr_buffer + 2, 8);
268
if (result < 8) break;
269
unsigned start = StringToLong(addr_buffer);
270
result = read(fd, addr_buffer + 2, 1);
271
if (result < 1) break;
272
if (addr_buffer[2] != '-') break;
273
result = read(fd, addr_buffer + 2, 8);
274
if (result < 8) break;
275
unsigned end = StringToLong(addr_buffer);
276
char buffer[MAP_LENGTH];
280
if (bytes_read >= MAP_LENGTH - 1)
282
result = read(fd, buffer + bytes_read, 1);
283
if (result < 1) break;
284
} while (buffer[bytes_read] != '\n');
285
buffer[bytes_read] = 0;
286
// Ignore mappings that are not executable.
287
if (buffer[3] != 'x') continue;
288
char* start_of_path = index(buffer, '/');
289
// There may be no filename in this line. Skip to next.
290
if (start_of_path == NULL) continue;
291
buffer[bytes_read] = 0;
292
LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end));
282
uintptr_t start, end;
283
char attr_r, attr_w, attr_x, attr_p;
284
// Parse the addresses and permission bits at the beginning of the line.
285
if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
286
if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
289
if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
290
// Found a read-only executable entry. Skip characters until we reach
291
// the beginning of the filename or the end of the line.
294
} while ((c != EOF) && (c != '\n') && (c != '/'));
295
if (c == EOF) break; // EOF: Was unexpected, just exit.
297
// Process the filename if found.
299
ungetc(c, fp); // Push the '/' back into the stream to be read below.
301
// Read to the end of the line. Exit if the read fails.
302
if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
304
// Drop the newline character read by fgets. We do not need to check
305
// for a zero-length string because we know that we at least read the
307
lib_name[strlen(lib_name) - 1] = '\0';
309
// No library name found, just record the raw address range.
310
snprintf(lib_name, kLibNameLen,
311
"%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
313
LOG(isolate, SharedLibraryEvent(lib_name, start, end));
315
// Entry not describing executable data. Skip to end of line to setup
316
// reading the next entry.
319
} while ((c != EOF) && (c != '\n'));
328
static const char kGCFakeMmap[] = "/tmp/__v8_gc__";
298
331
void OS::SignalCodeMovingGC() {
332
// Support for ll_prof.py.
334
// The Linux profiler built into the kernel logs all mmap's with
335
// PROT_EXEC so that analysis tools can properly attribute ticks. We
336
// do a mmap with a name known by ll_prof.py and immediately munmap
337
// it. This injects a GC marker into the stream of events generated
338
// by the kernel and allows us to synchronize V8 code log and the
340
int size = sysconf(_SC_PAGESIZE);
341
FILE* f = fopen(kGCFakeMmap, "w+");
342
void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE,
344
ASSERT(addr != MAP_FAILED);
345
OS::Free(addr, size);
302
350
int OS::StackWalk(Vector<OS::StackFrame> frames) {
351
// backtrace is a glibc extension.
303
352
int frames_size = frames.length();
304
353
ScopedVector<void*> addresses(frames_size);
331
380
static const int kMmapFd = -1;
332
381
static const int kMmapFdOffset = 0;
383
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
335
385
VirtualMemory::VirtualMemory(size_t size) {
336
address_ = mmap(NULL, size, PROT_NONE,
337
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
338
kMmapFd, kMmapFdOffset);
386
address_ = ReserveRegion(size);
391
VirtualMemory::VirtualMemory(size_t size, size_t alignment)
392
: address_(NULL), size_(0) {
393
ASSERT(IsAligned(alignment, static_cast<intptr_t>(OS::AllocateAlignment())));
394
size_t request_size = RoundUp(size + alignment,
395
static_cast<intptr_t>(OS::AllocateAlignment()));
396
void* reservation = mmap(GetRandomMmapAddr(),
399
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
402
if (reservation == MAP_FAILED) return;
404
Address base = static_cast<Address>(reservation);
405
Address aligned_base = RoundUp(base, alignment);
406
ASSERT_LE(base, aligned_base);
408
// Unmap extra memory reserved before and after the desired block.
409
if (aligned_base != base) {
410
size_t prefix_size = static_cast<size_t>(aligned_base - base);
411
OS::Free(base, prefix_size);
412
request_size -= prefix_size;
415
size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
416
ASSERT_LE(aligned_size, request_size);
418
if (aligned_size != request_size) {
419
size_t suffix_size = request_size - aligned_size;
420
OS::Free(aligned_base + aligned_size, suffix_size);
421
request_size -= suffix_size;
424
ASSERT(aligned_size == request_size);
426
address_ = static_cast<void*>(aligned_base);
427
size_ = aligned_size;
343
431
VirtualMemory::~VirtualMemory() {
344
432
if (IsReserved()) {
345
if (0 == munmap(address(), size())) address_ = MAP_FAILED;
433
bool result = ReleaseRegion(address(), size());
350
440
bool VirtualMemory::IsReserved() {
351
return address_ != MAP_FAILED;
355
bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
356
int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
357
if (MAP_FAILED == mmap(address, size, prot,
441
return address_ != NULL;
445
void VirtualMemory::Reset() {
451
bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
452
return CommitRegion(address, size, is_executable);
456
bool VirtualMemory::Uncommit(void* address, size_t size) {
457
return UncommitRegion(address, size);
461
void* VirtualMemory::ReserveRegion(size_t size) {
462
void* result = mmap(GetRandomMmapAddr(),
465
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
469
if (result == MAP_FAILED) return NULL;
475
bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
476
int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
477
if (MAP_FAILED == mmap(base,
358
480
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
359
kMmapFd, kMmapFdOffset)) {
363
UpdateAllocatedSpaceLimits(address, size);
486
UpdateAllocatedSpaceLimits(base, size);
368
bool VirtualMemory::Uncommit(void* address, size_t size) {
369
return mmap(address, size, PROT_NONE,
491
bool VirtualMemory::UncommitRegion(void* base, size_t size) {
370
495
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
371
kMmapFd, kMmapFdOffset) != MAP_FAILED;
497
kMmapFdOffset) != MAP_FAILED;
501
bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
502
return munmap(base, size) == 0;
375
506
class Thread::PlatformData : public Malloced {
508
PlatformData() : thread_(kNoThread) {}
377
510
pthread_t thread_; // Thread handle for pthread.
381
513
Thread::Thread(const Options& options)
382
: data_(new PlatformData),
514
: data_(new PlatformData()),
383
515
stack_size_(options.stack_size) {
384
516
set_name(options.name);
388
520
Thread::Thread(const char* name)
389
: data_(new PlatformData),
521
: data_(new PlatformData()),
640
779
explicit SignalSender(int interval)
641
780
: Thread("SignalSender"),
642
782
interval_(interval) {}
784
static void InstallSignalHandler() {
786
sa.sa_sigaction = ProfilerSignalHandler;
787
sigemptyset(&sa.sa_mask);
788
sa.sa_flags = SA_RESTART | SA_SIGINFO;
789
signal_handler_installed_ =
790
(sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
793
static void RestoreSignalHandler() {
794
if (signal_handler_installed_) {
795
sigaction(SIGPROF, &old_signal_handler_, 0);
796
signal_handler_installed_ = false;
644
800
static void AddActiveSampler(Sampler* sampler) {
645
801
ScopedLock lock(mutex_);
646
802
SamplerRegistry::AddActiveSampler(sampler);
647
803
if (instance_ == NULL) {
648
// Install a signal handler.
650
sa.sa_sigaction = ProfilerSignalHandler;
651
sigemptyset(&sa.sa_mask);
652
sa.sa_flags = SA_RESTART | SA_SIGINFO;
653
signal_handler_installed_ =
654
(sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
656
// Start a thread that sends SIGPROF signal to VM threads.
804
// Start a thread that will send SIGPROF signal to VM threads,
805
// when CPU profiling will be enabled.
657
806
instance_ = new SignalSender(sampler->interval());
658
807
instance_->Start();