-
Notifications
You must be signed in to change notification settings - Fork 296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add pipes for parent process IPC. #311
Conversation
Example parent process that uses the rx pipe to signal clean shutdown (does NOT work on windows because the os/exec package thinks it's somehow ok to try and call fork+exec):
|
Here is a similar example in C#:
|
Here is a more advanced parent process that also reads the lifetime events over the other pipe, and requests dcrd shutdown when startup has completed: using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading.Tasks;
namespace PipeIPCExample
{
class Program
{
static void Main(string[] args)
{
var outPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
var inPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
var procInfo = new ProcessStartInfo
{
FileName = "dcrd",
Arguments = $"--testnet --piperx {outPipe.GetClientHandleAsString()} --pipetx {inPipe.GetClientHandleAsString()} --lifetimeevents",
};
var procHandle = Process.Start(procInfo);
// Read lifetime events
Task.Run(async () =>
{
var headerBuffer = new byte[1 + 255 + 4];
while (true)
{
await inPipe.ReadAsync(headerBuffer, 0, 1);
await inPipe.ReadAsync(headerBuffer, 1, headerBuffer[0]);
var msgType = Encoding.UTF8.GetString(headerBuffer, 1, headerBuffer[0]);
await inPipe.ReadAsync(headerBuffer, 1 + headerBuffer[0], 4);
var payloadSize = ReadUInt32LE(headerBuffer, 1 + headerBuffer[0]);
var payload = new byte[payloadSize];
await inPipe.ReadAsync(payload, 0, (int)payloadSize);
Console.WriteLine($"{msgType}: {BitConverter.ToString(payload)}");
// Signal shutdown when startup finishes
if (msgType == "lifetimeevent" && payload[0] == 1)
{
Console.WriteLine("Startup finished: signaling shutdown...");
outPipe.Dispose();
}
Array.Clear(headerBuffer, 0, headerBuffer.Length);
}
});
procHandle.WaitForExit();
Console.WriteLine($"Exited with exit code {procHandle.ExitCode}.");
}
static uint ReadUInt32LE(byte[] array, int offset)
{
return (uint)(array[offset++] | array[offset++] << 8 | array[offset++] << 16 | array[offset] << 24);
}
}
} Output:
|
Rewrite startup/shutdown logic to simplify shutdown signaling. All cleanup is now run from deferred functions in the main function. Add two new config options to set the read and write ends of a pair of pipes. This is used as a simple mechanism for a parent process to communicate with, observe, and manage the lifetime of a child dcrd process. When the RX (read end) pipe is closed, clean shutdown automatically begins. Add a new flag --lifetimeevents to create and send lifetime event notifications over the TX (write end) pipe during bringup and shutdown. This allows the parent process to observe which subsystems are currently starting, running, and stopping. Fixes btcsuite#297. Fixes btcsuite#298.
Rebased over master. Once this is reviewed and merged I will open a new PR that backports this to the 0.4.0 release branch. |
I love this code but I am having a bit of heartburn about the encoding. I really think we should use xdr or something alike. So let's at the very least add a version byte in front of the entire message in case we want to change it in the future. |
|
||
// Messages sent over a pipe are encoded using a simple binary message format: | ||
// | ||
// - Protocol version (1 byte, currently 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't ever use 0 for a version. Experience tells us that always ends in tears.
ok |
Rewrite startup/shutdown logic to simplify shutdown signaling. All
cleanup is now run from deferred functions in the main function.
Add two new config options to set the read and write ends of a pair of
pipes. This is used as a simple mechanism for a parent process to
communicate with, observe, and manage the lifetime of a child dcrd
process. When the RX (read end) pipe is closed, clean shutdown
automatically begins.
Add a new flag --lifetimeevents to create and send lifetime event
notifications over the TX (write end) pipe during bringup and
shutdown. This allows the parent process to observe which subsystems
are currently starting, running, and stopping.
Fixes #297.
Fixes #298.