iniitial commit

This commit is contained in:
Suyono 2023-11-02 22:10:27 +00:00
commit af5cd07ab3
6 changed files with 199 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/pidproxy.iml" filepath="$PROJECT_DIR$/.idea/pidproxy.iml" />
</modules>
</component>
</project>

9
.idea/pidproxy.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module gitea.suyono.dev/suyono/pidproxy
go 1.21.3
require golang.org/x/sys v0.13.0 // indirect

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

167
main.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: pidproxy /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
}
}
}