Skip to content

Instantly share code, notes, and snippets.

@smallnest
Forked from wrfly/fork_and_daemon.go
Created April 20, 2020 06:52
Show Gist options
  • Select an option

  • Save smallnest/de6134e36b83fd6d215edf8db787235f to your computer and use it in GitHub Desktop.

Select an option

Save smallnest/de6134e36b83fd6d215edf8db787235f to your computer and use it in GitHub Desktop.

Revisions

  1. @wrfly wrfly renamed this gist Dec 12, 2018. 1 changed file with 16 additions and 10 deletions.
    26 changes: 16 additions & 10 deletions fork.go → fork_and_daemon.go
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,11 @@ func main() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    if s == syscall.SIGQUIT || s == syscall.SIGKILL {
    // see https://u.kfd.me/33
    // SIGINT means graceful stop
    // SIGTERM means graceful [or not], cleanup something
    // SIGQUIT SIGKILL means immediately shutdown
    if s == syscall.SIGQUIT || s == syscall.SIGTERM {
    log.Printf("[%d] exit\n", pid)
    // make sure that parent can send signals to the children
    for _, child := range children {
    @@ -87,7 +91,7 @@ func main() {
    }
    // print children
    log.Printf("parent: PID=%d children=%v", pid, children)
    if len(children) == 0 {
    if len(children) == 0 && fork != 0 {
    log.Fatalf("no child avaliable, exit")
    }

    @@ -100,15 +104,17 @@ func main() {
    }
    }

    // parent will only notify children
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    for _, child := range children {
    log.Printf("parent send %s to %d", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    go func() {
    // parent will [only] notify children
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    for _, child := range children {
    log.Printf("parent send %s to %d", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    }
    }
    }()

    }

  2. @wrfly wrfly revised this gist Dec 12, 2018. 1 changed file with 85 additions and 36 deletions.
    121 changes: 85 additions & 36 deletions fork.go
    Original file line number Diff line number Diff line change
    @@ -1,72 +1,121 @@
    package main

    import (
    "flag"
    "fmt"
    "log"
    "os"
    "os/signal"
    "strings"
    "syscall"
    "time"
    )

    var children = []int{}
    var (
    daemon bool
    fork int
    children = []int{}
    )

    func main() {
    func init() {
    flag.BoolVar(&daemon, "daemon", false, "run as daemon")
    flag.IntVar(&fork, "fork", 0, "fork how many sub process")

    flag.Parse()
    }

    func main() {
    pid := os.Getpid()
    ppid := os.Getppid()
    fmt.Printf("pid: %d, ppid: %d\n", pid, ppid)
    log.Printf("pid: %d, ppid: %d, args: %s", pid, ppid, os.Args)

    fmt.Println(fmt.Sprint(os.Args))
    // handle exit for every process
    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    if s == syscall.SIGQUIT || s == syscall.SIGKILL {
    log.Printf("[%d] exit\n", pid)
    // make sure that parent can send signals to the children
    for _, child := range children {
    log.Printf("parent send %s to %d", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    syscall.Exit(0)
    }
    }
    }()

    if strings.Contains(fmt.Sprint(os.Args), "#child_of_") {
    fmt.Println("child won't fork")
    } else {
    // only the parent process can do
    os.Args = append(os.Args, fmt.Sprintf("#child_of_%d", pid))
    for i := 0; i < 5; i++ {
    childPID, _ := syscall.ForkExec(os.Args[0], os.Args, &syscall.ProcAttr{
    // only the parent process can do
    if _, isChild := os.LookupEnv("CHILD_ID"); !isChild {
    if daemon {
    if _, isDaemon := os.LookupEnv("DAEMON"); !isDaemon {
    daemonENV := []string{"DAEMON=true"}
    childPID, _ := syscall.ForkExec(os.Args[0], os.Args,
    &syscall.ProcAttr{
    Env: append(os.Environ(), daemonENV...),
    Sys: &syscall.SysProcAttr{
    Setsid: true,
    },
    Files: []uintptr{0, 1, 2}, // print message to the same pty
    })
    log.Printf("process %d run as daemon, %d will exit", childPID, pid)
    return // this return will give back the pty
    }
    log.Printf("daemon %d running and won't fork another daemon", os.Getpid())
    }

    for i := 0; i < fork; i++ {
    args := append(os.Args, fmt.Sprintf("#child_%d_of_%d", i, os.Getpid()))
    childENV := []string{
    fmt.Sprintf("CHILD_ID=%d", i),
    }
    pwd, err := os.Getwd()
    if err != nil {
    log.Fatalf("getwd err: %s", err)
    }
    childPID, _ := syscall.ForkExec(args[0], args, &syscall.ProcAttr{
    Dir: pwd,
    Env: append(os.Environ(), childENV...),
    Sys: &syscall.SysProcAttr{
    Setsid: true,
    },
    Files: []uintptr{0, 1, 2},
    Files: []uintptr{0, 1, 2}, // print message to the same pty
    })
    fmt.Printf("fork %d\n", childPID)
    log.Printf("parent %d fork %d", pid, childPID)
    if childPID != 0 {
    children = append(children, childPID)
    }
    }
    // print children
    go func() {
    for {
    fmt.Printf("PID: %d children: %v\n", pid, children)
    time.Sleep(time.Second)
    log.Printf("parent: PID=%d children=%v", pid, children)
    if len(children) == 0 {
    log.Fatalf("no child avaliable, exit")
    }

    // set env
    for _, childID := range children {
    if c := os.Getenv("CHILDREN"); c != "" {
    os.Setenv("CHILDREN", fmt.Sprintf("%s,%d", c, childID))
    } else {
    os.Setenv("CHILDREN", fmt.Sprintf("%d", childID))
    }
    }()
    }

    // notify children
    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    for _, child := range children {
    fmt.Printf("send %s to %d\n", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    // parent will only notify children
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    for _, child := range children {
    log.Printf("parent send %s to %d", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    }()
    }

    }

    // main
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    fmt.Printf("%d got sig %s\n", pid, s)
    if s == syscall.SIGQUIT {
    time.Sleep(time.Second)
    fmt.Printf("%d exit\n", pid)
    syscall.Exit(0)
    }
    log.Printf("PID[%d] got sig %s", pid, s)
    }
    }
  3. @wrfly wrfly revised this gist Dec 12, 2018. 1 changed file with 16 additions and 16 deletions.
    32 changes: 16 additions & 16 deletions fork.go
    Original file line number Diff line number Diff line change
    @@ -17,16 +17,10 @@ func main() {
    ppid := os.Getppid()
    fmt.Printf("pid: %d, ppid: %d\n", pid, ppid)

    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    fmt.Printf("%d got sig %s\n", pid, s)
    }
    }()
    fmt.Println(fmt.Sprint(os.Args))

    if strings.Contains(strings.Join(os.Args, " "), "#child_of_") {
    fmt.Println("child fork return")
    if strings.Contains(fmt.Sprint(os.Args), "#child_of_") {
    fmt.Println("child won't fork")
    } else {
    // only the parent process can do
    os.Args = append(os.Args, fmt.Sprintf("#child_of_%d", pid))
    @@ -35,7 +29,7 @@ func main() {
    Sys: &syscall.SysProcAttr{
    Setsid: true,
    },
    Files: []uintptr{1, 2},
    Files: []uintptr{0, 1, 2},
    })
    fmt.Printf("fork %d\n", childPID)
    if childPID != 0 {
    @@ -50,7 +44,7 @@ func main() {
    }
    }()

    // notify children and handle exit
    // notify children
    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    @@ -59,14 +53,20 @@ func main() {
    fmt.Printf("send %s to %d\n", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    if s == syscall.SIGQUIT {
    time.Sleep(time.Second)
    syscall.Exit(0)
    }
    }
    }()

    }

    time.Sleep(time.Minute)
    // main
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    fmt.Printf("%d got sig %s\n", pid, s)
    if s == syscall.SIGQUIT {
    time.Sleep(time.Second)
    fmt.Printf("%d exit\n", pid)
    syscall.Exit(0)
    }
    }
    }
  4. @wrfly wrfly created this gist Dec 12, 2018.
    72 changes: 72 additions & 0 deletions fork.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@
    package main

    import (
    "fmt"
    "os"
    "os/signal"
    "strings"
    "syscall"
    "time"
    )

    var children = []int{}

    func main() {

    pid := os.Getpid()
    ppid := os.Getppid()
    fmt.Printf("pid: %d, ppid: %d\n", pid, ppid)

    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    fmt.Printf("%d got sig %s\n", pid, s)
    }
    }()

    if strings.Contains(strings.Join(os.Args, " "), "#child_of_") {
    fmt.Println("child fork return")
    } else {
    // only the parent process can do
    os.Args = append(os.Args, fmt.Sprintf("#child_of_%d", pid))
    for i := 0; i < 5; i++ {
    childPID, _ := syscall.ForkExec(os.Args[0], os.Args, &syscall.ProcAttr{
    Sys: &syscall.SysProcAttr{
    Setsid: true,
    },
    Files: []uintptr{1, 2},
    })
    fmt.Printf("fork %d\n", childPID)
    if childPID != 0 {
    children = append(children, childPID)
    }
    }
    // print children
    go func() {
    for {
    fmt.Printf("PID: %d children: %v\n", pid, children)
    time.Sleep(time.Second)
    }
    }()

    // notify children and handle exit
    go func() {
    sig := make(chan os.Signal)
    signal.Notify(sig)
    for s := range sig {
    for _, child := range children {
    fmt.Printf("send %s to %d\n", s, child)
    syscall.Kill(child, s.(syscall.Signal))
    }
    if s == syscall.SIGQUIT {
    time.Sleep(time.Second)
    syscall.Exit(0)
    }
    }
    }()

    }

    time.Sleep(time.Minute)
    }