exec.Command - pipe - 2 programs - trying kill

216 views
Skip to first unread message

GGGo

unread,
Oct 10, 2012, 12:41:54 PM10/10/12
to golan...@googlegroups.com
// begin code
package main

import "fmt"
import "os/exec"
import "log"
import "runtime"

var done = make(chan error)

func watch() {
for {
select {
case err := <-done:
log.Printf("process done with error = %v", err)
}
}
}

func main() {
go watch()
var err error
fmt.Println("Hello, playground")
app1 := exec.Command("arecord")
app2 := exec.Command("aplay")
if app2.Stdin, err = app1.StdoutPipe(); err != nil {
log.Fatal(err)
}
if err := app1.Start(); err != nil {
log.Fatal(err)
}
if err = app2.Start(); err != nil {
log.Fatal(err)
}
go func() {
done <- app1.Wait()
}()
go func() {
done <- app2.Wait()
}()

for{runtime.Gosched()}
}
//end code

When you execute in a shell `arecord|aplay`, you can killall aplay and arecord will exit OR you can killall arecord and aplay will exit.
I try to do the same thing in this example.
If I killall arecord, aplay will exit. Good
If I killall aplay, arecord stays there, and aplay exits. Not good.
Any idea ?
Thanks !

Skip Tavakkolian

unread,
Oct 10, 2012, 2:12:20 PM10/10/12
to GGGo, golan...@googlegroups.com
close app2.Stdin after sub processes have started.

in the first instance the reader gets an error because the writer has
gone away and closed the write end and the reader exits. in the second
case the writer doesn't get an error when a reader (aplay) has gone
away because your main proc still has a duplicate of the file; the
writer blocks when the pipe buffer is full.

http://play.golang.org/p/Lps1zNplPp
> --
>
>

GGGo

unread,
Oct 10, 2012, 3:52:29 PM10/10/12
to golan...@googlegroups.com, GGGo
I don't understand why the main func keep a duplicate of the file, but what you did solve my problem for sure. Thank you.

I also notice something, if I run ./main in the shell, and type Ctrl+C, the main program exits and app1 and app2 exit too. Great. But If I killall main, app1 and app2 still running. (killall main or kill -9 PID or kill -2 PID)

So it means if the main program crashes, app1 and app2 will continue to run. Right ? Is there something I can do to attach child commands to the main to prevent this ?

Skip Tavakkolian

unread,
Oct 10, 2012, 7:11:31 PM10/10/12
to GGGo, golan...@googlegroups.com
your code needs to handle signals sent to it. crashing should be
dealt with another way; i would not clean things up automatically
after a crash because i want to see what caused it.

here's a simplified version that handles signals.
http://play.golang.org/p/qh5G16TiKS

this book might be a good resource for you: Advanced Programming in
the UNIX Environment (Stevens)
> --
>
>

GGGo

unread,
Oct 10, 2012, 7:56:22 PM10/10/12
to golan...@googlegroups.com, GGGo
Ok you used signal.Notify, really nice example. I like the way you handle the signals.

I just found another way, and it seems to support crashing too.
Just add:
app1.SysProcAttr = &syscall.SysProcAttr{Pdeathsig:2}
app2.SysProcAttr = &syscall.SysProcAttr{Pdeathsig:2} // Signal that the process will get when its parent dies (Linux only)

Is a good one ?

Thank you !

minux

unread,
Oct 12, 2012, 11:35:40 AM10/12/12
to GGGo, golan...@googlegroups.com
On Thu, Oct 11, 2012 at 7:56 AM, GGGo <ggco...@gmail.com> wrote:
I just found another way, and it seems to support crashing too.
Just add:
app1.SysProcAttr = &syscall.SysProcAttr{Pdeathsig:2}
app2.SysProcAttr = &syscall.SysProcAttr{Pdeathsig:2} // Signal that the process will get when its parent dies (Linux only)
I suggest you use syscall.SIGINT instead of 2 here. 

Is a good one ?
Good if you don't (and won't) bother other OSes.
Reply all
Reply to author
Forward
0 new messages