ready to test: proxy

This commit is contained in:
2023-11-03 12:12:11 +11:00
parent 45d1c50501
commit e6e9bf291b
3 changed files with 180 additions and 1 deletions

167
pid1/pid1.go Normal file
View File

@@ -0,0 +1,167 @@
package main
import (
"errors"
"fmt"
"log"
"os"
"os/exec"
"os/signal"
"strconv"
"sync"
"golang.org/x/sys/unix"
)
type pidproxy struct {
pidPath string
targetArgs []string
pidMtx *sync.Mutex
firstPid, secondPid int
firstPidSettled bool
secondPidSettled bool
starterMtx *sync.Mutex
reaped map[int]any
}
func (p *pidproxy) CleanUpPid(pid int) {
p.reaped[pid] = nil
}
func (p *pidproxy) MonitorSecond() {
var (
pid int
pidstr string
err error
)
//TODO: need a proper error handling, refer to all todos in this function
func() {
f, err := os.Open(p.pidPath)
if err != nil {
log.Println("failed to open pid file: ", p.pidPath, ": ", err)
return //TODO: fix me
}
defer func() {
_ = f.Close()
}()
var n int
b := make([]byte, 64)
n, err = f.Read(b)
if err != nil {
log.Println("failed to read pid file: ", p.pidPath, ": ", err)
return //TODO: fix me
}
pidstr = string(b[:n])
}()
pid, err = strconv.Atoi(pidstr)
if err != nil {
log.Println("failed to parse pid file: ", p.pidPath, ": ", err)
return //TODO: fix me
}
p.secondPid = pid
}
func (p *pidproxy) Starter() {
var (
c *exec.Cmd
notRunning bool = true
pid int
)
func() {
p.starterMtx.Lock()
defer p.starterMtx.Unlock()
starterLoop:
for notRunning {
if len(p.targetArgs) == 1 {
c = exec.Command(p.targetArgs[0])
} else {
c = exec.Command(p.targetArgs[0], p.targetArgs[1:]...)
}
err := c.Start()
if err != nil {
log.Println("exec.Cmd: .Start: ", err)
continue starterLoop
}
pid = c.Process.Pid
notRunning = false
}
}()
//p.pidMtx.Lock()
p.firstPid = pid
//p.pidMtx.Unlock()
if _, ok := p.reaped[pid]; ok {
delete(p.reaped, pid)
} else {
}
}
func (p *pidproxy) WaitAny() {
var (
ws unix.WaitStatus
)
WaitPidLoop:
for {
wpid, err := unix.Wait4(-1, &ws, 0, nil)
if err != nil {
if errors.Is(err, unix.ECHILD) {
// no more child
//TODO: this could happen in the early stage of execution
break WaitPidLoop
}
log.Println("unix.Wait4:", err)
continue WaitPidLoop
}
if ws.Exited() {
p.CleanUpPid(wpid)
}
}
}
func main() {
if len(os.Args) < 3 {
_, _ = fmt.Fprintln(os.Stderr, "invalid parameter")
_, _ = fmt.Fprintln(os.Stderr, "usage: pid1 /path/to/pid/file program arguments ...")
os.Exit(2)
}
p := &pidproxy{
pidPath: os.Args[1],
targetArgs: os.Args[2:],
pidMtx: &sync.Mutex{},
firstPidSettled: false,
secondPidSettled: false,
starterMtx: &sync.Mutex{},
reaped: make(map[int]any),
}
c := make(chan os.Signal, 1)
signal.Notify(c, unix.SIGINT, unix.SIGTERM, unix.SIGCHLD)
go p.WaitAny()
for s := range c {
switch s {
case unix.SIGINT, unix.SIGTERM:
// do clean up
case unix.SIGCHLD:
// no handling
}
}
}