#if !defined(_RESREQ_H_) #define _RESREQ_H_ 1 #include #include #include #include #include #include "kvmgr.h" #include "xlist.h" #include "xvec.h" /* ────────────────────────────────────────────────────────────────────────── * Select-expression AST (Phase 3-4 implementation) * ────────────────────────────────────────────────────────────────────────── */ typedef enum { SEL_AND, /* && — commutative binary */ SEL_OR, /* || — commutative binary */ SEL_NOT, /* ! — unary */ SEL_GT, /* > — numeric only */ SEL_LT, /* < — numeric only */ SEL_GE, /* >= — numeric only */ SEL_LE, /* <= — numeric only */ SEL_EQ, /* == — commutative, all types */ SEL_NE, /* != — commutative, all types */ SEL_RESNAME, /* leaf: resource variable */ SEL_NUM, /* leaf: numeric literal */ SEL_STR, /* leaf: string literal (xstring-interned) */ SEL_ANY, /* leaf: 'any' keyword — eliminated by const-fold */ SEL_TRUE, /* leaf: const true — produced by const-fold only */ SEL_FALSE, /* leaf: const false — produced by const-fold only */ } sel_node_type_t; typedef enum { RES_TYPE_NUMERIC = 0, /* float — supports all comparison operators */ RES_TYPE_STRING, /* char* — supports == != only */ RES_TYPE_BOOL, /* int — standalone boolean use */ } res_type_t; typedef struct xce_select_node_ xce_select_node_t; struct xce_select_node_ { sel_node_type_t type; uint32_t hashcode; uint32_t node_id; unsigned gc_mark; union { struct { xce_select_node_t *left, *right; } binop; /* AND / OR / GT / LT / GE / LE / EQ / NE */ xce_select_node_t* operand; /* NOT */ struct { int res_idx; res_type_t res_type; } resname; double numval; /* SEL_NUM */ char* strval; /* SEL_STR — xstring-interned */ } u; }; /* Evaluation context forward declarations */ typedef struct select_eval_ctx_ select_eval_ctx_t; typedef struct host_eval_ctx_ host_eval_ctx_t; /* Host snapshot: per-resource numeric (incl. bool as 0.0/1.0) and string values */ struct host_eval_ctx_ { int num_res; const double* numvals; /* indexed by res_idx */ const char** strvals; /* indexed by res_idx */ }; /* Per-evaluation-session memoization context */ struct select_eval_ctx_ { const host_eval_ctx_t* host; uint8_t* bool_bits; /* 2 bits per node_id: NONE/TRUE/FALSE/ERROR */ uint32_t bool_bits_cap; /* capacity in nodes (each uses 2 bits) */ uint32_t node_count; /* snapshot of sel_node_next_id at init */ double* num_vals; /* numeric/bool leaf cache, indexed by node_id */ uint32_t num_vals_cap; const char** str_vals; /* string leaf cache, indexed by node_id */ uint32_t str_vals_cap; }; /* Scheduler job forward declaration for GC API */ typedef struct xce_sched_job_ xce_sched_job_t; /* makeSelectNode — intern or allocate a select AST node. * Returns NULL on OOM or intern-table cap exceeded. */ extern xce_select_node_t* makeSelectNode(sel_node_type_t type, uintptr_t op1, uintptr_t op2); /* Resreq subsystem lifecycle — call once at process startup/shutdown. * resreq_init sets the optimization level and initializes the intern table. * resreq_fini tears down the intern table. * optimize_level: 0 = disabled (API server); >0 = CSE+memoization (scheduler). */ extern void resreq_init(int optimize_level); extern void resreq_fini(void); /* Optimization level — set once at process startup. * 0 = disabled (API server); >0 = CSE+memoization (scheduler). */ extern void sel_optimize_set(int level); extern int sel_get_optimize_level(void); /* Register the calling thread as the sole allocator/eval/GC thread. * Must be called once at scheduler startup (before eval_select or * gc_sweep_select_nodes). When unregistered (id==0) the checks are skipped. */ extern void sel_register_alloc_thread(void); /* Intern table lifecycle */ extern void sel_node_table_init(void); extern void sel_node_table_fini(void); /* Test-only reset (requires #define UNIT_TEST before this header) */ #ifdef UNIT_TEST extern void sel_optimize_test_reset(void); #endif /* Evaluation APIs */ extern int eval_select(const xce_select_node_t* node, select_eval_ctx_t* ctx); extern int eval_select_simple(const xce_select_node_t* root, const host_eval_ctx_t* host); /* Eval context lifecycle */ extern select_eval_ctx_t* select_eval_ctx_init(uint32_t max_node_id); extern void select_eval_ctx_reset(select_eval_ctx_t* ctx, const host_eval_ctx_t* host); extern void select_eval_ctx_fini(select_eval_ctx_t* ctx); /* Mark-and-sweep GC between scheduling sessions */ extern void gc_sweep_select_nodes(const xce_sched_job_t** live_jobs, size_t njobs); extern void recompact_node_ids(void); /* GC mark primitives — called by scheduler to implement the mark phase. * Protocol: gc_clear_marks() → gc_mark_select_tree(root) per live node * → gc_sweep_select_nodes(NULL, 0) → recompact_node_ids() */ extern void gc_clear_marks(void); extern void gc_mark_select_tree(xce_select_node_t* node); /* Flatten AND/OR right-associative chains to left-associative form. * Returns the new root (may differ from the input root). * Sets *changed to 1 if any re-association took place, leaves it unchanged * otherwise (callers must initialise *changed to 0 before the first call). * In level==0 mode: frees orphaned intermediate nodes (NOT their re-parented * children). In CSE mode (level > 0): no explicit freeing — GC owns nodes. */ extern xce_select_node_t* sel_flatten_pass(xce_select_node_t* root, int* changed); /* Single-pass const-fold transform (Phase 4d). * In level==0: may return a new allocation; frees consumed subtrees. * In CSE mode (level > 0): returns an interned singleton; GC owns nodes. */ extern xce_select_node_t* sel_const_fold_pass(xce_select_node_t* node); typedef struct xce_resreq_select_ xce_select_t; typedef struct xce_resreq_rusages_ xce_rusages_t; typedef struct xce_resreq_span_ xce_span_t; typedef struct xce_resreq_same_ xce_same_t; typedef struct xce_resreq_affinity_ xce_affinity_t; typedef struct xce_resreq_data_ xce_resreq_data_t; struct xce_resreq_data_ { char* selectString; char* rusageString; char* spanString; char* sameString; char* affinityString; }; typedef struct { const char* input; int pos; char* errmsg; int err_pos; int has_error; xce_resreq_data_t data; } section_context_t; /* Maximum allowed select expression length and nesting depth */ #define SELECT_MAX_INPUT_LEN 8192 #define SELECT_MAX_DEPTH 64 /* Parse context for xce_select.peg — auxil struct for packcc-generated parser */ typedef struct select_context_t_ select_context_t; struct select_context_t_ { var resmgr; /* resource manager for name resolution */ const char* input; int pos; int err_pos; int has_error; char errmsg[256]; /* fixed-size — no alloc/free in grammar actions */ int depth; /* current nesting depth — guard vs SELECT_MAX_DEPTH */ xce_select_node_t* root; /* result root set by grammar top-level action */ }; typedef enum { PER_TASK = 0, PER_JOB, PER_HOST, PER_DEFAULT } rusage_per_type_t; typedef struct { const char* input; int pos; int err_pos; int has_error; xlist_t* rusages; char* resname; rusage_per_type_t per_flag; float resvalue; float duration_value; int decay_flag; float tmp_value; float duration_multiply; } rusage_context_t; typedef struct { char* res; float value; rusage_per_type_t per_flag; float duration; int decay_flag; } rusage_value_t; struct xce_resreq_select_ { xce_select_node_t* root; }; struct xce_resreq_span_ { }; struct xce_resreq_same_ { }; struct xce_resreq_affinity_ { }; typedef struct { int minTasks; int maxTasks; xce_select_t* select; xlist_t rusages; xce_span_t* span; xce_same_t* same; xce_affinity_t* affinity; } xce_primary_resreq_t; typedef struct { xlist_t primaries; } xce_compound_resreq_t; typedef struct { xlist_t compounds; } xce_alter_resreq_t; typedef enum { XCE_RESREQ_PRIMARY = 0, XCE_RESREQ_COMPOUND, XCE_RESREQ_ALTER } xce_resreq_tag_t; typedef struct { xce_resreq_tag_t tag; union { xce_primary_resreq_t* primary; xce_compound_resreq_t* compound; xce_alter_resreq_t* alter; } u; } xce_resreq_t; typedef struct { var resmgr; const char* input; int pos; int err_pos; int has_error; char* errmsg; xce_resreq_t* resreq; xce_alter_resreq_t* alter; xce_compound_resreq_t* compound; xce_primary_resreq_t* primary; int resreq_fact_count; } resreq_context_t; extern res_type_t valtype_to_res_type(int v); /* Single comparison point for string-valued resources. * Returns 1 if a == b, 0 otherwise. Named for future wildcard extension. */ static inline int xce_str_match(const char* a, const char* b) { /* NULL means the resource has no value — treat as no-match */ if (a == NULL || b == NULL) return 0; return strcmp(a, b) == 0; } extern void kill_select(xce_select_t*); extern void sel_free_tree(xce_select_node_t*); extern void kill_section_ctx(section_context_t*); extern void kill_resreq_data(xce_resreq_data_t*); extern int parse_section(xce_resreq_data_t*, char*, char**); extern int parse_rusage(xlist_t*, char*, char**); extern void kill_rusage_value(rusage_value_t*); extern int parse_resreq_primary(xce_primary_resreq_t*, char*, var, char**); extern void kill_primary_resreq(xce_primary_resreq_t*); extern int parse_resreq(xce_resreq_t*, char*, var, char**); extern void kill_resreq(xce_resreq_t*); extern int format_resreq(char**, xce_resreq_t*); extern int calc_wanted_global_resvals(xvec_idval_t*, var, xlist_t*, rusage_per_type_t, int, int); extern int calc_wanted_host_resvals(xvec_idval_t*, var, xlist_t*, rusage_per_type_t, int, int); #endif