~ubuntu-branches/ubuntu/trusty/libv8/trusty

« back to all changes in this revision

Viewing changes to src/platform-openbsd.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-02-20 14:08:17 UTC
  • mfrom: (15.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20120220140817-bsvmeoa4sxsj5hbz
Tags: 3.7.12.22-3
Fix mipsel build, allow test debug-step-3 to fail (non-crucial)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2006-2011 the V8 project authors. All rights reserved.
 
1
// Copyright 2011 the V8 project authors. All rights reserved.
2
2
// Redistribution and use in source and binary forms, with or without
3
3
// modification, are permitted provided that the following conditions are
4
4
// met:
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>
38
39
 
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
46
47
#include <errno.h>
47
48
#include <stdarg.h>
48
 
#include <limits.h>
49
49
 
50
50
#undef MAP_TYPE
51
51
 
52
52
#include "v8.h"
 
53
 
 
54
#include "platform.h"
53
55
#include "v8threads.h"
54
 
 
55
 
#include "platform.h"
56
56
#include "vm-state-inl.h"
57
57
 
58
58
 
59
59
namespace v8 {
60
60
namespace internal {
61
61
 
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;
65
65
 
66
66
 
67
67
double ceiling(double x) {
68
 
    // Correct as on OS X
69
 
    if (-1.0 < x && x < 0.0) {
70
 
        return -0.0;
71
 
    } else {
72
 
        return ceil(x);
73
 
    }
 
68
  return ceil(x);
74
69
}
75
70
 
76
71
 
77
72
static Mutex* limit_mutex = NULL;
78
73
 
79
74
 
 
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);
 
89
#else
 
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;
 
95
#endif
 
96
    return reinterpret_cast<void*>(raw_addr);
 
97
  }
 
98
  return NULL;
 
99
}
 
100
 
 
101
 
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();
89
107
}
90
108
 
91
109
 
 
110
uint64_t OS::CpuFeaturesImpliedByPlatform() {
 
111
  return 0;
 
112
}
 
113
 
 
114
 
 
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.
 
118
  return 16;
 
119
}
 
120
 
 
121
 
92
122
void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
93
123
  __asm__ __volatile__("" : : : "memory");
 
124
  // An x86 store acts as a release barrier.
94
125
  *ptr = value;
95
126
}
96
127
 
97
128
 
98
 
uint64_t OS::CpuFeaturesImpliedByPlatform() {
99
 
  return 0;  // OpenBSD runs on anything.
100
 
}
101
 
 
102
 
 
103
 
int OS::ActivationFrameAlignment() {
104
 
  // 16 byte alignment on OpenBSD
105
 
  return 16;
106
 
}
107
 
 
108
 
 
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));
150
170
 
151
171
 
152
172
size_t OS::AllocateAlignment() {
153
 
  return getpagesize();
 
173
  return sysconf(_SC_PAGESIZE);
154
174
}
155
175
 
156
176
 
157
177
void* OS::Allocate(const size_t requested,
158
178
                   size_t* allocated,
159
 
                   bool executable) {
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);
163
 
 
 
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"));
166
187
    return NULL;
167
188
  }
168
189
  *allocated = msize;
171
192
}
172
193
 
173
194
 
174
 
void OS::Free(void* buf, const size_t length) {
 
195
void OS::Free(void* address, const size_t size) {
175
196
  // TODO(1240712): munmap has a return value which is ignored here.
176
 
  int result = munmap(buf, length);
 
197
  int result = munmap(address, size);
177
198
  USE(result);
178
199
  ASSERT(result == 0);
179
200
}
192
213
 
193
214
 
194
215
void OS::DebugBreak() {
195
 
#if (defined(__arm__) || defined(__thumb__))
196
 
# if defined(CAN_USE_ARMV5_INSTRUCTIONS)
197
 
  asm("bkpt 0");
198
 
# endif
199
 
#else
200
216
  asm("int $3");
201
 
#endif
202
217
}
203
218
 
204
219
 
245
260
 
246
261
 
247
262
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
248
 
  if (memory_) munmap(memory_, size_);
 
263
  if (memory_) OS::Free(memory_, size_);
249
264
  fclose(file_);
250
265
}
251
266
 
252
267
 
253
 
