blob: 3727be207dbbdfc0a05862ec690c02f04eae446d [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090016
17import (
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090018 "container/heap"
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +090019 "errors"
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090020 "fmt"
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +090021 "os"
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090022 "os/exec"
23 "strings"
24 "syscall"
25 "time"
26)
27
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090028type job struct {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090029 n *DepNode
30 ex *Executor
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090031 parents []*job
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090032 outputTs int64
33 numDeps int
34 depsTs int64
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090035 id int
Shinichiro Hamajia6808422015-05-13 18:00:50 +090036
37 runners []runner
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090038}
39
40type runner struct {
41 output string
42 cmd string
43 echo bool
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090044 ignoreError bool
45 shell string
46}
47
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090048type jobResult struct {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090049 j *job
50 w *worker
51 err error
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090052}
53
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090054type newDep struct {
55 j *job
56 neededBy *job
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090057}
58
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090059type worker struct {
60 wm *workerManager
61 jobChan chan *job
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090062 waitChan chan bool
63 doneChan chan bool
64}
65
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090066type jobQueue []*job
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090067
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090068func (jq jobQueue) Len() int { return len(jq) }
69func (jq jobQueue) Swap(i, j int) { jq[i], jq[j] = jq[j], jq[i] }
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090070
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090071func (jq jobQueue) Less(i, j int) bool {
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090072 // First come, first serve, for GNU make compatibility.
73 return jq[i].id < jq[j].id
74}
75
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090076func (jq *jobQueue) Push(x interface{}) {
77 item := x.(*job)
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090078 *jq = append(*jq, item)
79}
80
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090081func (jq *jobQueue) Pop() interface{} {
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +090082 old := *jq
83 n := len(old)
84 item := old[n-1]
85 *jq = old[0 : n-1]
86 return item
87}
88
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090089func newWorker(wm *workerManager) *worker {
90 w := &worker{
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090091 wm: wm,
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090092 jobChan: make(chan *job),
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090093 waitChan: make(chan bool),
94 doneChan: make(chan bool),
95 }
96 return w
97}
98
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090099func (w *worker) Run() {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900100 done := false
101 for !done {
102 select {
103 case j := <-w.jobChan:
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900104 err := j.build()
105 w.wm.ReportResult(w, j, err)
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900106 case done = <-w.waitChan:
107 }
108 }
109 w.doneChan <- true
110}
111
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900112func (w *worker) PostJob(j *job) {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900113 w.jobChan <- j
114}
115
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900116func (w *worker) Wait() {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900117 w.waitChan <- true
118 <-w.doneChan
119}
120
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900121func evalCmd(ev *Evaluator, r runner, s string) ([]runner, error) {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900122 r = newRunner(r, s)
123 if strings.IndexByte(r.cmd, '$') < 0 {
124 // fast path
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900125 return []runner{r}, nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900126 }
127 // TODO(ukai): parse once more earlier?
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900128 expr, _, err := parseExpr([]byte(r.cmd), nil, false)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900129 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900130 return nil, ev.errorf("parse cmd %q: %v", r.cmd, err)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900131 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900132 buf := newBuf()
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900133 err = expr.Eval(buf, ev)
134 if err != nil {
135 return nil, err
136 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900137 cmds := buf.String()
138 freeBuf(buf)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900139 var runners []runner
140 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji212abfb2015-04-29 03:02:59 +0900141 if len(runners) > 0 && strings.HasSuffix(runners[len(runners)-1].cmd, "\\") {
142 runners[len(runners)-1].cmd += "\n"
143 runners[len(runners)-1].cmd += cmd
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900144 } else {
145 runners = append(runners, newRunner(r, cmd))
146 }
147 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900148 return runners, nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900149}
150
151func newRunner(r runner, s string) runner {
152 for {
153 s = trimLeftSpace(s)
154 if s == "" {
155 return runner{}
156 }
157 switch s[0] {
158 case '@':
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900159 if !DryRunFlag {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900160 r.echo = false
161 }
162 s = s[1:]
163 continue
164 case '-':
165 r.ignoreError = true
166 s = s[1:]
167 continue
168 }
169 break
170 }
171 r.cmd = s
172 return r
173}
174
175func (r runner) run(output string) error {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900176 if r.echo || DryRunFlag {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900177 fmt.Printf("%s\n", r.cmd)
178 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900179 if DryRunFlag {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900180 return nil
181 }
182 args := []string{r.shell, "-c", r.cmd}
183 cmd := exec.Cmd{
184 Path: args[0],
185 Args: args,
186 }
187 out, err := cmd.CombinedOutput()
188 fmt.Printf("%s", out)
189 exit := exitStatus(err)
190 if r.ignoreError && exit != 0 {
191 fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
192 err = nil
193 }
194 return err
195}
196
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900197func (j *job) createRunners() ([]runner, error) {
198 runners, _, err := j.ex.createRunners(j.n, false)
199 return runners, err
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900200}
201
Shinichiro Hamaji71fae4c2015-05-25 17:48:34 +0900202// TODO(ukai): use time.Time?
203func getTimestamp(filename string) int64 {
204 st, err := os.Stat(filename)
205 if err != nil {
206 return -2
207 }
208 return st.ModTime().Unix()
209}
210
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900211func (j *job) build() error {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900212 if j.n.IsPhony {
213 j.outputTs = -2 // trigger cmd even if all inputs don't exist.
214 } else {
215 j.outputTs = getTimestamp(j.n.Output)
216 }
217
218 if !j.n.HasRule {
219 if j.outputTs >= 0 || j.n.IsPhony {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900220 return nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900221 }
222 if len(j.parents) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900223 return fmt.Errorf("*** No rule to make target %q.", j.n.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900224 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900225 return fmt.Errorf("*** No rule to make target %q, needed by %q.", j.n.Output, j.parents[0].n.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900226 }
227
228 if j.outputTs >= j.depsTs {
229 // TODO: stats.
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900230 return nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900231 }
232
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900233 rr, err := j.createRunners()
234 if err != nil {
235 return err
236 }
237 for _, r := range rr {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900238 err := r.run(j.n.Output)
239 if err != nil {
240 exit := exitStatus(err)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900241 return fmt.Errorf("[%s] Error %d: %v", j.n.Output, exit, err)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900242 }
243 }
244
245 if j.n.IsPhony {
246 j.outputTs = time.Now().Unix()
247 } else {
248 j.outputTs = getTimestamp(j.n.Output)
249 if j.outputTs < 0 {
250 j.outputTs = time.Now().Unix()
251 }
252 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900253 return nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900254}
255
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900256func (wm *workerManager) handleJobs() error {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900257 for {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900258 if wm.para == nil && len(wm.freeWorkers) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900259 return nil
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900260 }
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900261 if wm.readyQueue.Len() == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900262 return nil
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900263 }
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900264 j := heap.Pop(&wm.readyQueue).(*job)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900265 logf("run: %s", j.n.Output)
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900266
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900267 if wm.para != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900268 var err error
269 j.runners, err = j.createRunners()
270 if err != nil {
271 return err
272 }
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900273 if len(j.runners) == 0 {
274 wm.updateParents(j)
275 wm.finishCnt++
276 } else {
277 wm.runnings[j.n.Output] = j
278 wm.para.RunCommand(j.runners)
279 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900280 } else {
281 j.numDeps = -1 // Do not let other workers pick this.
282 w := wm.freeWorkers[0]
283 wm.freeWorkers = wm.freeWorkers[1:]
284 wm.busyWorkers[w] = true
285 w.jobChan <- j
286 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900287 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900288}
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900289
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900290func (wm *workerManager) updateParents(j *job) {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900291 for _, p := range j.parents {
292 p.numDeps--
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900293 logf("child: %s (%d)", p.n.Output, p.numDeps)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900294 if p.depsTs < j.outputTs {
295 p.depsTs = j.outputTs
296 }
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900297 wm.maybePushToReadyQueue(p)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900298 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900299}
300
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900301type workerManager struct {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900302 maxJobs int
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900303 jobs []*job
304 readyQueue jobQueue
305 jobChan chan *job
306 resultChan chan jobResult
307 newDepChan chan newDep
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900308 stopChan chan bool
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +0900309 waitChan chan bool
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900310 doneChan chan error
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900311 freeWorkers []*worker
312 busyWorkers map[*worker]bool
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900313 ex *Executor
Fumitoshi Ukaiff4e5802015-06-25 13:12:26 +0900314 para *paraWorker
315 paraChan chan *paraResult
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900316 runnings map[string]*job
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900317
318 finishCnt int
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900319}
320
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900321func newWorkerManager(numJobs int, paraPath string) (*workerManager, error) {
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900322 wm := &workerManager{
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900323 maxJobs: numJobs,
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900324 jobChan: make(chan *job),
325 resultChan: make(chan jobResult),
326 newDepChan: make(chan newDep),
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900327 stopChan: make(chan bool),
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +0900328 waitChan: make(chan bool),
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900329 doneChan: make(chan error),
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900330 busyWorkers: make(map[*worker]bool),
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900331 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900332
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900333 if paraPath != "" {
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900334 wm.runnings = make(map[string]*job)
Fumitoshi Ukaiff4e5802015-06-25 13:12:26 +0900335 wm.paraChan = make(chan *paraResult)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900336 var err error
337 wm.para, err = newParaWorker(wm.paraChan, numJobs, paraPath)
338 if err != nil {
339 return nil, err
340 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900341 go wm.para.Run()
342 } else {
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900343 wm.busyWorkers = make(map[*worker]bool)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900344 for i := 0; i < numJobs; i++ {
345 w := newWorker(wm)
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900346 wm.freeWorkers = append(wm.freeWorkers, w)
347 go w.Run()
348 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900349 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900350 heap.Init(&wm.readyQueue)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900351 go wm.Run()
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900352 return wm, nil
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900353}
354
355func exitStatus(err error) int {
356 if err == nil {
357 return 0
358 }
359 exit := 1
360 if err, ok := err.(*exec.ExitError); ok {
361 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
362 return w.ExitStatus()
363 }
364 }
365 return exit
366}
367
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900368func (wm *workerManager) hasTodo() bool {
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900369 return wm.finishCnt != len(wm.jobs)
370}
371
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900372func (wm *workerManager) maybePushToReadyQueue(j *job) {
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900373 if j.numDeps != 0 {
374 return
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900375 }
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900376 heap.Push(&wm.readyQueue, j)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900377 logf("ready: %s", j.n.Output)
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900378}
379
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900380func (wm *workerManager) handleNewDep(j *job, neededBy *job) {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900381 if j.numDeps < 0 {
382 neededBy.numDeps--
Shinichiro Hamaji5180c972015-04-28 20:14:38 +0900383 if neededBy.id > 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900384 panic("FIXME: already in WM... can this happen?")
Shinichiro Hamaji5180c972015-04-28 20:14:38 +0900385 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900386 } else {
387 j.parents = append(j.parents, neededBy)
388 }
389}
390
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900391func (wm *workerManager) Run() {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900392 done := false
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900393 var err error
394Loop:
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900395 for wm.hasTodo() || len(wm.busyWorkers) > 0 || len(wm.runnings) > 0 || !done {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900396 select {
397 case j := <-wm.jobChan:
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900398 logf("wait: %s (%d)", j.n.Output, j.numDeps)
Shinichiro Hamaji5180c972015-04-28 20:14:38 +0900399 j.id = len(wm.jobs) + 1
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900400 wm.jobs = append(wm.jobs, j)
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900401 wm.maybePushToReadyQueue(j)
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900402 case jr := <-wm.resultChan:
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900403 logf("done: %s", jr.j.n.Output)
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900404 delete(wm.busyWorkers, jr.w)
405 wm.freeWorkers = append(wm.freeWorkers, jr.w)
406 wm.updateParents(jr.j)
Shinichiro Hamajidbc6c132015-04-28 18:26:36 +0900407 wm.finishCnt++
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900408 if jr.err != nil {
409 err = jr.err
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900410 close(wm.stopChan)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900411 break Loop
412 }
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +0900413 case af := <-wm.newDepChan:
414 wm.handleNewDep(af.j, af.neededBy)
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900415 logf("dep: %s (%d) %s", af.neededBy.n.Output, af.neededBy.numDeps, af.j.n.Output)
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900416 case pr := <-wm.paraChan:
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900417 if pr.status < 0 && pr.signal < 0 {
418 j := wm.runnings[pr.output]
419 for _, r := range j.runners {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900420 if r.echo || DryRunFlag {
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900421 fmt.Printf("%s\n", r.cmd)
422 }
423 }
424 } else {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900425 fmt.Fprint(os.Stdout, pr.stdout)
426 fmt.Fprint(os.Stderr, pr.stderr)
Shinichiro Hamajia6808422015-05-13 18:00:50 +0900427 j := wm.runnings[pr.output]
428 wm.updateParents(j)
429 delete(wm.runnings, pr.output)
430 wm.finishCnt++
431 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900432 case done = <-wm.waitChan:
433 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900434 err = wm.handleJobs()
435 if err != nil {
436 break Loop
437 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900438
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900439 if wm.para != nil {
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900440 numBusy := len(wm.runnings)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900441 if numBusy > wm.maxJobs {
442 numBusy = wm.maxJobs
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900443 }
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900444 logf("job=%d ready=%d free=%d busy=%d", len(wm.jobs)-wm.finishCnt, wm.readyQueue.Len(), wm.maxJobs-numBusy, numBusy)
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900445 } else {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900446 logf("job=%d ready=%d free=%d busy=%d", len(wm.jobs)-wm.finishCnt, wm.readyQueue.Len(), len(wm.freeWorkers), len(wm.busyWorkers))
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900447 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900448 }
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900449 if !done {
450 <-wm.waitChan
451 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900452
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900453 if wm.para != nil {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900454 logf("Wait for para to finish")
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900455 err := wm.para.Wait()
456 if err != nil {
457 logf("para failed: %v", err)
458 }
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900459 } else {
460 for _, w := range wm.freeWorkers {
461 w.Wait()
462 }
463 for w := range wm.busyWorkers {
464 w.Wait()
465 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900466 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900467 wm.doneChan <- err
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900468}
469
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900470func (wm *workerManager) PostJob(j *job) error {
471 select {
472 case wm.jobChan <- j:
473 return nil
474 case <-wm.stopChan:
475 return errors.New("worker manager stopped")
476 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900477}
478
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900479func (wm *workerManager) ReportResult(w *worker, j *job, err error) {
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900480 select {
481 case wm.resultChan <- jobResult{w: w, j: j, err: err}:
482 case <-wm.stopChan:
483 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900484}
485
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900486func (wm *workerManager) ReportNewDep(j *job, neededBy *job) {
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900487 select {
488 case wm.newDepChan <- newDep{j: j, neededBy: neededBy}:
489 case <-wm.stopChan:
490 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900491}
492
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900493func (wm *workerManager) Wait() error {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900494 wm.waitChan <- true
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900495 return <-wm.doneChan
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900496}