aboutsummaryrefslogtreecommitdiffstats
path: root/worker.go
diff options
context:
space:
mode:
authorFumitoshi Ukai <fumitoshi.ukai@gmail.com>2015-06-26 21:32:50 +0900
committerFumitoshi Ukai <fumitoshi.ukai@gmail.com>2015-06-26 23:08:01 +0900
commit65c7233c02ba0f62c38ef96e4bb59dcb273542e9 (patch)
tree9b02ced4ebe2cff26d772431cc81b4ecfc2425ff /worker.go
parent480bca50f6f74c0021910540a6e0ea8761eb5f61 (diff)
downloadandroid_build_kati-65c7233c02ba0f62c38ef96e4bb59dcb273542e9.tar.gz
android_build_kati-65c7233c02ba0f62c38ef96e4bb59dcb273542e9.tar.bz2
android_build_kati-65c7233c02ba0f62c38ef96e4bb59dcb273542e9.zip
fix panic based error reporting
Diffstat (limited to 'worker.go')
-rw-r--r--worker.go103
1 files changed, 65 insertions, 38 deletions
diff --git a/worker.go b/worker.go
index 8948ac6..9d3fd09 100644
--- a/worker.go
+++ b/worker.go
@@ -45,8 +45,9 @@ type runner struct {
}
type jobResult struct {
- j *job
- w *worker
+ j *job
+ w *worker
+ err error
}
type newDep struct {
@@ -99,8 +100,8 @@ func (w *worker) Run() {
for !done {
select {
case j := <-w.jobChan:
- j.build()
- w.wm.ReportResult(w, j)
+ err := j.build()
+ w.wm.ReportResult(w, j, err)
case done = <-w.waitChan:
}
}
@@ -116,19 +117,22 @@ func (w *worker) Wait() {
<-w.doneChan
}
-func evalCmd(ev *Evaluator, r runner, s string) []runner {
+func evalCmd(ev *Evaluator, r runner, s string) ([]runner, error) {
r = newRunner(r, s)
if strings.IndexByte(r.cmd, '$') < 0 {
// fast path
- return []runner{r}
+ return []runner{r}, nil
}
// TODO(ukai): parse once more earlier?
expr, _, err := parseExpr([]byte(r.cmd), nil, false)
if err != nil {
- panic(fmt.Errorf("parse cmd %q: %v", r.cmd, err))
+ return nil, ev.errorf("parse cmd %q: %v", r.cmd, err)
}
buf := newBuf()
- expr.Eval(buf, ev)
+ err = expr.Eval(buf, ev)
+ if err != nil {
+ return nil, err
+ }
cmds := buf.String()
freeBuf(buf)
var runners []runner
@@ -140,7 +144,7 @@ func evalCmd(ev *Evaluator, r runner, s string) []runner {
runners = append(runners, newRunner(r, cmd))
}
}
- return runners
+ return runners, nil
}
func newRunner(r runner, s string) runner {
@@ -189,9 +193,9 @@ func (r runner) run(output string) error {
return err
}
-func (j *job) createRunners() []runner {
- runners, _ := j.ex.createRunners(j.n, false)
- return runners
+func (j *job) createRunners() ([]runner, error) {
+ runners, _, err := j.ex.createRunners(j.n, false)
+ return runners, err
}
// TODO(ukai): use time.Time?
@@ -203,7 +207,7 @@ func getTimestamp(filename string) int64 {
return st.ModTime().Unix()
}
-func (j *job) build() {
+func (j *job) build() error {
if j.n.IsPhony {
j.outputTs = -2 // trigger cmd even if all inputs don't exist.
} else {
@@ -212,26 +216,28 @@ func (j *job) build() {
if !j.n.HasRule {
if j.outputTs >= 0 || j.n.IsPhony {
- return
+ return nil
}
if len(j.parents) == 0 {
- errorNoLocationExit("*** No rule to make target %q.", j.n.Output)
- } else {
- errorNoLocationExit("*** No rule to make target %q, needed by %q.", j.n.Output, j.parents[0].n.Output)
+ return fmt.Errorf("*** No rule to make target %q.", j.n.Output)
}
- errorNoLocationExit("no rule to make target %q", j.n.Output)
+ return fmt.Errorf("*** No rule to make target %q, needed by %q.", j.n.Output, j.parents[0].n.Output)
}
if j.outputTs >= j.depsTs {
// TODO: stats.
- return
+ return nil
}
- for _, r := range j.createRunners() {
+ rr, err := j.createRunners()
+ if err != nil {
+ return err
+ }
+ for _, r := range rr {
err := r.run(j.n.Output)
if err != nil {
exit := exitStatus(err)
- errorNoLocationExit("[%s] Error %d: %v", j.n.Output, exit, err)
+ return fmt.Errorf("[%s] Error %d: %v", j.n.Output, exit, err)
}
}
@@ -243,21 +249,26 @@ func (j *job) build() {
j.outputTs = time.Now().Unix()
}
}
+ return nil
}
-func (wm *workerManager) handleJobs() {
+func (wm *workerManager) handleJobs() error {
for {
if wm.para == nil && len(wm.freeWorkers) == 0 {
- return
+ return nil
}
if wm.readyQueue.Len() == 0 {
- return
+ return nil
}
j := heap.Pop(&wm.readyQueue).(*job)
logf("run: %s", j.n.Output)
if wm.para != nil {
- j.runners = j.createRunners()
+ var err error
+ j.runners, err = j.createRunners()
+ if err != nil {
+ return err
+ }
if len(j.runners) == 0 {
wm.updateParents(j)
wm.finishCnt++
@@ -294,7 +305,7 @@ type workerManager struct {
resultChan chan jobResult
newDepChan chan newDep
waitChan chan bool
- doneChan chan bool
+ doneChan chan error
freeWorkers []*worker
busyWorkers map[*worker]bool
ex *Executor
@@ -305,21 +316,25 @@ type workerManager struct {
finishCnt int
}
-func newWorkerManager(numJobs int, paraPath string) *workerManager {
+func newWorkerManager(numJobs int, paraPath string) (*workerManager, error) {
wm := &workerManager{
maxJobs: numJobs,
jobChan: make(chan *job),
resultChan: make(chan jobResult),
newDepChan: make(chan newDep),
waitChan: make(chan bool),
- doneChan: make(chan bool),
+ doneChan: make(chan error),
busyWorkers: make(map[*worker]bool),
}
if paraPath != "" {
wm.runnings = make(map[string]*job)
wm.paraChan = make(chan *paraResult)
- wm.para = newParaWorker(wm.paraChan, numJobs, paraPath)
+ var err error
+ wm.para, err = newParaWorker(wm.paraChan, numJobs, paraPath)
+ if err != nil {
+ return nil, err
+ }
go wm.para.Run()
} else {
wm.busyWorkers = make(map[*worker]bool)
@@ -331,7 +346,7 @@ func newWorkerManager(numJobs int, paraPath string) *workerManager {
}
heap.Init(&wm.readyQueue)
go wm.Run()
- return wm
+ return wm, nil
}
func exitStatus(err error) int {
@@ -363,7 +378,7 @@ func (wm *workerManager) handleNewDep(j *job, neededBy *job) {
if j.numDeps < 0 {
neededBy.numDeps--
if neededBy.id > 0 {
- panic("already in WM... can this happen?")
+ panic("FIXME: already in WM... can this happen?")
}
} else {
j.parents = append(j.parents, neededBy)
@@ -372,6 +387,8 @@ func (wm *workerManager) handleNewDep(j *job, neededBy *job) {
func (wm *workerManager) Run() {
done := false
+ var err error
+Loop:
for wm.hasTodo() || len(wm.busyWorkers) > 0 || len(wm.runnings) > 0 || !done {
select {
case j := <-wm.jobChan:
@@ -385,6 +402,10 @@ func (wm *workerManager) Run() {
wm.freeWorkers = append(wm.freeWorkers, jr.w)
wm.updateParents(jr.j)
wm.finishCnt++
+ if jr.err != nil {
+ err = jr.err
+ break Loop
+ }
case af := <-wm.newDepChan:
wm.handleNewDep(af.j, af.neededBy)
logf("dep: %s (%d) %s", af.neededBy.n.Output, af.neededBy.numDeps, af.j.n.Output)
@@ -406,7 +427,10 @@ func (wm *workerManager) Run() {
}
case done = <-wm.waitChan:
}
- wm.handleJobs()
+ err = wm.handleJobs()
+ if err != nil {
+ break Loop
+ }
if wm.para != nil {
numBusy := len(wm.runnings)
@@ -421,7 +445,10 @@ func (wm *workerManager) Run() {
if wm.para != nil {
logf("Wait for para to finish")
- wm.para.Wait()
+ err := wm.para.Wait()
+ if err != nil {
+ logf("para failed: %v", err)
+ }
} else {
for _, w := range wm.freeWorkers {
w.Wait()
@@ -430,22 +457,22 @@ func (wm *workerManager) Run() {
w.Wait()
}
}
- wm.doneChan <- true
+ wm.doneChan <- err
}
func (wm *workerManager) PostJob(j *job) {
wm.jobChan <- j
}
-func (wm *workerManager) ReportResult(w *worker, j *job) {
- wm.resultChan <- jobResult{w: w, j: j}
+func (wm *workerManager) ReportResult(w *worker, j *job, err error) {
+ wm.resultChan <- jobResult{w: w, j: j, err: err}
}
func (wm *workerManager) ReportNewDep(j *job, neededBy *job) {
wm.newDepChan <- newDep{j: j, neededBy: neededBy}
}
-func (wm *workerManager) Wait() {
+func (wm *workerManager) Wait() error {
wm.waitChan <- true
- <-wm.doneChan
+ return <-wm.doneChan
}