static unsigned StringToLong(char* buffer) {
254
 
  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
255
 
}
256
 
 
257
 
 
258
268
void OS::LogSharedLibraryAddresses() {
259
 
  static const int MAP_LENGTH = 1024;
260
 
  int fd = open("/proc/self/maps", O_RDONLY);
261
 
  if (fd < 0) return;
 
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;
 
274
 
 
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));
 
278
 
 
279
  i::Isolate* isolate = ISOLATE;
 
280
  // This loop will terminate once the scanning hits an EOF.
262
281
  while (true) {
263
 
    char addr_buffer[11];
264
 
    addr_buffer[0] = '0';
265
 
    addr_buffer[1] = 'x';
266
 
    addr_buffer[10] = 0;
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];
277
 
    int bytes_read = -1;
278
 
    do {
279
 
      bytes_read++;
280
 
      if (bytes_read >= MAP_LENGTH - 1)
281
 
        break;
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;
 
287
 
 
288
    int c;
 
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.
 
292
      do {
 
293
        c = getc(fp);
 
294
      } while ((c != EOF) && (c != '\n') && (c != '/'));
 
295
      if (c == EOF) break;  // EOF: Was unexpected, just exit.
 
296
 
 
297
      // Process the filename if found.
 
298
      if (c == '/') {
 
299
        ungetc(c, fp);  // Push the '/' back into the stream to be read below.
 
300
 
 
301
        // Read to the end of the line. Exit if the read fails.
 
302
        if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
 
303
 
 
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
 
306
        // '/' character.
 
307
        lib_name[strlen(lib_name) - 1] = '\0';
 
308
      } else {
 
309
        // No library name found, just record the raw address range.
 
310
        snprintf(lib_name, kLibNameLen,
 
311
                 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end);
 
312
      }
 
313
      LOG(isolate, SharedLibraryEvent(lib_name, start, end));
 
314
    } else {
 
315
      // Entry not describing executable data. Skip to end of line to setup
 
316
      // reading the next entry.
 
317
      do {
 
318
        c = getc(fp);
 
319
      } while ((c != EOF) && (c != '\n'));
 
320
      if (c == EOF) break;
 
321
    }
293
322
  }
294
 
  close(fd);
 
323
  free(lib_name);
 
324
  fclose(fp);
295
325
}
296
326
 
297
327
 
 
328
static const char kGCFakeMmap[] = "/tmp/__v8_gc__";
 
329
 
 
330
 
298
331
void OS::SignalCodeMovingGC() {
 
332
  // Support for ll_prof.py.
 
333
  //
 
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
 
339
  // kernel log.
 
340
  int size = sysconf(_SC_PAGESIZE);
 
341
  FILE* f = fopen(kGCFakeMmap, "w+");
 
342
  void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE,
 
343
                    fileno(f), 0);
 
344
  ASSERT(addr != MAP_FAILED);
 
345
  OS::Free(addr, size);
 
346
  fclose(f);
299
347
}
300
348
 
301
349
 
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);
305
354
 
331
380
static const int kMmapFd = -1;
332
381
static const int kMmapFdOffset = 0;
333
382
 
 
383
VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
334
384
 
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);
339
387
  size_ = size;
340
388
}
341
389
 
342
390
 
 
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(),
 
397
                           request_size,
 
398
                           PROT_NONE,
 
399
                           MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
 
400
                           kMmapFd,
 
401
                           kMmapFdOffset);
 
402
  if (reservation == MAP_FAILED) return;
 
403
 
 
404
  Address base = static_cast<Address>(reservation);
 
405
  Address aligned_base = RoundUp(base, alignment);
 
406
  ASSERT_LE(base, aligned_base);
 
407
 
 
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;
 
413
  }
 
414
 
 
415
  size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
 
416
  ASSERT_LE(aligned_size, request_size);
 
417
 
 
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;
 
422
  }
 
423
 
 
424
  ASSERT(aligned_size == request_size);
 
425
 
 
426
  address_ = static_cast<void*>(aligned_base);
 
427
  size_ = aligned_size;
 
428
}
 
429
 
 
430
 
343
431
VirtualMemory::~VirtualMemory() {
344
432
  if (IsReserved()) {
345
 
    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
 
433
    bool result = ReleaseRegion(address(), size());
 
434
    ASSERT(result);
 
435
    USE(result);
346
436
  }
347
437
}
348
438
 
