runner.h (6483B)
1 #ifndef KIT_BUILD_RUNNER_H 2 #define KIT_BUILD_RUNNER_H 3 4 #include <kit/core.h> 5 #include <stddef.h> 6 #include <stdint.h> 7 8 #include "build.h" 9 #include "cfg.h" 10 #include "coord.h" 11 #include "resolve.h" 12 #include "trace.h" 13 14 /* 15 * Phase 3: running a recipe (the server side of the recipe protocol). Acquires 16 * a job slot, stages a sandbox, spawns the recipe via the exec host, services 17 * its protocol requests over the transport — logging each as a dependency — 18 * then on success ingests the output directory into the CAS, writes BOTH trace 19 * kinds, prepends them to the target record, installs the output in the tree 20 * cache, and returns the result. A nonzero exit propagates failure and writes 21 * NO trace. 22 * 23 * Writing both traces on every real build is what lets a later request take 24 * whichever path fits the change it sees. 25 */ 26 27 /* One submitted-but-not-yet-awaited need: the coordinator-assigned token, the 28 * (overlay-id, argv-id) it was dispatched under, and the in-flight future. 29 * Becomes a recorded dep edge only when AWAITED; un-awaited entries are 30 * cancelled when the recipe exits. */ 31 typedef struct BuildPendingNeed { 32 uint64_t token; 33 char dep[BUILD_TARGET_MAX]; 34 uint8_t overlay_id[BUILD_HASH_LEN]; 35 uint8_t argv_id[BUILD_HASH_LEN]; 36 BuildTargetFuture* future; /* from build_coord_dispatch */ 37 int awaited; 38 BuildResolved result; 39 } BuildPendingNeed; 40 41 /* The dependency log accumulated while servicing one recipe: the direct base 42 * inputs and direct target-dep edges, plus each dep's resolved deepset node, plus 43 * the live pending-needs table (submitted, not yet awaited). Converted on success 44 * into a shallow trace (direct inputs + dep edges) and a deep trace (a single 45 * pointer to the root deepset node, built by build_leafset_union over these direct 46 * leaves + dep edges + child nodes). Sections hang off caller/arena storage (no VLAs). */ 47 typedef struct BuildDepLog { 48 BuildConfigLeaf* configs; /* direct propagated-config observations */ 49 size_t n_configs, cap_configs; 50 BuildSourceLeaf* sources; /* direct source reads (absent recorded) */ 51 size_t n_sources, cap_sources; 52 BuildGlobLeaf* globs; /* direct globs */ 53 size_t n_globs, cap_globs; 54 BuildBlobLeaf* blobs; /* direct hash-pinned blobs */ 55 size_t n_blobs, cap_blobs; 56 BuildDepEdge* deps; /* AWAITED `need` edges (recorded) */ 57 size_t n_deps, cap_deps; 58 const BuildLeafSet** child_leafsets; /* one deepset node per awaited dep */ 59 size_t n_children, cap_children; 60 BuildPendingNeed* pending; /* submitted, not yet awaited */ 61 size_t n_pending, cap_pending; 62 uint64_t next_token; /* monotonic per-recipe token allocator */ 63 } BuildDepLog; 64 65 /* build_run_recipe — the Phase 3 entry, the continuation of build_resolve — is 66 * declared in resolve.h (so resolve.c can call it without including runner.h) 67 * and IMPLEMENTED in runner.c: it acquires a job slot, stages the sandbox, 68 * spawns the recipe (process argv = `argv`, delivered as-is), services its 69 * protocol connection via build_runner_service, and on success ingests the 70 * output and records both trace kinds. The two helpers below are the pieces of 71 * that flow split out so the in-process transport and the trace writer are 72 * independently testable. 73 * 74 * Recipe environment is CLEAN: the recipe receives its COMPLETE environment from 75 * the host (KitBuildExec.spawn does not inherit the coordinator's ambient env) — 76 * the KIT_BUILD_* vars plus the build's declared pass-through, sourced from the 77 * effective config's `env.` namespace (KIT_BUILD_ENV_PREFIX). Those keys are 78 * ordinary tracked config, so a recipe's environment is hermetic and cache- 79 * visible and replays/bundles like any other config. */ 80 81 /* Service one recipe connection until it exits: read framed requests and 82 * dispatch them, appending each dependency to `log`. Drives the protocol.h 83 * codec over the transport. `chain` is this recipe's chain frame (its dispatched 84 * needs extend it). Commands: 85 * config-get/source/glob/blob — synchronous; log the dep, reply. 86 * need (fused) — build_resolve inline on this thread; log the edge. 87 * need-submit — build_coord_dispatch(dep) (concurrent, no block), 88 * stash a BuildPendingNeed, reply a token. Cycles and 89 * unknown targets fail fast here. 90 * need-await <token> — release this recipe's job slot, await the pending 91 * need's future, reacquire; THEN log the dep edge + 92 * push its child node, and reply. The job slot is held 93 * only while actively running, so a chain deeper than 94 * `jobs` cannot deadlock (the same release/reacquire 95 * applies to the fused `need`). 96 * On EOF, any still-pending (submitted, never-awaited) needs are cancelled 97 * (exec->kill) and recorded as NO dependency. Separated so the in-process 98 * transport can reuse it. */ 99 int build_runner_service(KitBuildCoordinator*, KitBuildConn*, KitSlice target, 100 const BuildConfig* cfg, const BuildChainFrame* chain, 101 BuildDepLog* log); 102 103 /* Convert a completed dep-log + output into the canonical persisted state: 104 * - build the root deepset node (build_leafset_union over the log's direct 105 * leaves + recipe-id + dep edges + child nodes), which stores it as a CAS blob and yields 106 * its deep-set-id; 107 * - emit + store the SHALLOW trace (direct inputs + dep edges, by hash) and the 108 * DEEP trace (scalars + the root deep-set-id), and prepend both to the target 109 * record. 110 * Records the target's recipe-id and argv-id, its propagated-config 111 * observations, and each dep edge's (overlay-id, argv-id). Returns the root 112 * deepset node via *out_leafset so the caller can hand it back in 113 * BuildResolved. */ 114 int build_runner_record_traces(KitBuildCoordinator*, KitSlice target, 115 const BuildArgv* argv, const BuildDepLog*, 116 const uint8_t output[BUILD_HASH_LEN], 117 const BuildLeafSet** out_leafset); 118 int build_runner_record_test_traces(KitBuildCoordinator*, KitSlice target, 119 const BuildArgv* argv, 120 const BuildDepLog*, 121 const uint8_t result[BUILD_HASH_LEN], 122 const BuildLeafSet** out_leafset); 123 124 #endif