Cleanup Semaphore class.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Sep 2013 12:26:06 +0000 (12:26 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Sep 2013 12:26:06 +0000 (12:26 +0000)
Drop the previous Semaphore class from platform files.

Add new Semaphore class using the new TimeDelta class for
the WaitFor() operation. Consistently assert correct behaviour
for the different implementations.

Improve test coverage of the Semaphore class.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/23748003

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

45 files changed:
src/api.cc
src/d8-debug.cc
src/d8-debug.h
src/d8.cc
src/d8.h
src/debug-agent.cc
src/debug-agent.h
src/debug.cc
src/debug.h
src/isolate.cc
src/log.cc
src/marking-thread.cc
src/marking-thread.h
src/optimizing-compiler-thread.cc
src/optimizing-compiler-thread.h
src/platform-cygwin.cc
src/platform-freebsd.cc
src/platform-linux.cc
src/platform-macos.cc
src/platform-openbsd.cc
src/platform-solaris.cc
src/platform-win32.cc
src/platform.h
src/platform/semaphore.cc [new file with mode: 0644]
src/platform/semaphore.h [new file with mode: 0644]
src/platform/time.cc
src/platform/time.h
src/profile-generator.cc
src/profile-generator.h
src/sweeper-thread.cc
src/sweeper-thread.h
test/cctest/cctest.gyp
test/cctest/cctest.h
test/cctest/test-api.cc
test/cctest/test-circular-queue.cc
test/cctest/test-debug.cc
test/cctest/test-lock.cc [deleted file]
test/cctest/test-lockers.cc
test/cctest/test-log.cc
test/cctest/test-semaphore.cc [new file with mode: 0644]
test/cctest/test-sockets.cc
test/cctest/test-thread-termination.cc
test/cctest/test-threads.cc
test/cctest/test-time.cc
tools/gyp/v8.gyp

index aecb58c..6de4dfd 100644 (file)
@@ -7095,7 +7095,8 @@ void Debug::SetHostDispatchHandler(HostDispatchHandler handler,
   i::Isolate* isolate = i::Isolate::Current();
   EnsureInitializedForIsolate(isolate, "v8::Debug::SetHostDispatchHandler");
   ENTER_V8(isolate);
-  isolate->debugger()->SetHostDispatchHandler(handler, period);
+  isolate->debugger()->SetHostDispatchHandler(
+      handler, i::TimeDelta::FromMilliseconds(period));
 }
 
 
index 3adeb71..2905500 100644 (file)
@@ -201,7 +201,7 @@ void RemoteDebugger::Run() {
   // Process events received from debugged VM and from the keyboard.
   bool terminate = false;
   while (!terminate) {
-    event_available_->Wait();
+    event_available_.Wait();
     RemoteDebuggerEvent* event = GetEvent();
     switch (event->type()) {
       case RemoteDebuggerEvent::kMessage:
@@ -258,7 +258,7 @@ void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
     tail_->set_next(event);
     tail_ = event;
   }
-  event_available_->Signal();
+  event_available_.Signal();
 }
 
 
index 276cbd8..5587622 100644 (file)
@@ -53,7 +53,7 @@ class RemoteDebugger {
   explicit RemoteDebugger(Isolate* isolate, int port)
       : isolate_(isolate),
         port_(port),
-        event_available_(i::OS::CreateSemaphore(0)),
+        event_available_(0),
         head_(NULL), tail_(NULL) {}
   void Run();
 
@@ -84,7 +84,7 @@ class RemoteDebugger {
   // the list is guarded by a mutex and a semaphore signals new items in the
   // list.
   i::Mutex event_access_;
-  i::Semaphore* event_available_;
+  i::Semaphore event_available_;
   RemoteDebuggerEvent* head_;
   RemoteDebuggerEvent* tail_;
 
index 4a10550..6f41dc4 100644 (file)
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1220,10 +1220,6 @@ void ShellThread::Run() {
 
 SourceGroup::~SourceGroup() {
 #ifndef V8_SHARED
-  delete next_semaphore_;
-  next_semaphore_ = NULL;
-  delete done_semaphore_;
-  done_semaphore_ = NULL;
   delete thread_;
   thread_ = NULL;
 #endif  // V8_SHARED
@@ -1284,7 +1280,7 @@ i::Thread::Options SourceGroup::GetThreadOptions() {
 void SourceGroup::ExecuteInThread() {
   Isolate* isolate = Isolate::New();
   do {
-    if (next_semaphore_ != NULL) next_semaphore_->Wait();
+    next_semaphore_.Wait();
     {
       Isolate::Scope iscope(isolate);
       Locker lock(isolate);
@@ -1304,7 +1300,7 @@ void SourceGroup::ExecuteInThread() {
         V8::IdleNotification(kLongIdlePauseInMs);
       }
     }
-    if (done_semaphore_ != NULL) done_semaphore_->Signal();
+    done_semaphore_.Signal();
   } while (!Shell::options.last_run);
   isolate->Dispose();
 }
@@ -1315,7 +1311,7 @@ void SourceGroup::StartExecuteInThread() {
     thread_ = new IsolateThread(this);
     thread_->Start();
   }
-  next_semaphore_->Signal();
+  next_semaphore_.Signal();
 }
 
 
@@ -1324,7 +1320,7 @@ void SourceGroup::WaitForThread() {
   if (Shell::options.last_run) {
     thread_->Join();
   } else {
-    done_semaphore_->Wait();
+    done_semaphore_.Wait();
   }
 }
 #endif  // V8_SHARED
index fbc7a10..1ae1bcf 100644 (file)
--- a/src/d8.h
+++ b/src/d8.h
@@ -140,8 +140,8 @@ class SourceGroup {
  public:
   SourceGroup() :
 #ifndef V8_SHARED
-      next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
-      done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
+      next_semaphore_(0),
+      done_semaphore_(0),
       thread_(NULL),
 #endif  // V8_SHARED
       argv_(NULL),
@@ -180,8 +180,8 @@ class SourceGroup {
   static i::Thread::Options GetThreadOptions();
   void ExecuteInThread();
 
-  i::Semaphore* next_semaphore_;
-  i::Semaphore* done_semaphore_;
+  i::Semaphore next_semaphore_;
+  i::Semaphore done_semaphore_;
   i::Thread* thread_;
 #endif  // V8_SHARED
 
index b390cc5..51bd4b1 100644 (file)
@@ -46,8 +46,6 @@ void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
 
 // Debugger agent main thread.
 void DebuggerAgent::Run() {
-  const int kOneSecondInMicros = 1000000;
-
   // Allow this socket to reuse port even if still in TIME_WAIT.
   server_->SetReuseAddress(true);
 
@@ -60,16 +58,20 @@ void DebuggerAgent::Run() {
     // would be that the port is already in use so this avoids a busy loop and
     // make the agent take over the port when it becomes free.
     if (!bound) {
+      const TimeDelta kTimeout = TimeDelta::FromSeconds(1);
       PrintF("Failed to open socket on port %d, "
-          "waiting %d ms before retrying\n", port_, kOneSecondInMicros / 1000);
-      terminate_now_->Wait(kOneSecondInMicros);
+          "waiting %d ms before retrying\n", port_,
+          static_cast<int>(kTimeout.InMilliseconds()));
+      if (!terminate_now_.WaitFor(kTimeout)) {
+        if (terminate_) return;
+      }
     }
   }
 
   // Accept connections on the bound port.
   while (!terminate_) {
     bool ok = server_->Listen(1);
-    listening_->Signal();
+    listening_.Signal();
     if (ok) {
       // Accept the new connection.
       Socket* client = server_->Accept();
@@ -89,7 +91,7 @@ void DebuggerAgent::Shutdown() {
 
   // Signal termination and make the server exit either its listen call or its
   // binding loop. This makes sure that no new sessions can be established.
-  terminate_now_->Signal();
+  terminate_now_.Signal();
   server_->Shutdown();
   Join();
 
@@ -99,7 +101,7 @@ void DebuggerAgent::Shutdown() {
 
 
 void DebuggerAgent::WaitUntilListening() {
-  listening_->Wait();
+  listening_.Wait();
 }
 
 static const char* kCreateSessionMessage =
index e78ed67..3f22715 100644 (file)
@@ -49,8 +49,8 @@ class DebuggerAgent: public Thread {
         name_(StrDup(name)), port_(port),
         server_(OS::CreateSocket()), terminate_(false),
         session_(NULL),
-        terminate_now_(OS::CreateSemaphore(0)),
-        listening_(OS::CreateSemaphore(0)) {
+        terminate_now_(0),
+        listening_(0) {
     ASSERT(isolate_->debugger_agent_instance() == NULL);
     isolate_->set_debugger_agent_instance(this);
   }
@@ -78,8 +78,8 @@ class DebuggerAgent: public Thread {
   bool terminate_;  // Termination flag.
   RecursiveMutex session_access_;  // Mutex guarding access to session_.
   DebuggerAgentSession* session_;  // Current active session if any.
-  Semaphore* terminate_now_;  // Semaphore to signal termination.
-  Semaphore* listening_;
+  Semaphore terminate_now_;  // Semaphore to signal termination.
+  Semaphore listening_;
 
   friend class DebuggerAgentSession;
   friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message);
index 93bd22b..603a2d7 100644 (file)
@@ -2614,19 +2614,16 @@ Debugger::Debugger(Isolate* isolate)
       host_dispatch_handler_(NULL),
       debug_message_dispatch_handler_(NULL),
       message_dispatch_helper_thread_(NULL),
-      host_dispatch_micros_(100 * 1000),
+      host_dispatch_period_(TimeDelta::FromMilliseconds(100)),
       agent_(NULL),
       command_queue_(isolate->logger(), kQueueInitialSize),
-      command_received_(OS::CreateSemaphore(0)),
+      command_received_(0),
       event_command_queue_(isolate->logger(), kQueueInitialSize),
       isolate_(isolate) {
 }
 
 
-Debugger::~Debugger() {
-  delete command_received_;
-  command_received_ = 0;
-}
+Debugger::~Debugger() {}
 
 
 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
@@ -3149,14 +3146,14 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
     // Wait for new command in the queue.
     if (Debugger::host_dispatch_handler_) {
       // In case there is a host dispatch - do periodic dispatches.
-      if (!command_received_->Wait(host_dispatch_micros_)) {
+      if (!command_received_.WaitFor(host_dispatch_period_)) {
         // Timout expired, do the dispatch.
         Debugger::host_dispatch_handler_();
         continue;
       }
     } else {
       // In case there is no host dispatch - just wait.
-      command_received_->Wait();
+      command_received_.Wait();
     }
 
     // Get the command from the queue.
@@ -3298,9 +3295,9 @@ void Debugger::ListenersChanged() {
 
 
 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
-                                      int period) {
+                                      TimeDelta period) {
   host_dispatch_handler_ = handler;
-  host_dispatch_micros_ = period * 1000;
+  host_dispatch_period_ = period;
 }
 
 
@@ -3340,7 +3337,7 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
       client_data);
   isolate_->logger()->DebugTag("Put command on command_queue.");
   command_queue_.Put(message);
-  command_received_->Signal();
+  command_received_.Signal();
 
   // Set the debug command break flag to have the command processed.
   if (!isolate_->debug()->InDebugger()) {
@@ -3822,16 +3819,11 @@ void LockingCommandMessageQueue::Clear() {
 
 MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
     : Thread("v8:MsgDispHelpr"),
-      isolate_(isolate), sem_(OS::CreateSemaphore(0)),
+      isolate_(isolate), sem_(0),
       already_signalled_(false) {
 }
 
 
-MessageDispatchHelperThread::~MessageDispatchHelperThread() {
-  delete sem_;
-}
-
-
 void MessageDispatchHelperThread::Schedule() {
   {
     LockGuard<Mutex> lock_guard(&mutex_);
@@ -3840,13 +3832,13 @@ void MessageDispatchHelperThread::Schedule() {
     }
     already_signalled_ = true;
   }
-  sem_->Signal();
+  sem_.Signal();
 }
 
 
 void MessageDispatchHelperThread::Run() {
   while (true) {
-    sem_->Wait();
+    sem_.Wait();
     {
       LockGuard<Mutex> lock_guard(&mutex_);
       already_signalled_ = false;
index 2333b07..042b9bb 100644 (file)
@@ -820,7 +820,7 @@ class Debugger {
   void SetEventListener(Handle<Object> callback, Handle<Object> data);
   void SetMessageHandler(v8::Debug::MessageHandler2 handler);
   void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
-                              int period);
+                              TimeDelta period);
   void SetDebugMessageDispatchHandler(
       v8::Debug::DebugMessageDispatchHandler handler,
       bool provide_locker);
@@ -931,13 +931,13 @@ class Debugger {
   Mutex dispatch_handler_access_;  // Mutex guarding dispatch handler.
   v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
   MessageDispatchHelperThread* message_dispatch_helper_thread_;
-  int host_dispatch_micros_;
+  TimeDelta host_dispatch_period_;
 
   DebuggerAgent* agent_;
 
   static const int kQueueInitialSize = 4;
   LockingCommandMessageQueue command_queue_;
-  Semaphore* command_received_;  // Signaled for each command received.
+  Semaphore command_received_;  // Signaled for each command received.
   LockingCommandMessageQueue event_command_queue_;
 
   Isolate* isolate_;
@@ -1046,7 +1046,7 @@ class Debug_Address {
 class MessageDispatchHelperThread: public Thread {
  public:
   explicit MessageDispatchHelperThread(Isolate* isolate);
-  ~MessageDispatchHelperThread();
+  ~MessageDispatchHelperThread() {}
 
   void Schedule();
 
@@ -1054,7 +1054,7 @@ class MessageDispatchHelperThread: public Thread {
   void Run();
 
   Isolate* isolate_;
-  Semaphore* const sem_;
+  Semaphore sem_;
   Mutex mutex_;
   bool already_signalled_;
 
index 0e7b6d5..2450d36 100644 (file)
@@ -226,8 +226,8 @@ class PreallocatedMemoryThread: public Thread {
   PreallocatedMemoryThread()
       : Thread("v8:PreallocMem"),
         keep_running_(true),
-        wait_for_ever_semaphore_(OS::CreateSemaphore(0)),
-        data_ready_semaphore_(OS::CreateSemaphore(0)),
+        wait_for_ever_semaphore_(new Semaphore(0)),
+        data_ready_semaphore_(new Semaphore(0)),
         data_(NULL),
         length_(0) {
   }
index 158d652..77bb9b3 100644 (file)
@@ -556,7 +556,7 @@ class Profiler: public Thread {
     } else {
       buffer_[head_] = *sample;
       head_ = Succ(head_);
-      buffer_semaphore_->Signal();  // Tell we have an element.
+      buffer_semaphore_.Signal();  // Tell we have an element.
     }
   }
 
@@ -569,7 +569,7 @@ class Profiler: public Thread {
  private:
   // Waits for a signal and removes profiling data.
   bool Remove(TickSample* sample) {
-    buffer_semaphore_->Wait();  // Wait for an element.
+    buffer_semaphore_.Wait();  // Wait for an element.
     *sample = buffer_[tail_];
     bool result = overflow_;
     tail_ = Succ(tail_);
@@ -589,7 +589,7 @@ class Profiler: public Thread {
   int tail_;  // Index to the buffer tail.
   bool overflow_;  // Tell whether a buffer overflow has occurred.
   // Sempahore used for buffer synchronization.
-  SmartPointer<Semaphore> buffer_semaphore_;
+  Semaphore buffer_semaphore_;
 
   // Tells whether profiler is engaged, that is, processing thread is stated.
   bool engaged_;
@@ -645,7 +645,7 @@ Profiler::Profiler(Isolate* isolate)
       head_(0),
       tail_(0),
       overflow_(false),
-      buffer_semaphore_(OS::CreateSemaphore(0)),
+      buffer_semaphore_(0),
       engaged_(false),
       running_(false),
       paused_(false) {
index ac9f944..58bca36 100644 (file)
@@ -39,9 +39,9 @@ MarkingThread::MarkingThread(Isolate* isolate)
      : Thread("MarkingThread"),
        isolate_(isolate),
        heap_(isolate->heap()),
-       start_marking_semaphore_(OS::CreateSemaphore(0)),
-       end_marking_semaphore_(OS::CreateSemaphore(0)),
-       stop_semaphore_(OS::CreateSemaphore(0)) {
+       start_marking_semaphore_(0),
+       end_marking_semaphore_(0),
+       stop_semaphore_(0) {
   NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(false));
   id_ = NoBarrier_AtomicIncrement(&id_counter_, 1);
 }
@@ -57,33 +57,33 @@ void MarkingThread::Run() {
   DisallowHandleDereference no_deref;
 
   while (true) {
-    start_marking_semaphore_->Wait();
+    start_marking_semaphore_.Wait();
 
     if (Acquire_Load(&stop_thread_)) {
-      stop_semaphore_->Signal();
+      stop_semaphore_.Signal();
       return;
     }
 
-    end_marking_semaphore_->Signal();
+    end_marking_semaphore_.Signal();
   }
 }
 
 
 void MarkingThread::Stop() {
   Release_Store(&stop_thread_, static_cast<AtomicWord>(true));
-  start_marking_semaphore_->Signal();
-  stop_semaphore_->Wait();
+  start_marking_semaphore_.Signal();
+  stop_semaphore_.Wait();
   Join();
 }
 
 
 void MarkingThread::StartMarking() {
-  start_marking_semaphore_->Signal();
+  start_marking_semaphore_.Signal();
 }
 
 
 void MarkingThread::WaitForMarkingThread() {
-  end_marking_semaphore_->Wait();
+  end_marking_semaphore_.Wait();
 }
 
 } }  // namespace v8::internal
index 9efa3af..021cd5b 100644 (file)
@@ -43,24 +43,19 @@ namespace internal {
 class MarkingThread : public Thread {
  public:
   explicit MarkingThread(Isolate* isolate);
+  ~MarkingThread() {}
 
   void Run();
   void Stop();
   void StartMarking();
   void WaitForMarkingThread();
 
-  ~MarkingThread() {
-    delete start_marking_semaphore_;
-    delete end_marking_semaphore_;
-    delete stop_semaphore_;
-  }
-
  private:
   Isolate* isolate_;
   Heap* heap_;
-  Semaphore* start_marking_semaphore_;
-  Semaphore* end_marking_semaphore_;
-  Semaphore* stop_semaphore_;
+  Semaphore start_marking_semaphore_;
+  Semaphore end_marking_semaphore_;
+  Semaphore stop_semaphore_;
   volatile AtomicWord stop_thread_;
   int id_;
   static Atomic32 id_counter_;
index 1f77d5a..96847dc 100644 (file)
@@ -52,7 +52,7 @@ void OptimizingCompilerThread::Run() {
   if (FLAG_trace_concurrent_recompilation) total_timer.Start();
 
   while (true) {
-    input_queue_semaphore_->Wait();
+    input_queue_semaphore_.Wait();
     Logger::TimerEventScope timer(
         isolate_, Logger::TimerEventScope::v8_recompile_concurrent);
 
@@ -67,7 +67,7 @@ void OptimizingCompilerThread::Run() {
         if (FLAG_trace_concurrent_recompilation) {
           time_spent_total_ = total_timer.Elapsed();
         }
-        stop_semaphore_->Signal();
+        stop_semaphore_.Signal();
         return;
       case FLUSH:
         // The main thread is blocked, waiting for the stop semaphore.
@@ -76,7 +76,7 @@ void OptimizingCompilerThread::Run() {
         }
         Release_Store(&queue_length_, static_cast<AtomicWord>(0));
         Release_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
-        stop_semaphore_->Signal();
+        stop_semaphore_.Signal();
         // Return to start of consumer loop.
         continue;
     }
@@ -123,7 +123,7 @@ void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
   while (input_queue_.Dequeue(&optimizing_compiler)) {
     // This should not block, since we have one signal on the input queue
     // semaphore corresponding to each element in the input queue.
-    input_queue_semaphore_->Wait();
+    input_queue_semaphore_.Wait();
     CompilationInfo* info = optimizing_compiler->info();
     if (restore_function_code) {
       Handle<JSFunction> function = info->closure();
@@ -151,8 +151,8 @@ void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
 void OptimizingCompilerThread::Flush() {
   ASSERT(!IsOptimizerThread());
   Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH));
-  input_queue_semaphore_->Signal();
-  stop_semaphore_->Wait();
+  input_queue_semaphore_.Signal();
+  stop_semaphore_.Wait();
   FlushOutputQueue(true);
 }
 
@@ -160,8 +160,8 @@ void OptimizingCompilerThread::Flush() {
 void OptimizingCompilerThread::Stop() {
   ASSERT(!IsOptimizerThread());
   Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP));
-  input_queue_semaphore_->Signal();
-  stop_semaphore_->Wait();
+  input_queue_semaphore_.Signal();
+  stop_semaphore_.Wait();
 
   if (FLAG_concurrent_recompilation_delay != 0) {
     // Barrier when loading queue length is not necessary since the write
@@ -204,7 +204,7 @@ void OptimizingCompilerThread::QueueForOptimization(
   Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
   optimizing_compiler->info()->closure()->MarkInRecompileQueue();
   input_queue_.Enqueue(optimizing_compiler);
-  input_queue_semaphore_->Signal();
+  input_queue_semaphore_.Signal();
 }
 
 
index 10ed420..bb96c74 100644 (file)
@@ -50,11 +50,12 @@ class OptimizingCompilerThread : public Thread {
       thread_id_(0),
 #endif
       isolate_(isolate),
-      stop_semaphore_(OS::CreateSemaphore(0)),
-      input_queue_semaphore_(OS::CreateSemaphore(0)) {
+      stop_semaphore_(0),
+      input_queue_semaphore_(0) {
     NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
     NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
   }
+  ~OptimizingCompilerThread() {}
 
   void Run();
   void Stop();
@@ -80,13 +81,6 @@ class OptimizingCompilerThread : public Thread {
   bool IsOptimizerThread();
 #endif
 
-  ~OptimizingCompilerThread() {
-    delete input_queue_semaphore_;
-    delete stop_semaphore_;
-#ifdef DEBUG
-#endif
-  }
-
  private:
   enum StopFlag { CONTINUE, STOP, FLUSH };
 
@@ -101,8 +95,8 @@ class OptimizingCompilerThread : public Thread {
 #endif
 
   Isolate* isolate_;
-  Semaphore* stop_semaphore_;
-  Semaphore* input_queue_semaphore_;
+  Semaphore stop_semaphore_;
+  Semaphore input_queue_semaphore_;
   UnboundQueue<OptimizingCompiler*> input_queue_;
   UnboundQueue<OptimizingCompiler*> output_queue_;
   Mutex install_mutex_;
index 7bedfe8..10525d9 100644 (file)
@@ -398,71 +398,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class CygwinSemaphore : public Semaphore {
- public:
-  explicit CygwinSemaphore(int count) {  sem_init(&sem_, 0, count); }
-  virtual ~CygwinSemaphore() { sem_destroy(&sem_); }
-
-  virtual void Wait();
-  virtual bool Wait(int timeout);
-  virtual void Signal() { sem_post(&sem_); }
- private:
-  sem_t sem_;
-};
-
-
-void CygwinSemaphore::Wait() {
-  while (true) {
-    int result = sem_wait(&sem_);
-    if (result == 0) return;  // Successfully got semaphore.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
-    (ts)->tv_sec = (tv)->tv_sec;                                    \
-    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
-} while (false)
-#endif
-
-
-bool CygwinSemaphore::Wait(int timeout) {
-  const long kOneSecondMicros = 1000000;  // NOLINT
-
-  // Split timeout into second and nanosecond parts.
-  struct timeval delta;
-  delta.tv_usec = timeout % kOneSecondMicros;
-  delta.tv_sec = timeout / kOneSecondMicros;
-
-  struct timeval current_time;
-  // Get the current time.
-  if (gettimeofday(&current_time, NULL) == -1) {
-    return false;
-  }
-
-  // Calculate time for end of timeout.
-  struct timeval end_time;
-  timeradd(&current_time, &delta, &end_time);
-
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
-  // Wait for semaphore signalled or timeout.
-  while (true) {
-    int result = sem_timedwait(&sem_, &ts);
-    if (result == 0) return true;  // Successfully got semaphore.
-    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new CygwinSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
index 0b32b32..5e4e828 100644 (file)
@@ -372,62 +372,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class FreeBSDSemaphore : public Semaphore {
- public:
-  explicit FreeBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
-  virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
-
-  virtual void Wait();
-  virtual bool Wait(int timeout);
-  virtual void Signal() { sem_post(&sem_); }
- private:
-  sem_t sem_;
-};
-
-
-void FreeBSDSemaphore::Wait() {
-  while (true) {
-    int result = sem_wait(&sem_);
-    if (result == 0) return;  // Successfully got semaphore.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-bool FreeBSDSemaphore::Wait(int timeout) {
-  const long kOneSecondMicros = 1000000;  // NOLINT
-
-  // Split timeout into second and nanosecond parts.
-  struct timeval delta;
-  delta.tv_usec = timeout % kOneSecondMicros;
-  delta.tv_sec = timeout / kOneSecondMicros;
-
-  struct timeval current_time;
-  // Get the current time.
-  if (gettimeofday(&current_time, NULL) == -1) {
-    return false;
-  }
-
-  // Calculate time for end of timeout.
-  struct timeval end_time;
-  timeradd(&current_time, &delta, &end_time);
-
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
-  while (true) {
-    int result = sem_timedwait(&sem_, &ts);
-    if (result == 0) return true;  // Successfully got semaphore.
-    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new FreeBSDSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
index 37b4b11..3416da3 100644 (file)
@@ -497,76 +497,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class LinuxSemaphore : public Semaphore {
- public:
-  explicit LinuxSemaphore(int count) {  sem_init(&sem_, 0, count); }
-  virtual ~LinuxSemaphore() { sem_destroy(&sem_); }
-
-  virtual void Wait();
-  virtual bool Wait(int timeout);
-  virtual void Signal() { sem_post(&sem_); }
- private:
-  sem_t sem_;
-};
-
-
-void LinuxSemaphore::Wait() {
-  while (true) {
-    int result = sem_wait(&sem_);
-    if (result == 0) return;  // Successfully got semaphore.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
-    (ts)->tv_sec = (tv)->tv_sec;                                    \
-    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
-} while (false)
-#endif
-
-
-bool LinuxSemaphore::Wait(int timeout) {
-  const long kOneSecondMicros = 1000000;  // NOLINT
-
-  // Split timeout into second and nanosecond parts.
-  struct timeval delta;
-  delta.tv_usec = timeout % kOneSecondMicros;
-  delta.tv_sec = timeout / kOneSecondMicros;
-
-  struct timeval current_time;
-  // Get the current time.
-  if (gettimeofday(&current_time, NULL) == -1) {
-    return false;
-  }
-
-  // Calculate time for end of timeout.
-  struct timeval end_time;
-  timeradd(&current_time, &delta, &end_time);
-
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
-  // Wait for semaphore signalled or timeout.
-  while (true) {
-    int result = sem_timedwait(&sem_, &ts);
-    if (result == 0) return true;  // Successfully got semaphore.
-    if (result > 0) {
-      // For glibc prior to 2.3.4 sem_timedwait returns the error instead of -1.
-      errno = result;
-      result = -1;
-    }
-    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new LinuxSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
index 7aa02a7..d6d3128 100644 (file)
@@ -392,53 +392,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class MacOSSemaphore : public Semaphore {
- public:
-  explicit MacOSSemaphore(int count) {
-    int r;
-    r = semaphore_create(mach_task_self(),
-                         &semaphore_,
-                         SYNC_POLICY_FIFO,
-                         count);
-    ASSERT(r == KERN_SUCCESS);
-  }
-
-  ~MacOSSemaphore() {
-    int r;
-    r = semaphore_destroy(mach_task_self(), semaphore_);
-    ASSERT(r == KERN_SUCCESS);
-  }
-
-  void Wait() {
-    int r;
-    do {
-      r = semaphore_wait(semaphore_);
-      ASSERT(r == KERN_SUCCESS || r == KERN_ABORTED);
-    } while (r == KERN_ABORTED);
-  }
-
-  bool Wait(int timeout);
-
-  void Signal() { semaphore_signal(semaphore_); }
-
- private:
-  semaphore_t semaphore_;
-};
-
-
-bool MacOSSemaphore::Wait(int timeout) {
-  mach_timespec_t ts;
-  ts.tv_sec = timeout / 1000000;
-  ts.tv_nsec = (timeout % 1000000) * 1000;
-  return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT;
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new MacOSSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
index 114b8e2..84039d3 100644 (file)
@@ -429,75 +429,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class OpenBSDSemaphore : public Semaphore {
- public:
-  explicit OpenBSDSemaphore(int count) {  sem_init(&sem_, 0, count); }
-  virtual ~OpenBSDSemaphore() { sem_destroy(&sem_); }
-
-  virtual void Wait();
-  virtual bool Wait(int timeout);
-  virtual void Signal() { sem_post(&sem_); }
- private:
-  sem_t sem_;
-};
-
-
-void OpenBSDSemaphore::Wait() {
-  while (true) {
-    int result = sem_wait(&sem_);
-    if (result == 0) return;  // Successfully got semaphore.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
-    (ts)->tv_sec = (tv)->tv_sec;                                    \
-    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
-} while (false)
-#endif
-
-
-bool OpenBSDSemaphore::Wait(int timeout) {
-  const long kOneSecondMicros = 1000000;  // NOLINT
-
-  // Split timeout into second and nanosecond parts.
-  struct timeval delta;
-  delta.tv_usec = timeout % kOneSecondMicros;
-  delta.tv_sec = timeout / kOneSecondMicros;
-
-  struct timeval current_time;
-  // Get the current time.
-  if (gettimeofday(&current_time, NULL) == -1) {
-    return false;
-  }
-
-  // Calculate time for end of timeout.
-  struct timeval end_time;
-  timeradd(&current_time, &delta, &end_time);
-
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
-
-  int to = ts.tv_sec;
-
-  while (true) {
-    int result = sem_trywait(&sem_);
-    if (result == 0) return true;  // Successfully got semaphore.
-    if (!to) return false;  // Timeout.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-    usleep(ts.tv_nsec / 1000);
-    to--;
-  }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new OpenBSDSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
index dd5c7a0..99636d6 100644 (file)
@@ -393,84 +393,6 @@ bool VirtualMemory::HasLazyCommits() {
 }
 
 
-class SolarisSemaphore : public Semaphore {
- public:
-  explicit SolarisSemaphore(int count) {  sem_init(&sem_, 0, count); }
-  virtual ~SolarisSemaphore() { sem_destroy(&sem_); }
-
-  virtual void Wait();
-  virtual bool Wait(int timeout);
-  virtual void Signal() { sem_post(&sem_); }
- private:
-  sem_t sem_;
-};
-
-
-void SolarisSemaphore::Wait() {
-  while (true) {
-    int result = sem_wait(&sem_);
-    if (result == 0) return;  // Successfully got semaphore.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-#ifndef TIMEVAL_TO_TIMESPEC
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do {                            \
-    (ts)->tv_sec = (tv)->tv_sec;                                    \
-    (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
-} while (false)
-#endif
-
-
-#ifndef timeradd
-#define timeradd(a, b, result) \
-  do { \
-    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
-    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
-    if ((result)->tv_usec >= 1000000) { \
-      ++(result)->tv_sec; \
-      (result)->tv_usec -= 1000000; \
-    } \
-  } while (0)
-#endif
-
-
-bool SolarisSemaphore::Wait(int timeout) {
-  const long kOneSecondMicros = 1000000;  // NOLINT
-
-  // Split timeout into second and nanosecond parts.
-  struct timeval delta;
-  delta.tv_usec = timeout % kOneSecondMicros;
-  delta.tv_sec = timeout / kOneSecondMicros;
-
-  struct timeval current_time;
-  // Get the current time.
-  if (gettimeofday(&current_time, NULL) == -1) {
-    return false;
-  }
-
-  // Calculate time for end of timeout.
-  struct timeval end_time;
-  timeradd(&current_time, &delta, &end_time);
-
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC(&end_time, &ts);
-  // Wait for semaphore signalled or timeout.
-  while (true) {
-    int result = sem_timedwait(&sem_, &ts);
-    if (result == 0) return true;  // Successfully got semaphore.
-    if (result == -1 && errno == ETIMEDOUT) return false;  // Timeout.
-    CHECK(result == -1 && errno == EINTR);  // Signal caused spurious wakeup.
-  }
-}
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new SolarisSemaphore(count);
-}
-
-
 void OS::SetUp() {
   // Seed the random number generator.
   // Convert the current time to a 64-bit integer first, before converting it
index 2775453..199ed2d 100644 (file)
@@ -1616,49 +1616,6 @@ void Thread::YieldCPU() {
 
 
 // ----------------------------------------------------------------------------
-// Win32 semaphore support.
-//
-// On Win32 semaphores are implemented using Win32 Semaphore objects. The
-// semaphores are anonymous. Also, the semaphores are initialized to have
-// no upper limit on count.
-
-
-class Win32Semaphore : public Semaphore {
- public:
-  explicit Win32Semaphore(int count) {
-    sem = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
-  }
-
-  ~Win32Semaphore() {
-    CloseHandle(sem);
-  }
-
-  void Wait() {
-    WaitForSingleObject(sem, INFINITE);
-  }
-
-  bool Wait(int timeout) {
-    // Timeout in Windows API is in milliseconds.
-    DWORD millis_timeout = timeout / 1000;
-    return WaitForSingleObject(sem, millis_timeout) != WAIT_TIMEOUT;
-  }
-
-  void Signal() {
-    LONG dummy;
-    ReleaseSemaphore(sem, 1, &dummy);
-  }
-
- private:
-  HANDLE sem;
-};
-
-
-Semaphore* OS::CreateSemaphore(int count) {
-  return new Win32Semaphore(count);
-}
-
-
-// ----------------------------------------------------------------------------
 // Win32 socket support.
 //
 
index 5f93106..8565775 100644 (file)
@@ -47,6 +47,7 @@
 #include <cstdarg>
 
 #include "platform/mutex.h"
+#include "platform/semaphore.h"
 #include "utils.h"
 #include "v8globals.h"
 
@@ -93,8 +94,6 @@ int random();
 namespace v8 {
 namespace internal {
 
-class Semaphore;
-
 double ceiling(double x);
 double modulo(double x, double y);
 
@@ -288,10 +287,6 @@ class OS {
 
   static int StackWalk(Vector<StackFrame> frames);
 
-  // Factory method for creating platform dependent Semaphore.
-  // Please use delete to reclaim the storage for the returned Semaphore.
-  static Semaphore* CreateSemaphore(int count);
-
   // Factory method for creating platform dependent Socket.
   // Please use delete to reclaim the storage for the returned Socket.
   static Socket* CreateSocket();
@@ -510,59 +505,6 @@ class VirtualMemory {
 
 
 // ----------------------------------------------------------------------------
-// Semaphore
-//
-// A semaphore object is a synchronization object that maintains a count. The
-// count is decremented each time a thread completes a wait for the semaphore
-// object and incremented each time a thread signals the semaphore. When the
-// count reaches zero,  threads waiting for the semaphore blocks until the
-// count becomes non-zero.
-
-class Semaphore {
- public:
-  virtual ~Semaphore() {}
-
-  // Suspends the calling thread until the semaphore counter is non zero
-  // and then decrements the semaphore counter.
-  virtual void Wait() = 0;
-
-  // Suspends the calling thread until the counter is non zero or the timeout
-  // time has passed. If timeout happens the return value is false and the
-  // counter is unchanged. Otherwise the semaphore counter is decremented and
-  // true is returned. The timeout value is specified in microseconds.
-  virtual bool Wait(int timeout) = 0;
-
-  // Increments the semaphore counter.
-  virtual void Signal() = 0;
-};
-
-template <int InitialValue>
-struct CreateSemaphoreTrait {
-  static Semaphore* Create() {
-    return OS::CreateSemaphore(InitialValue);
-  }
-};
-
-// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
-// Usage:
-//   // The following semaphore starts at 0.
-//   static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
-//
-//   void my_function() {
-//     // Do something with my_semaphore.Pointer().
-//   }
-//
-template <int InitialValue>
-struct LazySemaphore {
-  typedef typename LazyDynamicInstance<
-      Semaphore, CreateSemaphoreTrait<InitialValue>,
-      ThreadSafeInitOnceTrait>::type type;
-};
-
-#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
-
-
-// ----------------------------------------------------------------------------
 // Thread
 //
 // Thread objects are used for creating and running threads. When the start()
@@ -604,7 +546,7 @@ class Thread {
 
   // Start new thread and wait until Run() method is called on the new thread.
   void StartSynchronously() {
-    start_semaphore_ = OS::CreateSemaphore(0);
+    start_semaphore_ = new Semaphore(0);
     Start();
     start_semaphore_->Wait();
     delete start_semaphore_;
diff --git a/src/platform/semaphore.cc b/src/platform/semaphore.cc
new file mode 100644 (file)
index 0000000..c3e5826
--- /dev/null
@@ -0,0 +1,214 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "platform/semaphore.h"
+
+#if V8_OS_MACOSX
+#include <mach/mach_init.h>
+#include <mach/task.h>
+#endif
+
+#include <cerrno>
+
+#include "checks.h"
+#include "platform/time.h"
+
+namespace v8 {
+namespace internal {
+
+#if V8_OS_MACOSX
+
+Semaphore::Semaphore(int count) {
+  kern_return_t result = semaphore_create(
+      mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count);
+  ASSERT_EQ(KERN_SUCCESS, result);
+  USE(result);
+}
+
+
+Semaphore::~Semaphore() {
+  kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_);
+  ASSERT_EQ(KERN_SUCCESS, result);
+  USE(result);
+}
+
+
+void Semaphore::Signal() {
+  kern_return_t result = semaphore_signal(native_handle_);
+  ASSERT_EQ(KERN_SUCCESS, result);
+  USE(result);
+}
+
+
+void Semaphore::Wait() {
+  while (true) {
+    kern_return_t result = semaphore_wait(native_handle_);
+    if (result == KERN_SUCCESS) return;  // Semaphore was signalled.
+    ASSERT_EQ(KERN_ABORTED, result);
+  }
+}
+
+
+bool Semaphore::WaitFor(const TimeDelta& rel_time) {
+  TimeTicks now = TimeTicks::Now();
+  TimeTicks end = now + rel_time;
+  while (true) {
+    mach_timespec_t ts;
+    if (now >= end) {
+      // Return immediately if semaphore was not signalled.
+      ts.tv_sec = 0;
+      ts.tv_nsec = 0;
+    } else {
+      ts = (end - now).ToMachTimespec();
+    }
+    kern_return_t result = semaphore_timedwait(native_handle_, ts);
+    if (result == KERN_SUCCESS) return true;  // Semaphore was signalled.
+    if (result == KERN_OPERATION_TIMED_OUT) return false;  // Timeout.
+    ASSERT_EQ(KERN_ABORTED, result);
+    now = TimeTicks::Now();
+  }
+}
+
+#elif V8_OS_POSIX
+
+Semaphore::Semaphore(int count) {
+  ASSERT(count >= 0);
+  int result = sem_init(&native_handle_, 0, count);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+Semaphore::~Semaphore() {
+  int result = sem_destroy(&native_handle_);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+void Semaphore::Signal() {
+  int result = sem_post(&native_handle_);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+void Semaphore::Wait() {
+  while (true) {
+    int result = sem_wait(&native_handle_);
+    if (result == 0) return;  // Semaphore was signalled.
+    // Signal caused spurious wakeup.
+    ASSERT_EQ(-1, result);
+    ASSERT_EQ(EINTR, errno);
+  }
+}
+
+
+bool Semaphore::WaitFor(const TimeDelta& rel_time) {
+  // Compute the time for end of timeout.
+  const Time time = Time::NowFromSystemTime() + rel_time;
+  const struct timespec ts = time.ToTimespec();
+
+  // Wait for semaphore signalled or timeout.
+  while (true) {
+    int result = sem_timedwait(&native_handle_, &ts);
+    if (result == 0) return true;  // Semaphore was signalled.
+#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
+    if (result > 0) {
+      // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
+      errno = result;
+      result = -1;
+    }
+#endif
+    if (result == -1 && errno == ETIMEDOUT) {
+      // Timed out while waiting for semaphore.
+      return false;
+    }
+    // Signal caused spurious wakeup.
+    ASSERT_EQ(-1, result);
+    ASSERT_EQ(EINTR, errno);
+  }
+}
+
+#elif V8_OS_WIN
+
+Semaphore::Semaphore(int count) {
+  ASSERT(count >= 0);
+  native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
+  ASSERT(native_handle_ != NULL);
+}
+
+
+Semaphore::~Semaphore() {
+  BOOL result = CloseHandle(native_handle_);
+  ASSERT(result);
+  USE(result);
+}
+
+
+void Semaphore::Signal() {
+  LONG dummy;
+  BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
+  ASSERT(result);
+  USE(result);
+}
+
+
+void Semaphore::Wait() {
+  DWORD result = WaitForSingleObject(native_handle_, INFINITE);
+  ASSERT(result == WAIT_OBJECT_0);
+  USE(result);
+}
+
+
+bool Semaphore::WaitFor(const TimeDelta& rel_time) {
+  TimeTicks now = TimeTicks::Now();
+  TimeTicks end = now + rel_time;
+  while (true) {
+    int64_t msec = (end - now).InMilliseconds();
+    if (msec >= static_cast<int64_t>(INFINITE)) {
+      DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
+      if (result == WAIT_OBJECT_0) {
+        return true;
+      }
+      ASSERT(result == WAIT_TIMEOUT);
+      now = TimeTicks::Now();
+    } else {
+      DWORD result = WaitForSingleObject(
+          native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
+      if (result == WAIT_TIMEOUT) {
+        return false;
+      }
+      ASSERT(result == WAIT_OBJECT_0);
+      return true;
+    }
+  }
+}
+
+#endif  // V8_OS_MACOSX
+
+} }  // namespace v8::internal
diff --git a/src/platform/semaphore.h b/src/platform/semaphore.h
new file mode 100644 (file)
index 0000000..221c7a3
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_PLATFORM_SEMAPHORE_H_
+#define V8_PLATFORM_SEMAPHORE_H_
+
+#include "lazy-instance.h"
+#if V8_OS_WIN
+#include "win32-headers.h"
+#endif
+
+#if V8_OS_MACOSX
+#include <mach/semaphore.h>  // NOLINT
+#elif V8_OS_POSIX
+#include <semaphore.h>  // NOLINT
+#endif
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class TimeDelta;
+
+// ----------------------------------------------------------------------------
+// Semaphore
+//
+// A semaphore object is a synchronization object that maintains a count. The
+// count is decremented each time a thread completes a wait for the semaphore
+// object and incremented each time a thread signals the semaphore. When the
+// count reaches zero,  threads waiting for the semaphore blocks until the
+// count becomes non-zero.
+
+class Semaphore V8_FINAL {
+ public:
+  explicit Semaphore(int count);
+  ~Semaphore();
+
+  // Increments the semaphore counter.
+  void Signal();
+
+  // Suspends the calling thread until the semaphore counter is non zero
+  // and then decrements the semaphore counter.
+  void Wait();
+
+  // Suspends the calling thread until the counter is non zero or the timeout
+  // time has passed. If timeout happens the return value is false and the
+  // counter is unchanged. Otherwise the semaphore counter is decremented and
+  // true is returned.
+  bool WaitFor(const TimeDelta& rel_time) V8_WARN_UNUSED_RESULT;
+
+#if V8_OS_MACOSX
+  typedef semaphore_t NativeHandle;
+#elif V8_OS_POSIX
+  typedef sem_t NativeHandle;
+#elif V8_OS_WIN
+  typedef HANDLE NativeHandle;
+#endif
+
+  NativeHandle& native_handle() V8_WARN_UNUSED_RESULT {
+    return native_handle_;
+  }
+  const NativeHandle& native_handle() const V8_WARN_UNUSED_RESULT {
+    return native_handle_;
+  }
+
+ private:
+  NativeHandle native_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(Semaphore);
+};
+
+
+// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+//   // The following semaphore starts at 0.
+//   static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
+//
+//   void my_function() {
+//     // Do something with my_semaphore.Pointer().
+//   }
+//
+
+template <int N>
+struct CreateSemaphoreTrait {
+  static Semaphore* Create() {
+    return new Semaphore(N);
+  }
+};
+
+template <int N>
+struct LazySemaphore {
+  typedef typename LazyDynamicInstance<
+      Semaphore,
+      CreateSemaphoreTrait<N>,
+      ThreadSafeInitOnceTrait>::type type;
+};
+
+#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
+
+} }  // namespace v8::internal
+
+#endif  // V8_PLATFORM_SEMAPHORE_H_
index 073ca1e..756be93 100644 (file)
@@ -123,6 +123,27 @@ int64_t TimeDelta::InNanoseconds() const {
 }
 
 
+#if V8_OS_MACOSX
+
+TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
+  ASSERT(ts.tv_nsec >= 0);
+  return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
+                   ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
+}
+
+
+struct mach_timespec TimeDelta::ToMachTimespec() const {
+  struct mach_timespec ts;
+  ASSERT(delta_ >= 0);
+  ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond;
+  ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
+      Time::kNanosecondsPerMicrosecond;
+  return ts;
+}
+
+#endif  // V8_OS_MACOSX
+
+
 #if V8_OS_WIN
 
 // We implement time using the high-resolution timers so that we can get
@@ -246,6 +267,39 @@ Time Time::NowFromSystemTime() {
 }
 
 
+Time Time::FromTimespec(struct timespec ts) {
+  ASSERT(ts.tv_nsec >= 0);
+  ASSERT(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond));  // NOLINT
+  if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
+    return Time();
+  }
+  if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) &&  // NOLINT
+      ts.tv_sec == std::numeric_limits<time_t>::max()) {
+    return Max();
+  }
+  return Time(ts.tv_sec * kMicrosecondsPerSecond +
+              ts.tv_nsec / kNanosecondsPerMicrosecond);
+}
+
+
+struct timespec Time::ToTimespec() const {
+  struct timespec ts;
+  if (IsNull()) {
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+    return ts;
+  }
+  if (IsMax()) {
+    ts.tv_sec = std::numeric_limits<time_t>::max();
+    ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1);  // NOLINT
+    return ts;
+  }
+  ts.tv_sec = us_ / kMicrosecondsPerSecond;
+  ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
+  return ts;
+}
+
+
 Time Time::FromTimeval(struct timeval tv) {
   ASSERT(tv.tv_usec >= 0);
   ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
index 57b894d..a0d5425 100644 (file)
@@ -36,6 +36,8 @@
 // Forward declarations.
 extern "C" {
 struct _FILETIME;
+struct mach_timespec;
+struct timespec;
 struct timeval;
 }
 
@@ -82,6 +84,10 @@ class TimeDelta V8_FINAL BASE_EMBEDDED {
   int64_t InMicroseconds() const { return delta_; }
   int64_t InNanoseconds() const;
 
+  // Converts to/from Mach time specs.
+  static TimeDelta FromMachTimespec(struct mach_timespec ts);
+  struct mach_timespec ToMachTimespec() const;
+
   TimeDelta& operator=(const TimeDelta& other) {
     delta_ = other.delta_;
     return *this;
@@ -212,6 +218,10 @@ class Time V8_FINAL BASE_EMBEDDED {
   // with which we might compare it.
   static Time Max() { return Time(std::numeric_limits<int64_t>::max()); }
 
+  // Converts to/from POSIX time specs.
+  static Time FromTimespec(struct timespec ts);
+  struct timespec ToTimespec() const;
+
   // Converts to/from POSIX time values.
   static Time FromTimeval(struct timeval tv);
   struct timeval ToTimeval() const;
index def0097..19090a0 100644 (file)
@@ -442,7 +442,7 @@ void CodeMap::Print() {
 
 
 CpuProfilesCollection::CpuProfilesCollection()
-    : current_profiles_semaphore_(OS::CreateSemaphore(1)) {
+    : current_profiles_semaphore_(1) {
 }
 
 
@@ -457,7 +457,6 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) {
 
 
 CpuProfilesCollection::~CpuProfilesCollection() {
-  delete current_profiles_semaphore_;
   finished_profiles_.Iterate(DeleteCpuProfile);
   current_profiles_.Iterate(DeleteCpuProfile);
   code_entries_.Iterate(DeleteCodeEntry);
@@ -467,20 +466,20 @@ CpuProfilesCollection::~CpuProfilesCollection() {
 bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid,
                                            bool record_samples) {
   ASSERT(uid > 0);
-  current_profiles_semaphore_->Wait();
+  current_profiles_semaphore_.Wait();
   if (current_profiles_.length() >= kMaxSimultaneousProfiles) {
-    current_profiles_semaphore_->Signal();
+    current_profiles_semaphore_.Signal();
     return false;
   }
   for (int i = 0; i < current_profiles_.length(); ++i) {
     if (strcmp(current_profiles_[i]->title(), title) == 0) {
       // Ignore attempts to start profile with the same title.
-      current_profiles_semaphore_->Signal();
+      current_profiles_semaphore_.Signal();
       return false;
     }
   }
   current_profiles_.Add(new CpuProfile(title, uid, record_samples));
-  current_profiles_semaphore_->Signal();
+  current_profiles_semaphore_.Signal();
   return true;
 }
 
@@ -488,14 +487,14 @@ bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid,
 CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
   const int title_len = StrLength(title);
   CpuProfile* profile = NULL;
-  current_profiles_semaphore_->Wait();
+  current_profiles_semaphore_.Wait();
   for (int i = current_profiles_.length() - 1; i >= 0; --i) {
     if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
       profile = current_profiles_.Remove(i);
       break;
     }
   }
-  current_profiles_semaphore_->Signal();
+  current_profiles_semaphore_.Signal();
 
   if (profile == NULL) return NULL;
   profile->CalculateTotalTicksAndSamplingRate();
@@ -531,11 +530,11 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
   // As starting / stopping profiles is rare relatively to this
   // method, we don't bother minimizing the duration of lock holding,
   // e.g. copying contents of the list to a local vector.
-  current_profiles_semaphore_->Wait();
+  current_profiles_semaphore_.Wait();
   for (int i = 0; i < current_profiles_.length(); ++i) {
     current_profiles_[i]->AddPath(path);
   }
-  current_profiles_semaphore_->Signal();
+  current_profiles_semaphore_.Signal();
 }
 
 
index 5edcac8..70f00de 100644 (file)
@@ -312,7 +312,7 @@ class CpuProfilesCollection {
 
   // Accessed by VM thread and profile generator thread.
   List<CpuProfile*> current_profiles_;
-  Semaphore* current_profiles_semaphore_;
+  Semaphore current_profiles_semaphore_;
 
   DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
 };
index ede567a..58c684a 100644 (file)
@@ -42,9 +42,9 @@ SweeperThread::SweeperThread(Isolate* isolate)
        isolate_(isolate),
        heap_(isolate->heap()),
        collector_(heap_->mark_compact_collector()),
-       start_sweeping_semaphore_(OS::CreateSemaphore(0)),
-       end_sweeping_semaphore_(OS::CreateSemaphore(0)),
-       stop_semaphore_(OS::CreateSemaphore(0)),
+       start_sweeping_semaphore_(0),
+       end_sweeping_semaphore_(0),
+       stop_semaphore_(0),
        free_list_old_data_space_(heap_->paged_space(OLD_DATA_SPACE)),
        free_list_old_pointer_space_(heap_->paged_space(OLD_POINTER_SPACE)),
        private_free_list_old_data_space_(heap_->paged_space(OLD_DATA_SPACE)),
@@ -61,10 +61,10 @@ void SweeperThread::Run() {
   DisallowHandleDereference no_deref;
 
   while (true) {
-    start_sweeping_semaphore_->Wait();
+    start_sweeping_semaphore_.Wait();
 
     if (Acquire_Load(&stop_thread_)) {
-      stop_semaphore_->Signal();
+      stop_semaphore_.Signal();
       return;
     }
 
@@ -74,7 +74,7 @@ void SweeperThread::Run() {
     collector_->SweepInParallel(heap_->old_pointer_space(),
                                 &private_free_list_old_pointer_space_,
                                 &free_list_old_pointer_space_);
-    end_sweeping_semaphore_->Signal();
+    end_sweeping_semaphore_.Signal();
   }
 }
 
@@ -91,18 +91,18 @@ intptr_t SweeperThread::StealMemory(PagedSpace* space) {
 
 void SweeperThread::Stop() {
   Release_Store(&stop_thread_, static_cast<AtomicWord>(true));
-  start_sweeping_semaphore_->Signal();
-  stop_semaphore_->Wait();
+  start_sweeping_semaphore_.Signal();
+  stop_semaphore_.Wait();
   Join();
 }
 
 
 void SweeperThread::StartSweeping() {
-  start_sweeping_semaphore_->Signal();
+  start_sweeping_semaphore_.Signal();
 }
 
 
 void SweeperThread::WaitForSweeperThread() {
-  end_sweeping_semaphore_->Wait();
+  end_sweeping_semaphore_.Wait();
 }
 } }  // namespace v8::internal
index a170982..c36cfc3 100644 (file)
@@ -43,6 +43,7 @@ namespace internal {
 class SweeperThread : public Thread {
  public:
   explicit SweeperThread(Isolate* isolate);
+  ~SweeperThread() {}
 
   void Run();
   void Stop();
@@ -50,19 +51,13 @@ class SweeperThread : public Thread {
   void WaitForSweeperThread();
   intptr_t StealMemory(PagedSpace* space);
 
-  ~SweeperThread() {
-    delete start_sweeping_semaphore_;
-    delete end_sweeping_semaphore_;
-    delete stop_semaphore_;
-  }
-
  private:
   Isolate* isolate_;
   Heap* heap_;
   MarkCompactCollector* collector_;
-  Semaphore* start_sweeping_semaphore_;
-  Semaphore* end_sweeping_semaphore_;
-  Semaphore* stop_semaphore_;
+  Semaphore start_sweeping_semaphore_;
+  Semaphore end_sweeping_semaphore_;
+  Semaphore stop_semaphore_;
   FreeList free_list_old_data_space_;
   FreeList free_list_old_pointer_space_;
   FreeList private_free_list_old_data_space_;
index 051d382..d93ae2f 100644 (file)
@@ -80,7 +80,6 @@
         'test-heap-profiler.cc',
         'test-list.cc',
         'test-liveedit.cc',
-        'test-lock.cc',
         'test-lockers.cc',
         'test-log.cc',
         'test-mark-compact.cc',
@@ -93,6 +92,7 @@
         'test-random.cc',
         'test-regexp.cc',
         'test-reloc-info.cc',
+        'test-semaphore.cc',
         'test-serialize.cc',
         'test-sockets.cc',
         'test-spaces.cc',
index 193126a..7fb25e8 100644 (file)
@@ -144,10 +144,10 @@ class ApiTestFuzzer: public v8::internal::Thread {
   explicit ApiTestFuzzer(int num)
       : Thread("ApiTestFuzzer"),
         test_number_(num),
-        gate_(v8::internal::OS::CreateSemaphore(0)),
+        gate_(0),
         active_(true) {
   }
-  ~ApiTestFuzzer() { delete gate_; }
+  ~ApiTestFuzzer() {}
 
   static bool fuzzing_;
   static int tests_being_run_;
@@ -155,11 +155,11 @@ class ApiTestFuzzer: public v8::internal::Thread {
   static int active_tests_;
   static bool NextThread();
   int test_number_;
-  v8::internal::Semaphore* gate_;
+  v8::internal::Semaphore gate_;
   bool active_;
   void ContextSwitch();
   static int GetNextTestNumber();
-  static v8::internal::Semaphore* all_tests_done_;
+  static v8::internal::Semaphore all_tests_done_;
 };
 
 
index dcfd342..00585bf 100644 (file)
@@ -12237,8 +12237,7 @@ THREADED_TEST(ObjectGetConstructorName) {
 
 
 bool ApiTestFuzzer::fuzzing_ = false;
-i::Semaphore* ApiTestFuzzer::all_tests_done_=
-  i::OS::CreateSemaphore(0);
+i::Semaphore ApiTestFuzzer::all_tests_done_(0);
 int ApiTestFuzzer::active_tests_;
 int ApiTestFuzzer::tests_being_run_;
 int ApiTestFuzzer::current_;
@@ -12269,14 +12268,14 @@ bool ApiTestFuzzer::NextThread() {
            RegisterThreadedTest::nth(test_position)->name());
   }
   current_ = test_position;
-  RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
+  RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
   return true;
 }
 
 
 void ApiTestFuzzer::Run() {
   // When it is our turn...
-  gate_->Wait();
+  gate_.Wait();
   {
     // ... get the V8 lock and start running the test.
     v8::Locker locker(CcTest::default_isolate());
@@ -12287,7 +12286,7 @@ void ApiTestFuzzer::Run() {
   active_tests_--;
   // If it was the last then signal that fact.
   if (active_tests_ == 0) {
-    all_tests_done_->Signal();
+    all_tests_done_.Signal();
   } else {
     // Otherwise select a new test and start that.
     NextThread();
@@ -12324,7 +12323,7 @@ void ApiTestFuzzer::RunAllTests() {
   current_ = -1;
   NextThread();
   // Wait till they are all done.
-  all_tests_done_->Wait();
+  all_tests_done_.Wait();
 }
 
 
@@ -12345,7 +12344,7 @@ void ApiTestFuzzer::ContextSwitch() {
     // Now it can start.
     v8::Unlocker unlocker(CcTest::default_isolate());
     // Wait till someone starts us again.
-    gate_->Wait();
+    gate_.Wait();
     // And we're off.
   }
 }
@@ -14061,10 +14060,9 @@ THREADED_TEST(CrossContextNew) {
 
 class RegExpInterruptTest {
  public:
-  RegExpInterruptTest() : block_(NULL) {}
-  ~RegExpInterruptTest() { delete block_; }
+  RegExpInterruptTest() : block_(0) {}
+  ~RegExpInterruptTest() {}
   void RunTest() {
-    block_ = i::OS::CreateSemaphore(0);
     gc_count_ = 0;
     gc_during_regexp_ = 0;
     regexp_success_ = false;
@@ -14099,7 +14097,7 @@ class RegExpInterruptTest {
   };
 
   void CollectGarbage() {
-    block_->Wait();
+    block_.Wait();
     while (gc_during_regexp_ < kRequiredGCs) {
       {
         v8::Locker lock(CcTest::default_isolate());
@@ -14113,7 +14111,7 @@ class RegExpInterruptTest {
   }
 
   void LongRunningRegExp() {
-    block_->Signal();  // Enable garbage collection thread on next preemption.
+    block_.Signal();  // Enable garbage collection thread on next preemption.
     int rounds = 0;
     while (gc_during_regexp_ < kRequiredGCs) {
       int gc_before = gc_count_;
@@ -14151,7 +14149,7 @@ class RegExpInterruptTest {
     regexp_success_ = true;
   }
 
-  i::Semaphore* block_;
+  i::Semaphore block_;
   int gc_count_;
   int gc_during_regexp_;
   bool regexp_success_;
@@ -14184,10 +14182,9 @@ TEST(RegExpInterruption) {
 
 class ApplyInterruptTest {
  public:
-  ApplyInterruptTest() : block_(NULL) {}
-  ~ApplyInterruptTest() { delete block_; }
+  ApplyInterruptTest() : block_(0) {}
+  ~ApplyInterruptTest() {}
   void RunTest() {
-    block_ = i::OS::CreateSemaphore(0);
     gc_count_ = 0;
     gc_during_apply_ = 0;
     apply_success_ = false;
@@ -14222,7 +14219,7 @@ class ApplyInterruptTest {
   };
 
   void CollectGarbage() {
-    block_->Wait();
+    block_.Wait();
     while (gc_during_apply_ < kRequiredGCs) {
       {
         v8::Locker lock(CcTest::default_isolate());
@@ -14235,7 +14232,7 @@ class ApplyInterruptTest {
   }
 
   void LongRunningApply() {
-    block_->Signal();
+    block_.Signal();
     int rounds = 0;
     while (gc_during_apply_ < kRequiredGCs) {
       int gc_before = gc_count_;
@@ -14260,7 +14257,7 @@ class ApplyInterruptTest {
     apply_success_ = true;
   }
 
-  i::Semaphore* block_;
+  i::Semaphore block_;
   int gc_count_;
   int gc_during_apply_;
   bool apply_success_;
@@ -14473,12 +14470,12 @@ TEST(CompileExternalTwoByteSource) {
 class RegExpStringModificationTest {
  public:
   RegExpStringModificationTest()
-      : block_(i::OS::CreateSemaphore(0)),
+      : block_(0),
         morphs_(0),
         morphs_during_regexp_(0),
         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
-  ~RegExpStringModificationTest() { delete block_; }
+  ~RegExpStringModificationTest() {}
   void RunTest() {
     i::Factory* factory = i::Isolate::Current()->factory();
 
@@ -14535,7 +14532,7 @@ class RegExpStringModificationTest {
   };
 
   void MorphString() {
-    block_->Wait();
+    block_.Wait();
     while (morphs_during_regexp_ < kRequiredModifications &&
            morphs_ < kMaxModifications) {
       {
@@ -14551,7 +14548,7 @@ class RegExpStringModificationTest {
   }
 
   void LongRunningRegExp() {
-    block_->Signal();  // Enable morphing thread on next preemption.
+    block_.Signal();  // Enable morphing thread on next preemption.
     while (morphs_during_regexp_ < kRequiredModifications &&
            morphs_ < kMaxModifications) {
       int morphs_before = morphs_;
@@ -14573,7 +14570,7 @@ class RegExpStringModificationTest {
   }
 
   i::uc16 two_byte_content_[15];
-  i::Semaphore* block_;
+  i::Semaphore block_;
   int morphs_;
   int morphs_during_regexp_;
   bool regexp_success_;
@@ -20070,16 +20067,14 @@ THREADED_TEST(JSONParseNumber) {
 #if V8_OS_POSIX
 class ThreadInterruptTest {
  public:
-  ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
-  ~ThreadInterruptTest() { delete sem_; }
+  ThreadInterruptTest() : sem_(0), sem_value_(0) { }
+  ~ThreadInterruptTest() {}
 
   void RunTest() {
-    sem_ = i::OS::CreateSemaphore(0);
-
     InterruptThread i_thread(this);
     i_thread.Start();
 
-    sem_->Wait();
+    sem_.Wait();
     CHECK_EQ(kExpectedValue, sem_value_);
   }
 
@@ -20110,7 +20105,7 @@ class ThreadInterruptTest {
 
       // Set value and signal semaphore
       test_->sem_value_ = 1;
-      test_->sem_->Signal();
+      test_->sem_.Signal();
     }
 
     static void SignalHandler(int signal) {
@@ -20120,7 +20115,7 @@ class ThreadInterruptTest {
      ThreadInterruptTest* test_;
   };
 
-  i::Semaphore* sem_;
+  i::Semaphore sem_;
   volatile int sem_value_;
 };
 
index 7b21d1e..1d6775d 100644 (file)
@@ -142,15 +142,15 @@ TEST(SamplingCircularQueueMultithreading) {
 
   const int kRecordsPerChunk = 4;
   TestSampleQueue scq;
-  i::Semaphore* semaphore = i::OS::CreateSemaphore(0);
+  i::Semaphore semaphore(0);
 
-  ProducerThread producer1(&scq, kRecordsPerChunk, 1, semaphore);
-  ProducerThread producer2(&scq, kRecordsPerChunk, 10, semaphore);
-  ProducerThread producer3(&scq, kRecordsPerChunk, 20, semaphore);
+  ProducerThread producer1(&scq, kRecordsPerChunk, 1, &semaphore);
+  ProducerThread producer2(&scq, kRecordsPerChunk, 10, &semaphore);
+  ProducerThread producer3(&scq, kRecordsPerChunk, 20, &semaphore);
 
   CHECK_EQ(NULL, scq.StartDequeue());
   producer1.Start();
-  semaphore->Wait();
+  semaphore.Wait();
   for (Record i = 1; i < 1 + kRecordsPerChunk; ++i) {
     Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
     CHECK_NE(NULL, rec);
@@ -162,7 +162,7 @@ TEST(SamplingCircularQueueMultithreading) {
 
   CHECK_EQ(NULL, scq.StartDequeue());
   producer2.Start();
-  semaphore->Wait();
+  semaphore.Wait();
   for (Record i = 10; i < 10 + kRecordsPerChunk; ++i) {
     Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
     CHECK_NE(NULL, rec);
@@ -174,7 +174,7 @@ TEST(SamplingCircularQueueMultithreading) {
 
   CHECK_EQ(NULL, scq.StartDequeue());
   producer3.Start();
-  semaphore->Wait();
+  semaphore.Wait();
   for (Record i = 20; i < 20 + kRecordsPerChunk; ++i) {
     Record* rec = reinterpret_cast<Record*>(scq.StartDequeue());
     CHECK_NE(NULL, rec);
@@ -185,6 +185,4 @@ TEST(SamplingCircularQueueMultithreading) {
   }
 
   CHECK_EQ(NULL, scq.StartDequeue());
-
-  delete semaphore;
 }
index c12cb58..4cea3c3 100644 (file)
@@ -4679,13 +4679,12 @@ class ThreadBarrier {
   int num_threads_;
   int num_blocked_;
   v8::internal::Mutex lock_;
-  v8::internal::Semaphore* sem_;
+  v8::internal::Semaphore sem_;
   bool invalid_;
 };
 
 ThreadBarrier::ThreadBarrier(int num_threads)
-    : num_threads_(num_threads), num_blocked_(0) {
-  sem_ = OS::CreateSemaphore(0);
+    : num_threads_(num_threads), num_blocked_(0), sem_(0) {
   invalid_ = false;  // A barrier may only be used once.  Then it is invalid.
 }
 
@@ -4693,7 +4692,6 @@ ThreadBarrier::ThreadBarrier(int num_threads)
 // Do not call, due to race condition with Wait().
 // Could be resolved with Pthread condition variables.
 ThreadBarrier::~ThreadBarrier() {
-  delete sem_;
 }
 
 
@@ -4703,7 +4701,7 @@ void ThreadBarrier::Wait() {
   if (num_blocked_ == num_threads_ - 1) {
     // Signal and unblock all waiting threads.
     for (int i = 0; i < num_threads_ - 1; ++i) {
-      sem_->Signal();
+      sem_.Signal();
     }
     invalid_ = true;
     printf("BARRIER\n\n");
@@ -4712,7 +4710,7 @@ void ThreadBarrier::Wait() {
   } else {  // Wait for the semaphore.
     ++num_blocked_;
     lock_.Unlock();  // Potential race condition with destructor because
-    sem_->Wait();  // these two lines are not atomic.
+    sem_.Wait();  // these two lines are not atomic.
   }
 }
 
@@ -4735,8 +4733,8 @@ Barriers::Barriers() : barrier_1(2), barrier_2(2),
     barrier_3(2), barrier_4(2), barrier_5(2) {}
 
 void Barriers::Initialize() {
-  semaphore_1 = OS::CreateSemaphore(0);
-  semaphore_2 = OS::CreateSemaphore(0);
+  semaphore_1 = new v8::internal::Semaphore(0);
+  semaphore_2 = new v8::internal::Semaphore(0);
 }
 
 
@@ -5990,17 +5988,16 @@ class DebuggerAgentProtocolServerThread : public i::Thread {
         port_(port),
         server_(NULL),
         client_(NULL),
-        listening_(OS::CreateSemaphore(0)) {
+        listening_(0) {
   }
   ~DebuggerAgentProtocolServerThread() {
     // Close both sockets.
     delete client_;
     delete server_;
-    delete listening_;
   }
 
   void Run();
-  void WaitForListening() { listening_->Wait(); }
+  void WaitForListening() { listening_.Wait(); }
   char* body() { return *body_; }
 
  private:
@@ -6008,7 +6005,7 @@ class DebuggerAgentProtocolServerThread : public i::Thread {
   i::SmartArrayPointer<char> body_;
   i::Socket* server_;  // Server socket used for bind/accept.
   i::Socket* client_;  // Single client connection used by the test.
-  i::Semaphore* listening_;  // Signalled when the server is in listen mode.
+  i::Semaphore listening_;  // Signalled when the server is in listen mode.
 };
 
 
@@ -6024,7 +6021,7 @@ void DebuggerAgentProtocolServerThread::Run() {
   // Listen for new connections.
   ok = server_->Listen(1);
   CHECK(ok);
-  listening_->Signal();
+  listening_.Signal();
 
   // Accept a connection.
   client_ = server_->Accept();
diff --git a/test/cctest/test-lock.cc b/test/cctest/test-lock.cc
deleted file mode 100644 (file)
index 0603e44..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Tests of the TokenLock class from lock.h
-
-#include <stdlib.h>
-
-#include "v8.h"
-
-#include "platform.h"
-#include "cctest.h"
-
-
-using namespace ::v8::internal;
-
-
-TEST(SemaphoreTimeout) {
-  bool ok;
-  Semaphore* sem = OS::CreateSemaphore(0);
-
-  // Semaphore not signalled - timeout.
-  ok = sem->Wait(0);
-  CHECK(!ok);
-  ok = sem->Wait(100);
-  CHECK(!ok);
-  ok = sem->Wait(1000);
-  CHECK(!ok);
-
-  // Semaphore signalled - no timeout.
-  sem->Signal();
-  ok = sem->Wait(0);
-  sem->Signal();
-  ok = sem->Wait(100);
-  sem->Signal();
-  ok = sem->Wait(1000);
-  CHECK(ok);
-  delete sem;
-}
index 90e1f75..a143d58 100644 (file)
@@ -129,20 +129,18 @@ class JoinableThread {
  public:
   explicit JoinableThread(const char* name)
     : name_(name),
-      semaphore_(i::OS::CreateSemaphore(0)),
+      semaphore_(0),
       thread_(this) {
   }
 
-  virtual ~JoinableThread() {
-    delete semaphore_;
-  }
+  virtual ~JoinableThread() {}
 
   void Start() {
     thread_.Start();
   }
 
   void Join() {
-    semaphore_->Wait();
+    semaphore_.Wait();
   }
 
   virtual void Run() = 0;
@@ -157,7 +155,7 @@ class JoinableThread {
 
     virtual void Run() {
       joinable_thread_->Run();
-      joinable_thread_->semaphore_->Signal();
+      joinable_thread_->semaphore_.Signal();
     }
 
    private:
@@ -165,7 +163,7 @@ class JoinableThread {
   };
 
   const char* name_;
-  i::Semaphore* semaphore_;
+  i::Semaphore semaphore_;
   ThreadWithSemaphore thread_;
 
   friend class ThreadWithSemaphore;
index 6bf56f0..8bf306f 100644 (file)
@@ -127,7 +127,7 @@ class LoopingThread : public v8::internal::Thread {
  public:
   explicit LoopingThread(v8::internal::Isolate* isolate)
       : v8::internal::Thread(isolate),
-        semaphore_(v8::internal::OS::CreateSemaphore(0)),
+        semaphore_(new v8::internal::Semaphore(0)),
         run_(true) {
   }
 
@@ -213,7 +213,7 @@ class TestSampler : public v8::internal::Sampler {
  public:
   explicit TestSampler(v8::internal::Isolate* isolate)
       : Sampler(isolate, 0, true, true),
-        semaphore_(v8::internal::OS::CreateSemaphore(0)),
+        semaphore_(new v8::internal::Semaphore(0)),
         was_sample_stack_called_(false) {
   }
 
diff --git a/test/cctest/test-semaphore.cc b/test/cctest/test-semaphore.cc
new file mode 100644 (file)
index 0000000..a043911
--- /dev/null
@@ -0,0 +1,152 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "platform.h"
+#include "cctest.h"
+
+
+using namespace ::v8::internal;
+
+
+TEST(WaitAndSignal) {
+  class WaitAndSignalThread V8_FINAL : public Thread {
+   public:
+    explicit WaitAndSignalThread(Semaphore* semaphore)
+        : Thread("WaitAndSignalThread"), semaphore_(semaphore) {}
+    virtual ~WaitAndSignalThread() {}
+
+    virtual void Run() V8_OVERRIDE {
+      for (int n = 0; n < 1000; ++n) {
+        semaphore_->Wait();
+        bool result = semaphore_->WaitFor(TimeDelta::FromMicroseconds(1));
+        ASSERT(!result);
+        USE(result);
+        semaphore_->Signal();
+      }
+    }
+
+   private:
+    Semaphore* semaphore_;
+  };
+
+  Semaphore semaphore(0);
+  WaitAndSignalThread t1(&semaphore);
+  WaitAndSignalThread t2(&semaphore);
+
+  t1.Start();
+  t2.Start();
+
+  // Make something available.
+  semaphore.Signal();
+
+  t1.Join();
+  t2.Join();
+
+  semaphore.Wait();
+
+  bool result = semaphore.WaitFor(TimeDelta::FromMicroseconds(1));
+  ASSERT(!result);
+  USE(result);
+}
+
+
+TEST(WaitFor) {
+  bool ok;
+  Semaphore semaphore(0);
+
+  // Semaphore not signalled - timeout.
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(0));
+  CHECK(!ok);
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(100));
+  CHECK(!ok);
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(1000));
+  CHECK(!ok);
+
+  // Semaphore signalled - no timeout.
+  semaphore.Signal();
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(0));
+  semaphore.Signal();
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(100));
+  semaphore.Signal();
+  ok = semaphore.WaitFor(TimeDelta::FromMicroseconds(1000));
+  CHECK(ok);
+}
+
+
+static const char alphabet[] = "XKOAD";
+static const int kAlphabetSize = sizeof(alphabet) - 1;
+static const int kBufferSize = 4096;  // GCD(buffer size, alphabet size) = 1
+static char buffer[kBufferSize];
+static const int kDataSize = kBufferSize * kAlphabetSize * 10;
+
+static Semaphore free_space(kBufferSize);
+static Semaphore used_space(0);
+
+
+class ProducerThread V8_FINAL : public Thread {
+  public:
+  ProducerThread() : Thread("ProducerThread") {}
+  virtual ~ProducerThread() {}
+
+  virtual void Run() V8_OVERRIDE {
+    for (int n = 0; n < kDataSize; ++n) {
+      free_space.Wait();
+      buffer[n % kBufferSize] = alphabet[n % kAlphabetSize];
+      used_space.Signal();
+    }
+  }
+};
+
+
+class ConsumerThread V8_FINAL : public Thread {
+  public:
+  ConsumerThread() : Thread("ConsumerThread") {}
+  virtual ~ConsumerThread() {}
+
+  virtual void Run() V8_OVERRIDE {
+    for (int n = 0; n < kDataSize; ++n) {
+      used_space.Wait();
+      ASSERT_EQ(static_cast<int>(alphabet[n % kAlphabetSize]),
+                static_cast<int>(buffer[n % kBufferSize]));
+      free_space.Signal();
+    }
+  }
+};
+
+
+TEST(ProducerConsumer) {
+  ProducerThread producer_thread;
+  ConsumerThread consumer_thread;
+  producer_thread.Start();
+  consumer_thread.Start();
+  producer_thread.Join();
+  consumer_thread.Join();
+}
index a9e31fc..87a62ce 100644 (file)
@@ -41,19 +41,18 @@ class SocketListenerThread : public Thread {
         data_size_(data_size),
         server_(NULL),
         client_(NULL),
-        listening_(OS::CreateSemaphore(0)) {
+        listening_(0) {
     data_ = new char[data_size_];
   }
   ~SocketListenerThread() {
     // Close both sockets.
     delete client_;
     delete server_;
-    delete listening_;
     delete[] data_;
   }
 
   void Run();
-  void WaitForListening() { listening_->Wait(); }
+  void WaitForListening() { listening_.Wait(); }
   char* data() { return data_; }
 
  private:
@@ -62,7 +61,7 @@ class SocketListenerThread : public Thread {
   int data_size_;
   Socket* server_;  // Server socket used for bind/accept.
   Socket* client_;  // Single client connection used by the test.
-  Semaphore* listening_;  // Signalled when the server socket is in listen mode.
+  Semaphore listening_;  // Signalled when the server socket is in listen mode.
 };
 
 
@@ -79,7 +78,7 @@ void SocketListenerThread::Run() {
   // Listen for new connections.
   ok = server_->Listen(1);
   CHECK(ok);
-  listening_->Signal();
+  listening_.Signal();
 
   // Accept a connection.
   client_ = server_->Accept();
index b29b1dc..4c08539 100644 (file)
@@ -171,7 +171,7 @@ class TerminatorThread : public v8::internal::Thread {
 // Test that a single thread of JavaScript execution can be terminated
 // from the side by another thread.
 TEST(TerminateOnlyV8ThreadFromOtherThread) {
-  semaphore = v8::internal::OS::CreateSemaphore(0);
+  semaphore = new v8::internal::Semaphore(0);
   TerminatorThread thread(i::Isolate::Current());
   thread.Start();
 
@@ -225,7 +225,7 @@ TEST(TerminateMultipleV8ThreadsDefaultIsolate) {
     v8::Locker locker(CcTest::default_isolate());
     v8::V8::Initialize();
     v8::Locker::StartPreemption(1);
-    semaphore = v8::internal::OS::CreateSemaphore(0);
+    semaphore = new v8::internal::Semaphore(0);
   }
   const int kThreads = 2;
   i::List<LoopingThread*> threads(kThreads);
index a35a88d..6cc5f52 100644 (file)
@@ -180,7 +180,7 @@ TEST(ThreadIdValidation) {
   const int kNThreads = 100;
   i::List<ThreadIdValidationThread*> threads(kNThreads);
   i::List<i::ThreadId> refs(kNThreads);
-  i::Semaphore* semaphore = i::OS::CreateSemaphore(0);
+  i::Semaphore* semaphore = new i::Semaphore(0);
   ThreadIdValidationThread* prev = NULL;
   for (int i = kNThreads - 1; i >= 0; i--) {
     ThreadIdValidationThread* newThread =
index b53ee73..8b92d8d 100644 (file)
@@ -56,6 +56,18 @@ TEST(TimeDeltaFromAndIn) {
 }
 
 
+#if V8_OS_MACOSX
+TEST(TimeDeltaFromMachTimespec) {
+  TimeDelta null = TimeDelta();
+  CHECK(null == TimeDelta::FromMachTimespec(null.ToMachTimespec()));
+  TimeDelta delta1 = TimeDelta::FromMilliseconds(42);
+  CHECK(delta1 == TimeDelta::FromMachTimespec(delta1.ToMachTimespec()));
+  TimeDelta delta2 = TimeDelta::FromDays(42);
+  CHECK(delta2 == TimeDelta::FromMachTimespec(delta2.ToMachTimespec()));
+}
+#endif
+
+
 TEST(TimeJsTime) {
   Time t = Time::FromJsTime(700000.3);
   CHECK_EQ(700000.3, t.ToJsTime());
@@ -63,7 +75,23 @@ TEST(TimeJsTime) {
 
 
 #if V8_OS_POSIX
-TEST(TimeFromTimeVal) {
+TEST(TimeFromTimespec) {
+  Time null;
+  CHECK(null.IsNull());
+  CHECK(null == Time::FromTimespec(null.ToTimespec()));
+  Time now = Time::Now();
+  CHECK(now == Time::FromTimespec(now.ToTimespec()));
+  Time now_sys = Time::NowFromSystemTime();
+  CHECK(now_sys == Time::FromTimespec(now_sys.ToTimespec()));
+  Time unix_epoch = Time::UnixEpoch();
+  CHECK(unix_epoch == Time::FromTimespec(unix_epoch.ToTimespec()));
+  Time max = Time::Max();
+  CHECK(max.IsMax());
+  CHECK(max == Time::FromTimespec(max.ToTimespec()));
+}
+
+
+TEST(TimeFromTimeval) {
   Time null;
   CHECK(null.IsNull());
   CHECK(null == Time::FromTimeval(null.ToTimeval()));
index ca81736..469eaca 100644 (file)
         '../../src/platform.h',
         '../../src/platform/mutex.cc',
         '../../src/platform/mutex.h',
+        '../../src/platform/semaphore.cc',
+        '../../src/platform/semaphore.h',
         '../../src/preparse-data-format.h',
         '../../src/preparse-data.cc',
         '../../src/preparse-data.h',