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