blob: 54ce341676ae74a598910519b11d24741f6a1187 [file] [log] [blame]
Cosmos Nicolaou62613842014-08-25 21:57:37 -07001package modules
2
3import (
Cosmos Nicolaou62613842014-08-25 21:57:37 -07004 "fmt"
5 "io"
6 "os"
7 "sync"
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -07008
9 "veyron.io/veyron/veyron2/vlog"
Cosmos Nicolaou62613842014-08-25 21:57:37 -070010)
11
12type pipe struct {
13 r, w *os.File
14}
15type functionHandle struct {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070016 mu sync.Mutex
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070017 name string
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070018 main Main
19 stdin, stdout pipe
20 stderr *os.File
21 err error
22 sh *Shell
23 wg sync.WaitGroup
Cosmos Nicolaou62613842014-08-25 21:57:37 -070024}
25
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070026func newFunctionHandle(name string, main Main) command {
27 return &functionHandle{name: name, main: main}
Cosmos Nicolaou62613842014-08-25 21:57:37 -070028}
29
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070030func (fh *functionHandle) Stdout() io.Reader {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070031 fh.mu.Lock()
32 defer fh.mu.Unlock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070033 return fh.stdout.r
Cosmos Nicolaou62613842014-08-25 21:57:37 -070034}
35
36func (fh *functionHandle) Stderr() io.Reader {
37 fh.mu.Lock()
38 defer fh.mu.Unlock()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070039 return os.NewFile(fh.stderr.Fd(), "stderr")
Cosmos Nicolaou62613842014-08-25 21:57:37 -070040}
41
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070042func (fh *functionHandle) Stdin() io.Writer {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070043 fh.mu.Lock()
44 defer fh.mu.Unlock()
45 return fh.stdin.w
46}
47
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070048func (fh *functionHandle) CloseStdin() {
49 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070050 fh.stdin.w.Close()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070051 fh.mu.Unlock()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070052}
53
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070054func (fh *functionHandle) envelope(sh *Shell, env []string, args ...string) ([]string, []string) {
55 return args, env
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070056}
57
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070058func (fh *functionHandle) start(sh *Shell, env []string, args ...string) (Handle, error) {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070059 fh.mu.Lock()
60 defer fh.mu.Unlock()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070061 fh.sh = sh
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070062 for _, p := range []*pipe{&fh.stdin, &fh.stdout} {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070063 var err error
64 if p.r, p.w, err = os.Pipe(); err != nil {
65 return nil, err
66 }
67 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070068 stderr, err := newLogfile(args[0])
69 if err != nil {
70 return nil, err
71 }
72 fh.stderr = stderr
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070073 fh.wg.Add(1)
74
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070075 go func(env []string) {
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070076 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070077 stdin := fh.stdin.r
78 stdout := fh.stdout.w
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070079 stderr := fh.stderr
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070080 main := fh.main
81 fh.mu.Unlock()
82
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070083 cenv := envSliceToMap(env)
84 vlog.VI(1).Infof("Start: %q args: %v", fh.name, args)
85 vlog.VI(2).Infof("Start: %q env: %v", fh.name, cenv)
86 err := main(stdin, stdout, stderr, cenv, args...)
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070087 if err != nil {
88 fmt.Fprintf(stderr, "%s\n", err)
89 }
90
91 fh.mu.Lock()
92 fh.stdin.r.Close()
93 fh.stdout.w.Close()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070094 fh.err = err
95 fh.mu.Unlock()
96 fh.wg.Done()
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070097 }(env)
Cosmos Nicolaou62613842014-08-25 21:57:37 -070098 return fh, nil
99}
100
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700101func (eh *functionHandle) Pid() int {
102 return os.Getpid()
103}
104
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700105func (fh *functionHandle) Shutdown(stdout_w, stderr_w io.Writer) error {
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700106 fh.mu.Lock()
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700107 vlog.VI(1).Infof("Shutdown: %q", fh.name)
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700108 fh.stdin.w.Close()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700109 stdout := fh.stdout.r
110 stderr := fh.stderr
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700111 fh.mu.Unlock()
112
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700113 // Read stdout until EOF to ensure that we read all of it.
114 readTo(stdout, stdout_w)
115 fh.wg.Wait()
116
117 fh.mu.Lock()
118 funcErr := fh.err
119 fh.mu.Unlock()
120
121 // Safe to close stderr now.
122 stderr.Close()
123 stderr, err := os.Open(stderr.Name())
124 if err == nil {
125 readTo(stderr, stderr_w)
126 stderr.Close()
127 } else {
Jiri Simsa5ef07842014-10-14 13:37:16 -0700128 fmt.Fprintf(os.Stderr, "failed to open %q: %s\n", stderr.Name(), err)
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700129 }
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700130
131 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700132 fh.stdout.r.Close()
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700133 fh.sh.Forget(fh)
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700134 fh.mu.Unlock()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700135 return funcErr
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700136}