summaryrefslogtreecommitdiff
path: root/src/debug/debug-pal/unix/twowaypipe.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/debug-pal/unix/twowaypipe.cpp')
-rw-r--r--src/debug/debug-pal/unix/twowaypipe.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/debug/debug-pal/unix/twowaypipe.cpp b/src/debug/debug-pal/unix/twowaypipe.cpp
new file mode 100644
index 0000000000..db4599aeb9
--- /dev/null
+++ b/src/debug/debug-pal/unix/twowaypipe.cpp
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <pal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <pal_assert.h>
+#include "twowaypipe.h"
+
+// Creates a server side of the pipe.
+// Id is used to create pipes names and uniquely identify the pipe on the machine.
+// true - success, false - failure (use GetLastError() for more details)
+bool TwoWayPipe::CreateServer(DWORD id)
+{
+ _ASSERTE(m_state == NotInitialized);
+ if (m_state != NotInitialized)
+ return false;
+
+ m_id = id;
+ PAL_GetTransportPipeName(m_inPipeName, id, "in");
+ PAL_GetTransportPipeName(m_outPipeName, id, "out");
+
+ if (mkfifo(m_inPipeName, S_IRWXU) == -1)
+ {
+ return false;
+ }
+
+ if (mkfifo(m_outPipeName, S_IRWXU) == -1)
+ {
+ unlink(m_inPipeName);
+ return false;
+ }
+
+ m_state = Created;
+ return true;
+}
+
+// Connects to a previously opened server side of the pipe.
+// Id is used to locate the pipe on the machine.
+// true - success, false - failure (use GetLastError() for more details)
+bool TwoWayPipe::Connect(DWORD id)
+{
+ _ASSERTE(m_state == NotInitialized);
+ if (m_state != NotInitialized)
+ return false;
+
+ m_id = id;
+ //"in" and "out" are switched deliberately, because we're on the client
+ PAL_GetTransportPipeName(m_inPipeName, id, "out");
+ PAL_GetTransportPipeName(m_outPipeName, id, "in");
+
+ // Pipe opening order is reversed compared to WaitForConnection()
+ // in order to avaid deadlock.
+ m_outboundPipe = open(m_outPipeName, O_WRONLY);
+ if (m_outboundPipe == INVALID_PIPE)
+ {
+ return false;
+ }
+
+ m_inboundPipe = open(m_inPipeName, O_RDONLY);
+ if (m_inboundPipe == INVALID_PIPE)
+ {
+ close(m_outboundPipe);
+ m_outboundPipe = INVALID_PIPE;
+ return false;
+ }
+
+ m_state = ClientConnected;
+ return true;
+
+}
+
+// Waits for incoming client connections, assumes GetState() == Created
+// true - success, false - failure (use GetLastError() for more details)
+bool TwoWayPipe::WaitForConnection()
+{
+ _ASSERTE(m_state == Created);
+ if (m_state != Created)
+ return false;
+
+ m_inboundPipe = open(m_inPipeName, O_RDONLY);
+ if (m_inboundPipe == INVALID_PIPE)
+ {
+ return false;
+ }
+
+ m_outboundPipe = open(m_outPipeName, O_WRONLY);
+ if (m_outboundPipe == INVALID_PIPE)
+ {
+ close(m_inboundPipe);
+ m_inboundPipe = INVALID_PIPE;
+ return false;
+ }
+
+ m_state = ServerConnected;
+ return true;
+}
+
+// Reads data from pipe. Returns number of bytes read or a negative number in case of an error.
+// use GetLastError() for more details
+// UNIXTODO - mjm 9/6/15 - does not set last error on failure
+int TwoWayPipe::Read(void *buffer, DWORD bufferSize)
+{
+ _ASSERTE(m_state == ServerConnected || m_state == ClientConnected);
+
+ int totalBytesRead = 0;
+ int bytesRead;
+ int cb = bufferSize;
+
+ while ((bytesRead = (int)read(m_inboundPipe, buffer, cb)) > 0)
+ {
+ totalBytesRead += bytesRead;
+ _ASSERTE(totalBytesRead <= bufferSize);
+ if (totalBytesRead >= bufferSize)
+ {
+ break;
+ }
+
+ buffer = (char*)buffer + bytesRead;
+ cb -= bytesRead;
+ }
+
+ return bytesRead == -1 ? -1 : totalBytesRead;
+}
+
+// Writes data to pipe. Returns number of bytes written or a negative number in case of an error.
+// use GetLastError() for more details
+// UNIXTODO - mjm 9/6/15 - does not set last error on failure
+int TwoWayPipe::Write(const void *data, DWORD dataSize)
+{
+ _ASSERTE(m_state == ServerConnected || m_state == ClientConnected);
+
+ int totalBytesWritten = 0;
+ int bytesWritten;
+ int cb = dataSize;
+
+ while ((bytesWritten = (int)write(m_outboundPipe, data, cb)) > 0)
+ {
+ totalBytesWritten += bytesWritten;
+ _ASSERTE(totalBytesWritten <= dataSize);
+ if (totalBytesWritten >= dataSize)
+ {
+ break;
+ }
+
+ data = (char*)data + bytesWritten;
+ cb -= bytesWritten;
+ }
+
+ return bytesWritten == -1 ? -1 : totalBytesWritten;
+}
+
+// Disconnect server or client side of the pipe.
+// true - success, false - failure (use GetLastError() for more details)
+bool TwoWayPipe::Disconnect()
+{
+ // IMPORTANT NOTE: This function must not call any signal unsafe functions
+ // since it is called from signal handlers.
+ // That includes ASSERT and TRACE macros.
+
+ if (m_state == ServerConnected || m_state == Created)
+ {
+ unlink(m_inPipeName);
+ unlink(m_outPipeName);
+ }
+
+ m_state = NotInitialized;
+ return true;
+}
+
+// Used by debugger side (RS) to cleanup the target (LS) named pipes
+// and semaphores when the debugger detects the debuggee process exited.
+void TwoWayPipe::CleanupTargetProcess()
+{
+ unlink(m_inPipeName);
+ unlink(m_outPipeName);
+}