The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / platform-freebsd.cc @ 40c0f755

History | View | Annotate | Download (16.5 KB)

1
// Copyright 2006-2008 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28
// Platform specific code for FreeBSD goes here. For the POSIX comaptible parts
29
// the implementation is in platform-posix.cc.
30

    
31
#include <pthread.h>
32
#include <semaphore.h>
33
#include <signal.h>
34
#include <sys/time.h>
35
#include <sys/resource.h>
36
#include <sys/types.h>
37
#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
45
#include <execinfo.h>   // backtrace, backtrace_symbols
46
#include <strings.h>    // index
47
#include <errno.h>
48
#include <stdarg.h>
49
#include <limits.h>
50

    
51
#undef MAP_TYPE
52

    
53
#include "v8.h"
54

    
55
#include "platform.h"
56

    
57

    
58
namespace v8 { namespace internal {
59

    
60
// 0 is never a valid thread id on FreeBSD since tids and pids share a
61
// name space and pid 0 is used to kill the group (see man 2 kill).
62
static const pthread_t kNoThread = (pthread_t) 0;
63

    
64

    
65
double ceiling(double x) {
66
    // Correct as on OS X
67
    if (-1.0 < x && x < 0.0) {
68
        return -0.0;
69
    } else {
70
        return ceil(x);
71
    }
72
}
73

    
74

    
75
void OS::Setup() {
76
  // Seed the random number generator.
77
  // Convert the current time to a 64-bit integer first, before converting it
78
  // to an unsigned. Going directly can cause an overflow and the seed to be
79
  // set to all ones. The seed will be identical for different instances that
80
  // call this setup code within the same millisecond.
81
  uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
82
  srandom(static_cast<unsigned int>(seed));
83
}
84

    
85

    
86
double OS::nan_value() {
87
  return NAN;
88
}
89

    
90

    
91
int OS::ActivationFrameAlignment() {
92
  // 16 byte alignment on FreeBSD
93
  return 16;
94
}
95

    
96

    
97
// We keep the lowest and highest addresses mapped as a quick way of
98
// determining that pointers are outside the heap (used mostly in assertions
99
// and verification).  The estimate is conservative, ie, not all addresses in
100
// 'allocated' space are actually allocated to our heap.  The range is
101
// [lowest, highest), inclusive on the low and and exclusive on the high end.
102
static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
103
static void* highest_ever_allocated = reinterpret_cast<void*>(0);
104

    
105

    
106
static void UpdateAllocatedSpaceLimits(void* address, int size) {
107
  lowest_ever_allocated = Min(lowest_ever_allocated, address);
108
  highest_ever_allocated =
109
      Max(highest_ever_allocated,
110
          reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
111
}
112

    
113

    
114
bool OS::IsOutsideAllocatedSpace(void* address) {
115
  return address < lowest_ever_allocated || address >= highest_ever_allocated;
116
}
117

    
118

    
119
size_t OS::AllocateAlignment() {
120
  return getpagesize();
121
}
122

    
123

    
124
void* OS::Allocate(const size_t requested,
125
                   size_t* allocated,
126
                   bool executable) {
127
  const size_t msize = RoundUp(requested, getpagesize());
128
  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
129
  void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
130

    
131
  if (mbase == MAP_FAILED) {
132
    LOG(StringEvent("OS::Allocate", "mmap failed"));
133
    return NULL;
134
  }
135
  *allocated = msize;
136
  UpdateAllocatedSpaceLimits(mbase, msize);
137
  return mbase;
138
}
139

    
140

    
141
void OS::Free(void* buf, const size_t length) {
142
  // TODO(1240712): munmap has a return value which is ignored here.
143
  munmap(buf, length);
144
}
145

    
146

    
147
#ifdef ENABLE_HEAP_PROTECTION
148

    
149
void OS::Protect(void* address, size_t size) {
150
  UNIMPLEMENTED();
151
}
152

    
153

    
154
void OS::Unprotect(void* address, size_t size, bool is_executable) {
155
  UNIMPLEMENTED();
156
}
157

    
158
#endif
159

    
160

    
161
void OS::Sleep(int milliseconds) {
162
  unsigned int ms = static_cast<unsigned int>(milliseconds);
163
  usleep(1000 * ms);
164
}
165

    
166

    
167
void OS::Abort() {
168
  // Redirect to std abort to signal abnormal program termination.
169
  abort();
170
}
171

    
172

    
173
void OS::DebugBreak() {
174
#if defined (__arm__) || defined(__thumb__)
175
  asm("bkpt 0");
176
#else
177
  asm("int $3");
178
#endif
179
}
180

    
181

    
182
class PosixMemoryMappedFile : public OS::MemoryMappedFile {
183
 public:
184
  PosixMemoryMappedFile(FILE* file, void* memory, int size)
185
    : file_(file), memory_(memory), size_(size) { }
186
  virtual ~PosixMemoryMappedFile();
187
  virtual void* memory() { return memory_; }
188
 private:
189
  FILE* file_;
190
  void* memory_;
191
  int size_;
192
};
193

    
194

    
195
OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
196
    void* initial) {
197
  FILE* file = fopen(name, "w+");
198
  if (file == NULL) return NULL;
199
  int result = fwrite(initial, size, 1, file);
200
  if (result < 1) {
201
    fclose(file);
202
    return NULL;
203
  }
204
  void* memory =
205
      mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
206
  return new PosixMemoryMappedFile(file, memory, size);
207
}
208

    
209

    
210
PosixMemoryMappedFile::~PosixMemoryMappedFile() {
211
  if (memory_) munmap(memory_, size_);
212
  fclose(file_);
213
}
214

    
215

    
216
#ifdef ENABLE_LOGGING_AND_PROFILING
217
static unsigned StringToLong(char* buffer) {
218
  return static_cast<unsigned>(strtol(buffer, NULL, 16));  // NOLINT
219
}
220
#endif
221

    
222

    
223
void OS::LogSharedLibraryAddresses() {
224
#ifdef ENABLE_LOGGING_AND_PROFILING
225
  static const int MAP_LENGTH = 1024;
226
  int fd = open("/proc/self/maps", O_RDONLY);
227
  if (fd < 0) return;
228
  while (true) {
229
    char addr_buffer[11];
230
    addr_buffer[0] = '0';
231
    addr_buffer[1] = 'x';
232
    addr_buffer[10] = 0;
233
    int result = read(fd, addr_buffer + 2, 8);
234
    if (result < 8) break;
235
    unsigned start = StringToLong(addr_buffer);
236
    result = read(fd, addr_buffer + 2, 1);
237
    if (result < 1) break;
238
    if (addr_buffer[2] != '-') break;
239
    result = read(fd, addr_buffer + 2, 8);
240
    if (result < 8) break;
241
    unsigned end = StringToLong(addr_buffer);
242
    char buffer[MAP_LENGTH];
243
    int bytes_read = -1;
244
    do {
245
      bytes_read++;
246
      if (bytes_read >= MAP_LENGTH - 1)
247
        break;
248
      result = read(fd, buffer + bytes_read, 1);
249
      if (result < 1) break;
250
    } while (buffer[bytes_read] != '\n');
251
    buffer[bytes_read] = 0;
252
    // Ignore mappings that are not executable.
253
    if (buffer[3] != 'x') continue;
254
    char* start_of_path = index(buffer, '/');
255
    // There may be no filename in this line.  Skip to next.
256
    if (start_of_path == NULL) continue;
257
    buffer[bytes_read] = 0;
258
    LOG(SharedLibraryEvent(start_of_path, start, end));
259
  }
260
  close(fd);
261
#endif
262
}
263

    
264

    
265
int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
266
  void** addresses = NewArray<void*>(frames_size);
267

    
268
  int frames_count = backtrace(addresses, frames_size);
269

    
270
  char** symbols;
271
  symbols = backtrace_symbols(addresses, frames_count);
272
  if (symbols == NULL) {
273
    DeleteArray(addresses);
274
    return kStackWalkError;
275
  }
276

    
277
  for (int i = 0; i < frames_count; i++) {
278
    frames[i].address = addresses[i];
279
    // Format a text representation of the frame based on the information
280
    // available.
281
    SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
282
             "%s",
283
             symbols[i]);
284
    // Make sure line termination is in place.
285
    frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
286
  }
287

    
288
  DeleteArray(addresses);
289
  free(symbols);
290

    
291
  return frames_count;
292
}
293

    
294

    
295
// Constants used for mmap.
296
static const int kMmapFd = -1;
297
static const int kMmapFdOffset = 0;
298

    
299

    
300
VirtualMemory::VirtualMemory(size_t size) {
301
  address_ = mmap(NULL, size, PROT_NONE,
302
                  MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
303
                  kMmapFd, kMmapFdOffset);
304
  size_ = size;
305
}
306

    
307

    
308
VirtualMemory::~VirtualMemory() {
309
  if (IsReserved()) {
310
    if (0 == munmap(address(), size())) address_ = MAP_FAILED;
311
  }
312
}
313

    
314

    
315
bool VirtualMemory::IsReserved() {
316
  return address_ != MAP_FAILED;
317
}
318

    
319

    
320
bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
321
  int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
