* Fix build errors on FreeBSD 8.2
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Mar 2011 11:15:43 +0000 (11:15 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 16 Mar 2011 11:15:43 +0000 (11:15 +0000)
* Fix Crankshaft on FreeBSD.
* Partially fix profiling on FreeBSD.
* Remove bash-isms from tick processor script.
Review URL: http://codereview.chromium.org/6673045

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7200 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

SConstruct
src/d8-posix.cc
src/platform-freebsd.cc
src/platform.h
tools/freebsd-tick-processor [new file with mode: 0755]
tools/linux-tick-processor

index 84707e9..8b09ca1 100644 (file)
@@ -174,6 +174,7 @@ LIBRARY_FLAGS = {
       'CPPPATH' : ['/usr/local/include'],
       'LIBPATH' : ['/usr/local/lib'],
       'CCFLAGS':      ['-ansi'],
+      'LIBS': ['execinfo']
     },
     'os:openbsd': {
       'CPPPATH' : ['/usr/local/include'],
index 335bd2b..a7a4049 100644 (file)
@@ -375,8 +375,10 @@ static Handle<Value> GetStdout(int child_fd,
 // a parent process hangs on waiting while a child process is already a zombie.
 // See http://code.google.com/p/v8/issues/detail?id=401.
 #if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__)
+#if !defined(__FreeBSD__)
 #define HAS_WAITID 1
 #endif
+#endif
 
 
 // Get exit status of child.
index 21763b5..c2c81dc 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/stat.h>   // open
 #include <sys/fcntl.h>  // open
 #include <unistd.h>     // getpagesize
+// If you don't have execinfo.h then you need devel/libexecinfo from ports.
 #include <execinfo.h>   // backtrace, backtrace_symbols
 #include <strings.h>    // index
 #include <errno.h>
@@ -526,6 +527,16 @@ class FreeBSDMutex : public Mutex {
     return result;
   }
 
+  virtual bool TryLock() {
+    int result = pthread_mutex_trylock(&mutex_);
+    // Return false if the lock is busy and locking failed.
+    if (result == EBUSY) {
+      return false;
+    }
+    ASSERT(result == 0);  // Verify no other errors.
+    return true;
+  }
+
  private:
   pthread_mutex_t mutex_;   // Pthread mutex for POSIX platforms.
 };
@@ -595,52 +606,116 @@ Semaphore* OS::CreateSemaphore(int count) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
 
 static Sampler* active_sampler_ = NULL;
+static pthread_t vm_tid_ = NULL;
+
+
+static pthread_t GetThreadID() {
+  pthread_t thread_id = pthread_self();
+  return thread_id;
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+  enum SleepInterval {
+    FULL_INTERVAL,
+    HALF_INTERVAL
+  };
+
+  explicit PlatformData(Sampler* sampler)
+      : sampler_(sampler),
+        signal_handler_installed_(false),
+        signal_sender_launched_(false) {
+  }
+
+  void SignalSender() {
+    while (sampler_->IsActive()) {
+      if (rate_limiter_.SuspendIfNecessary()) continue;
+      if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) {
+        Sleep(FULL_INTERVAL);
+        RuntimeProfiler::NotifyTick();
+      } else {
+        if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+        Sleep(FULL_INTERVAL);
+      }
+    }
+  }
+
+  void Sleep(SleepInterval full_or_half) {
+    // Convert ms to us and subtract 100 us to compensate delays
+    // occuring during signal delivery.
+    useconds_t interval = sampler_->interval_ * 1000 - 100;
+    if (full_or_half == HALF_INTERVAL) interval /= 2;
+    int result = usleep(interval);
+#ifdef DEBUG
+    if (result != 0 && errno != EINTR) {
+      fprintf(stderr,
+              "SignalSender usleep error; interval = %u, errno = %d\n",
+              interval,
+              errno);
+      ASSERT(result == 0 || errno == EINTR);
+    }
+#endif
+    USE(result);
+  }
+
+  Sampler* sampler_;
+  bool signal_handler_installed_;
+  struct sigaction old_signal_handler_;
+  struct itimerval old_timer_value_;
+  bool signal_sender_launched_;
+  pthread_t signal_sender_thread_;
+  RuntimeProfilerRateLimiter rate_limiter_;
+};
+
 
 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
   USE(info);
   if (signal != SIGPROF) return;
   if (active_sampler_ == NULL) return;
+  if (!active_sampler_->IsActive()) {
+    // Restore old signal handler
+    Sampler::PlatformData* data = active_sampler_->data();
+    if (data->signal_handler_installed_) {
+      sigaction(SIGPROF, &data->old_signal_handler_, 0);
+      data->signal_handler_installed_ = false;
+    }
+    return;
+  }
 
-  TickSample sample;
+  if (vm_tid_ != GetThreadID()) return;
 
-  // We always sample the VM state.
-  sample.state = VMState::current_state();
+  TickSample sample_obj;
+  TickSample* sample = CpuProfiler::TickSampleEvent();
+  if (sample == NULL) sample = &sample_obj;
 
-  // If profiling, we extract the current pc and sp.
-  if (active_sampler_->IsProfiling()) {
-    // Extracting the sample from the context is extremely machine dependent.
-    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-    mcontext_t& mcontext = ucontext->uc_mcontext;
+  // Extracting the sample from the context is extremely machine dependent.
+  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+  mcontext_t& mcontext = ucontext->uc_mcontext;
 #if V8_HOST_ARCH_IA32
-    sample.pc = reinterpret_cast<Address>(mcontext.mc_eip);
-    sample.sp = reinterpret_cast<Address>(mcontext.mc_esp);
-    sample.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_eip);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_esp);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp);
 #elif V8_HOST_ARCH_X64
