Jammer
Jammer

Reputation: 562

How to verify that parent process has exited in golang on Windows?

So I am writing a small utility which should be able to update itself (replace it's own binary).

The best way to do this on Windows seems to be:

  1. Download the new version of the binary as my.exe.new
  2. my.exes runs my.exe.new and exits
  3. my.exe.new waits for my.exe to exit
  4. my.exe.new copies itself as my.exe
  5. my.exe.new starts another copy of itself as my.exe and exits
  6. my.exe waits for my.exe.new to exit
  7. my.exe removes my.exe.new

Now for all of this to work I have to be able to synchronize the state between the processes (being able to know when the parent has exited), but it seems that os.Getppid (nor syscall.Getppid) in golang Windows is not implemented as it always returns -1.

I've seen that patches are underway, but I am not willing to patch my standard libraries.

Is there an easy way to make Getppid working on even older versions of Go (perhaps reimplementing it?), or perhaps anyone can suggest a better method of synchronizing between the process state?

The thing which comes to mind is binding on a socket, but thats a big hacky.

Perhaps passing a pipe to the child process, and the child waiting for the pipe to close?

Thanks

Upvotes: 2

Views: 1243

Answers (2)

arx
arx

Reputation: 16896

The parent process can pass its PID to the child.

You could use a command-line parameter or an environment variable to do this.

Upvotes: 1

OneOfOne
OneOfOne

Reputation: 99225

You could use os.Stdin with exec.Cmd, now I don't have access to windows to test this, however the same concept should apply there just fine:

var child = flag.Bool("child", false, "damn children and their music")

func init() {
    flag.Parse()
}

func main() {
    if *child {
        fmt.Println("child start", time.Now())

        // wait until the parent dies and bufio closes the stdin
        ioutil.ReadAll(os.Stdin)
        fmt.Println("the parent is dead", time.Now())
        time.Sleep(5 * time.Second)
        fmt.Println("tada\n")

    } else {
        fmt.Fprintln(os.Stdout, time.Now())
        cmd := exec.Command(os.Args[0], "-child")
        cmd.Stdout = os.Stdout //not needed in a real program.

        //this is important, bufio will close after the parent exits, 
        // unlike os.Stdin which screws up, at least on linux
        cmd.Stdin = bufio.NewReader(os.Stdin) 

        fmt.Println("giving painful birth:", cmd.Start())
        time.Sleep(2 * time.Second)
    }
}

Upvotes: 2

Related Questions