From e76482f2daa9f88e54928f07e89a7a2ba7ba1703 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Thu, 29 Aug 2013 09:58:30 +0000 Subject: [PATCH] Cleanup Mutex and related classes. 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 --- src/assembler.cc | 5 +- src/d8-debug.cc | 4 +- src/d8-debug.h | 3 +- src/d8.cc | 5 +- src/d8.h | 2 +- src/debug-agent.cc | 8 +- src/debug-agent.h | 4 +- src/debug.cc | 39 +++---- src/debug.h | 11 +- src/gdb-jit.cc | 6 +- src/heap.cc | 4 +- src/heap.h | 2 +- src/isolate.cc | 22 ++-- src/isolate.h | 16 +-- src/log-utils.cc | 7 +- src/log-utils.h | 4 +- src/optimizing-compiler-thread.cc | 8 +- src/optimizing-compiler-thread.h | 11 +- src/platform-cygwin.cc | 4 +- src/platform-freebsd.cc | 4 +- src/platform-linux.cc | 4 +- src/platform-macos.cc | 4 +- src/platform-openbsd.cc | 4 +- src/platform-posix.cc | 42 ------- src/platform-solaris.cc | 4 +- src/platform-win32.cc | 44 +------- src/platform.h | 73 +----------- src/platform/mutex.cc | 223 +++++++++++++++++++++++++++++++++++++ src/platform/mutex.h | 223 +++++++++++++++++++++++++++++++++++++ src/platform/time.cc | 28 +++-- src/sampler.cc | 10 +- src/spaces.cc | 4 +- src/spaces.h | 10 +- src/v8.cc | 2 +- src/v8globals.h | 1 + src/v8threads.cc | 8 +- src/v8threads.h | 2 +- src/win32-headers.h | 1 - test/cctest/cctest.gyp | 1 + test/cctest/test-debug.cc | 11 +- test/cctest/test-lock.cc | 27 ----- test/cctest/test-mutex.cc | 118 ++++++++++++++++++++ test/cctest/test-platform-linux.cc | 13 +-- tools/gyp/v8.gyp | 2 + 44 files changed, 685 insertions(+), 343 deletions(-) create mode 100644 src/platform/mutex.cc create mode 100644 src/platform/mutex.h create mode 100644 test/cctest/test-mutex.cc diff --git a/src/assembler.cc b/src/assembler.cc index ae8a0b5..a9587f3 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -891,7 +891,7 @@ void ExternalReference::SetUp() { double_constants.the_hole_nan = BitCast(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 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(); } diff --git a/src/d8-debug.cc b/src/d8-debug.cc index 9a72518..3adeb71 100644 --- a/src/d8-debug.cc +++ b/src/d8-debug.cc @@ -248,7 +248,7 @@ void RemoteDebugger::ConnectionClosed() { void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) { - i::ScopedLock lock(event_access_); + i::LockGuard 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 lock_guard(&event_access_); ASSERT(head_ != NULL); RemoteDebuggerEvent* result = head_; head_ = head_->next(); diff --git a/src/d8-debug.h b/src/d8-debug.h index 2386b6b..276cbd8 100644 --- a/src/d8-debug.h +++ b/src/d8-debug.h @@ -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_; diff --git a/src/d8.cc b/src/d8.cc index fe4d744..4a10550 100644 --- 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 Shell::utility_context_; #endif // V8_SHARED @@ -925,7 +925,7 @@ void Shell::InitializeDebugger(Isolate* isolate) { Local 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 lock_guard(&context_mutex_); #endif // V8_SHARED // Initialize the global objects Handle 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 diff --git a/src/d8.h b/src/d8.h index 6008d35..fbc7a10 100644 --- 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); diff --git a/src/debug-agent.cc b/src/debug-agent.cc index 811c00e..b390cc5 100644 --- a/src/debug-agent.cc +++ b/src/debug-agent.cc @@ -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 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 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 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 session_access_guard(&session_access_); ASSERT(session == session_); if (session == session_) { session_->Shutdown(); diff --git a/src/debug-agent.h b/src/debug-agent.h index 6115190..e78ed67 100644 --- a/src/debug-agent.h +++ b/src/debug-agent.h @@ -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_; diff --git a/src/debug.cc b/src/debug.cc index bf208b2..dfe7b97 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -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 callback, void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) { - ScopedLock with(debugger_access_); + LockGuard 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 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 with(debugger_access_); if (message_handler_ != NULL) { message_handler_(message); @@ -3352,7 +3349,7 @@ void Debugger::ProcessCommand(Vector command, MessageDispatchHelperThread* dispatch_thread; { - ScopedLock with(dispatch_handler_access_); + LockGuard 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 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 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 lock_guard(&mutex_); return queue_.IsEmpty(); } CommandMessage LockingCommandMessageQueue::Get() { - ScopedLock sl(lock_); + LockGuard 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 lock_guard(&mutex_); queue_.Put(message); logger_->DebugEvent("Put", message.text()); } void LockingCommandMessageQueue::Clear() { - ScopedLock sl(lock_); + LockGuard 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 lock_guard(&mutex_); if (already_signalled_) { return; } @@ -3859,7 +3848,7 @@ void MessageDispatchHelperThread::Run() { while (true) { sem_->Wait(); { - ScopedLock lock(mutex_); + LockGuard lock_guard(&mutex_); already_signalled_ = false; } { diff --git a/src/debug.h b/src/debug.h index 67debc7..2333b07 100644 --- a/src/debug.h +++ b/src/debug.h @@ -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 lock_guard(debugger_access_); // Check whether the message handler was been cleared. if (debugger_unload_pending_) { @@ -918,7 +917,7 @@ class Debugger { Handle event_data); void ListenersChanged(); - Mutex* debugger_access_; // Mutex guarding debugger variables. + RecursiveMutex* debugger_access_; // Mutex guarding debugger variables. Handle event_listener_; // Global handle to listener. Handle 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); diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc index 664673f..21cfd22 100644 --- a/src/gdb-jit.cc +++ b/src/gdb-jit.cc @@ -2063,7 +2063,7 @@ void GDBJITInterface::AddCode(const char* name, CompilationInfo* info) { if (!FLAG_gdbjit) return; - ScopedLock lock(mutex.Pointer()); + LockGuard 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 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 lock_guard(mutex.Pointer()); ASSERT(!IsLineInfoTagged(line_info)); HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); ASSERT(e->value == NULL); diff --git a/src/heap.cc b/src/heap.cc index 4fd478f..7bfb07e 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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 lock_guard(checkpoint_object_stats_mutex.Pointer()); Counters* counters = isolate()->counters(); #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ counters->count_of_##name()->Increment( \ diff --git a/src/heap.h b/src/heap.h index f0920b3..14b395f 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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: diff --git a/src/isolate.cc b/src/isolate.cc index 54329b7..d0b6d46 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -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 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 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 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 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 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 lock_guard(debugger_access()); if (NoBarrier_Load(&debugger_initialized_)) return; InitializeLoggingAndCounters(); debug_ = new Debug(this); diff --git a/src/isolate.h b/src/isolate.h index 751f995..2f09285 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -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: diff --git a/src/log-utils.cc b/src/log-utils.cc index 6bba882..98f4fdf 100644 --- a/src/log-utils.cc +++ b/src/log-utils.cc @@ -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(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); } diff --git a/src/log-utils.h b/src/log-utils.h index 861a826..ec8415e 100644 --- a/src/log-utils.h +++ b/src/log-utils.h @@ -107,7 +107,7 @@ class Log { private: Log* log_; - ScopedLock sl; + LockGuard 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. diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc index added33..1f77d5a 100644 --- a/src/optimizing-compiler-thread.cc +++ b/src/optimizing-compiler-thread.cc @@ -39,7 +39,7 @@ namespace internal { void OptimizingCompilerThread::Run() { #ifdef DEBUG - { ScopedLock lock(thread_id_mutex_); + { LockGuard 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 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 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 lock_guard(&thread_id_mutex_); return ThreadId::Current().ToInteger() == thread_id_; } #endif diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h index 1b06208..10ed420 100644 --- a/src/optimizing-compiler-thread.h +++ b/src/optimizing-compiler-thread.h @@ -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(CONTINUE)); NoBarrier_Store(&queue_length_, static_cast(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 input_queue_; UnboundQueue output_queue_; - Mutex* install_mutex_; + Mutex install_mutex_; volatile AtomicWord stop_thread_; volatile Atomic32 queue_length_; TimeDelta time_spent_compiling_; diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc index 4c7b017..7bedfe8 100644 --- a/src/platform-cygwin.cc +++ b/src/platform-cygwin.cc @@ -87,7 +87,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc index e0917fa..0b32b32 100644 --- a/src/platform-freebsd.cc +++ b/src/platform-freebsd.cc @@ -95,7 +95,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-linux.cc b/src/platform-linux.cc index b27c1fd..37b4b11 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -151,7 +151,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()) ^ (getpid() << 16); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-macos.cc b/src/platform-macos.cc index 9d8d076..7aa02a7 100644 --- a/src/platform-macos.cc +++ b/src/platform-macos.cc @@ -93,7 +93,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()) ^ (getpid() << 16); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc index a027944..114b8e2 100644 --- a/src/platform-openbsd.cc +++ b/src/platform-openbsd.cc @@ -93,7 +93,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()) ^ (getpid() << 16); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-posix.cc b/src/platform-posix.cc index dd6b77c..aaf0ca7 100644 --- a/src/platform-posix.cc +++ b/src/platform-posix.cc @@ -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. // diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc index b1d88af..dd5c7a0 100644 --- a/src/platform-solaris.cc +++ b/src/platform-solaris.cc @@ -110,7 +110,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()); srandom(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform-win32.cc b/src/platform-win32.cc index cdd9a4f..2775453 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -761,7 +761,7 @@ static void* highest_ever_allocated = reinterpret_cast(0); static void UpdateAllocatedSpaceLimits(void* address, int size) { ASSERT(limit_mutex != NULL); - ScopedLock lock(limit_mutex); + LockGuard 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(TimeCurrentMillis()); srand(static_cast(seed)); - limit_mutex = CreateMutex(); + limit_mutex = new Mutex(); } diff --git a/src/platform.h b/src/platform.h index 44817b4..5f93106 100644 --- a/src/platform.h +++ b/src/platform.h @@ -46,7 +46,7 @@ #include -#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 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 index 0000000..c8d75c7 --- /dev/null +++ b/src/platform/mutex.cc @@ -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 + +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 index 0000000..1940542 --- /dev/null +++ b/src/platform/mutex.h @@ -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 // 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 guard(my_mutex.Pointer()); +// // Do something. +// } +// +typedef LazyStaticInstance, + 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 guard(my_mutex.Pointer()); +// // Do something. +// } +// +typedef LazyStaticInstance, + 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 +class LockGuard V8_FINAL { + public: + explicit LockGuard(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } + ~LockGuard() { mutex_->Unlock(); } + + private: + Mutex* mutex_; + + LockGuard(const LockGuard& other) V8_DELETE; + LockGuard& operator=(const LockGuard& other) V8_DELETE; +}; + +} } // namespace v8::internal + +#endif // V8_PLATFORM_MUTEX_H_ diff --git a/src/platform/time.cc b/src/platform/time.cc index 927cb92..653eb14 100644 --- a/src/platform/time.cc +++ b/src/platform/time.cc @@ -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 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 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 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_; }; diff --git a/src/sampler.cc b/src/sampler.cc index 59ef278..c5551e1 100644 --- a/src/sampler.cc +++ b/src/sampler.cc @@ -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 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 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 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. diff --git a/src/spaces.cc b/src/spaces.cc index 8a5aa03..e62d381 100644 --- a/src/spaces.cc +++ b/src/spaces.cc @@ -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 target_lock_guard(mutex()); + LockGuard source_lock_guard(category->mutex()); free_bytes = category->available(); if (end_ == NULL) { end_ = category->end(); diff --git a/src/spaces.h b/src/spaces.h index aa864b6..7f8ab5e 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -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_; diff --git a/src/v8.cc b/src/v8.cc index 2933a94..7d2294e 100644 --- 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 lock_guard(entropy_mutex.Pointer()); entropy_source(reinterpret_cast(&val), sizeof(uint32_t)); state[i] = val; } else { diff --git a/src/v8globals.h b/src/v8globals.h index 8a1cc17..95187e6 100644 --- a/src/v8globals.h +++ b/src/v8globals.h @@ -163,6 +163,7 @@ class Deserializer; class MessageLocation; class VirtualMemory; class Mutex; +class RecursiveMutex; typedef bool (*WeakSlotCallback)(Object** pointer); diff --git a/src/v8threads.cc b/src/v8threads.cc index 2df187a..c1f20b1 100644 --- a/src/v8threads.cc +++ b/src/v8threads.cc @@ -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_); } diff --git a/src/v8threads.h b/src/v8threads.h index 8dce860..b8ed817 100644 --- a/src/v8threads.h +++ b/src/v8threads.h @@ -119,7 +119,7 @@ class ThreadManager { void EagerlyArchiveThread(); - Mutex* mutex_; + Mutex mutex_; ThreadId mutex_owner_; ThreadId lazily_archived_thread_; ThreadState* lazily_archived_thread_state_; diff --git a/src/win32-headers.h b/src/win32-headers.h index 2443685..98b0120 100644 --- a/src/win32-headers.h +++ b/src/win32-headers.h @@ -95,7 +95,6 @@ #undef ANY #undef IGNORE #undef GetObject -#undef CreateMutex #undef CreateSemaphore #undef Yield diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index 47efae1..051d382 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -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', diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 9281337..c12cb58 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -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. } } diff --git a/test/cctest/test-lock.cc b/test/cctest/test-lock.cc index d4387d0..0603e44 100644 --- a/test/cctest/test-lock.cc +++ b/test/cctest/test-lock.cc @@ -38,33 +38,6 @@ 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 index 0000000..cdc829f --- /dev/null +++ b/test/cctest/test-mutex.cc @@ -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 + +#include "v8.h" + +#include "cctest.h" +#include "platform/mutex.h" + +using namespace ::v8::internal; + + +TEST(LockGuardMutex) { + Mutex mutex; + { LockGuard lock_guard(&mutex); + } + { LockGuard lock_guard(&mutex); + } +} + + +TEST(LockGuardRecursiveMutex) { + RecursiveMutex recursive_mutex; + { LockGuard lock_guard(&recursive_mutex); + } + { LockGuard lock_guard1(&recursive_mutex); + LockGuard lock_guard2(&recursive_mutex); + } +} + + +TEST(LockGuardLazyMutex) { + LazyMutex lazy_mutex = LAZY_MUTEX_INITIALIZER; + { LockGuard lock_guard(lazy_mutex.Pointer()); + } + { LockGuard lock_guard(lazy_mutex.Pointer()); + } +} + + +TEST(LockGuardLazyRecursiveMutex) { + LazyRecursiveMutex lazy_recursive_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER; + { LockGuard lock_guard(lazy_recursive_mutex.Pointer()); + } + { LockGuard lock_guard1(lazy_recursive_mutex.Pointer()); + LockGuard 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(); +} diff --git a/test/cctest/test-platform-linux.cc b/test/cctest/test-platform-linux.cc index 6bb2902..7347aac 100644 --- a/test/cctest/test-platform-linux.cc +++ b/test/cctest/test-platform-linux.cc @@ -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 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 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; } diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 708defe..3f99b13 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -441,6 +441,8 @@ '../../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', -- 2.7.4