Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 1 | package modules |
| 2 | |
| 3 | import ( |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 4 | "fmt" |
| 5 | "io" |
| 6 | "os" |
| 7 | "sync" |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 8 | |
| 9 | "veyron.io/veyron/veyron2/vlog" |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 10 | ) |
| 11 | |
| 12 | type pipe struct { |
| 13 | r, w *os.File |
| 14 | } |
| 15 | type functionHandle struct { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 16 | mu sync.Mutex |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 17 | name string |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 18 | main Main |
| 19 | stdin, stdout pipe |
| 20 | stderr *os.File |
| 21 | err error |
| 22 | sh *Shell |
| 23 | wg sync.WaitGroup |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 24 | } |
| 25 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 26 | func newFunctionHandle(name string, main Main) command { |
| 27 | return &functionHandle{name: name, main: main} |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 28 | } |
| 29 | |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 30 | func (fh *functionHandle) Stdout() io.Reader { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 31 | fh.mu.Lock() |
| 32 | defer fh.mu.Unlock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 33 | return fh.stdout.r |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | func (fh *functionHandle) Stderr() io.Reader { |
| 37 | fh.mu.Lock() |
| 38 | defer fh.mu.Unlock() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 39 | return os.NewFile(fh.stderr.Fd(), "stderr") |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 40 | } |
| 41 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 42 | func (fh *functionHandle) Stdin() io.Writer { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 43 | fh.mu.Lock() |
| 44 | defer fh.mu.Unlock() |
| 45 | return fh.stdin.w |
| 46 | } |
| 47 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 48 | func (fh *functionHandle) CloseStdin() { |
| 49 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 50 | fh.stdin.w.Close() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 51 | fh.mu.Unlock() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 52 | } |
| 53 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 54 | func (fh *functionHandle) envelope(sh *Shell, env []string, args ...string) ([]string, []string) { |
| 55 | return args, env |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 56 | } |
| 57 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 58 | func (fh *functionHandle) start(sh *Shell, env []string, args ...string) (Handle, error) { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 59 | fh.mu.Lock() |
| 60 | defer fh.mu.Unlock() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 61 | fh.sh = sh |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 62 | for _, p := range []*pipe{&fh.stdin, &fh.stdout} { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 63 | var err error |
| 64 | if p.r, p.w, err = os.Pipe(); err != nil { |
| 65 | return nil, err |
| 66 | } |
| 67 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 68 | stderr, err := newLogfile(args[0]) |
| 69 | if err != nil { |
| 70 | return nil, err |
| 71 | } |
| 72 | fh.stderr = stderr |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 73 | fh.wg.Add(1) |
| 74 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 75 | go func(env []string) { |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 76 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 77 | stdin := fh.stdin.r |
| 78 | stdout := fh.stdout.w |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 79 | stderr := fh.stderr |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 80 | main := fh.main |
| 81 | fh.mu.Unlock() |
| 82 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 83 | 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 Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 87 | 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 Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 94 | fh.err = err |
| 95 | fh.mu.Unlock() |
| 96 | fh.wg.Done() |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 97 | }(env) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 98 | return fh, nil |
| 99 | } |
| 100 | |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 101 | func (eh *functionHandle) Pid() int { |
| 102 | return os.Getpid() |
| 103 | } |
| 104 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 105 | func (fh *functionHandle) Shutdown(stdout_w, stderr_w io.Writer) error { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 106 | fh.mu.Lock() |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 107 | vlog.VI(1).Infof("Shutdown: %q", fh.name) |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 108 | fh.stdin.w.Close() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 109 | stdout := fh.stdout.r |
| 110 | stderr := fh.stderr |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 111 | fh.mu.Unlock() |
| 112 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 113 | // 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 Simsa | 5ef0784 | 2014-10-14 13:37:16 -0700 | [diff] [blame] | 128 | fmt.Fprintf(os.Stderr, "failed to open %q: %s\n", stderr.Name(), err) |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 129 | } |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 130 | |
| 131 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 132 | fh.stdout.r.Close() |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 133 | fh.sh.Forget(fh) |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 134 | fh.mu.Unlock() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 135 | return funcErr |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 136 | } |