349
439
 
350
440
bool VirtualMemory::IsReserved() {
351
 
  return address_ != MAP_FAILED;
352
 
}
353
 
 
354
 
 
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;
 
442
}
 
443
 
 
444
 
 
445
void VirtualMemory::Reset() {
 
446
  address_ = NULL;
 
447
  size_ = 0;
 
448
}
 
449
 
 
450
 
 
451
bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
 
452
  return CommitRegion(address, size, is_executable);
 
453
}
 
454
 
 
455
 
 
456
bool VirtualMemory::Uncommit(void* address, size_t size) {
 
457
  return UncommitRegion(address, size);
 
458
}
 
459
 
 
460
 
 
461
void* VirtualMemory::ReserveRegion(size_t size) {
 
462
  void* result = mmap(GetRandomMmapAddr(),
 
463
                      size,
 
464
                      PROT_NONE,
 
465
                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
 
466
                      kMmapFd,
 
467
                      kMmapFdOffset);
 
468
 
 
469
  if (result == MAP_FAILED) return NULL;
 
470
 
 
471
  return result;
 
472
}
 
473
 
 
474
 
 
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,
 
478
                         size,
 
479
                         prot,
358
480
                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
359
 
                         kMmapFd, kMmapFdOffset)) {
 
481
                         kMmapFd,
 
482
                         kMmapFdOffset)) {
360
483
    return false;
361
484
  }
362
485
 
363
 
  UpdateAllocatedSpaceLimits(address, size);
 
486
  UpdateAllocatedSpaceLimits(base, size);
364
487
  return true;
365
488
}
366
489
 
367
490
 
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) {
 
492
  return mmap(base,
 
493
              size,
 
494
              PROT_NONE,
370
495
              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED,
371
 
              kMmapFd, kMmapFdOffset) != MAP_FAILED;
 
496
              kMmapFd,
 
497
              kMmapFdOffset) != MAP_FAILED;
 
498
}
 
499
 
 
500
 
 
501
bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
 
502
  return munmap(base, size) == 0;
372
503
}
373
504
 
374
505
 
375
506
class Thread::PlatformData : public Malloced {
376
507
 public:
 
508
  PlatformData() : thread_(kNoThread) {}
 
509
 
377
510
  pthread_t thread_;  // Thread handle for pthread.
378
511
};
379
512
 
380
 
 
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);
385
517
}
386
518
 
387
519
 
388
520
Thread::Thread(const char* name)
389
 
    : data_(new PlatformData),
 
521
    : data_(new PlatformData()),
390
522
      stack_size_(0) {
391
523
  set_name(name);
392
524
}
402
534
  // This is also initialized by the first argument to pthread_create() but we
403
535
  // don't know which thread will run first (the original thread or the new
404
536
  // one) so we initialize it here too.
 
537
#ifdef PR_SET_NAME
 
538
  prctl(PR_SET_NAME,
 
539
        reinterpret_cast<unsigned long>(thread->name()),  // NOLINT
 
540
        0, 0, 0);
 
541
#endif
405
542
  thread->data()->thread_ = pthread_self();
406
543
  ASSERT(thread->data()->thread_ != kNoThread);
407
544
  thread->Run();
477
614
    ASSERT(result == 0);
478
615
    result = pthread_mutex_init(&mutex_, &attrs);
479
616
    ASSERT(result == 0);
 
617
    USE(result);
480
618
  }
481
619
 
482
620
  virtual ~OpenBSDMutex() { pthread_mutex_destroy(&mutex_); }
533
671
}
534
672
 
535
673
 
 
674
#ifndef TIMEVAL_TO_TIMESPEC
 
675
#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
 
676
    (ts)->tv_sec = (tv)->tv_sec;                                    \
 
677
    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
 
678
} while (false)
 
679
#endif
 
680
 
 
681
 
536
682
bool OpenBSDSemaphore::Wait(int timeout) {
537
683
  const long kOneSecondMicros = 1000000;  // NOLINT
538
684
 
566
712
  }
567
713
}
568
714
 
