Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -107,6 +107,12 @@ Error SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) override; + Error + SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override; + + Error + RemoveWatchpoint (lldb::addr_t addr) override; + void DoStopIDBumped (uint32_t newBumpId) override; @@ -182,7 +188,6 @@ Mutex m_mem_region_cache_mutex; std::unique_ptr m_coordinator_up; - HostThread m_coordinator_thread; // List of thread ids stepping with a breakpoint with the address of // the relevan breakpoint @@ -297,15 +302,6 @@ GetCrashReasonForSIGBUS(const siginfo_t *info); #endif - Error - StartCoordinatorThread (); - - static void* - CoordinatorThread (void *arg); - - void - StopCoordinatorThread (); - /// Stops monitoring the child process thread. void StopMonitor(); Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -1070,6 +1070,20 @@ PTRACE(PTRACE_DETACH, m_tid, nullptr, 0, 0, m_error); } + class LambdaOperation : public Operation + { + public: + typedef std::function Lambda; + + explicit LambdaOperation(Lambda &&lambda) : m_lambda(std::move(lambda)) {} + + // We assume the lambda has captured the NativeProcessLinux instance if it needed it. + void Execute(NativeProcessLinux *) override { m_lambda(); } + + private: + Lambda m_lambda; + }; + } // end of anonymous namespace // Simple helper function to ensure flags are enabled on the given file @@ -1105,7 +1119,8 @@ // pipe, and the completion of the operation is signalled over the semaphore. // - thread exit event: this is signaled from the Monitor destructor by closing the write end // of the command pipe. -class NativeProcessLinux::Monitor { +class NativeProcessLinux::Monitor +{ private: // The initial monitor operation (launch or attach). It returns a inferior process id. std::unique_ptr m_initial_operation_up; @@ -1617,8 +1632,7 @@ m_supports_mem_region (eLazyBoolCalculate), m_mem_region_cache (), m_mem_region_cache_mutex (), - m_coordinator_up (new ThreadStateCoordinator (GetThreadLoggerFunction ())), - m_coordinator_thread () + m_coordinator_up (new ThreadStateCoordinator (GetThreadLoggerFunction ())) { } @@ -1652,10 +1666,6 @@ StartMonitorThread ([&] (Error &e) { return Launch(args.get(), e); }, error); if (!error.Success ()) return; - - error = StartCoordinatorThread (); - if (!error.Success ()) - return; } void @@ -1705,10 +1715,6 @@ StartMonitorThread ([=] (Error &e) { return Attach(pid, e); }, error); if (!error.Success ()) return; - - error = StartCoordinatorThread (); - if (!error.Success ()) - return; } void @@ -2946,6 +2952,9 @@ Error NativeProcessLinux::Resume (const ResumeActionList &resume_actions) { + Error error; + LambdaOperation op( [&] { + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); if (log) log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ()); @@ -2971,9 +2980,9 @@ if (action->state == eStateStepping) { - Error error = SetupSoftwareSingleStepping(thread_sp); + error = SetupSoftwareSingleStepping(thread_sp); if (error.Fail()) - return error; + return; } } } @@ -3055,8 +3064,9 @@ break; default: - return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64, + error = Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ()); + return; } } @@ -3080,7 +3090,11 @@ }); } - return Error(); + }); + + m_monitor_up->DoOperation(&op); + + return error; } Error @@ -3129,6 +3143,9 @@ Error NativeProcessLinux::Interrupt () { + Error error; + LambdaOperation op( [&] { + // Pick a running thread (or if none, a not-dead stopped thread) as // the chosen thread that will be the stop-reason thread. Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -3165,11 +3182,11 @@ if (!running_thread_sp && !stopped_thread_sp) { - Error error("found no running/stepping or live stopped threads as target for interrupt"); + error = Error("found no running/stepping or live stopped threads as target for interrupt"); if (log) log->Printf ("NativeProcessLinux::%s skipping due to error: %s", __FUNCTION__, error.AsCString ()); - return error; + return; } NativeThreadProtocolSP deferred_signal_thread_sp = running_thread_sp ? running_thread_sp : stopped_thread_sp; @@ -3193,7 +3210,11 @@ // Tell the process delegate that the process is in a stopped state. SetState (StateType::eStateStopped, true); }); - return Error(); + }); + + m_monitor_up->DoOperation(&op); + + return error; } Error @@ -3797,6 +3818,30 @@ #endif Error +NativeProcessLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) +{ + Error error; + LambdaOperation op([&] { + error = NativeProcessProtocol::SetWatchpoint(addr, size, watch_flags, hardware); + }); + + m_monitor_up->DoOperation(&op); + return error; +} + +Error +NativeProcessLinux::RemoveWatchpoint (lldb::addr_t addr) +{ + Error error; + LambdaOperation op([&] { + error = NativeProcessProtocol::RemoveWatchpoint(addr); + }); + + m_monitor_up->DoOperation(&op); + return error; +} + +Error NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) { ReadOperation op(addr, buf, size, bytes_read); @@ -3955,74 +4000,9 @@ void NativeProcessLinux::StopMonitor() { - StopCoordinatorThread (); m_monitor_up.reset(); } -Error -NativeProcessLinux::StartCoordinatorThread () -{ - Error error; - static const char *g_thread_name = "lldb.process.linux.ts_coordinator"; - Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - - // Skip if thread is already running - if (m_coordinator_thread.IsJoinable()) - { - error.SetErrorString ("ThreadStateCoordinator's run loop is already running"); - if (log) - log->Printf ("NativeProcessLinux::%s %s", __FUNCTION__, error.AsCString ()); - return error; - } - - // Enable verbose logging if lldb thread logging is enabled. - m_coordinator_up->LogEnableEventProcessing (log != nullptr); - - if (log) - log->Printf ("NativeProcessLinux::%s launching ThreadStateCoordinator thread for pid %" PRIu64, __FUNCTION__, GetID ()); - m_coordinator_thread = ThreadLauncher::LaunchThread(g_thread_name, CoordinatorThread, this, &error); - return error; -} - -void * -NativeProcessLinux::CoordinatorThread (void *arg) -{ - Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - - NativeProcessLinux *const process = static_cast (arg); - assert (process && "null process passed to CoordinatorThread"); - if (!process) - { - if (log) - log->Printf ("NativeProcessLinux::%s null process, exiting ThreadStateCoordinator processing loop", __FUNCTION__); - return nullptr; - } - - // Run the thread state coordinator loop until it is done. This call uses - // efficient waiting for an event to be ready. - while (process->m_coordinator_up->ProcessNextEvent () == ThreadStateCoordinator::eventLoopResultContinue) - { - } - - if (log) - log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " exiting ThreadStateCoordinator processing loop due to coordinator indicating completion", __FUNCTION__, process->GetID ()); - - return nullptr; -} - -void -NativeProcessLinux::StopCoordinatorThread() -{ - Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("NativeProcessLinux::%s requesting ThreadStateCoordinator stop for pid %" PRIu64, __FUNCTION__, GetID ()); - - // Tell the coordinator we're done. This will cause the coordinator - // run loop thread to exit when the processing queue hits this message. - m_coordinator_up->StopCoordinator (); - m_coordinator_thread.Join (nullptr); -} - bool NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id) { Index: source/Plugins/Process/Linux/ThreadStateCoordinator.h =================================================================== --- source/Plugins/Process/Linux/ThreadStateCoordinator.h +++ source/Plugins/Process/Linux/ThreadStateCoordinator.h @@ -10,10 +10,8 @@ #ifndef lldb_ThreadStateCoordinator_h #define lldb_ThreadStateCoordinator_h -#include #include #include -#include #include #include @@ -126,24 +124,9 @@ // Indicate the calling process did an exec and that the thread state // should be 100% cleared. - // - // Note this will clear out any pending notifications, but will not stop - // a notification currently in progress via ProcessNextEvent(). void ResetForExec (); - // Indicate when the coordinator should shut down. - void - StopCoordinator (); - - // Process the next event, returning false when the coordinator is all done. - // This call is synchronous and blocks when there are no events pending. - // Expected usage is to run this in a separate thread until the function - // returns false. Always call this from the same thread. The processing - // logic assumes the execution of this is implicitly serialized. - EventLoopResult - ProcessNextEvent (); - // Enable/disable verbose logging of event processing. void LogEnableEventProcessing (bool enabled); @@ -159,13 +142,10 @@ class EventThreadDeath; class EventRequestResume; - class EventStopCoordinator; class EventReset; typedef std::shared_ptr EventBaseSP; - typedef std::queue QueueType; - enum class ThreadState { Running, @@ -181,12 +161,10 @@ typedef std::unordered_map TIDContextMap; - // Private member functions. - void - EnqueueEvent (EventBaseSP event_sp); + std::mutex m_event_mutex; // Serializes execution of ProcessEvent. - EventBaseSP - DequeueEventWithWait (); + void + ProcessEvent (const EventBaseSP &event_sp); void SetPendingNotification (const EventBaseSP &event_sp); @@ -215,14 +193,6 @@ // Member variables. LogFunction m_log_function; - QueueType m_event_queue; - // For now we do simple read/write lock strategy with efficient wait-for-data. - // We can replace with an entirely non-blocking queue later but we still want the - // reader to sleep when nothing is available - this will be a bursty but infrequent - // event mechanism. - std::condition_variable m_queue_condition; - std::mutex m_queue_mutex; - EventBaseSP m_pending_notification_sp; // Maps known TIDs to ThreadContext. Index: source/Plugins/Process/Linux/ThreadStateCoordinator.cpp =================================================================== --- source/Plugins/Process/Linux/ThreadStateCoordinator.cpp +++ source/Plugins/Process/Linux/ThreadStateCoordinator.cpp @@ -46,29 +46,6 @@ //===----------------------------------------------------------------------===// -class ThreadStateCoordinator::EventStopCoordinator : public ThreadStateCoordinator::EventBase -{ -public: - EventStopCoordinator (): - EventBase () - { - } - - EventLoopResult - ProcessEvent(ThreadStateCoordinator &coordinator) override - { - return eventLoopResultStop; - } - - std::string - GetDescription () override - { - return "EventStopCoordinator"; - } -}; - -//===----------------------------------------------------------------------===// - class ThreadStateCoordinator::EventCallAfterThreadsStop : public ThreadStateCoordinator::EventBase { public: @@ -588,42 +565,12 @@ ThreadStateCoordinator::ThreadStateCoordinator (const LogFunction &log_function) : m_log_function (log_function), - m_event_queue (), - m_queue_condition (), - m_queue_mutex (), m_tid_map (), m_log_event_processing (false) { } void -ThreadStateCoordinator::EnqueueEvent (EventBaseSP event_sp) -{ - std::lock_guard lock (m_queue_mutex); - - m_event_queue.push (event_sp); - if (m_log_event_processing) - Log ("ThreadStateCoordinator::%s enqueued event: %s", __FUNCTION__, event_sp->GetDescription ().c_str ()); - - m_queue_condition.notify_one (); -} - -ThreadStateCoordinator::EventBaseSP -ThreadStateCoordinator::DequeueEventWithWait () -{ - // Wait for an event to be present. - std::unique_lock lock (m_queue_mutex); - m_queue_condition.wait (lock, - [this] { return !m_event_queue.empty (); }); - - // Grab the event and pop it off the queue. - EventBaseSP event_sp = m_event_queue.front (); - m_event_queue.pop (); - - return event_sp; -} - -void ThreadStateCoordinator::SetPendingNotification (const EventBaseSP &event_sp) { assert (event_sp && "null event_sp"); @@ -653,11 +600,11 @@ const ThreadIDFunction &call_after_function, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventCallAfterThreadsStop (triggering_tid, - wait_for_stop_tids, - request_thread_stop_function, - call_after_function, - error_function))); + ProcessEvent(EventBaseSP(new EventCallAfterThreadsStop (triggering_tid, + wait_for_stop_tids, + request_thread_stop_function, + call_after_function, + error_function))); } void @@ -666,10 +613,10 @@ const ThreadIDFunction &call_after_function, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventCallAfterThreadsStop (triggering_tid, - request_thread_stop_function, - call_after_function, - error_function))); + ProcessEvent(EventBaseSP(new EventCallAfterThreadsStop (triggering_tid, + request_thread_stop_function, + call_after_function, + error_function))); } void @@ -679,11 +626,11 @@ const ThreadIDFunction &call_after_function, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventCallAfterThreadsStop (triggering_tid, - request_thread_stop_function, - call_after_function, - skip_stop_request_tids, - error_function))); + ProcessEvent(EventBaseSP(new EventCallAfterThreadsStop (triggering_tid, + request_thread_stop_function, + call_after_function, + skip_stop_request_tids, + error_function))); } @@ -826,7 +773,7 @@ bool initiated_by_llgs, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventThreadStopped (tid, initiated_by_llgs, error_function))); + ProcessEvent(EventBaseSP(new EventThreadStopped (tid, initiated_by_llgs, error_function))); } void @@ -834,7 +781,7 @@ const ResumeThreadFunction &request_thread_resume_function, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, true))); + ProcessEvent(EventBaseSP(new EventRequestResume (tid, request_thread_resume_function, error_function, true))); } void @@ -842,7 +789,7 @@ const ResumeThreadFunction &request_thread_resume_function, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, false))); + ProcessEvent(EventBaseSP(new EventRequestResume (tid, request_thread_resume_function, error_function, false))); } void @@ -850,56 +797,26 @@ bool is_stopped, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventThreadCreate (tid, is_stopped, error_function))); + ProcessEvent(EventBaseSP(new EventThreadCreate (tid, is_stopped, error_function))); } void ThreadStateCoordinator::NotifyThreadDeath (lldb::tid_t tid, const ErrorFunction &error_function) { - EnqueueEvent (EventBaseSP (new EventThreadDeath (tid, error_function))); + ProcessEvent(EventBaseSP(new EventThreadDeath (tid, error_function))); } void ThreadStateCoordinator::ResetForExec () { - std::lock_guard lock (m_queue_mutex); - - // Remove everything from the queue. This is the only - // state mutation that takes place outside the processing - // loop. - QueueType empty_queue; - m_event_queue.swap (empty_queue); - - // Do the real clear behavior on the the queue to eliminate - // the chance that processing of a dequeued earlier event is - // overlapping with the clearing of state here. Push it - // directly because we need to have this happen with the lock, - // and so far I only have this one place that needs a no-lock - // variant. - m_event_queue.push (EventBaseSP (new EventReset ())); + ProcessEvent(EventBaseSP(new EventReset())); } void -ThreadStateCoordinator::StopCoordinator () +ThreadStateCoordinator::ProcessEvent (const EventBaseSP &event_sp) { - EnqueueEvent (EventBaseSP (new EventStopCoordinator ())); -} - -ThreadStateCoordinator::EventLoopResult -ThreadStateCoordinator::ProcessNextEvent () -{ - // Dequeue the next event, synchronous. - if (m_log_event_processing) - Log ("ThreadStateCoordinator::%s about to dequeue next event in blocking mode", __FUNCTION__); - - EventBaseSP event_sp = DequeueEventWithWait(); - assert (event_sp && "event should never be null"); - if (!event_sp) - { - Log ("ThreadStateCoordinator::%s error: event_sp was null, signaling exit of event loop.", __FUNCTION__); - return eventLoopResultStop; - } + std::lock_guard lock(m_event_mutex); if (m_log_event_processing) { @@ -907,15 +824,12 @@ } // Process the event. - const EventLoopResult result = event_sp->ProcessEvent (*this); + event_sp->ProcessEvent (*this); if (m_log_event_processing) { - Log ("ThreadStateCoordinator::%s event processing returned value %s", __FUNCTION__, - result == eventLoopResultContinue ? "eventLoopResultContinue" : "eventLoopResultStop"); + Log ("ThreadStateCoordinator::%s event processing done", __FUNCTION__); } - - return result; } void