feat(scheduler-core): implement scheduler-side admin request handler (task 9.4)
Implements the scheduler's first request-reply opcode (OPCode_schedAdmin). sched_handle_admin_request() (handler.c) decodes SchedAdminRequest and dispatches by action: recordStatus answers synchronously (pure read); recordStart/recordStop are deferred onto the existing pend_updates queue (XCE_SCHED_OP_ADMIN_RECORD) since sched_record_start()'s snapshot call requires the session_active==0 precondition only guaranteed on the driver thread, not the async request-handling thread. driver.c's xce_sched_driver_translate_pending_events() performs the deferred action and sends the reply via a new xcecli_reply_schedadmin() (client.c/client.h), correlated by seq copied before the original request is freed. Adversarial review found a genuine cross-thread race: sched_record_status() read driver-owned recording state (including a pointer the driver thread frees) from the vtask thread with no lock -- the codebase's first such race, missed by ASan (doesn't detect races). Fixed with a dedicated record_lock scoped strictly to in-memory field access, never spanning file I/O; sched_record_status() now strdup()s under the lock instead of returning a borrowed live pointer. Verified with a real two-thread lock-contention test (independently confirmed non-vacuous by removing the lock and observing the test fail) plus a deterministic use-after-free reproduction. 26/26 scheduler suite, clang-format clean.
This commit is contained in:
parent
7494542a60
commit
e819a50600
19 changed files with 1761 additions and 115 deletions
|
|
@ -969,6 +969,40 @@ int xcecli_reply_fetchfile(xcecli_ctx_t c, xce_request_t* request,
|
|||
return xce_reply(&(ctx->ep), &(ctx->ctx.myinfo), &reply);
|
||||
}
|
||||
|
||||
/*
|
||||
* xcecli_reply_schedadmin - see client.h's declaration comment for the full
|
||||
* contract (scheduler-core spec, task 9.4, Req 5 AC 10). Builds the
|
||||
* RequestReply envelope directly (no init_reply_by_req(): unlike
|
||||
* xcecli_reply_fetchfile() above, the caller may not have a live
|
||||
* xce_request_t any more -- recordStart/recordStop replies are sent from
|
||||
* the driver thread, after the original request has already been freed).
|
||||
* `reply.status` is always 0: a successfully-built SchedAdminReply is
|
||||
* always a valid RPC response, whether its own `.ok` field is true or
|
||||
* false (business-level success/failure lives inside the SchedAdminReply
|
||||
* payload itself, per its own `ok`/`error` fields -- same convention
|
||||
* handle_config_request() (controller/config_repl.c) uses for
|
||||
* ReplConfigReply's "up to date" case).
|
||||
*/
|
||||
int xcecli_reply_schedadmin(xcecli_ctx_t c, uint64_t seq,
|
||||
sched_admin_reply_t* areply)
|
||||
{
|
||||
api_ctx_t* ctx = (api_ctx_t*)c;
|
||||
xce_reply_t reply;
|
||||
|
||||
if ((ctx == NULL) || (areply == NULL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
reply.seq = seq;
|
||||
reply.opcode = OPCode_schedAdmin;
|
||||
reply.status = 0;
|
||||
reply.data_which = RequestReply_data_schedadminreplymsg;
|
||||
reply.data.schedadminreplymsg = areply;
|
||||
|
||||
return xce_reply(&(ctx->ep), &(ctx->ctx.myinfo), &reply);
|
||||
}
|
||||
|
||||
int xcecli_fetchfile(xcecli_ctx_t c, xce_fetchfile_t* msg,
|
||||
xce_fetchfile_reply_t** reply)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue