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" |
James Ring | 9d9489d | 2015-01-27 15:48:07 -0800 | [diff] [blame] | 8 | "time" |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 9 | |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 10 | "v.io/core/veyron2/vlog" |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 11 | ) |
| 12 | |
| 13 | type pipe struct { |
| 14 | r, w *os.File |
| 15 | } |
| 16 | type functionHandle struct { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 17 | mu sync.Mutex |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 18 | name string |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 19 | main Main |
| 20 | stdin, stdout pipe |
| 21 | stderr *os.File |
| 22 | err error |
| 23 | sh *Shell |
| 24 | wg sync.WaitGroup |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 25 | } |
| 26 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 27 | func newFunctionHandle(name string, main Main) command { |
| 28 | return &functionHandle{name: name, main: main} |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 29 | } |
| 30 | |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 31 | func (fh *functionHandle) Stdout() io.Reader { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 32 | fh.mu.Lock() |
| 33 | defer fh.mu.Unlock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 34 | return fh.stdout.r |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | func (fh *functionHandle) Stderr() io.Reader { |
| 38 | fh.mu.Lock() |
| 39 | defer fh.mu.Unlock() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 40 | return os.NewFile(fh.stderr.Fd(), "stderr") |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 41 | } |
| 42 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 43 | func (fh *functionHandle) Stdin() io.Writer { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 44 | fh.mu.Lock() |
| 45 | defer fh.mu.Unlock() |
| 46 | return fh.stdin.w |
| 47 | } |
| 48 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 49 | func (fh *functionHandle) CloseStdin() { |
| 50 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 51 | fh.stdin.w.Close() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 52 | fh.mu.Unlock() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 53 | } |
| 54 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 55 | func (fh *functionHandle) envelope(sh *Shell, env []string, args ...string) ([]string, []string) { |
| 56 | return args, env |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 57 | } |
| 58 | |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 59 | func (fh *functionHandle) start(sh *Shell, agent *os.File, env []string, args ...string) (Handle, error) { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 60 | fh.mu.Lock() |
| 61 | defer fh.mu.Unlock() |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 62 | // In process commands need their own reference to a principal. |
| 63 | if agent != nil { |
| 64 | agent.Close() |
| 65 | } |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 66 | fh.sh = sh |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 67 | for _, p := range []*pipe{&fh.stdin, &fh.stdout} { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 68 | var err error |
| 69 | if p.r, p.w, err = os.Pipe(); err != nil { |
| 70 | return nil, err |
| 71 | } |
| 72 | } |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 73 | stderr, err := newLogfile("stderr", args[0]) |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 74 | if err != nil { |
| 75 | return nil, err |
| 76 | } |
| 77 | fh.stderr = stderr |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 78 | fh.wg.Add(1) |
| 79 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 80 | go func(env []string) { |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 81 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 82 | stdin := fh.stdin.r |
| 83 | stdout := fh.stdout.w |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 84 | stderr := fh.stderr |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 85 | main := fh.main |
| 86 | fh.mu.Unlock() |
| 87 | |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 88 | cenv := envSliceToMap(env) |
| 89 | vlog.VI(1).Infof("Start: %q args: %v", fh.name, args) |
| 90 | vlog.VI(2).Infof("Start: %q env: %v", fh.name, cenv) |
| 91 | err := main(stdin, stdout, stderr, cenv, args...) |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 92 | if err != nil { |
| 93 | fmt.Fprintf(stderr, "%s\n", err) |
| 94 | } |
| 95 | |
| 96 | fh.mu.Lock() |
| 97 | fh.stdin.r.Close() |
| 98 | fh.stdout.w.Close() |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 99 | fh.err = err |
| 100 | fh.mu.Unlock() |
| 101 | fh.wg.Done() |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 102 | }(env) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 103 | return fh, nil |
| 104 | } |
| 105 | |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 106 | func (eh *functionHandle) Pid() int { |
| 107 | return os.Getpid() |
| 108 | } |
| 109 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 110 | func (fh *functionHandle) Shutdown(stdout_w, stderr_w io.Writer) error { |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 111 | fh.mu.Lock() |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 112 | vlog.VI(1).Infof("Shutdown: %q", fh.name) |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 113 | fh.stdin.w.Close() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 114 | stdout := fh.stdout.r |
| 115 | stderr := fh.stderr |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 116 | fh.mu.Unlock() |
| 117 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 118 | // Read stdout until EOF to ensure that we read all of it. |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 119 | if stdout_w != nil { |
| 120 | io.Copy(stdout_w, stdout) |
| 121 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 122 | fh.wg.Wait() |
| 123 | |
| 124 | fh.mu.Lock() |
| 125 | funcErr := fh.err |
| 126 | fh.mu.Unlock() |
| 127 | |
| 128 | // Safe to close stderr now. |
Robin Thellend | 1c8a828 | 2014-12-09 10:38:36 -0800 | [diff] [blame] | 129 | stderrName := stderr.Name() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 130 | stderr.Close() |
Robin Thellend | 1c8a828 | 2014-12-09 10:38:36 -0800 | [diff] [blame] | 131 | defer os.Remove(stderrName) |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 132 | if stderr_w != nil { |
Robin Thellend | 1c8a828 | 2014-12-09 10:38:36 -0800 | [diff] [blame] | 133 | if stderr, err := os.Open(stderrName); err == nil { |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 134 | io.Copy(stderr_w, stderr) |
| 135 | stderr.Close() |
| 136 | } else { |
Robin Thellend | 1c8a828 | 2014-12-09 10:38:36 -0800 | [diff] [blame] | 137 | fmt.Fprintf(os.Stderr, "failed to open %q: %s\n", stderrName, err) |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 138 | } |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 139 | } |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 140 | |
| 141 | fh.mu.Lock() |
Cosmos Nicolaou | 9ca249d | 2014-09-18 15:07:12 -0700 | [diff] [blame] | 142 | fh.stdout.r.Close() |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 143 | fh.sh.Forget(fh) |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 144 | fh.mu.Unlock() |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 145 | return funcErr |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 146 | } |
James Ring | 9d9489d | 2015-01-27 15:48:07 -0800 | [diff] [blame] | 147 | |
| 148 | func (fh *functionHandle) WaitForReady(time.Duration) error { |
| 149 | return nil |
| 150 | } |