322
  if (MAP_FAILED == mmap(address, size, prot,
323
                         MAP_PRIVATE | MAP_ANON | MAP_FIXED,
324
                         kMmapFd, kMmapFdOffset)) {
325
    return false;
326
  }
327

    
328
  UpdateAllocatedSpaceLimits(address, size);
329
  return true;
330
}
331

    
332

    
333
bool VirtualMemory::Uncommit(void* address, size_t size) {
334
  return mmap(address, size, PROT_NONE,
335
              MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
336
              kMmapFd, kMmapFdOffset) != MAP_FAILED;
337
}
338

    
339

    
340
class ThreadHandle::PlatformData : public Malloced {
341
 public:
342
  explicit PlatformData(ThreadHandle::Kind kind) {
343
    Initialize(kind);
344
  }
345

    
346
  void Initialize(ThreadHandle::Kind kind) {
347
    switch (kind) {
348
      case ThreadHandle::SELF: thread_ = pthread_self(); break;
349
      case ThreadHandle::INVALID: thread_ = kNoThread; break;
350
    }
351
  }
352
  pthread_t thread_;  // Thread handle for pthread.
353
};
354

    
355

    
356
ThreadHandle::ThreadHandle(Kind kind) {
357
  data_ = new PlatformData(kind);
358
}
359

    
360

    
361
void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
362
  data_->Initialize(kind);
