iniitial commit
This commit is contained in:
commit
af5cd07ab3
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
8
.idea/modules.xml
generated
Normal 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
9
.idea/pidproxy.iml
generated
Normal 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
5
go.mod
Normal 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
2
go.sum
Normal 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
167
main.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user