Cleanup Mutex and related classes.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Aug 2013 09:58:30 +0000 (09:58 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 29 Aug 2013 09:58:30 +0000 (09:58 +0000)
Drop the previous Mutex and ScopedLock classes from platform files.

Add new Mutex, RecursiveMutex and LockGuard classes, which are
designed after their C++11 counterparts, so that at some point
we can simply drop our custom code and switch to the C++11
classes. We distinguish regular and recursive mutexes, as the
latter don't work well with condition variables, which will be
introduced by a followup CL.

R=mstarzinger@chromium.org

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

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

44 files changed:
src/assembler.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/gdb-jit.cc
src/heap.cc
src/heap.h
src/isolate.cc
src/isolate.h
src/log-utils.cc
src/log-utils.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-posix.cc
src/platform-solaris.cc
src/platform-win32.cc
src/platform.h
src/platform/mutex.cc [new file with mode: 0644]
src/platform/mutex.h [new file with mode: 0644]
src/platform/time.cc
src/sampler.cc
src/spaces.cc
src/spaces.h
src/v8.cc
src/v8globals.h
src/v8threads.cc
src/v8threads.h
src/win32-headers.h
test/cctest/cctest.gyp
test/cctest/test-debug.cc
test/cctest/test-lock.cc
test/cctest/test-mutex.cc [new file with mode: 0644]
test/cctest/test-platform-linux.cc
tools/gyp/v8.gyp

index ae8a0b5..a9587f3 100644 (file)
@@ -891,7 +891,7 @@ void ExternalReference::SetUp() {
   double_constants.the_hole_nan = BitCast<double>(kHoleNanInt64);
   double_constants.negative_infinity = -V8_INFINITY;
 
-  math_exp_data_mutex = OS::CreateMutex();
+  math_exp_data_mutex = new Mutex();
 }
 
 
@@ -899,7 +899,7 @@ void ExternalReference::InitializeMathExpData() {
   // Early return?
   if (math_exp_data_initialized) return;
 
-  math_exp_data_mutex->Lock();
+  LockGuard<Mutex> lock_guard(math_exp_data_mutex);
   if (!math_exp_data_initialized) {
     // If this is changed, generated code must be adapted too.
     const int kTableSizeBits = 11;
@@ -935,7 +935,6 @@ void ExternalReference::InitializeMathExpData() {
 
     math_exp_data_initialized = true;
   }
-  math_exp_data_mutex->Unlock();
 }
 
 
index 9a72518..3adeb71 100644 (file)
@@ -248,7 +248,7 @@ void RemoteDebugger::ConnectionClosed() {
 
 
 void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
-  i::ScopedLock lock(event_access_);
+  i::LockGuard<i::Mutex> lock_guard(&event_access_);
   if (head_ == NULL) {
     ASSERT(tail_ == NULL);
     head_ = event;
@@ -263,7 +263,7 @@ void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
 
 
 RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
-  i::ScopedLock lock(event_access_);
+  i::LockGuard<i::Mutex> lock_guard(&event_access_);
   ASSERT(head_ != NULL);
   RemoteDebuggerEvent* result = head_;
   head_ = head_->next();
index 2386b6b..276cbd8 100644 (file)
@@ -53,7 +53,6 @@ class RemoteDebugger {
   explicit RemoteDebugger(Isolate* isolate, int port)
       : isolate_(isolate),
         port_(port),
-        event_access_(i::OS::CreateMutex()),
         event_available_(i::OS::CreateSemaphore(0)),
         head_(NULL), tail_(NULL) {}
   void Run();
@@ -84,7 +83,7 @@ class RemoteDebugger {
   // Linked list of events from debugged V8 and from keyboard input. Access to
   // the list is guarded by a mutex and a semaphore signals new items in the
   // list.
-  i::Mutex* event_access_;
+  i::Mutex event_access_;
   i::Semaphore* event_available_;
   RemoteDebuggerEvent* head_;
   RemoteDebuggerEvent* tail_;
index fe4d744..4a10550 100644 (file)
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -157,7 +157,7 @@ CounterMap* Shell::counter_map_;
 i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
 CounterCollection Shell::local_counters_;
 CounterCollection* Shell::counters_ = &local_counters_;
-i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
+i::Mutex Shell::context_mutex_;
 Persistent<Context> Shell::utility_context_;
 #endif  // V8_SHARED
 
@@ -925,7 +925,7 @@ void Shell::InitializeDebugger(Isolate* isolate) {
 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
 #ifndef V8_SHARED
   // This needs to be a critical section since this is not thread-safe
-  i::ScopedLock lock(context_mutex_);
+  i::LockGuard<i::Mutex> lock_guard(&context_mutex_);
 #endif  // V8_SHARED
   // Initialize the global objects
   Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
@@ -1011,7 +1011,6 @@ void Shell::OnExit() {
            "-------------+\n");
     delete [] counters;
   }
-  delete context_mutex_;
   delete counters_file_;
   delete counter_map_;
 #endif  // V8_SHARED
index 6008d35..fbc7a10 100644 (file)
--- a/src/d8.h
+++ b/src/d8.h
@@ -390,7 +390,7 @@ class Shell : public i::AllStatic {
   static CounterCollection local_counters_;
   static CounterCollection* counters_;
   static i::OS::MemoryMappedFile* counters_file_;
-  static i::Mutex* context_mutex_;
+  static i::Mutex context_mutex_;
 
   static Counter* GetCounter(const char* name, bool is_histogram);
   static void InstallUtilityScript(Isolate* isolate);
index 811c00e..b390cc5 100644 (file)
@@ -106,7 +106,7 @@ static const char* kCreateSessionMessage =
     "Remote debugging session already active\r\n";
 
 void DebuggerAgent::CreateSession(Socket* client) {
-  ScopedLock with(session_access_);
+  LockGuard<RecursiveMutex> session_access_guard(&session_access_);
 
   // If another session is already established terminate this one.
   if (session_ != NULL) {
@@ -123,7 +123,7 @@ void DebuggerAgent::CreateSession(Socket* client) {
 
 
 void DebuggerAgent::CloseSession() {
-  ScopedLock with(session_access_);
+  LockGuard<RecursiveMutex> session_access_guard(&session_access_);
 
   // Terminate the session.
   if (session_ != NULL) {
@@ -136,7 +136,7 @@ void DebuggerAgent::CloseSession() {
 
 
 void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
-  ScopedLock with(session_access_);
+  LockGuard<RecursiveMutex> session_access_guard(&session_access_);
 
   // Forward the message handling to the session.
   if (session_ != NULL) {
@@ -154,7 +154,7 @@ void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
   }
 
   // Terminate the session.
-  ScopedLock with(session_access_);
+  LockGuard<RecursiveMutex> session_access_guard(&session_access_);
   ASSERT(session == session_);
   if (session == session_) {
     session_->Shutdown();
index 6115190..e78ed67 100644 (file)
@@ -48,7 +48,7 @@ class DebuggerAgent: public Thread {
         isolate_(Isolate::Current()),
         name_(StrDup(name)), port_(port),
         server_(OS::CreateSocket()), terminate_(false),
-        session_access_(OS::CreateMutex()), session_(NULL),
+        session_(NULL),
         terminate_now_(OS::CreateSemaphore(0)),
         listening_(OS::CreateSemaphore(0)) {
     ASSERT(isolate_->debugger_agent_instance() == NULL);
@@ -76,7 +76,7 @@ class DebuggerAgent: public Thread {
   int port_;  // Port to use for the agent.
   Socket* server_;  // Server socket for listen/accept.
   bool terminate_;  // Termination flag.
-  Mutex* session_access_;  // Mutex guarging access to session_.
+  RecursiveMutex session_access_;  // Mutex guarding access to session_.
   DebuggerAgentSession* session_;  // Current active session if any.
   Semaphore* terminate_now_;  // Semaphore to signal termination.
   Semaphore* listening_;
index bf208b2..dfe7b97 100644 (file)
@@ -2612,7 +2612,6 @@ Debugger::Debugger(Isolate* isolate)
       message_handler_(NULL),
       debugger_unload_pending_(false),
       host_dispatch_handler_(NULL),
-      dispatch_handler_access_(OS::CreateMutex()),
       debug_message_dispatch_handler_(NULL),
       message_dispatch_helper_thread_(NULL),
       host_dispatch_micros_(100 * 1000),
@@ -2625,8 +2624,6 @@ Debugger::Debugger(Isolate* isolate)
 
 
 Debugger::~Debugger() {
-  delete dispatch_handler_access_;
-  dispatch_handler_access_ = 0;
   delete command_received_;
   command_received_ = 0;
 }
@@ -3272,7 +3269,7 @@ void Debugger::SetEventListener(Handle<Object> callback,
 
 
 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
-  ScopedLock with(debugger_access_);
+  LockGuard<RecursiveMutex> with(debugger_access_);
 
   message_handler_ = handler;
   ListenersChanged();
@@ -3309,7 +3306,7 @@ void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
 
 void Debugger::SetDebugMessageDispatchHandler(
     v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
-  ScopedLock with(dispatch_handler_access_);
+  LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
   debug_message_dispatch_handler_ = handler;
 
   if (provide_locker && message_dispatch_helper_thread_ == NULL) {
@@ -3322,7 +3319,7 @@ void Debugger::SetDebugMessageDispatchHandler(
 // Calls the registered debug message handler. This callback is part of the
 // public API.
 void Debugger::InvokeMessageHandler(MessageImpl message) {
-  ScopedLock with(debugger_access_);
+  LockGuard<RecursiveMutex> with(debugger_access_);
 
   if (message_handler_ != NULL) {
     message_handler_(message);
@@ -3352,7 +3349,7 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
 
   MessageDispatchHelperThread* dispatch_thread;
   {
-    ScopedLock with(dispatch_handler_access_);
+    LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
     dispatch_thread = message_dispatch_helper_thread_;
   }
 
@@ -3381,7 +3378,7 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
 
 
 bool Debugger::IsDebuggerActive() {
-  ScopedLock with(debugger_access_);
+  LockGuard<RecursiveMutex> with(debugger_access_);
 
   return message_handler_ != NULL ||
       !event_listener_.is_null() ||
@@ -3472,7 +3469,7 @@ void Debugger::WaitForAgent() {
 void Debugger::CallMessageDispatchHandler() {
   v8::Debug::DebugMessageDispatchHandler handler;
   {
-    ScopedLock with(dispatch_handler_access_);
+    LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
     handler = Debugger::debug_message_dispatch_handler_;
   }
   if (handler != NULL) {
@@ -3793,24 +3790,17 @@ void CommandMessageQueue::Expand() {
 
 
 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
-    : logger_(logger), queue_(size) {
-  lock_ = OS::CreateMutex();
-}
-
-
-LockingCommandMessageQueue::~LockingCommandMessageQueue() {
-  delete lock_;
-}
+    : logger_(logger), queue_(size) {}
 
 
 bool LockingCommandMessageQueue::IsEmpty() const {
-  ScopedLock sl(lock_);
+  LockGuard<Mutex> lock_guard(&mutex_);
   return queue_.IsEmpty();
 }
 
 
 CommandMessage LockingCommandMessageQueue::Get() {
-  ScopedLock sl(lock_);
+  LockGuard<Mutex> lock_guard(&mutex_);
   CommandMessage result = queue_.Get();
   logger_->DebugEvent("Get", result.text());
   return result;
@@ -3818,14 +3808,14 @@ CommandMessage LockingCommandMessageQueue::Get() {
 
 
 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
-  ScopedLock sl(lock_);
+  LockGuard<Mutex> lock_guard(&mutex_);
   queue_.Put(message);
   logger_->DebugEvent("Put", message.text());
 }
 
 
 void LockingCommandMessageQueue::Clear() {
-  ScopedLock sl(lock_);
+  LockGuard<Mutex> lock_guard(&mutex_);
   queue_.Clear();
 }
 
@@ -3833,19 +3823,18 @@ void LockingCommandMessageQueue::Clear() {
 MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
     : Thread("v8:MsgDispHelpr"),
       isolate_(isolate), sem_(OS::CreateSemaphore(0)),
-      mutex_(OS::CreateMutex()), already_signalled_(false) {
+      already_signalled_(false) {
 }
 
 
 MessageDispatchHelperThread::~MessageDispatchHelperThread() {
-  delete mutex_;
   delete sem_;
 }
 
 
 void MessageDispatchHelperThread::Schedule() {
   {
-    ScopedLock lock(mutex_);
+    LockGuard<Mutex> lock_guard(&mutex_);
     if (already_signalled_) {
       return;
     }
@@ -3859,7 +3848,7 @@ void MessageDispatchHelperThread::Run() {
   while (true) {
     sem_->Wait();
     {
-      ScopedLock lock(mutex_);
+      LockGuard<Mutex> lock_guard(&mutex_);
       already_signalled_ = false;
     }
     {
index 67debc7..2333b07 100644 (file)
@@ -762,7 +762,6 @@ class MessageDispatchHelperThread;
 class LockingCommandMessageQueue BASE_EMBEDDED {
  public:
   LockingCommandMessageQueue(Logger* logger, int size);
-  ~LockingCommandMessageQueue();
   bool IsEmpty() const;
   CommandMessage Get();
   void Put(const CommandMessage& message);
@@ -770,7 +769,7 @@ class LockingCommandMessageQueue BASE_EMBEDDED {
  private:
   Logger* logger_;
   CommandMessageQueue queue_;
-  Mutex* lock_;
+  mutable Mutex mutex_;
   DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue);
 };
 
@@ -863,7 +862,7 @@ class Debugger {
   friend void ForceUnloadDebugger();  // In test-debug.cc
 
   inline bool EventActive(v8::DebugEvent event) {
-    ScopedLock with(debugger_access_);
+    LockGuard<RecursiveMutex> lock_guard(debugger_access_);
 
     // Check whether the message handler was been cleared.
     if (debugger_unload_pending_) {
@@ -918,7 +917,7 @@ class Debugger {
                            Handle<Object> event_data);
   void ListenersChanged();
 
-  Mutex* debugger_access_;  // Mutex guarding debugger variables.
+  RecursiveMutex* debugger_access_;  // Mutex guarding debugger variables.
   Handle<Object> event_listener_;  // Global handle to listener.
   Handle<Object> event_listener_data_;
   bool compiling_natives_;  // Are we compiling natives?
@@ -929,7 +928,7 @@ class Debugger {
   v8::Debug::MessageHandler2 message_handler_;
   bool debugger_unload_pending_;  // Was message handler cleared?
   v8::Debug::HostDispatchHandler host_dispatch_handler_;
-  Mutex* dispatch_handler_access_;  // Mutex guarding dispatch handler.
+  Mutex dispatch_handler_access_;  // Mutex guarding dispatch handler.
   v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
   MessageDispatchHelperThread* message_dispatch_helper_thread_;
   int host_dispatch_micros_;
@@ -1056,7 +1055,7 @@ class MessageDispatchHelperThread: public Thread {
 
   Isolate* isolate_;
   Semaphore* const sem_;
-  Mutex* const mutex_;
+  Mutex mutex_;
   bool already_signalled_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread);
index 664673f..21cfd22 100644 (file)
@@ -2063,7 +2063,7 @@ void GDBJITInterface::AddCode(const char* name,
                               CompilationInfo* info) {
   if (!FLAG_gdbjit) return;
 
-  ScopedLock lock(mutex.Pointer());
+  LockGuard<Mutex> lock_guard(mutex.Pointer());
   DisallowHeapAllocation no_gc;
 
   HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
@@ -2149,7 +2149,7 @@ void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, Code* code) {
 void GDBJITInterface::RemoveCode(Code* code) {
   if (!FLAG_gdbjit) return;
 
-  ScopedLock lock(mutex.Pointer());
+  LockGuard<Mutex> lock_guard(mutex.Pointer());
   HashMap::Entry* e = GetEntries()->Lookup(code,
                                            HashForCodeObject(code),
                                            false);
@@ -2187,7 +2187,7 @@ void GDBJITInterface::RemoveCodeRange(Address start, Address end) {
 
 void GDBJITInterface::RegisterDetailedLineInfo(Code* code,
                                                GDBJITLineInfo* line_info) {
-  ScopedLock lock(mutex.Pointer());
+  LockGuard<Mutex> lock_guard(mutex.Pointer());
   ASSERT(!IsLineInfoTagged(line_info));
   HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
   ASSERT(e->value == NULL);
index 4fd478f..7bfb07e 100644 (file)
@@ -6927,7 +6927,7 @@ bool Heap::SetUp() {
 
   store_buffer()->SetUp();
 
-  if (FLAG_concurrent_recompilation) relocation_mutex_ = OS::CreateMutex();
+  if (FLAG_concurrent_recompilation) relocation_mutex_ = new Mutex;
 #ifdef DEBUG
   relocation_mutex_locked_by_optimizer_thread_ = false;
 #endif  // DEBUG
@@ -8032,7 +8032,7 @@ static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
 
 
 void Heap::CheckpointObjectStats() {
-  ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
+  LockGuard<Mutex> lock_guard(checkpoint_object_stats_mutex.Pointer());
   Counters* counters = isolate()->counters();
 #define ADJUST_LAST_TIME_OBJECT_COUNT(name)                                    \
   counters->count_of_##name()->Increment(                                      \
index f0920b3..14b395f 100644 (file)
@@ -1882,7 +1882,7 @@ class Heap {
 
   void CheckpointObjectStats();
 
-  // We don't use a ScopedLock here since we want to lock the heap
+  // We don't use a LockGuard here since we want to lock the heap
   // only when FLAG_concurrent_recompilation is true.
   class RelocationLock {
    public:
index 54329b7..d0b6d46 100644 (file)
@@ -343,7 +343,7 @@ Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
 #ifdef DEBUG
 Thread::LocalStorageKey PerThreadAssertScopeBase::thread_local_key;
 #endif  // DEBUG
-Mutex* Isolate::process_wide_mutex_ = OS::CreateMutex();
+RecursiveMutex Isolate::process_wide_mutex_;
 Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
 Atomic32 Isolate::isolate_counter_ = 0;
 
@@ -352,7 +352,7 @@ Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData(
   ASSERT(!thread_id.Equals(ThreadId::Invalid()));
   PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id);
   {
-    ScopedLock lock(process_wide_mutex_);
+    LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
     ASSERT(thread_data_table_->Lookup(this, thread_id) == NULL);
     thread_data_table_->Insert(per_thread);
     ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread);
@@ -366,7 +366,7 @@ Isolate::PerIsolateThreadData*
   ThreadId thread_id = ThreadId::Current();
   PerIsolateThreadData* per_thread = NULL;
   {
-    ScopedLock lock(process_wide_mutex_);
+    LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
     per_thread = thread_data_table_->Lookup(this, thread_id);
     if (per_thread == NULL) {
       per_thread = AllocatePerIsolateThreadData(thread_id);
@@ -386,7 +386,7 @@ Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
     ThreadId thread_id) {
   PerIsolateThreadData* per_thread = NULL;
   {
-    ScopedLock lock(process_wide_mutex_);
+    LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
     per_thread = thread_data_table_->Lookup(this, thread_id);
   }
   return per_thread;
@@ -394,7 +394,7 @@ Isolate::PerIsolateThreadData* Isolate::FindPerThreadDataForThread(
 
 
 void Isolate::EnsureDefaultIsolate() {
-  ScopedLock lock(process_wide_mutex_);
+  LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
   if (default_isolate_ == NULL) {
     isolate_key_ = Thread::CreateThreadLocalKey();
     thread_id_key_ = Thread::CreateThreadLocalKey();
@@ -1750,11 +1750,7 @@ Isolate::Isolate()
       compilation_cache_(NULL),
       counters_(NULL),
       code_range_(NULL),
-      // Must be initialized early to allow v8::SetResourceConstraints calls.
-      break_access_(OS::CreateMutex()),
       debugger_initialized_(false),
-      // Must be initialized early to allow v8::Debug calls.
-      debugger_access_(OS::CreateMutex()),
       logger_(NULL),
       stats_table_(NULL),
       stub_cache_(NULL),
@@ -1854,7 +1850,7 @@ void Isolate::TearDown() {
 
   Deinit();
 
-  { ScopedLock lock(process_wide_mutex_);
+  { LockGuard<RecursiveMutex> lock_guard(&process_wide_mutex_);
     thread_data_table_->RemoveAllThreads(this);
   }
 
@@ -2025,10 +2021,6 @@ Isolate::~Isolate() {
 
   delete handle_scope_implementer_;
   handle_scope_implementer_ = NULL;
-  delete break_access_;
-  break_access_ = NULL;
-  delete debugger_access_;
-  debugger_access_ = NULL;
 
   delete compilation_cache_;
   compilation_cache_ = NULL;
@@ -2127,7 +2119,7 @@ void Isolate::InitializeLoggingAndCounters() {
 
 void Isolate::InitializeDebugger() {
 #ifdef ENABLE_DEBUGGER_SUPPORT
-  ScopedLock lock(debugger_access_);
+  LockGuard<RecursiveMutex> lock_guard(debugger_access());
   if (NoBarrier_Load(&debugger_initialized_)) return;
   InitializeLoggingAndCounters();
   debug_ = new Debug(this);
index 751f995..2f09285 100644 (file)
@@ -541,10 +541,10 @@ class Isolate {
   static void EnterDefaultIsolate();
 
   // Mutex for serializing access to break control structures.
-  Mutex* break_access() { return break_access_; }
+  RecursiveMutex* break_access() { return &break_access_; }
 
   // Mutex for serializing access to debugger.
-  Mutex* debugger_access() { return debugger_access_; }
+  RecursiveMutex* debugger_access() { return &debugger_access_; }
 
   Address get_address_from_id(AddressId id);
 
@@ -1185,7 +1185,7 @@ class Isolate {
 
   // This mutex protects highest_thread_id_, thread_data_table_ and
   // default_isolate_.
-  static Mutex* process_wide_mutex_;
+  static RecursiveMutex process_wide_mutex_;
 
   static Thread::LocalStorageKey per_isolate_thread_data_key_;
   static Thread::LocalStorageKey isolate_key_;
@@ -1253,9 +1253,9 @@ class Isolate {
   CompilationCache* compilation_cache_;
   Counters* counters_;
   CodeRange* code_range_;
-  Mutex* break_access_;
+  RecursiveMutex break_access_;
   Atomic32 debugger_initialized_;
-  Mutex* debugger_access_;
+  RecursiveMutex debugger_access_;
   Logger* logger_;
   StackGuard stack_guard_;
   StatsTable* stats_table_;
@@ -1440,11 +1440,11 @@ class ExecutionAccess BASE_EMBEDDED {
   }
   ~ExecutionAccess() { Unlock(isolate_); }
 
-  static void Lock(Isolate* isolate) { isolate->break_access_->Lock(); }
-  static void Unlock(Isolate* isolate) { isolate->break_access_->Unlock(); }
+  static void Lock(Isolate* isolate) { isolate->break_access()->Lock(); }
+  static void Unlock(Isolate* isolate) { isolate->break_access()->Unlock(); }
 
   static bool TryLock(Isolate* isolate) {
-    return isolate->break_access_->TryLock();
+    return isolate->break_access()->TryLock();
   }
 
  private:
index 6bba882..98f4fdf 100644 (file)
@@ -41,14 +41,12 @@ const char* const Log::kLogToConsole = "-";
 Log::Log(Logger* logger)
   : is_stopped_(false),
     output_handle_(NULL),
-    mutex_(NULL),
     message_buffer_(NULL),
     logger_(logger) {
 }
 
 
 void Log::Initialize(const char* log_file_name) {
-  mutex_ = OS::CreateMutex();
   message_buffer_ = NewArray<char>(kMessageBufferSize);
 
   // --log-all enables all the log flags.
@@ -116,9 +114,6 @@ FILE* Log::Close() {
   DeleteArray(message_buffer_);
   message_buffer_ = NULL;
 
-  delete mutex_;
-  mutex_ = NULL;
-
   is_stopped_ = false;
   return result;
 }
@@ -126,7 +121,7 @@ FILE* Log::Close() {
 
 Log::MessageBuilder::MessageBuilder(Log* log)
   : log_(log),
-    sl(log_->mutex_),
+    lock_guard_(&log_->mutex_),
     pos_(0) {
   ASSERT(log_->message_buffer_ != NULL);
 }
index 861a826..ec8415e 100644 (file)
@@ -107,7 +107,7 @@ class Log {
 
    private:
     Log* log_;
-    ScopedLock sl;
+    LockGuard<Mutex> lock_guard_;
     int pos_;
   };
 
@@ -142,7 +142,7 @@ class Log {
 
   // mutex_ is a Mutex used for enforcing exclusive
   // access to the formatting buffer and the log file or log memory buffer.
-  Mutex* mutex_;
+  Mutex mutex_;
 
   // Buffer used for formatting log messages. This is a singleton buffer and
   // mutex_ should be acquired before using it.
index added33..1f77d5a 100644 (file)
@@ -39,7 +39,7 @@ namespace internal {
 
 void OptimizingCompilerThread::Run() {
 #ifdef DEBUG
-  { ScopedLock lock(thread_id_mutex_);
+  { LockGuard<Mutex> lock_guard(&thread_id_mutex_);
     thread_id_ = ThreadId::Current().ToInteger();
   }
 #endif
@@ -108,7 +108,7 @@ void OptimizingCompilerThread::CompileNext() {
   // The function may have already been optimized by OSR.  Simply continue.
   // Use a mutex to make sure that functions marked for install
   // are always also queued.
-  ScopedLock mark_and_queue(install_mutex_);
+  LockGuard<Mutex> mark_and_queue(&install_mutex_);
   { Heap::RelocationLock relocation_lock(isolate_->heap());
     AllowHandleDereference ahd;
     optimizing_compiler->info()->closure()->MarkForInstallingRecompiledCode();
@@ -189,7 +189,7 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() {
   OptimizingCompiler* compiler;
   while (true) {
     { // Memory barrier to ensure marked functions are queued.
-      ScopedLock marked_and_queued(install_mutex_);
+      LockGuard<Mutex> marked_and_queued(&install_mutex_);
       if (!output_queue_.Dequeue(&compiler)) return;
     }
     Compiler::InstallOptimizedCode(compiler);
@@ -211,7 +211,7 @@ void OptimizingCompilerThread::QueueForOptimization(
 #ifdef DEBUG
 bool OptimizingCompilerThread::IsOptimizerThread() {
   if (!FLAG_concurrent_recompilation) return false;
-  ScopedLock lock(thread_id_mutex_);
+  LockGuard<Mutex> lock_guard(&thread_id_mutex_);
   return ThreadId::Current().ToInteger() == thread_id_;
 }
 #endif
index 1b06208..10ed420 100644 (file)
@@ -31,6 +31,7 @@
 #include "atomicops.h"
 #include "flags.h"
 #include "platform.h"
+#include "platform/mutex.h"
 #include "platform/time.h"
 #include "unbound-queue-inl.h"
 
@@ -47,12 +48,10 @@ class OptimizingCompilerThread : public Thread {
       Thread("OptimizingCompilerThread"),
 #ifdef DEBUG
       thread_id_(0),
-      thread_id_mutex_(OS::CreateMutex()),
 #endif
       isolate_(isolate),
       stop_semaphore_(OS::CreateSemaphore(0)),
-      input_queue_semaphore_(OS::CreateSemaphore(0)),
-      install_mutex_(OS::CreateMutex()) {
+      input_queue_semaphore_(OS::CreateSemaphore(0)) {
     NoBarrier_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
     NoBarrier_Store(&queue_length_, static_cast<AtomicWord>(0));
   }
@@ -82,11 +81,9 @@ class OptimizingCompilerThread : public Thread {
 #endif
 
   ~OptimizingCompilerThread() {
-    delete install_mutex_;
     delete input_queue_semaphore_;
     delete stop_semaphore_;
 #ifdef DEBUG
-    delete thread_id_mutex_;
 #endif
   }
 
@@ -100,7 +97,7 @@ class OptimizingCompilerThread : public Thread {
 
 #ifdef DEBUG
   int thread_id_;
-  Mutex* thread_id_mutex_;
+  Mutex thread_id_mutex_;
 #endif
 
   Isolate* isolate_;
@@ -108,7 +105,7 @@ class OptimizingCompilerThread : public Thread {
   Semaphore* input_queue_semaphore_;
   UnboundQueue<OptimizingCompiler*> input_queue_;
   UnboundQueue<OptimizingCompiler*> output_queue_;
-  Mutex* install_mutex_;
+  Mutex install_mutex_;
   volatile AtomicWord stop_thread_;
   volatile Atomic32 queue_length_;
   TimeDelta time_spent_compiling_;
index 4c7b017..7bedfe8 100644 (file)
@@ -87,7 +87,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock_guard(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -471,7 +471,7 @@ void OS::SetUp() {
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index e0917fa..0b32b32 100644 (file)
@@ -95,7 +95,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock_guard(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -436,7 +436,7 @@ void OS::SetUp() {
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index b27c1fd..37b4b11 100644 (file)
@@ -151,7 +151,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock_guard(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -571,7 +571,7 @@ void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index 9d8d076..7aa02a7 100644 (file)
@@ -93,7 +93,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -443,7 +443,7 @@ void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index a027944..114b8e2 100644 (file)
@@ -93,7 +93,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -502,7 +502,7 @@ void OS::SetUp() {
   // Seed the random number generator. We preserve microsecond resolution.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()) ^ (getpid() << 16);
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index dd6b77c..aaf0ca7 100644 (file)
@@ -739,48 +739,6 @@ void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
 }
 
 
-class POSIXMutex : public Mutex {
- public:
-  POSIXMutex() {
-    pthread_mutexattr_t attr;
-    memset(&attr, 0, sizeof(attr));
-    int result = pthread_mutexattr_init(&attr);
-    ASSERT(result == 0);
-    result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-    ASSERT(result == 0);
-    result = pthread_mutex_init(&mutex_, &attr);
-    ASSERT(result == 0);
-    result = pthread_mutexattr_destroy(&attr);
-    ASSERT(result == 0);
-    USE(result);
-  }
-
-  virtual ~POSIXMutex() { pthread_mutex_destroy(&mutex_); }
-
-  virtual int Lock() { return pthread_mutex_lock(&mutex_); }
-
-  virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
-
-  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.
-};
-
-
-Mutex* OS::CreateMutex() {
-  return new POSIXMutex();
-}
-
-
 // ----------------------------------------------------------------------------
 // POSIX socket support.
 //
index b1d88af..dd5c7a0 100644 (file)
@@ -110,7 +110,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock_guard(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -479,7 +479,7 @@ void OS::SetUp() {
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srandom(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index cdd9a4f..2775453 100644 (file)
@@ -761,7 +761,7 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
 
 static void UpdateAllocatedSpaceLimits(void* address, int size) {
   ASSERT(limit_mutex != NULL);
-  ScopedLock lock(limit_mutex);
+  LockGuard<Mutex> lock_guard(limit_mutex);
 
   lowest_ever_allocated = Min(lowest_ever_allocated, address);
   highest_ever_allocated =
@@ -1616,46 +1616,6 @@ void Thread::YieldCPU() {
 
 
 // ----------------------------------------------------------------------------
-// Win32 mutex support.
-//
-// On Win32 mutexes are implemented using CRITICAL_SECTION objects. These are
-// faster than Win32 Mutex objects because they are implemented using user mode
-// atomic instructions. Therefore we only do ring transitions if there is lock
-// contention.
-
-class Win32Mutex : public Mutex {
- public:
-  Win32Mutex() { InitializeCriticalSection(&cs_); }
-
-  virtual ~Win32Mutex() { DeleteCriticalSection(&cs_); }
-
-  virtual int Lock() {
-    EnterCriticalSection(&cs_);
-    return 0;
-  }
-
-  virtual int Unlock() {
-    LeaveCriticalSection(&cs_);
-    return 0;
-  }
-
-
-  virtual bool TryLock() {
-    // Returns non-zero if critical section is entered successfully entered.
-    return TryEnterCriticalSection(&cs_);
-  }
-
- private:
-  CRITICAL_SECTION cs_;  // Critical section used for mutex
-};
-
-
-Mutex* OS::CreateMutex() {
-  return new Win32Mutex();
-}
-
-
-// ----------------------------------------------------------------------------
 // Win32 semaphore support.
 //
 // On Win32 semaphores are implemented using Win32 Semaphore objects. The
@@ -1898,7 +1858,7 @@ void OS::SetUp() {
   // call this setup code within the same millisecond.
   uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
   srand(static_cast<unsigned int>(seed));
-  limit_mutex = CreateMutex();
+  limit_mutex = new Mutex();
 }
 
 
index 44817b4..5f93106 100644 (file)
@@ -46,7 +46,7 @@
 
 #include <cstdarg>
 
-#include "lazy-instance.h"
+#include "platform/mutex.h"
 #include "utils.h"
 #include "v8globals.h"
 
@@ -94,7 +94,6 @@ namespace v8 {
 namespace internal {
 
 class Semaphore;
-class Mutex;
 
 double ceiling(double x);
 double modulo(double x, double y);
@@ -289,10 +288,6 @@ class OS {
 
   static int StackWalk(Vector<StackFrame> frames);
 
-  // Factory method for creating platform dependent Mutex.
-  // Please use delete to reclaim the storage for the returned Mutex.
-  static Mutex* CreateMutex();
-
   // Factory method for creating platform dependent Semaphore.
   // Please use delete to reclaim the storage for the returned Semaphore.
   static Semaphore* CreateSemaphore(int count);
@@ -684,72 +679,6 @@ class Thread {
 
 
 // ----------------------------------------------------------------------------
-// Mutex
-//
-// Mutexes are used for serializing access to non-reentrant sections of code.
-// The implementations of mutex should allow for nested/recursive locking.
-
-class Mutex {
- public:
-  virtual ~Mutex() {}
-
-  // Locks the given mutex. If the mutex is currently unlocked, it becomes
-  // locked and owned by the calling thread, and immediately. If the mutex
-  // is already locked by another thread, suspends the calling thread until
-  // the mutex is unlocked.
-  virtual int Lock() = 0;
-
-  // Unlocks the given mutex. The mutex is assumed to be locked and owned by
-  // the calling thread on entrance.
-  virtual int Unlock() = 0;
-
-  // Tries to lock the given mutex. Returns whether the mutex was
-  // successfully locked.
-  virtual bool TryLock() = 0;
-};
-
-struct CreateMutexTrait {
-  static Mutex* Create() {
-    return OS::CreateMutex();
-  }
-};
-
-// POD Mutex initialized lazily (i.e. the first time Pointer() is called).
-// Usage:
-//   static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER;
-//
-//   void my_function() {
-//     ScopedLock my_lock(my_mutex.Pointer());
-//     // Do something.
-//   }
-//
-typedef LazyDynamicInstance<
-    Mutex, CreateMutexTrait, ThreadSafeInitOnceTrait>::type LazyMutex;
-
-#define LAZY_MUTEX_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
-
-// ----------------------------------------------------------------------------
-// ScopedLock
-//
-// Stack-allocated ScopedLocks provide block-scoped locking and
-// unlocking of a mutex.
-class ScopedLock {
- public:
-  explicit ScopedLock(Mutex* mutex): mutex_(mutex) {
-    ASSERT(mutex_ != NULL);
-    mutex_->Lock();
-  }
-  ~ScopedLock() {
-    mutex_->Unlock();
-  }
-
- private:
-  Mutex* mutex_;
-  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
-};
-
-
-// ----------------------------------------------------------------------------
 // Socket
 //
 
diff --git a/src/platform/mutex.cc b/src/platform/mutex.cc
new file mode 100644 (file)
index 0000000..c8d75c7
--- /dev/null
@@ -0,0 +1,223 @@
+// 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/mutex.h"
+
+#include <cerrno>
+
+namespace v8 {
+namespace internal {
+
+#if V8_OS_POSIX
+
+static V8_INLINE(void InitializeNativeHandle(pthread_mutex_t* mutex)) {
+  int result;
+#if defined(DEBUG)
+  // Use an error checking mutex in debug mode.
+  pthread_mutexattr_t attr;
+  result = pthread_mutexattr_init(&attr);
+  ASSERT_EQ(0, result);
+  result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+  ASSERT_EQ(0, result);
+  result = pthread_mutex_init(mutex, &attr);
+  ASSERT_EQ(0, result);
+  result = pthread_mutexattr_destroy(&attr);
+#else
+  // Use a fast mutex (default attributes).
+  result = pthread_mutex_init(mutex, NULL);
+#endif  // defined(DEBUG)
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+static V8_INLINE(void InitializeRecursiveNativeHandle(pthread_mutex_t* mutex)) {
+  pthread_mutexattr_t attr;
+  int result = pthread_mutexattr_init(&attr);
+  ASSERT_EQ(0, result);
+  result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+  ASSERT_EQ(0, result);
+  result = pthread_mutex_init(mutex, &attr);
+  ASSERT_EQ(0, result);
+  result = pthread_mutexattr_destroy(&attr);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+static V8_INLINE(void DestroyNativeHandle(pthread_mutex_t* mutex)) {
+  int result = pthread_mutex_destroy(mutex);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+static V8_INLINE(void LockNativeHandle(pthread_mutex_t* mutex)) {
+  int result = pthread_mutex_lock(mutex);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+static V8_INLINE(void UnlockNativeHandle(pthread_mutex_t* mutex)) {
+  int result = pthread_mutex_unlock(mutex);
+  ASSERT_EQ(0, result);
+  USE(result);
+}
+
+
+static V8_INLINE(bool TryLockNativeHandle(pthread_mutex_t* mutex)) {
+  int result = pthread_mutex_trylock(mutex);
+  if (result == EBUSY) {
+    return false;
+  }
+  ASSERT_EQ(0, result);
+  return true;
+}
+
+#elif V8_OS_WIN
+
+static V8_INLINE(void InitializeNativeHandle(CRITICAL_SECTION* cs)) {
+  InitializeCriticalSection(cs);
+}
+
+
+static V8_INLINE(void InitializeRecursiveNativeHandle(CRITICAL_SECTION* cs)) {
+  InitializeCriticalSection(cs);
+}
+
+
+static V8_INLINE(void DestroyNativeHandle(CRITICAL_SECTION* cs)) {
+  DeleteCriticalSection(cs);
+}
+
+
+static V8_INLINE(void LockNativeHandle(CRITICAL_SECTION* cs)) {
+  EnterCriticalSection(cs);
+}
+
+
+static V8_INLINE(void UnlockNativeHandle(CRITICAL_SECTION* cs)) {
+  LeaveCriticalSection(cs);
+}
+
+
+static V8_INLINE(bool TryLockNativeHandle(CRITICAL_SECTION* cs)) {
+  return TryEnterCriticalSection(cs);
+}
+
+#endif  // V8_OS_POSIX
+
+
+Mutex::Mutex() {
+  InitializeNativeHandle(&native_handle_);
+#ifdef DEBUG
+  level_ = 0;
+#endif
+}
+
+
+Mutex::~Mutex() {
+  DestroyNativeHandle(&native_handle_);
+  ASSERT_EQ(0, level_);
+}
+
+
+void Mutex::Lock() {
+  LockNativeHandle(&native_handle_);
+#ifdef DEBUG
+  ASSERT_EQ(0, level_);
+  level_++;
+#endif
+}
+
+
+void Mutex::Unlock() {
+#ifdef DEBUG
+  ASSERT_EQ(1, level_);
+  level_--;
+#endif
+  UnlockNativeHandle(&native_handle_);
+}
+
+
+bool Mutex::TryLock() {
+  if (!TryLockNativeHandle(&native_handle_)) {
+    return false;
+  }
+#ifdef DEBUG
+  ASSERT_EQ(0, level_);
+  level_++;
+#endif
+  return true;
+}
+
+
+RecursiveMutex::RecursiveMutex() {
+  InitializeRecursiveNativeHandle(&native_handle_);
+#ifdef DEBUG
+  level_ = 0;
+#endif
+}
+
+
+RecursiveMutex::~RecursiveMutex() {
+  DestroyNativeHandle(&native_handle_);
+  ASSERT_EQ(0, level_);
+}
+
+
+void RecursiveMutex::Lock() {
+  LockNativeHandle(&native_handle_);
+#ifdef DEBUG
+  ASSERT_LE(0, level_);
+  level_++;
+#endif
+}
+
+
+void RecursiveMutex::Unlock() {
+#ifdef DEBUG
+  ASSERT_LT(0, level_);
+  level_--;
+#endif
+  UnlockNativeHandle(&native_handle_);
+}
+
+
+bool RecursiveMutex::TryLock() {
+  if (!TryLockNativeHandle(&native_handle_)) {
+    return false;
+  }
+#ifdef DEBUG
+  ASSERT_LE(0, level_);
+  level_++;
+#endif
+  return true;
+}
+
+} }  // namespace v8::internal
diff --git a/src/platform/mutex.h b/src/platform/mutex.h
new file mode 100644 (file)
index 0000000..1940542
--- /dev/null
@@ -0,0 +1,223 @@
+// 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_MUTEX_H_
+#define V8_PLATFORM_MUTEX_H_
+
+#include "lazy-instance.h"
+#if V8_OS_WIN
+#include "win32-headers.h"
+#endif
+
+#if V8_OS_POSIX
+#include <pthread.h>  // NOLINT
+#endif
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Mutex
+//
+// This class is a synchronization primitive that can be used to protect shared
+// data from being simultaneously accessed by multiple threads. A mutex offers
+// exclusive, non-recursive ownership semantics:
+// - A calling thread owns a mutex from the time that it successfully calls
+//   either |Lock()| or |TryLock()| until it calls |Unlock()|.
+// - When a thread owns a mutex, all other threads will block (for calls to
+//   |Lock()|) or receive a |false| return value (for |TryLock()|) if they
+//   attempt to claim ownership of the mutex.
+// A calling thread must not own the mutex prior to calling |Lock()| or
+// |TryLock()|. The behavior of a program is undefined if a mutex is destroyed
+// while still owned by some thread. The Mutex class is non-copyable.
+
+class Mutex V8_FINAL {
+ public:
+  Mutex();
+  ~Mutex();
+
+  // Locks the given mutex. If the mutex is currently unlocked, it becomes
+  // locked and owned by the calling thread, and immediately. If the mutex
+  // is already locked by another thread, suspends the calling thread until
+  // the mutex is unlocked.
+  void Lock();
+
+  // Unlocks the given mutex. The mutex is assumed to be locked and owned by
+  // the calling thread on entrance.
+  void Unlock();
+
+  // Tries to lock the given mutex. Returns whether the mutex was
+  // successfully locked.
+  bool TryLock() V8_WARN_UNUSED_RESULT;
+
+  // The implementation-defined native handle type.
+#if V8_OS_POSIX
+  typedef pthread_mutex_t NativeHandle;
+#elif V8_OS_WIN
+  typedef CRITICAL_SECTION 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_;
+#ifdef DEBUG
+  int level_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(Mutex);
+};
+
+
+// POD Mutex initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+//   static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER;
+//
+//   void my_function() {
+//     LockGuard<Mutex> guard(my_mutex.Pointer());
+//     // Do something.
+//   }
+//
+typedef LazyStaticInstance<Mutex,
+                           DefaultConstructTrait<Mutex>,
+                           ThreadSafeInitOnceTrait>::type LazyMutex;
+
+#define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
+
+
+// -----------------------------------------------------------------------------
+// RecursiveMutex
+//
+// This class is a synchronization primitive that can be used to protect shared
+// data from being simultaneously accessed by multiple threads. A recursive
+// mutex offers exclusive, recursive ownership semantics:
+// - A calling thread owns a recursive mutex for a period of time that starts
+//   when it successfully calls either |Lock()| or |TryLock()|. During this
+//   period, the thread may make additional calls to |Lock()| or |TryLock()|.
+//   The period of ownership ends when the thread makes a matching number of
+//   calls to |Unlock()|.
+// - When a thread owns a recursive mutex, all other threads will block (for
+//   calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if
+//   they attempt to claim ownership of the recursive mutex.
+// - The maximum number of times that a recursive mutex may be locked is
+//   unspecified, but after that number is reached, calls to |Lock()| will
+//   probably abort the process and calls to |TryLock()| return false.
+// The behavior of a program is undefined if a recursive mutex is destroyed
+// while still owned by some thread. The RecursiveMutex class is non-copyable.
+
+class RecursiveMutex V8_FINAL {
+ public:
+  RecursiveMutex();
+  ~RecursiveMutex();
+
+  // Locks the mutex. If another thread has already locked the mutex, a call to
+  // |Lock()| will block execution until the lock is acquired. A thread may call
+  // |Lock()| on a recursive mutex repeatedly. Ownership will only be released
+  // after the thread makes a matching number of calls to |Unlock()|.
+  // The behavior is undefined if the mutex is not unlocked before being
+  // destroyed, i.e. some thread still owns it.
+  void Lock();
+
+  // Unlocks the mutex if its level of ownership is 1 (there was exactly one
+  // more call to |Lock()| than there were calls to unlock() made by this
+  // thread), reduces the level of ownership by 1 otherwise. The mutex must be
+  // locked by the current thread of execution, otherwise, the behavior is
+  // undefined.
+  void Unlock();
+
+  // Tries to lock the given mutex. Returns whether the mutex was
+  // successfully locked.
+  bool TryLock() V8_WARN_UNUSED_RESULT;
+
+  // The implementation-defined native handle type.
+  typedef Mutex::NativeHandle NativeHandle;
+
+  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_;
+#ifdef DEBUG
+  int level_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(RecursiveMutex);
+};
+
+
+// POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is
+// called).
+// Usage:
+//   static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
+//
+//   void my_function() {
+//     LockGuard<RecursiveMutex> guard(my_mutex.Pointer());
+//     // Do something.
+//   }
+//
+typedef LazyStaticInstance<RecursiveMutex,
+                           DefaultConstructTrait<RecursiveMutex>,
+                           ThreadSafeInitOnceTrait>::type LazyRecursiveMutex;
+
+#define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
+
+
+// -----------------------------------------------------------------------------
+// LockGuard
+//
+// This class is a mutex wrapper that provides a convenient RAII-style mechanism
+// for owning a mutex for the duration of a scoped block.
+// When a LockGuard object is created, it attempts to take ownership of the
+// mutex it is given. When control leaves the scope in which the LockGuard
+// object was created, the LockGuard is destructed and the mutex is released.
+// The LockGuard class is non-copyable.
+
+template <typename Mutex>
+class LockGuard V8_FINAL {
+ public:
+  explicit LockGuard(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); }
+  ~LockGuard() { mutex_->Unlock(); }
+
+ private:
+  Mutex* mutex_;
+
+  LockGuard(const LockGuard<Mutex>& other) V8_DELETE;
+  LockGuard<Mutex>& operator=(const LockGuard<Mutex>& other) V8_DELETE;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_PLATFORM_MUTEX_H_
index 927cb92..653eb14 100644 (file)
@@ -131,14 +131,11 @@ int64_t TimeDelta::InNanoseconds() const {
 class Clock V8_FINAL {
  public:
   Clock() : initial_time_(CurrentWallclockTime()),
-            initial_ticks_(TimeTicks::Now()),
-            mutex_(OS::CreateMutex()) {}
-
-  ~Clock() { delete mutex_; }
+            initial_ticks_(TimeTicks::Now()) {}
 
   Time Now() {
     // This must be executed under lock.
-    ScopedLock sl(mutex_);
+    LockGuard<Mutex> lock_guard(&mutex_);
 
     // Calculate the time elapsed since we started our timer.
     TimeDelta elapsed = TimeTicks::Now() - initial_ticks_;
@@ -155,7 +152,10 @@ class Clock V8_FINAL {
   }
 
   Time NowFromSystemTime() {
-    ScopedLock sl(mutex_);
+    // This must be executed under lock.
+    LockGuard<Mutex> lock_guard(&mutex_);
+
+    // Resynchronize with the wallclock.
     initial_ticks_ = TimeTicks::Now();
     initial_time_ = CurrentWallclockTime();
     return initial_time_;
@@ -174,7 +174,7 @@ class Clock V8_FINAL {
 
   TimeTicks initial_ticks_;
   Time initial_time_;
-  Mutex* mutex_;
+  Mutex mutex_;
 };
 
 
@@ -396,15 +396,13 @@ class WindowsVistaTickClock V8_FINAL : public TickClock {
 
 class RolloverProtectedTickClock V8_FINAL : public TickClock {
  public:
-  RolloverProtectedTickClock()
-      : mutex_(OS::CreateMutex()), last_seen_now_(0), rollover_ms_(1) {
-    // We initialize rollover_ms_ to 1 to ensure that we will never
-    // return 0 from TimeTicks::HighResNow() and TimeTicks::Now() below.
-  }
-  virtual ~RolloverProtectedTickClock() { delete mutex_; }
+  // We initialize rollover_ms_ to 1 to ensure that we will never
+  // return 0 from TimeTicks::HighResNow() and TimeTicks::Now() below.
+  RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {}
+  virtual ~RolloverProtectedTickClock() {}
 
   virtual int64_t Now() V8_OVERRIDE {
-    ScopedLock sl(mutex_);
+    LockGuard<Mutex> lock_guard(&mutex_);
     // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
     // every ~49.7 days. We try to track rollover ourselves, which works if
     // TimeTicks::Now() is called at least every 49 days.
@@ -420,7 +418,7 @@ class RolloverProtectedTickClock V8_FINAL : public TickClock {
   }
 
  private:
-  Mutex* mutex_;
+  Mutex mutex_;
   DWORD last_seen_now_;
   int64_t rollover_ms_;
 };
index 59ef278..c5551e1 100644 (file)
@@ -418,12 +418,12 @@ class SamplerThread : public Thread {
       : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
         interval_(interval) {}
 
-  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
-  static void TearDown() { delete mutex_; }
+  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
+  static void TearDown() { delete mutex_; mutex_ = NULL; }
 
   static void AddActiveSampler(Sampler* sampler) {
     bool need_to_start = false;
-    ScopedLock lock(mutex_);
+    LockGuard<Mutex> lock_guard(mutex_);
     if (instance_ == NULL) {
       // Start a thread that will send SIGPROF signal to VM threads,
       // when CPU profiling will be enabled.
@@ -445,7 +445,7 @@ class SamplerThread : public Thread {
   static void RemoveActiveSampler(Sampler* sampler) {
     SamplerThread* instance_to_remove = NULL;
     {
-      ScopedLock lock(mutex_);
+      LockGuard<Mutex> lock_guard(mutex_);
 
       ASSERT(sampler->IsActive());
       bool removed = instance_->active_samplers_.RemoveElement(sampler);
@@ -472,7 +472,7 @@ class SamplerThread : public Thread {
   virtual void Run() {
     while (true) {
       {
-        ScopedLock lock(mutex_);
+        LockGuard<Mutex> lock_guard(mutex_);
         if (active_samplers_.is_empty()) break;
         // When CPU profiling is enabled both JavaScript and C++ code is
         // profiled. We must not suspend.
index 8a5aa03..e62d381 100644 (file)
@@ -2043,8 +2043,8 @@ intptr_t FreeListCategory::Concatenate(FreeListCategory* category) {
     // This is safe (not going to deadlock) since Concatenate operations
     // are never performed on the same free lists at the same time in
     // reverse order.
-    ScopedLock lock_target(mutex_);
-    ScopedLock lock_source(category->mutex());
+    LockGuard<Mutex> target_lock_guard(mutex());
+    LockGuard<Mutex> source_lock_guard(category->mutex());
     free_bytes = category->available();
     if (end_ == NULL) {
       end_ = category->end();
index aa864b6..7f8ab5e 100644 (file)
@@ -32,6 +32,7 @@
 #include "hashmap.h"
 #include "list.h"
 #include "log.h"
+#include "platform/mutex.h"
 #include "v8utils.h"
 
 namespace v8 {
@@ -1445,13 +1446,8 @@ class FreeListCategory {
   FreeListCategory() :
       top_(NULL),
       end_(NULL),
-      mutex_(OS::CreateMutex()),
       available_(0) {}
 
-  ~FreeListCategory() {
-    delete mutex_;
-  }
-
   intptr_t Concatenate(FreeListCategory* category);
 
   void Reset();
@@ -1477,7 +1473,7 @@ class FreeListCategory {
   int available() const { return available_; }
   void set_available(int available) { available_ = available; }
 
-  Mutex* mutex() { return mutex_; }
+  Mutex* mutex() { return &mutex_; }
 
 #ifdef DEBUG
   intptr_t SumFreeList();
@@ -1487,7 +1483,7 @@ class FreeListCategory {
  private:
   FreeListNode* top_;
   FreeListNode* end_;
-  Mutex* mutex_;
+  Mutex mutex_;
 
   // Total available bytes in all blocks of this free list category.
   int available_;
index 2933a94..7d2294e 100644 (file)
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -135,7 +135,7 @@ static void seed_random(uint32_t* state) {
       state[i] = FLAG_random_seed;
     } else if (entropy_source != NULL) {
       uint32_t val;
-      ScopedLock lock(entropy_mutex.Pointer());
+      LockGuard<Mutex> lock_guard(entropy_mutex.Pointer());
       entropy_source(reinterpret_cast<unsigned char*>(&val), sizeof(uint32_t));
       state[i] = val;
     } else {
index 8a1cc17..95187e6 100644 (file)
@@ -163,6 +163,7 @@ class Deserializer;
 class MessageLocation;
 class VirtualMemory;
 class Mutex;
+class RecursiveMutex;
 
 typedef bool (*WeakSlotCallback)(Object** pointer);
 
index 2df187a..c1f20b1 100644 (file)
@@ -214,7 +214,7 @@ bool ThreadManager::RestoreThread() {
 
 
 void ThreadManager::Lock() {
-  mutex_->Lock();
+  mutex_.Lock();
   mutex_owner_ = ThreadId::Current();
   ASSERT(IsLockedByCurrentThread());
 }
@@ -222,7 +222,7 @@ void ThreadManager::Lock() {
 
 void ThreadManager::Unlock() {
   mutex_owner_ = ThreadId::Invalid();
-  mutex_->Unlock();
+  mutex_.Unlock();
 }
 
 
@@ -303,8 +303,7 @@ ThreadState* ThreadState::Next() {
 // be distinguished from not having a thread id at all (since NULL is
 // defined as 0.)
 ThreadManager::ThreadManager()
-    : mutex_(OS::CreateMutex()),
-      mutex_owner_(ThreadId::Invalid()),
+    : mutex_owner_(ThreadId::Invalid()),
       lazily_archived_thread_(ThreadId::Invalid()),
       lazily_archived_thread_state_(NULL),
       free_anchor_(NULL),
@@ -315,7 +314,6 @@ ThreadManager::ThreadManager()
 
 
 ThreadManager::~ThreadManager() {
-  delete mutex_;
   DeleteThreadStateList(free_anchor_);
   DeleteThreadStateList(in_use_anchor_);
 }
index 8dce860..b8ed817 100644 (file)
@@ -119,7 +119,7 @@ class ThreadManager {
 
   void EagerlyArchiveThread();
 
-  Mutex* mutex_;
+  Mutex mutex_;
   ThreadId mutex_owner_;
   ThreadId lazily_archived_thread_;
   ThreadState* lazily_archived_thread_state_;
index 2443685..98b0120 100644 (file)
@@ -95,7 +95,6 @@
 #undef ANY
 #undef IGNORE
 #undef GetObject
-#undef CreateMutex
 #undef CreateSemaphore
 #undef Yield
 
index 47efae1..051d382 100644 (file)
@@ -84,6 +84,7 @@
         'test-lockers.cc',
         'test-log.cc',
         'test-mark-compact.cc',
+        'test-mutex.cc',
         'test-object-observe.cc',
         'test-parsing.cc',
         'test-platform.cc',
index 9281337..c12cb58 100644 (file)
@@ -4678,14 +4678,13 @@ class ThreadBarrier {
  private:
   int num_threads_;
   int num_blocked_;
-  v8::internal::Mutex* lock_;
+  v8::internal::Mutex lock_;
   v8::internal::Semaphore* sem_;
   bool invalid_;
 };
 
 ThreadBarrier::ThreadBarrier(int num_threads)
     : num_threads_(num_threads), num_blocked_(0) {
-  lock_ = OS::CreateMutex();
   sem_ = OS::CreateSemaphore(0);
   invalid_ = false;  // A barrier may only be used once.  Then it is invalid.
 }
@@ -4694,14 +4693,12 @@ ThreadBarrier::ThreadBarrier(int num_threads)
 // Do not call, due to race condition with Wait().
 // Could be resolved with Pthread condition variables.
 ThreadBarrier::~ThreadBarrier() {
-  lock_->Lock();
-  delete lock_;
   delete sem_;
 }
 
 
 void ThreadBarrier::Wait() {
-  lock_->Lock();
+  lock_.Lock();
   CHECK(!invalid_);
   if (num_blocked_ == num_threads_ - 1) {
     // Signal and unblock all waiting threads.
@@ -4711,10 +4708,10 @@ void ThreadBarrier::Wait() {
     invalid_ = true;
     printf("BARRIER\n\n");
     fflush(stdout);
-    lock_->Unlock();
+    lock_.Unlock();
   } else {  // Wait for the semaphore.
     ++num_blocked_;
-    lock_->Unlock();  // Potential race condition with destructor because
+    lock_.Unlock();  // Potential race condition with destructor because
     sem_->Wait();  // these two lines are not atomic.
   }
 }
index d4387d0..0603e44 100644 (file)
 using namespace ::v8::internal;
 
 
-// Simple test of locking logic
-TEST(Simple) {
-  Mutex* mutex = OS::CreateMutex();
-  CHECK_EQ(0, mutex->Lock());  // acquire the lock with the right token
-  CHECK_EQ(0, mutex->Unlock());  // can unlock with the right token
-  delete mutex;
-}
-
-
-TEST(MultiLock) {
-  Mutex* mutex = OS::CreateMutex();
-  CHECK_EQ(0, mutex->Lock());
-  CHECK_EQ(0, mutex->Unlock());
-  delete mutex;
-}
-
-
-TEST(ShallowLock) {
-  Mutex* mutex = OS::CreateMutex();
-  CHECK_EQ(0, mutex->Lock());
-  CHECK_EQ(0, mutex->Unlock());
-  CHECK_EQ(0, mutex->Lock());
-  CHECK_EQ(0, mutex->Unlock());
-  delete mutex;
-}
-
-
 TEST(SemaphoreTimeout) {
   bool ok;
   Semaphore* sem = OS::CreateSemaphore(0);
diff --git a/test/cctest/test-mutex.cc b/test/cctest/test-mutex.cc
new file mode 100644 (file)
index 0000000..cdc829f
--- /dev/null
@@ -0,0 +1,118 @@
+// 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 <cstdlib>
+
+#include "v8.h"
+
+#include "cctest.h"
+#include "platform/mutex.h"
+
+using namespace ::v8::internal;
+
+
+TEST(LockGuardMutex) {
+  Mutex mutex;
+  { LockGuard<Mutex> lock_guard(&mutex);
+  }
+  { LockGuard<Mutex> lock_guard(&mutex);
+  }
+}
+
+
+TEST(LockGuardRecursiveMutex) {
+  RecursiveMutex recursive_mutex;
+  { LockGuard<RecursiveMutex> lock_guard(&recursive_mutex);
+  }
+  { LockGuard<RecursiveMutex> lock_guard1(&recursive_mutex);
+    LockGuard<RecursiveMutex> lock_guard2(&recursive_mutex);
+  }
+}
+
+
+TEST(LockGuardLazyMutex) {
+  LazyMutex lazy_mutex = LAZY_MUTEX_INITIALIZER;
+  { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer());
+  }
+  { LockGuard<Mutex> lock_guard(lazy_mutex.Pointer());
+  }
+}
+
+
+TEST(LockGuardLazyRecursiveMutex) {
+  LazyRecursiveMutex lazy_recursive_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
+  { LockGuard<RecursiveMutex> lock_guard(lazy_recursive_mutex.Pointer());
+  }
+  { LockGuard<RecursiveMutex> lock_guard1(lazy_recursive_mutex.Pointer());
+    LockGuard<RecursiveMutex> lock_guard2(lazy_recursive_mutex.Pointer());
+  }
+}
+
+
+TEST(MultipleMutexes) {
+  Mutex mutex1;
+  Mutex mutex2;
+  Mutex mutex3;
+  // Order 1
+  mutex1.Lock();
+  mutex2.Lock();
+  mutex3.Lock();
+  mutex1.Unlock();
+  mutex2.Unlock();
+  mutex3.Unlock();
+  // Order 2
+  mutex1.Lock();
+  mutex2.Lock();
+  mutex3.Lock();
+  mutex3.Unlock();
+  mutex2.Unlock();
+  mutex1.Unlock();
+}
+
+
+TEST(MultipleRecursiveMutexes) {
+  RecursiveMutex recursive_mutex1;
+  RecursiveMutex recursive_mutex2;
+  // Order 1
+  recursive_mutex1.Lock();
+  recursive_mutex2.Lock();
+  CHECK(recursive_mutex1.TryLock());
+  CHECK(recursive_mutex2.TryLock());
+  recursive_mutex1.Unlock();
+  recursive_mutex1.Unlock();
+  recursive_mutex2.Unlock();
+  recursive_mutex2.Unlock();
+  // Order 2
+  recursive_mutex1.Lock();
+  CHECK(recursive_mutex1.TryLock());
+  recursive_mutex2.Lock();
+  CHECK(recursive_mutex2.TryLock());
+  recursive_mutex2.Unlock();
+  recursive_mutex1.Unlock();
+  recursive_mutex2.Unlock();
+  recursive_mutex1.Unlock();
+}
index 6bb2902..7347aac 100644 (file)
@@ -52,18 +52,16 @@ static void LoopIncrement(Mutex* mutex, int rem) {
     int count = 0;
     int last_count = -1;
     do {
-      CHECK_EQ(0, mutex->Lock());
+      LockGuard<Mutex> lock_guard(mutex);
       count = busy_lock_counter;
-      CHECK_EQ(0, mutex->Unlock());
       yield();
     } while (count % 2 == rem && count < kLockCounterLimit);
     if (count >= kLockCounterLimit) break;
-    CHECK_EQ(0, mutex->Lock());
+    LockGuard<Mutex> lock_guard(mutex);
     CHECK_EQ(count, busy_lock_counter);
     CHECK(last_count == -1 || count == last_count + 1);
     busy_lock_counter++;
     last_count = count;
-    CHECK_EQ(0, mutex->Unlock());
     yield();
   }
 }
@@ -79,15 +77,14 @@ static void* RunTestBusyLock(void* arg) {
 // increment a variable.
 TEST(BusyLock) {
   pthread_t other;
-  Mutex* mutex = OS::CreateMutex();
+  Mutex mutex;
   int thread_created = pthread_create(&other,
                                       NULL,
                                       &RunTestBusyLock,
-                                      mutex);
+                                      &mutex);
   CHECK_EQ(0, thread_created);
-  LoopIncrement(mutex, 1);
+  LoopIncrement(&mutex, 1);
   pthread_join(other, NULL);
-  delete mutex;
 }
 
 
index 708defe..3f99b13 100644 (file)
         '../../src/platform/time.h',
         '../../src/platform-posix.h',
         '../../src/platform.h',
+        '../../src/platform/mutex.cc',
+        '../../src/platform/mutex.h',
         '../../src/preparse-data-format.h',
         '../../src/preparse-data.cc',
         '../../src/preparse-data.h',