363
}
364

    
365

    
366
ThreadHandle::~ThreadHandle() {
367
  delete data_;
368
}
369

    
370

    
371
bool ThreadHandle::IsSelf() const {
372
  return pthread_equal(data_->thread_, pthread_self());
373
}
374

    
375

    
376
bool ThreadHandle::IsValid() const {
377
  return data_->thread_ != kNoThread;
378
}
379

    
380

    
381
Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
382
}
383

    
384

    
385
Thread::~Thread() {
386
}
387

    
388

    
389
static void* ThreadEntry(void* arg) {
390
  Thread* thread = reinterpret_cast<Thread*>(arg);
391
  // This is also initialized by the first argument to pthread_create() but we
392
  // don't know which thread will run first (the original thread or the new
393
  // one) so we initialize it here too.
394
  thread->thread_handle_data()->thread_ = pthread_self();
395
  ASSERT(thread->IsValid());
396
  thread->Run();
397
  return NULL;
398
}
399

    
400

    
401
void Thread::Start() {
402
  pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
403
  ASSERT(IsValid());
404
}
405

    
406

    
407
void Thread::Join() {
408
  pthread_join(thread_handle_data()->thread_, NULL);
409
}
410

    
411

    
412
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
413
  pthread_key_t key;
414
  int result = pthread_key_create(&key, NULL);
415
  USE(result);
416
  ASSERT(result == 0);
417
  return static_cast<LocalStorageKey>(key);
418
}
419

    
420

    
421
void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
422
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
423
  int result = pthread_key_delete(pthread_key);
424
  USE(result);
425
  ASSERT(result == 0);
426
}
427

    
428

    
429
void* Thread::GetThreadLocal(LocalStorageKey key) {
430
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
431
  return pthread_getspecific(pthread_key);
432
}
433

    
434

    
435
void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
436
  pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
437
  pthread_setspecific(pthread_key, value);
438
}
439

    
440

    
441
void Thread::YieldCPU() {
442
  sched_yield();
443
}
444

    
445

    
446
class FreeBSDMutex : public Mutex {
447
 public:
448

    
449
  FreeBSDMutex() {
450
    pthread_mutexattr_t attrs;
451
    int result = pthread_mutexattr_init(&attrs);
452
    ASSERT(result == 0);
453
    result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
454
    ASSERT(result == 0);
455
    result = pthread_mutex_init(&mutex_, &attrs);
456
    ASSERT(result == 0);
457
  }
458

    
459
  virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
460

    
461
  virtual int Lock() {
462
    int result = pthread_mutex_lock(&mutex_);
463
    return result;
464
  }
465

    
466
  virtual int Unlock() {
467
    int result = pthread_mutex_unlock(&mutex_);
468
    return result;
469
  }
470

    
471
 private:
472
  pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
473
};
474

    
475

    
476
Mutex* OS::CreateMutex() {
477
  return new FreeBSDMutex();
478
}
479

    
480

    
481
class FreeBSDSemaphore : public Semaphore {
482
 public:
483
  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
484
  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
485

    
486
  virtual void Wait();
487
  virtual bool Wait(int timeout);
488
  virtual void Signal() { sem_post(&sem_); }
489
 private:
490
  sem_t sem_;
491
};
492

    
493

    
494
void FreeBSDSemaphore::Wait() {
495
  while (true) {
496
    int result = sem_wait(&sem_);
497
    if (result == 0) return;  // Successfully got semaphore.
498
    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
499
  }
500
}
501

    
502

    
503
bool FreeBSDSemaphore::Wait(int timeout) {
504
  const long kOneSecondMicros = 1000000;  // NOLINT
505
  const long kOneSecondNanos = 1000000000;  // NOLINT
506

    
507
  // Split timeout into second and nanosecond parts.
508
  long nanos = (timeout % kOneSecondMicros) * 1000;  // NOLINT
509
  time_t secs = timeout / kOneSecondMicros;
510

    
511
  // Get the current real time clock.
512
  struct timespec ts;
513
  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
514
    return false;
515
  }
