forked from OSchip/llvm-project
[LLGS] Get rid of the stdio forwarding thread
Summary: This commit removes the stdio forwarding thread in lldb-server in favor of a MainLoop callback. As in some situations we need to forcibly flush the stream ( => Read() is called from multiple places) and we still have multiple threads, I have had to additionally protect the communication instance with a mutex. Reviewers: ovyalov, tberghammer Subscribers: lldb-commits Differential Revision: http://reviews.llvm.org/D11296 llvm-svn: 242782
This commit is contained in:
parent
39e8823f84
commit
c7749c3acd
|
@ -731,10 +731,7 @@ GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProto
|
||||||
if (log)
|
if (log)
|
||||||
log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
|
||||||
|
|
||||||
// Send the exit result, and don't flush output.
|
PacketResult result = SendStopReasonForState(StateType::eStateExited);
|
||||||
// Note: flushing output here would join the inferior stdio reflection thread, which
|
|
||||||
// would gunk up the waitpid monitor thread that is calling this.
|
|
||||||
PacketResult result = SendStopReasonForState (StateType::eStateExited, false);
|
|
||||||
if (result != PacketResult::Success)
|
if (result != PacketResult::Success)
|
||||||
{
|
{
|
||||||
if (log)
|
if (log)
|
||||||
|
@ -752,22 +749,8 @@ GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME can't do this yet - since process state propagation is currently
|
|
||||||
// synchronous, it is running off the NativeProcessProtocol's innards and
|
|
||||||
// will tear down the NPP while it still has code to execute.
|
|
||||||
#if 0
|
|
||||||
// Clear the NativeProcessProtocol pointer.
|
|
||||||
{
|
|
||||||
Mutex::Locker locker (m_debugged_process_mutex);
|
|
||||||
m_debugged_process_sp.reset();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Close the pipe to the inferior terminal i/o if we launched it
|
// Close the pipe to the inferior terminal i/o if we launched it
|
||||||
// and set one up. Otherwise, 'k' and its flush of stdio could
|
// and set one up.
|
||||||
// end up waiting on a thread join that will never end. Consider
|
|
||||||
// adding a timeout to the connection thread join call so we
|
|
||||||
// can avoid that scenario altogether.
|
|
||||||
MaybeCloseInferiorTerminalConnection ();
|
MaybeCloseInferiorTerminalConnection ();
|
||||||
|
|
||||||
// We are ready to exit the debug monitor.
|
// We are ready to exit the debug monitor.
|
||||||
|
@ -793,7 +776,7 @@ GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProt
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// In all other cases, send the stop reason.
|
// In all other cases, send the stop reason.
|
||||||
PacketResult result = SendStopReasonForState (StateType::eStateStopped, false);
|
PacketResult result = SendStopReasonForState(StateType::eStateStopped);
|
||||||
if (result != PacketResult::Success)
|
if (result != PacketResult::Success)
|
||||||
{
|
{
|
||||||
if (log)
|
if (log)
|
||||||
|
@ -819,7 +802,7 @@ GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *pr
|
||||||
// Make sure we get all of the pending stdout/stderr from the inferior
|
// Make sure we get all of the pending stdout/stderr from the inferior
|
||||||
// and send it to the lldb host before we send the state change
|
// and send it to the lldb host before we send the state change
|
||||||
// notification
|
// notification
|
||||||
m_stdio_communication.SynchronizeWithReadThread();
|
SendProcessOutput();
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
|
@ -864,7 +847,6 @@ GDBRemoteCommunicationServerLLGS::DataAvailableCallback ()
|
||||||
if(log)
|
if(log)
|
||||||
log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting",
|
log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting",
|
||||||
__FUNCTION__);
|
__FUNCTION__);
|
||||||
m_read_handle_up.reset();
|
|
||||||
m_mainloop.RequestTermination();
|
m_mainloop.RequestTermination();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -885,7 +867,6 @@ GDBRemoteCommunicationServerLLGS::DataAvailableCallback ()
|
||||||
if(log)
|
if(log)
|
||||||
log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s",
|
log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s",
|
||||||
__FUNCTION__, error.AsCString());
|
__FUNCTION__, error.AsCString());
|
||||||
m_read_handle_up.reset();
|
|
||||||
m_mainloop.RequestTermination();
|
m_mainloop.RequestTermination();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -899,7 +880,7 @@ GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connecti
|
||||||
GDBRemoteCommunicationServer::SetConnection(connection.release());
|
GDBRemoteCommunicationServer::SetConnection(connection.release());
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
m_read_handle_up = m_mainloop.RegisterReadObject(read_object_sp,
|
m_network_handle_up = m_mainloop.RegisterReadObject(read_object_sp,
|
||||||
[this] (MainLoopBase &) { DataAvailableCallback(); }, error);
|
[this] (MainLoopBase &) { DataAvailableCallback(); }, error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -925,7 +906,7 @@ GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd)
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
|
|
||||||
// Set up the Read Thread for reading/handling process I/O
|
// Set up the reading/handling of process I/O
|
||||||
std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
|
std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
|
||||||
if (!conn_up)
|
if (!conn_up)
|
||||||
{
|
{
|
||||||
|
@ -933,6 +914,7 @@ GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mutex::Locker locker(m_stdio_communication_mutex);
|
||||||
m_stdio_communication.SetCloseOnEOF (false);
|
m_stdio_communication.SetCloseOnEOF (false);
|
||||||
m_stdio_communication.SetConnection (conn_up.release());
|
m_stdio_communication.SetConnection (conn_up.release());
|
||||||
if (!m_stdio_communication.IsConnected ())
|
if (!m_stdio_communication.IsConnected ())
|
||||||
|
@ -951,19 +933,55 @@ GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// output from the process must be forwarded over gdb-remote
|
// output from the process must be forwarded over gdb-remote
|
||||||
// create a thread to read the handle and send the data
|
m_stdio_handle_up = m_mainloop.RegisterReadObject(
|
||||||
m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
|
m_stdio_communication.GetConnection()->GetReadObject(),
|
||||||
m_stdio_communication.StartReadThread();
|
[this] (MainLoopBase &) { SendProcessOutput(); }, error);
|
||||||
|
if (! m_stdio_handle_up)
|
||||||
|
{
|
||||||
|
m_stdio_communication.Disconnect();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GDBRemoteCommunicationServerLLGS::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
|
GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding()
|
||||||
{
|
{
|
||||||
GDBRemoteCommunicationServerLLGS *server = reinterpret_cast<GDBRemoteCommunicationServerLLGS*> (baton);
|
Mutex::Locker locker(m_stdio_communication_mutex);
|
||||||
static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
|
m_stdio_handle_up.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GDBRemoteCommunicationServerLLGS::SendProcessOutput()
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
ConnectionStatus status;
|
||||||
|
Error error;
|
||||||
|
Mutex::Locker locker(m_stdio_communication_mutex);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
size_t bytes_read = m_stdio_communication.Read(buffer, sizeof buffer, 0, status, &error);
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case eConnectionStatusSuccess:
|
||||||
|
SendONotification(buffer, bytes_read);
|
||||||
|
break;
|
||||||
|
case eConnectionStatusLostConnection:
|
||||||
|
case eConnectionStatusEndOfFile:
|
||||||
|
case eConnectionStatusError:
|
||||||
|
case eConnectionStatusNoConnection:
|
||||||
|
if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS))
|
||||||
|
log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio forwarding as communication returned status %d (error: %s)", __FUNCTION__, status, error.AsCString());
|
||||||
|
m_stdio_handle_up.reset();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case eConnectionStatusInterrupted:
|
||||||
|
case eConnectionStatusTimedOut:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GDBRemoteCommunication::PacketResult
|
GDBRemoteCommunication::PacketResult
|
||||||
|
@ -1051,7 +1069,7 @@ GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushInferiorOutput ();
|
StopSTDIOForwarding();
|
||||||
|
|
||||||
// No OK response for kill packet.
|
// No OK response for kill packet.
|
||||||
// return SendOKResponse ();
|
// return SendOKResponse ();
|
||||||
|
@ -1384,11 +1402,11 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &
|
||||||
if (!m_debugged_process_sp)
|
if (!m_debugged_process_sp)
|
||||||
return SendErrorResponse (02);
|
return SendErrorResponse (02);
|
||||||
|
|
||||||
return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
|
return SendStopReasonForState (m_debugged_process_sp->GetState());
|
||||||
}
|
}
|
||||||
|
|
||||||
GDBRemoteCommunication::PacketResult
|
GDBRemoteCommunication::PacketResult
|
||||||
GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit)
|
GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state)
|
||||||
{
|
{
|
||||||
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
||||||
|
|
||||||
|
@ -1417,8 +1435,6 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType proces
|
||||||
case eStateInvalid:
|
case eStateInvalid:
|
||||||
case eStateUnloaded:
|
case eStateUnloaded:
|
||||||
case eStateExited:
|
case eStateExited:
|
||||||
if (flush_on_exit)
|
|
||||||
FlushInferiorOutput ();
|
|
||||||
return SendWResponse(m_debugged_process_sp.get());
|
return SendWResponse(m_debugged_process_sp.get());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1879,6 +1895,7 @@ GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet)
|
||||||
// TODO: enqueue this block in circular buffer and send window size to remote host
|
// TODO: enqueue this block in circular buffer and send window size to remote host
|
||||||
ConnectionStatus status;
|
ConnectionStatus status;
|
||||||
Error error;
|
Error error;
|
||||||
|
Mutex::Locker locker(m_stdio_communication_mutex);
|
||||||
m_stdio_communication.Write(tmp, read, status, &error);
|
m_stdio_communication.Write(tmp, read, status, &error);
|
||||||
if (error.Fail())
|
if (error.Fail())
|
||||||
{
|
{
|
||||||
|
@ -2623,7 +2640,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &pack
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify we attached by sending a stop packet.
|
// Notify we attached by sending a stop packet.
|
||||||
return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
|
return SendStopReasonForState (m_debugged_process_sp->GetState ());
|
||||||
}
|
}
|
||||||
|
|
||||||
GDBRemoteCommunication::PacketResult
|
GDBRemoteCommunication::PacketResult
|
||||||
|
@ -2631,6 +2648,8 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet)
|
||||||
{
|
{
|
||||||
Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
|
Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
|
||||||
|
|
||||||
|
StopSTDIOForwarding();
|
||||||
|
|
||||||
// Scope for mutex locker.
|
// Scope for mutex locker.
|
||||||
Mutex::Locker locker (m_spawned_pids_mutex);
|
Mutex::Locker locker (m_spawned_pids_mutex);
|
||||||
|
|
||||||
|
@ -2671,11 +2690,6 @@ GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet)
|
||||||
return SendIllFormedResponse (packet, "Invalid pid");
|
return SendIllFormedResponse (packet, "Invalid pid");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_stdio_communication.IsConnected ())
|
|
||||||
{
|
|
||||||
m_stdio_communication.StopReadThread ();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Error error = m_debugged_process_sp->Detach ();
|
const Error error = m_debugged_process_sp->Detach ();
|
||||||
if (error.Fail ())
|
if (error.Fail ())
|
||||||
{
|
{
|
||||||
|
@ -2839,26 +2853,12 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRem
|
||||||
return SendPacketNoLock(response.GetData(), response.GetSize());
|
return SendPacketNoLock(response.GetData(), response.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
GDBRemoteCommunicationServerLLGS::FlushInferiorOutput ()
|
|
||||||
{
|
|
||||||
// If we're not monitoring an inferior's terminal, ignore this.
|
|
||||||
if (!m_stdio_communication.IsConnected())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
|
|
||||||
if (log)
|
|
||||||
log->Printf ("GDBRemoteCommunicationServerLLGS::%s() called", __FUNCTION__);
|
|
||||||
|
|
||||||
// FIXME implement a timeout on the join.
|
|
||||||
m_stdio_communication.JoinReadThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection ()
|
GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection ()
|
||||||
{
|
{
|
||||||
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
||||||
|
|
||||||
|
Mutex::Locker locker(m_stdio_communication_mutex);
|
||||||
// Tell the stdio connection to shut down.
|
// Tell the stdio connection to shut down.
|
||||||
if (m_stdio_communication.IsConnected())
|
if (m_stdio_communication.IsConnected())
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,12 +119,16 @@ public:
|
||||||
protected:
|
protected:
|
||||||
lldb::PlatformSP m_platform_sp;
|
lldb::PlatformSP m_platform_sp;
|
||||||
MainLoop &m_mainloop;
|
MainLoop &m_mainloop;
|
||||||
MainLoop::ReadHandleUP m_read_handle_up;
|
MainLoop::ReadHandleUP m_network_handle_up;
|
||||||
lldb::tid_t m_current_tid;
|
lldb::tid_t m_current_tid;
|
||||||
lldb::tid_t m_continue_tid;
|
lldb::tid_t m_continue_tid;
|
||||||
Mutex m_debugged_process_mutex;
|
Mutex m_debugged_process_mutex;
|
||||||
NativeProcessProtocolSP m_debugged_process_sp;
|
NativeProcessProtocolSP m_debugged_process_sp;
|
||||||
|
|
||||||
|
Mutex m_stdio_communication_mutex; // Protects m_stdio_communication and m_stdio_handle_up
|
||||||
Communication m_stdio_communication;
|
Communication m_stdio_communication;
|
||||||
|
MainLoop::ReadHandleUP m_stdio_handle_up;
|
||||||
|
|
||||||
lldb::StateType m_inferior_prev_state;
|
lldb::StateType m_inferior_prev_state;
|
||||||
lldb::DataBufferSP m_active_auxv_buffer_sp;
|
lldb::DataBufferSP m_active_auxv_buffer_sp;
|
||||||
Mutex m_saved_registers_mutex;
|
Mutex m_saved_registers_mutex;
|
||||||
|
@ -142,7 +146,7 @@ protected:
|
||||||
SendStopReplyPacketForThread (lldb::tid_t tid);
|
SendStopReplyPacketForThread (lldb::tid_t tid);
|
||||||
|
|
||||||
PacketResult
|
PacketResult
|
||||||
SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
|
SendStopReasonForState (lldb::StateType process_state);
|
||||||
|
|
||||||
PacketResult
|
PacketResult
|
||||||
Handle_k (StringExtractorGDBRemote &packet);
|
Handle_k (StringExtractorGDBRemote &packet);
|
||||||
|
@ -264,9 +268,6 @@ protected:
|
||||||
Error
|
Error
|
||||||
SetSTDIOFileDescriptor (int fd);
|
SetSTDIOFileDescriptor (int fd);
|
||||||
|
|
||||||
static void
|
|
||||||
STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
|
|
||||||
|
|
||||||
FileSpec
|
FileSpec
|
||||||
FindModuleFile (const std::string& module_path, const ArchSpec& arch) override;
|
FindModuleFile (const std::string& module_path, const ArchSpec& arch) override;
|
||||||
|
|
||||||
|
@ -287,9 +288,6 @@ private:
|
||||||
void
|
void
|
||||||
HandleInferiorState_Stopped (NativeProcessProtocol *process);
|
HandleInferiorState_Stopped (NativeProcessProtocol *process);
|
||||||
|
|
||||||
void
|
|
||||||
FlushInferiorOutput ();
|
|
||||||
|
|
||||||
NativeThreadProtocolSP
|
NativeThreadProtocolSP
|
||||||
GetThreadFromSuffix (StringExtractorGDBRemote &packet);
|
GetThreadFromSuffix (StringExtractorGDBRemote &packet);
|
||||||
|
|
||||||
|
@ -308,6 +306,12 @@ private:
|
||||||
void
|
void
|
||||||
DataAvailableCallback ();
|
DataAvailableCallback ();
|
||||||
|
|
||||||
|
void
|
||||||
|
SendProcessOutput ();
|
||||||
|
|
||||||
|
void
|
||||||
|
StopSTDIOForwarding();
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// For GDBRemoteCommunicationServerLLGS only
|
// For GDBRemoteCommunicationServerLLGS only
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue