A high-performance process orchestration application written in C, featuring a stateless agent architecture for container-based process management. Named after the 19th century puppeteer Joseph Holden, it provides precise control over process lifecycles using pidfd-based monitoring.
- Stateless Agent: Spawns processes in containers and returns pidfd references via fd passing
- pidfd Monitor: Demonstrates pidfd-based process monitoring and restart capability
- Communication: Unix domain sockets for efficient IPC with fd passing
- Process Management: Caller-controlled using pidfds, no agent state
- Stateless Agent: No internal process tracking or state management
- pidfd-based Monitoring: Efficient process monitoring using Linux pidfds
- Container Namespace Inheritance: Spawned processes inherit agent's container context
- File Descriptor Passing: Agent returns pidfd references to caller via Unix sockets
- Process Restart Logic: Automatic restart capability using pidfd polling
- Simplified Architecture: Agent only spawns, caller manages everything else
make allThis creates two binaries in the bin/ directory:
agent- Stateless process spawning agentpidfd_monitor- pidfd-based monitor demonstration
./bin/agentThe agent listens on /tmp/process_orchestrator.sock by default. Configure with HOLDEN_SOCKET_PATH environment variable.
The pidfd monitor demonstrates the intended usage pattern:
# Monitor local and agent-spawned processes with automatic restart
./bin/pidfd_monitor "/bin/sleep 5" "/usr/bin/sleep 10"This example:
- Spawns
/bin/sleep 5locally using fork() and gets its pidfd - Spawns
/usr/bin/sleep 10via the agent and receives its pidfd - Monitors both processes using poll() on their pidfds
- Automatically restarts processes when they die
The simplified agent:
- Takes command line from caller
- Spawns process (inherits container/qm context)
- Calls pidfd_open() to get process reference
- Returns pidfd via fd passing over Unix socket
- Maintains no state - all management delegated to caller
// Agent workflow:
pid_t pid = fork();
// ... child execs command ...
int pidfd = pidfd_open(pid, 0);
send_fd(socket, pidfd); // Send pidfd to caller
close(pidfd); // Agent doesn't keep itWith the new architecture:
- Agent: Stateless process spawner only
- Caller: Receives pidfds and manages processes directly
- No Agent State: No process tracking, lists, or management in agent
- pidfd Control: Caller uses pidfds for stop, monitor, wait operations
- Container Context: Spawned processes inherit agent's namespace/cgroup context
FROM alpine:latest
RUN apk add --no-cache libc6-compat
COPY bin/agent /usr/local/bin/
CMD ["/usr/local/bin/agent"]# Agent provides qm/container context to spawned processes
podman run -d --name holden-agent \
-v /run/holden:/run/holden \
holden-agent
# Use pidfd monitor to spawn and manage processes
./bin/pidfd_monitor "your-app --config=prod" "monitoring-daemon"- Linux with pidfd support (kernel 5.3+)
- Container environment for agent (optional)
- GCC with C99 support
protocol.h/c- Communication protocol definitionsagent.c- Stateless process spawning agentorchestrator.c- pidfd-based process orchestrator demonstrationMakefile- Build system
The agent supports:
MSG_START_PROCESS- Spawn process and return pidfd via fd passingMSG_PING- Health check
Removed operations (handled by caller):
- No agent state to listLIST_PROCESSES- Caller uses pidfd directlySTOP_PROCESS- Caller applies via pidfdAPPLY_CONSTRAINTS
Simple Model: Agent spawns, caller manages via pidfd
pidfd_monitor app1 app2 # Agent spawns, returns pidfds
# Caller polls pidfds, handles restart, stop, etc.The agent is a pure process spawner - all management is handled by the caller using the returned pidfds.
- Unix domain sockets provide secure local communication
- File descriptor passing for pidfd security
- No network exposure by default
- Container namespace inheritance
- No agent state to compromise
This project is licensed under the MIT License - see the LICENSE file for details.