516

    
517
  // Calculate realtime for end of timeout.
518
  ts.tv_nsec += nanos;
519
  if (ts.tv_nsec >= kOneSecondNanos) {
520
    ts.tv_nsec -= kOneSecondNanos;
521
    ts.tv_nsec++;
522
  }
523
  ts.tv_sec += secs;
524

    
525
  // Wait for semaphore signalled or timeout.
526
  while (true) {
527
    int result = sem_timedwait(&sem_, &ts);
528
    if (result == 0) return true;  // Successfully got semaphore.
529
    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
530
    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
531
  }
532
}
533

    
534

    
535
Semaphore* OS::CreateSemaphore(int count) {
536
  return new FreeBSDSemaphore(count);
537
}
538

    
539

    
540
#ifdef ENABLE_LOGGING_AND_PROFILING
541

    
542
static Sampler* active_sampler_ = NULL;
543

    
544
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
545
  USE(info);
546
  if (signal != SIGPROF) return;
547
  if (active_sampler_ == NULL) return;
548

    
549
  TickSample sample;
550

    
551
  // If profiling, we extract the current pc and sp.
552
  if (active_sampler_->IsProfiling()) {
553
    // Extracting the sample from the context is extremely machine dependent.
554
    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
555
    mcontext_t& mcontext = ucontext->uc_mcontext;
556
#if defined (__arm__) || defined(__thumb__)
557
    sample.pc = mcontext.mc_r15;
558
    sample.sp = mcontext.mc_r13;
559
    sample.fp = mcontext.mc_r11;
560
#else
561
    sample.pc = mcontext.mc_eip;
562
    sample.sp = mcontext.mc_esp;
563
    sample.fp = mcontext.mc_ebp;
564
#endif
565
  }
566

    
567
  // We always sample the VM state.
568
  sample.state = Logger::state();
569

    
570
  active_sampler_->Tick(&sample);
571
}
572

    
573

    
574
class Sampler::PlatformData : public Malloced {
575
 public:
576
  PlatformData() {
577
    signal_handler_installed_ = false;
578
  }
579

    
580
  bool signal_handler_installed_;
581
  struct sigaction old_signal_handler_;
582
  struct itimerval old_timer_value_;
583
};
584

    
585

    
586
Sampler::Sampler(int interval, bool profiling)
587
    : interval_(interval), profiling_(profiling), active_(false) {
588
  data_ = new PlatformData();
589
}
590

    
591

    
592
Sampler::~Sampler() {
593
  delete data_;
594
}
595

    
596

    
597
void Sampler::Start() {
598
  // There can only be one active sampler at the time on POSIX
599
  // platforms.
600
  if (active_sampler_ != NULL) return;
601

    
602
  // Request profiling signals.
603
  struct sigaction sa;
604
  sa.sa_sigaction = ProfilerSignalHandler;
605
  sigemptyset(&sa.sa_mask);
606
  sa.sa_flags = SA_SIGINFO;
607
  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
608
  data_->signal_handler_installed_ = true;
609

    
610
  // Set the itimer to generate a tick for each interval.
611
  itimerval itimer;
612
  itimer.it_interval.tv_sec = interval_ / 1000;
613
  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
614
  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
615
  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
616
  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
617

    
618
  // Set this sampler as the active sampler.
619
  active_sampler_ = this;
620
  active_ = true;
621
}
622

    
623

    
624
void Sampler::Stop() {
625
  // Restore old signal handler
626
  if (data_->signal_handler_installed_) {
627
    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
628
    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
629
    data_->signal_handler_installed_ = false;
630
  }
631

    
632
  // This sampler is no longer the active sampler.
633
  active_sampler_ = NULL;
634
  active_ = false;
635
}
636

    
637
#endif  // ENABLE_LOGGING_AND_PROFILING
638

    
639
} }  // namespace v8::internal