feat(scheduler-core): implement session-start signal + decision callback (task 4.4)
Adds xce_core_go()/xce_core_end_session() (new core_session.c): xce_core_go() is non-blocking, performs begin-session state reset (select-eval-ctx, resval resets), signals the picker thread via wbuf, and returns -EINVAL on a reentrant call while a session is already active (proven a true no-op, not just an early return). Draining core->decisions and invoking the driver's on_decision callback is the driver's own responsibility between core_go() and core_end_session() (confirmed driver-owned, not core-owned, per the Driver <-> Core protocol). xce_core_set_decision_cb() registers the callback + driver context as a separate setter, keeping xce_sched_core_init()'s live sched_init() call site untouched. Adds XCE_DECISION_PREEMPT to decision.h (jobid/victims[]/reason) alongside the existing DISPATCH/ PEND types. Additive only — sched_go/sched_begin_session/ sched_end_session/sched_allocator/main.c remain untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019dw5WnN3DXStaEaPYfACU1
This commit is contained in:
parent
e6c0a2448a
commit
de69b6288d
9 changed files with 900 additions and 26 deletions
|
|
@ -31,6 +31,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "dataq.h"
|
||||
#include "decision.h"
|
||||
#include "mylock.h"
|
||||
#include "plugin.h"
|
||||
#include "sched/types.h"
|
||||
|
|
@ -45,6 +46,16 @@
|
|||
* matter). */
|
||||
typedef struct xce_sched_core_s xce_sched_core_t;
|
||||
|
||||
/*
|
||||
* xce_core_decision_cb_t - the driver-registered decision callback (task
|
||||
* 4.4, Req 5 AC 6): `int (*on_decision)(void* driver_ctx, xce_decision_t*
|
||||
* decision)`. Invoked once per decision, in allocator-output order, as the
|
||||
* driver drains `core->decisions` between `xce_core_go()` and
|
||||
* `xce_core_end_session()` -- see xce_core_go()/xce_core_end_session()'s
|
||||
* own doc comments (core_session.c) for the full protocol.
|
||||
*/
|
||||
typedef int (*xce_core_decision_cb_t)(void*, xce_decision_t*);
|
||||
|
||||
struct xce_sched_core_s {
|
||||
mylock_t lock;
|
||||
int stop;
|
||||
|
|
@ -55,30 +66,37 @@ struct xce_sched_core_s {
|
|||
* name. NULL until sched_set_default_job_pick_plugin() (schedobj.c)
|
||||
* applies the "builtin_fcfs" default, or a future config-driven
|
||||
* assignment sets it explicitly. */
|
||||
char* job_pick_plugin;
|
||||
var plugins;
|
||||
void* seqjob_allocator;
|
||||
void* parjob_allocator;
|
||||
void* affinity_allocator;
|
||||
void* gpu_allocator;
|
||||
dataq_t* pend_updates[2];
|
||||
var resmgr;
|
||||
var ugmgr;
|
||||
var qgmgr;
|
||||
var pgmgr;
|
||||
var hgmgr;
|
||||
zarray_t sharedInst;
|
||||
zarray_t sharedInUse;
|
||||
var jobs;
|
||||
var queues;
|
||||
var workers;
|
||||
var users;
|
||||
var projects;
|
||||
pthread_t jobpicker;
|
||||
pthread_t allocator;
|
||||
cbuf_t wbuf; /* action to trigger scheduling */
|
||||
cbuf_t jbuf; /* job picked for allocation */
|
||||
cbuf_t decisions; /* scheduler decisions */
|
||||
char* job_pick_plugin;
|
||||
var plugins;
|
||||
void* seqjob_allocator;
|
||||
void* parjob_allocator;
|
||||
void* affinity_allocator;
|
||||
void* gpu_allocator;
|
||||
dataq_t* pend_updates[2];
|
||||
var resmgr;
|
||||
var ugmgr;
|
||||
var qgmgr;
|
||||
var pgmgr;
|
||||
var hgmgr;
|
||||
zarray_t sharedInst;
|
||||
zarray_t sharedInUse;
|
||||
var jobs;
|
||||
var queues;
|
||||
var workers;
|
||||
var users;
|
||||
var projects;
|
||||
pthread_t jobpicker;
|
||||
pthread_t allocator;
|
||||
cbuf_t wbuf; /* action to trigger scheduling */
|
||||
cbuf_t jbuf; /* job picked for allocation */
|
||||
cbuf_t decisions; /* scheduler decisions */
|
||||
/* Req 5 AC 6 (scheduler-core spec, task 4.4): driver-registered
|
||||
* decision callback + opaque driver context, set via
|
||||
* xce_core_set_decision_cb() (core_session.c). NULL until a driver
|
||||
* registers one -- nothing in the still-live sched_go()/main.c path
|
||||
* reads these fields today. */
|
||||
void* driver_ctx;
|
||||
xce_core_decision_cb_t on_decision;
|
||||
_Atomic int session_active; /* 1 during scheduling session, 0 between */
|
||||
_Atomic int eval_in_progress; /* 1 while eval_select loop runs */
|
||||
_Atomic int staging_merge_complete; /* 1 after staging merge completes */
|
||||
|
|
@ -233,4 +251,55 @@ typedef struct {
|
|||
*/
|
||||
extern int xce_core_push_events(xce_sched_core_t*, xce_core_event_t*, int);
|
||||
|
||||
/*
|
||||
* xce_core_set_decision_cb - registers the driver's decision callback +
|
||||
* opaque driver context (task 4.4, Req 5 AC 6). May be called at any time
|
||||
* (typically once, at driver startup, before the first xce_core_go()) --
|
||||
* no session-active restriction, since it only stores two pointers and
|
||||
* neither is read outside the decision-drain window between
|
||||
* xce_core_go() and xce_core_end_session(). Returns -EINVAL if core is
|
||||
* NULL.
|
||||
*
|
||||
* Deliberately a separate setter rather than an xce_sched_core_init()
|
||||
* parameter (design.md's eventual `xce_sched_core_init(core, decision_cb,
|
||||
* driver_ctx, prng_seed)` signature, not yet adopted): the sole existing
|
||||
* xce_sched_core_init() call site (scheduler.c's sched_init(), still the
|
||||
* live production path) has no real driver/callback to pass yet, and this
|
||||
* task must not perturb that call site's behavior. A setter keeps
|
||||
* xce_sched_core_init() untouched while still letting a future driver (or
|
||||
* this task's own test) register a callback on an already-initialized
|
||||
* core.
|
||||
*/
|
||||
extern int xce_core_set_decision_cb(xce_sched_core_t*, xce_core_decision_cb_t,
|
||||
void*);
|
||||
|
||||
/*
|
||||
* xce_core_go - Req 5 AC 5 (scheduler-core spec, task 4.4). Starts a
|
||||
* scheduling session: NON-BLOCKING -- performs the begin-session state
|
||||
* reset (select-eval-ctx, shared resval, per-worker resval/host-ctx) then
|
||||
* signals the picker thread via a single `cbuf_put(&core->wbuf, ...)` and
|
||||
* returns immediately. Does NOT wait for the picker/allocator to produce
|
||||
* any decisions -- draining `core->decisions` and invoking the registered
|
||||
* `on_decision` callback is the driver's own responsibility, in the
|
||||
* driver's own loop between this call and xce_core_end_session()
|
||||
* (design.md's Normal-Mode Scheduling Round: "the drain loop in the
|
||||
* driver thread interleaves cbuf_get/on_decision one at a time").
|
||||
*
|
||||
* Returns 0 on success; -EINVAL if core is NULL OR a session is already
|
||||
* active (core->session_active != 0) -- the AC's required "distinct
|
||||
* error" for the reentrancy-rejection case.
|
||||
*/
|
||||
extern int xce_core_go(xce_sched_core_t*);
|
||||
|
||||
/*
|
||||
* xce_core_end_session - Req 5 AC 5 (scheduler-core spec, task 4.4). Called
|
||||
* by the driver after it has drained core->decisions down to the
|
||||
* end-of-session NULL marker (the marker itself terminates the driver's
|
||||
* drain loop -- it is never passed to on_decision; see core_session.c).
|
||||
* Performs the end-session cleanup (select-eval-ctx teardown, select-node
|
||||
* GC mark/sweep) then clears core->session_active to 0, unblocking the
|
||||
* next xce_core_go() call. Returns -EINVAL if core is NULL.
|
||||
*/
|
||||
extern int xce_core_end_session(xce_sched_core_t*);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -9,18 +9,47 @@ typedef enum {
|
|||
XCE_DECISION_NONE = 0,
|
||||
XCE_DECISION_DISPATCH,
|
||||
XCE_DECISION_PEND,
|
||||
XCE_DECISION_NEW_SESSION
|
||||
XCE_DECISION_NEW_SESSION,
|
||||
XCE_DECISION_PREEMPT
|
||||
} xce_decision_op_t;
|
||||
|
||||
/*
|
||||
* xce_preempt_victim_t / xce_preempt_t - PREEMPT decision payload
|
||||
* (scheduler-core spec, task 4.4, Req 5 AC 6). Scheduler-owned (not
|
||||
* xce/types.h): design.md's Boundary Commitments note that the PREEMPT
|
||||
* wire shape is owned by this spec while victim-*selection* semantics
|
||||
* belong to the (separate, not-yet-implemented) scheduler-preemption spec
|
||||
* -- so these two structs carry exactly AC 6's field list ("jobid,
|
||||
* victims[] (jobid, workerid per victim), reason") and nothing more.
|
||||
*
|
||||
* `victims` follows the same "int count; T** items" idiom as
|
||||
* xce_job_dispatch_t.allocs / xce_preason_set_t.reasons (xce/types.h) --
|
||||
* an array of pointers, not a flat array, for consistency with every other
|
||||
* decision-adjacent list in this codebase.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t jobid;
|
||||
char* workerid;
|
||||
} xce_preempt_victim_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t jobid;
|
||||
int nvictims;
|
||||
xce_preempt_victim_t** victims;
|
||||
xce_pendreason_t* reason;
|
||||
} xce_preempt_t;
|
||||
|
||||
typedef struct {
|
||||
xce_decision_op_t op;
|
||||
union {
|
||||
xce_job_alloc_t* alloc;
|
||||
xce_pendreason_t* reason;
|
||||
xce_preempt_t* preempt;
|
||||
} u;
|
||||
} xce_decision_t;
|
||||
|
||||
extern xce_decision_t* make_pend_decision(xce_pendreason_t*);
|
||||
extern xce_decision_t* make_dispatch_decision(xce_job_alloc_t*);
|
||||
extern xce_decision_t* make_preempt_decision(xce_preempt_t*);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue