master xplshn/aruu / cmd / dev / ninqu / schedule.c
 1#include "ninqu.h"
 2
 3#include <stdio.h>
 4#include <stdlib.h>
 5
 6/* kahn topo sort, one ready level at a time so each level
 7 * runs in parallel. failures are reported but do not stop the
 8 * batch, so one broken file does not block the rest */
 9void
10schedule_and_run(void)
11{
12  int  *indeg      = ecalloc((size_t)ninsts, sizeof *indeg);
13  int **dependents = emalloc((size_t)ninsts * sizeof *dependents);
14  int  *ndep       = ecalloc((size_t)ninsts, sizeof *ndep);
15  int  *capdep     = ecalloc((size_t)ninsts, sizeof *capdep);
16  int  *level      = emalloc((size_t)ninsts * sizeof *level);
17  int   levn = 0, done_count = 0;
18  int   i, j;
19
20  for (i = 0; i < ninsts; i++) {
21    indeg[i]      = insts[i].n_dep;
22    dependents[i] = NULL;
23  }
24  for (i = 0; i < ninsts; i++) {
25    for (j = 0; j < insts[i].n_dep; j++) {
26      int d = insts[i].dep_inst[j];
27      if (ndep[d] >= capdep[d]) {
28        capdep[d]     = capdep[d] ? capdep[d] * 2 : 4;
29        dependents[d] = erealloc(dependents[d], (size_t)capdep[d] * sizeof *dependents[d]);
30      }
31      dependents[d][ndep[d]++] = i;
32    }
33  }
34  for (i = 0; i < ninsts; i++)
35    if (indeg[i] == 0)
36      level[levn++] = i;
37
38  while (levn > 0) {
39    int *next_level = emalloc((size_t)ninsts * sizeof *next_level);
40    int  nextn      = 0;
41
42    if (summary_mode) {
43      for (i = 0; i < levn; i++) {
44        struct Inst *inst = &insts[level[i]];
45        int          will = inst_stale(inst);
46        int          d;
47        for (d = 0; d < inst->n_dep && !will; d++)
48          if (insts[inst->dep_inst[d]].will_build)
49            will = 1;
50        inst->will_build = will;
51        printf(
52            "%-4s %-12s %s\n",
53            will ? "BUILD" : "OK",
54            rules[inst->rule_idx].name,
55            inst->out[0] ? inst->out : "(phony)"
56        );
57        if (rules[inst->rule_idx].description[0])
58          printf("       # %s\n", rules[inst->rule_idx].description);
59        if (will) {
60          char *cmd = sl_join(&inst->cmd.argv);
61          printf("       cmd: %s\n", cmd);
62          free(cmd);
63        }
64      }
65    } else {
66      run_batch(level, levn);
67    }
68
69    done_count += levn;
70    for (i = 0; i < levn; i++) {
71      int u = level[i];
72      for (j = 0; j < ndep[u]; j++) {
73        int v = dependents[u][j];
74        if (--indeg[v] == 0)
75          next_level[nextn++] = v;
76      }
77    }
78    free(level);
79    level = next_level;
80    levn  = nextn;
81  }
82
83  if (done_count < ninsts)
84    eprintf("manifest: dependency cycle among %d instances\n", ninsts - done_count);
85
86  free(level);
87  free(indeg);
88  for (i = 0; i < ninsts; i++)
89    free(dependents[i]);
90  free(dependents);
91  free(ndep);
92  free(capdep);
93}