569
 
 
570
715
Semaphore* OS::CreateSemaphore(int count) {
571
716
  return new OpenBSDSemaphore(count);
572
717
}
573
718
 
574
719
 
575
720
static pthread_t GetThreadID() {
576
 
  pthread_t thread_id = pthread_self();
577
 
  return thread_id;
 
721
  return pthread_self();
578
722
}
579
723
 
580
 
 
581
 
class Sampler::PlatformData : public Malloced {
582
 
 public:
583
 
  PlatformData() : vm_tid_(GetThreadID()) {}
584
 
 
585
 
  pthread_t vm_tid() const { return vm_tid_; }
586
 
 
587
 
 private:
588
 
  pthread_t vm_tid_;
589
 
};
590
 
 
591
 
 
592
724
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
593
725
  USE(info);
594
726
  if (signal != SIGPROF) return;
620
752
  sample->pc = reinterpret_cast<Address>(ucontext->sc_rip);
621
753
  sample->sp = reinterpret_cast<Address>(ucontext->sc_rsp);
622
754
  sample->fp = reinterpret_cast<Address>(ucontext->sc_rbp);
623
 
#elif V8_HOST_ARCH_ARM
624
 
  sample->pc = reinterpret_cast<Address>(ucontext->sc_r15);
625
 
  sample->sp = reinterpret_cast<Address>(ucontext->sc_r13);
626
 
  sample->fp = reinterpret_cast<Address>(ucontext->sc_r11);
627
755
#endif
628
756
  sampler->SampleStack(sample);
629
757
  sampler->Tick(sample);
630
758
}
631
759
 
632
760
 
 
761
class Sampler::PlatformData : public Malloced {
 
762
 public:
 
763
  PlatformData() : vm_tid_(GetThreadID()) {}
 
764
 
 
765
  pthread_t vm_tid() const { return vm_tid_; }
 
766
 
 
767
 private:
 
768
  pthread_t vm_tid_;
 
769
};
 
770
 
 
771
 
633
772
class SignalSender : public Thread {
634
773
 public:
635
774
  enum SleepInterval {
639
778
 
640
779
  explicit SignalSender(int interval)
641
780
      : Thread("SignalSender"),
 
781
        vm_tgid_(getpid()),
642
782
        interval_(interval) {}
643
783
 
 
784
  static void InstallSignalHandler() {
 
785
    struct sigaction sa;
 
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);
 
791
  }
 
792
 
 
793
  static void RestoreSignalHandler() {
 
794
    if (signal_handler_installed_) {
 
795
      sigaction(SIGPROF, &old_signal_handler_, 0);
 
796
      signal_handler_installed_ = false;
 
797
    }
 
798
  }
 
799
 
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.
649
 
      struct sigaction sa;
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);
655
 
 
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();
659
808
    } else {
668
817
      RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
669
818
      delete instance_;
670
819
      instance_ = NULL;
671
 
 
672
 
      // Restore the old signal handler.
673
 
      if (signal_handler_installed_) {
674
 
        sigaction(SIGPROF, &old_signal_handler_, 0);
675
 
        signal_handler_installed_ = false;
676
 
      }
 
820
      RestoreSignalHandler();
677
821
    }
678
822
  }
679
823
 
685
829
      bool cpu_profiling_enabled =
686
830
          (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
687
831
      bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
 
832
      if (cpu_profiling_enabled && !signal_handler_installed_) {
 
833
        InstallSignalHandler();
 
834
      } else if (!cpu_profiling_enabled && signal_handler_installed_) {
 
835
        RestoreSignalHandler();
 
836
      }
688
837
      // When CPU profiling is enabled both JavaScript and C++ code is
689
838
      // profiled. We must not suspend.
690
839
      if (!cpu_profiling_enabled) {
751
900
    USE(result);
752
901
  }
753
902
 
 
903
  const int vm_tgid_;
754
904
  const int interval_;
755
905
  RuntimeProfilerRateLimiter rate_limiter_;
756
906
 
763
913
  DISALLOW_COPY_AND_ASSIGN(SignalSender);
764
914
};
765
915
 
 
916
 
766
917
Mutex* SignalSender::mutex_ = OS::CreateMutex();
767
918
SignalSender* SignalSender::instance_ = NULL;
768
919
struct sigaction SignalSender::old_signal_handler_;