-    sample.pc = reinterpret_cast<Address>(mcontext.mc_rip);
-    sample.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
-    sample.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_rip);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp);
 #elif V8_HOST_ARCH_ARM
-    sample.pc = reinterpret_cast<Address>(mcontext.mc_r15);
-    sample.sp = reinterpret_cast<Address>(mcontext.mc_r13);
-    sample.fp = reinterpret_cast<Address>(mcontext.mc_r11);
+  sample->pc = reinterpret_cast<Address>(mcontext.mc_r15);
+  sample->sp = reinterpret_cast<Address>(mcontext.mc_r13);
+  sample->fp = reinterpret_cast<Address>(mcontext.mc_r11);
 #endif
-    active_sampler_->SampleStack(&sample);
-  }
-
-  active_sampler_->Tick(&sample);
+  active_sampler_->SampleStack(sample);
+  active_sampler_->Tick(sample);
 }
 
 
-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() {
-    signal_handler_installed_ = false;
-  }
-
-  bool signal_handler_installed_;
-  struct sigaction old_signal_handler_;
-  struct itimerval old_timer_value_;
-};
+static void* SenderEntry(void* arg) {
+  Sampler::PlatformData* data =
+      reinterpret_cast<Sampler::PlatformData*>(arg);
+  data->SignalSender();
+  return 0;
+}
 
 
 Sampler::Sampler(int interval)
@@ -648,7 +723,7 @@ Sampler::Sampler(int interval)
       profiling_(false),
       active_(false),
       samples_taken_(0) {
-  data_ = new PlatformData();
+  data_ = new PlatformData(this);
 }
 
 
@@ -660,7 +735,8 @@ Sampler::~Sampler() {
 void Sampler::Start() {
   // There can only be one active sampler at the time on POSIX
   // platforms.
-  if (active_sampler_ != NULL) return;
+  ASSERT(!IsActive());
+  vm_tid_ = GetThreadID();
 
   // Request profiling signals.
   struct sigaction sa;
@@ -680,21 +756,29 @@ void Sampler::Start() {
 
   // Set this sampler as the active sampler.
   active_sampler_ = this;
-  active_ = true;
+  SetActive(true);
+
+  // There's no way to send a signal to a thread on FreeBSD, but we can
+  // start a thread that uses the stack guard to interrupt the JS thread.
+  if (pthread_create(
+          &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
+    data_->signal_sender_launched_ = true;
+  }
 }
 
 
 void Sampler::Stop() {
-  // Restore old signal handler
-  if (data_->signal_handler_installed_) {
-    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
-    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
-    data_->signal_handler_installed_ = false;
-  }
-
   // This sampler is no longer the active sampler.
   active_sampler_ = NULL;
-  active_ = false;
+  SetActive(false);
+
+  // Wait for signal sender termination (it will exit after setting
+  // active_ to false).
+  if (data_->signal_sender_launched_) {
+    Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
+    pthread_join(data_->signal_sender_thread_, NULL);
+    data_->signal_sender_launched_ = false;
+  }
 }
 
 #endif  // ENABLE_LOGGING_AND_PROFILING
index 88825e6..e2f50a6 100644 (file)
@@ -613,6 +613,7 @@ class Sampler {
   void ResetSamplesTaken() { samples_taken_ = 0; }
 
   class PlatformData;
+  PlatformData* data() { return data_; }
 
  protected:
   virtual void DoSampleStack(TickSample* sample) = 0;
diff --git a/tools/freebsd-tick-processor b/tools/freebsd-tick-processor
new file mode 100755 (executable)
index 0000000..2bb2618
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# A wrapper script to call 'linux-tick-processor'.
+
+# Known issues on FreeBSD:
+#  No ticks from C++ code.
+#  You must have d8 built and in your path before calling this.
+
+tools_path=`cd $(dirname "$0");pwd`
+$tools_path/linux-tick-processor "$@"
index 1715705..9789697 100755 (executable)
@@ -3,12 +3,12 @@
 tools_path=`cd $(dirname "$0");pwd`
 if [ ! "$D8_PATH" ]; then
   d8_public=`which d8`
-  if [ $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi
+  if [ -x $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi
 fi
 [ "$D8_PATH" ] || D8_PATH=$tools_path/..
 d8_exec=$D8_PATH/d8
 
-if [ "$1" == "--no-build" ]; then
+if [ "$1" = "--no-build" ]; then
   shift
 else
 # compile d8 if it doesn't exist, assuming this script
@@ -16,15 +16,17 @@ else
   [ -x $d8_exec ] || scons -j4 -C $D8_PATH -Y $tools_path/.. d8
 fi
 
+
 # find the name of the log file to process, it must not start with a dash.
 log_file="v8.log"
 for arg in "$@"
 do
-  if [[ "${arg}" != -* ]]; then
+  if ! expr "X${arg}" : "^X-" > /dev/null; then
     log_file=${arg}
   fi
 done
 
+
 # nm spits out 'no symbols found' messages to stderr.
 cat $log_file | $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \
   $tools_path/csvparser.js $tools_path/consarray.js \