fix(scheduler): free registry entries after their tables at core teardown; fix dup_val and the unmeet re-init leak (bug-1884, part 5)
A failed key_add() runs the table's datakiller on the rejected value, and callers keep using it (JOBS_PUSH merges a duplicate job into the existing one; sched_init_queues() re-adds every queue on each config apply), so the job, queue, worker and resource datakillers must stay shallow. Part 4 made kill_sched_job() free the whole job; that is reverted. Instead xce_sched_core_fini() collects each table's entries, destroys the table, then frees each entry with a full destructor (core.c). The resource table is released the same way (a reference per resobj). Also: - dup_val() tested which == XCE_VAL_STRING (0, the resource value type, equal to Value_u_ivalue32): real string values were shallow-copied and a nonzero int32 went to makeString() as a pointer. It now tests Value_u_svalue and strdup()s, as free_Value() expects. - The shared/host satisfy checks re-initialize the unmeet vector they are given; the allocators passed the ctx's live one, dropping its buffers on every candidate host. The callers finalize it first. - add_vres() registers a resobj via makeResource(), like every other resource, instead of a bare calloc(); test_limit.c drops it with dereference(). - plugin_register_core() rejects a duplicate name before init_fn/key_add, since a failed add now finalizes (frees) the plugin and callers free it on failure. - sharedInUse gets kill_sched_resval, as put_resvals() fills it. Exit-time leak on the reproduction replay 7,469 -> 928 bytes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ebfe4794f0
commit
c1cd8f917d
11 changed files with 216 additions and 122 deletions
|
|
@ -660,11 +660,10 @@ static void test_fmt_limit_wrapper_matches_fmt_limit_units_raw_mode(void)
|
|||
* private and its existing white-box test harness stubs get_resvals()/
|
||||
* put_resvals() as no-ops, see test_repl_limit_table.c).
|
||||
*
|
||||
* add_vres() (xcelimit.c) key_add()s the limit's own new "limit=<name>"
|
||||
* vres into resmgr with no datakiller, so each test frees that one entry
|
||||
* by hand before tearing down the shared make_test_resmgr() fixture --
|
||||
* mirroring free_test_resmgr()'s own manual-free pattern for its 8
|
||||
* pre-registered resources.
|
||||
* add_vres() (xcelimit.c) registers the limit's own new "limit=<name>"
|
||||
* vres resobj in resmgr, and this fixture's resmgr has no datakiller, so
|
||||
* each test drops that one entry by hand before tearing down the shared
|
||||
* make_test_resmgr() fixture.
|
||||
*/
|
||||
static void free_instantiated_vres(var resmgr, xce_vres_t* vres)
|
||||
{
|
||||
|
|
@ -674,8 +673,7 @@ static void free_instantiated_vres(var resmgr, xce_vres_t* vres)
|
|||
|
||||
if (vres->vres != NULL) {
|
||||
key_del(resmgr, (void*)vres->vres->name);
|
||||
FREEUP(vres->vres->name);
|
||||
FREEUP(vres->vres);
|
||||
dereference(vres->vres); /* a resobj since bug-1884 */
|
||||
}
|
||||
|
||||
FREEUP(vres);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "group.h"
|
||||
#include "kvmgr.h"
|
||||
#include "resobj.h"
|
||||
#include "utils.h"
|
||||
#include "xce/types.h"
|
||||
#include "xcelimit.h"
|
||||
|
|
@ -507,40 +508,31 @@ static const char* percent_capacity_resname(const char* resname)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* add_vres - registers a limit's virtual resource. bug-1884: built with
|
||||
* makeResource() like every other resmgr entry (a reference-counted
|
||||
* resobj the manager releases), not a bare calloc(). */
|
||||
int add_vres(xce_resource_t** pvres, var resmgr, char* name, int global)
|
||||
{
|
||||
xce_resource_t* vres = NULL;
|
||||
int rc;
|
||||
xce_resource_t tmpl;
|
||||
|
||||
vres = (xce_resource_t*)calloc(1, sizeof(*vres));
|
||||
*pvres = vres;
|
||||
|
||||
if (vres == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vres->name = strdup(name);
|
||||
vres->idx = -1;
|
||||
vres->desc = NULL;
|
||||
vres->valtype = XCE_VAL_NUMERIC;
|
||||
vres->ordtype = XCE_ORD_DECR;
|
||||
vres->flags = XCE_RESF_LIMIT | XCE_RESF_CONSUMABLE | XCE_RESF_RELEASE;
|
||||
memset(&tmpl, 0, sizeof(tmpl));
|
||||
tmpl.name = name;
|
||||
tmpl.idx = -1;
|
||||
tmpl.valtype = XCE_VAL_NUMERIC;
|
||||
tmpl.ordtype = XCE_ORD_DECR;
|
||||
tmpl.flags = XCE_RESF_LIMIT | XCE_RESF_CONSUMABLE | XCE_RESF_RELEASE;
|
||||
if (global) {
|
||||
vres->flags |= (XCE_RESF_SHARED | XCE_RESF_GLOBAL);
|
||||
tmpl.flags |= (XCE_RESF_SHARED | XCE_RESF_GLOBAL);
|
||||
} else {
|
||||
vres->flags |= XCE_RESF_DEFAULT_HOST;
|
||||
tmpl.flags |= XCE_RESF_DEFAULT_HOST;
|
||||
}
|
||||
|
||||
lock(resmgr, RTTI_LOCK_WRITE);
|
||||
rc = key_add(resmgr, (void*)vres->name, (void*)vres);
|
||||
unlock(resmgr);
|
||||
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
*pvres = makeResource(resmgr, &tmpl);
|
||||
if (*pvres == NULL) {
|
||||
return (errno > 0) ? -errno : -ENOMEM;
|
||||
}
|
||||
|
||||
vres->idx = rc;
|
||||
return rc;
|
||||
return (*pvres)->idx;
|
||||
}
|
||||
|
||||
int instantiate_limit(xce_vres_t** pvres, var resmgr, xce_limit_t* limit,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue