new models

This commit is contained in:
fy59 2026-08-07 09:24:01 +02:00
parent 60832b51cf
commit ad90295e0d
13 changed files with 617 additions and 102 deletions

View file

@ -5,7 +5,12 @@ model: opencode/nemotron-3-ultra-free
temperature: 0.1
permission:
edit: deny
bash: deny
bash:
"*": deny
"rg *": allow
"git grep*": allow
"git diff*": allow
"sed -n *": allow
task: deny
---

View file

@ -0,0 +1,79 @@
---
description: Reprend un build complexe via OpenRouter lorsque Google ou Zen sont indisponibles
mode: subagent
model: openrouter/nvidia/nemotron-3-ultra-550b-a55b:free
temperature: 0.1
permission:
edit:
"*": allow
"scan3d/**": deny
bash:
"*": deny
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
"CC=clang meson setup *": allow
"meson setup *": allow
"meson compile *": allow
"meson test *": allow
"ninja *": allow
"git diff --check*": allow
task: deny
---
Tu es le deuxième agent de secours pour l'implémentation de Lardon3D.
Tu interviens uniquement lorsqu'un ticket est déjà préparé et que le build
principal ou le premier backup sont indisponibles.
Commence par lire :
- `.opencode/work/current_ticket.md` ;
- le diff courant ;
- uniquement les fichiers explicitement cités dans le handoff.
Ne refais pas l'exploration ou l'architecture si le handoff contient déjà les
informations nécessaires.
Ne charge jamais tout le dépôt.
Ne lance jamais :
- `pwd`
- `ls`
- `find`
- glob global
- lecture complète de la documentation
Respecte strictement :
- l'objectif du ticket ;
- les contraintes ;
- les API existantes ;
- les invariants ;
- le périmètre de fichiers indiqué.
Ne crée aucune fonctionnalité supplémentaire.
Ne modifie jamais `scan3d/`.
Ne fais aucun commit.
Ne fais aucun push.
Après implémentation :
- exécute uniquement les validations demandées par le ticket ;
- ne tente pas de corriger un autre problème découvert hors périmètre ;
- signale-le seulement.
À la fin, rapporte uniquement :
- modification exacte ;
- fichiers modifiés ;
- validations exécutées ;
- erreurs éventuelles ;
- limites restantes ;
- prochaine action sûre.

View file

@ -1,12 +1,26 @@
---
description: Reprend les tickets complexes interrompus sans refaire l'analyse
mode: subagent
model: opencode/nemotron-3-ultra-free
model: opencode/deepseek-v4-flash-free
temperature: 0.1
permission:
edit:
"*": allow
"scan3d/**": deny
bash:
"*": deny
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
"CC=clang meson setup *": allow
"meson setup *": allow
"meson compile *": allow
"meson test *": allow
"ninja *": allow
"git diff --check*": allow
task: deny
---

View file

@ -7,6 +7,20 @@ permission:
edit:
"*": allow
"scan3d/**": deny
bash:
"*": deny
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
"CC=clang meson setup *": allow
"meson setup *": allow
"meson compile *": allow
"meson test *": allow
"ninja *": allow
"git diff --check*": allow
task: deny
---

View file

@ -1,12 +1,26 @@
---
description: Implémente seul les tickets complexes Lardon3D
mode: subagent
model: opencode/deepseek-v4-flash-free
model: google/gemini-3.6-flash
temperature: 0.1
permission:
edit:
"*": allow
"scan3d/**": deny
bash:
"*": deny
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
"CC=clang meson setup *": allow
"meson setup *": allow
"meson compile *": allow
"meson test *": allow
"ninja *": allow
"git diff --check*": allow
task: deny
---

View file

@ -7,8 +7,12 @@ permission:
edit: deny
bash:
"*": deny
"git diff*": allow
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
task: deny
---

View file

@ -9,6 +9,9 @@ permission:
"*": deny
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"sed -n *": allow
task: deny
---

View file

@ -16,6 +16,7 @@ permission:
"*": deny
"lardon-build": allow
"lardon-build-backup": allow
"lardon-build-backup-router": allow
"lardon-build-light": allow
"lardon-architect": allow
"lardon-explore": allow
@ -70,6 +71,21 @@ Cette règle sapplique même si le ticket ne crée aucun nouveau thread.
- fichiers concernés ;
- API et invariants ;
- tests requis.
Chaîne d'implémentation :
1. Utiliser `lardon-build` pour l'implémentation normale.
2. Si `lardon-build` échoue pour indisponibilité du fournisseur, quota ou erreur
429/503, conserver le handoff et utiliser `lardon-build-backup`.
3. Si le premier backup est lui-même indisponible, utiliser
`lardon-build-backup-router`.
4. Ne jamais recommencer l'exploration ou l'architecture lors d'un fallback si
le handoff contient déjà les informations nécessaires.
5. Ne jamais basculer vers un modèle payant.
Un fallback ne doit modifier ni l'objectif, ni le périmètre, ni les invariants
du ticket.
7. Mettre à jour le handoff après chaque phase importante.
Le répertoire `.opencode/work/` est préparé localement. Ne vérifie pas son

View file

@ -7,8 +7,12 @@ permission:
edit: deny
bash:
"*": deny
"git diff*": allow
"rg *": allow
"git grep*": allow
"git status*": allow
"git diff*": allow
"git log*": allow
"sed -n *": allow
task: deny
---

View file

@ -8,10 +8,11 @@ permission:
bash:
"*": deny
"CC=clang meson setup *": allow
"meson setup *": allow
"meson compile *": allow
"meson test *": allow
"ninja *": allow
"git diff --check*": allow
"git diff*": allow
"git status*": allow
task: deny
---

View file

@ -83,8 +83,11 @@ bool lardon3d_task_execution_contract(
);
/* Libère la réservation courante, en obtient une nouvelle auprès du gouverneur
* et met à jour le contrat. À appeler uniquement depuis le callback en cours
* d'exécution. Retourne false si pause/annulation est demandée ou si le
* gouverneur répond WAIT/REJECT (la tâche passe alors en échec). */
* d'exécution. Une réponse WAIT du gouverneur est une indisponibilité
* temporaire : la fonction attend un changement de ressources puis retente
* l'admission sans échouer la tâche. Retourne false si la tâche est annulée
* (TASK_CANCELLED), si le gouverneur répond REJECT ou en cas d'erreur interne
* (TASK_FAILED). */
bool lardon3d_task_sequence_break(
Lardon3DTask *task,
Lardon3DResourceGovernor *governor,

View file

@ -278,6 +278,11 @@ lardon3d_task_checkpoint(Lardon3DTask *task)
return continuing;
}
enum {
/* Attente bornée entre deux tentatives d'admission : 50 ms. */
LARDON3D_SEQUENCE_ADMISSION_WAIT_NS = 50000000ULL,
};
bool
lardon3d_task_sequence_break(
Lardon3DTask *task,
@ -302,6 +307,7 @@ lardon3d_task_sequence_break(
(void)pthread_cond_wait(&task->condition, &task->mutex);
}
if (task->cancel_requested) {
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
@ -314,95 +320,121 @@ lardon3d_task_sequence_break(
(void)lardon3d_resource_governor_release(governor, previous);
}
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *next = NULL;
bool reserved = lardon3d_resource_governor_reserve_available(
governor,
&task->estimate,
&decision,
&next
);
for (;;) {
/* Vérifier pause et annulation avant chaque tentative d'admission. */
(void)pthread_mutex_lock(&task->mutex);
while (task->pause_requested && !task->cancel_requested) {
task->state = TASK_PAUSED;
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
(void)pthread_cond_broadcast(&task->condition);
(void)pthread_cond_wait(&task->condition, &task->mutex);
}
if (task->cancel_requested) {
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
task->state = TASK_RUNNING;
(void)pthread_mutex_unlock(&task->mutex);
(void)pthread_mutex_lock(&task->mutex);
if (task->cancel_requested) {
if (next) {
(void)lardon3d_resource_governor_release(governor, next);
}
finish_locked(
task,
TASK_CANCELLED,
"Tâche annulée pendant sequence_break."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
while (task->pause_requested && !task->cancel_requested) {
task->state = TASK_PAUSED;
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
(void)pthread_cond_broadcast(&task->condition);
(void)pthread_cond_wait(&task->condition, &task->mutex);
}
if (task->cancel_requested) {
if (next) {
(void)lardon3d_resource_governor_release(governor, next);
}
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
if (!reserved || !next) {
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
"Impossible de réserver les ressources de la séquence."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
if (decision.kind == LARDON3D_RESOURCE_WAIT
|| decision.kind == LARDON3D_RESOURCE_REJECT) {
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
decision.reason[0] ? decision.reason
: "Ressources impossibles à réserver."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
Lardon3DResourceReservationInfo information;
if (!lardon3d_resource_reservation_get_active(
uint64_t generation = lardon3d_resource_governor_generation(governor);
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *next = NULL;
bool admitted = lardon3d_resource_governor_reserve_available(
governor,
next,
&information
)) {
(void)lardon3d_resource_governor_release(governor, next);
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
"Réservation de séquence invalide."
&task->estimate,
&decision,
&next
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
if (!admitted) {
/* Erreur interne : échec d'allocation ou d'instantané. */
(void)pthread_mutex_lock(&task->mutex);
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
"Impossible de réserver les ressources de la séquence."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
switch (decision.kind) {
case LARDON3D_RESOURCE_START:
case LARDON3D_RESOURCE_REDUCE_BATCH: {
if (!next) {
(void)pthread_mutex_lock(&task->mutex);
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
"Réservation de séquence invalide."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
Lardon3DResourceReservationInfo information;
if (!lardon3d_resource_reservation_get_active(
governor,
next,
&information
)) {
(void)lardon3d_resource_governor_release(governor, next);
(void)pthread_mutex_lock(&task->mutex);
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
"Réservation de séquence invalide."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
}
(void)pthread_mutex_lock(&task->mutex);
task->current_reservation = next;
task->contract = (Lardon3DTaskExecutionContract) {
.batch_size = information.batch_size,
.memory_bytes = information.memory_bytes,
.gpu_memory_bytes = information.gpu_memory_bytes,
.cpu_threads = information.cpu_threads,
.gpu_slots = information.gpu_slots,
.io_slots = information.io_slots,
};
task->has_contract = true;
++task->sequence_count;
*out_reservation = next;
*out_contract = task->contract;
(void)pthread_mutex_unlock(&task->mutex);
return true;
}
case LARDON3D_RESOURCE_REJECT:
if (next) {
(void)lardon3d_resource_governor_release(governor, next);
}
(void)pthread_mutex_lock(&task->mutex);
task->current_reservation = NULL;
finish_locked(
task,
TASK_FAILED,
decision.reason[0] ? decision.reason
: "Ressources impossibles à réserver."
);
(void)pthread_mutex_unlock(&task->mutex);
return false;
case LARDON3D_RESOURCE_WAIT:
default:
/* Indisponibilité temporaire : ne pas échouer, attendre un
* changement de ressources puis retenter l'admission. */
if (next) {
(void)lardon3d_resource_governor_release(governor, next);
}
(void)lardon3d_resource_governor_wait_for_change(
governor,
generation,
LARDON3D_SEQUENCE_ADMISSION_WAIT_NS
);
break;
}
}
task->current_reservation = next;
task->contract = (Lardon3DTaskExecutionContract) {
.batch_size = information.batch_size,
.memory_bytes = information.memory_bytes,
.gpu_memory_bytes = information.gpu_memory_bytes,
.cpu_threads = information.cpu_threads,
.gpu_slots = information.gpu_slots,
.io_slots = information.io_slots,
};
task->has_contract = true;
++task->sequence_count;
*out_reservation = next;
*out_contract = task->contract;
(void)pthread_mutex_unlock(&task->mutex);
return true;
}
unsigned int

View file

@ -28,7 +28,14 @@ typedef struct {
typedef struct {
Lardon3DResourceGovernor *governor;
} WaitContext;
pthread_mutex_t sync_mutex;
pthread_cond_t sync_cond;
bool in_break;
} WaitRetryContext;
typedef struct {
Lardon3DResourceGovernor *governor;
} RejectContext;
typedef struct {
Lardon3DResourceGovernor *governor;
@ -102,9 +109,27 @@ seq_callback(Lardon3DTask *task, void *userdata)
}
static bool
wait_callback(Lardon3DTask *task, void *userdata)
wait_retry_callback(Lardon3DTask *task, void *userdata)
{
WaitContext *ctx = userdata;
WaitRetryContext *ctx = userdata;
(void)pthread_mutex_lock(&ctx->sync_mutex);
ctx->in_break = true;
(void)pthread_cond_broadcast(&ctx->sync_cond);
(void)pthread_mutex_unlock(&ctx->sync_mutex);
Lardon3DResourceReservation *reservation = NULL;
Lardon3DTaskExecutionContract contract;
return lardon3d_task_sequence_break(
task,
ctx->governor,
&reservation,
&contract
);
}
static bool
reject_callback(Lardon3DTask *task, void *userdata)
{
RejectContext *ctx = userdata;
Lardon3DResourceReservation *reservation = NULL;
Lardon3DTaskExecutionContract contract;
return lardon3d_task_sequence_break(
@ -247,7 +272,7 @@ run_sequential_test(void)
}
static bool
run_wait_test(void)
run_wait_retry_test(void)
{
const Lardon3DResourceEstimate estimate = {
.minimum_batch_size = 1,
@ -274,7 +299,6 @@ run_wait_test(void)
Lardon3DResourceSnapshot resource_snapshot = {
.memory_available_bytes = UINT64_MAX,
.cpu_load_1m = 0.0,
.io_pressure_known = false,
};
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *reservation;
@ -285,11 +309,255 @@ run_wait_test(void)
&decision,
&reservation
));
WaitContext ctx = {.governor = governor};
CHECK(reservation);
WaitRetryContext ctx = {.governor = governor};
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
Lardon3DTask *task = lardon3d_task_create(
"Attente",
"Attente puis reprise",
&estimate,
wait_callback,
wait_retry_callback,
&ctx
);
CHECK(task);
StartContext start = {task, governor, reservation};
pthread_t thread;
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
(void)pthread_mutex_lock(&ctx.sync_mutex);
while (!ctx.in_break) {
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
}
(void)pthread_mutex_unlock(&ctx.sync_mutex);
/* Tant que la politique reste bloquante, le gouverneur répond WAIT :
* la tâche doit rester en cours et ne jamais passer en échec. */
Lardon3DTaskSnapshot snapshot;
for (size_t attempt = 0; attempt < 50; ++attempt) {
CHECK(lardon3d_task_snapshot(task, &snapshot));
CHECK(snapshot.state == TASK_RUNNING);
short_pause(1000000);
}
CHECK(lardon3d_task_sequence_count(task) == 0);
/* Lever la contrainte : la prochaine tentative doit réussir. */
Lardon3DResourcePolicy allowed = policy;
allowed.maximum_io_pressure_avg10 = 100.0;
CHECK(lardon3d_resource_governor_set_policy(governor, &allowed));
CHECK(lardon3d_task_join(task));
void *thread_result;
CHECK(pthread_join(thread, &thread_result) == 0);
CHECK((uintptr_t)thread_result == 1);
CHECK(lardon3d_task_snapshot(task, &snapshot));
CHECK(snapshot.state == TASK_COMPLETED);
CHECK(lardon3d_task_sequence_count(task) == 1);
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
lardon3d_task_destroy(task);
(void)pthread_cond_destroy(&ctx.sync_cond);
(void)pthread_mutex_destroy(&ctx.sync_mutex);
lardon3d_resource_governor_destroy(governor);
return true;
}
static bool
run_cancel_during_wait_test(void)
{
const Lardon3DResourceEstimate estimate = {
.minimum_batch_size = 1,
.maximum_batch_size = 100,
.desired_cpu_threads = 1,
.desired_io_slots = 1,
};
Lardon3DHardwareProfile profile = {
.logical_cpu_count = 16,
.page_size_bytes = 4096,
.memory_total_bytes = UINT64_MAX,
.cpu_architecture = "test",
};
Lardon3DResourcePolicy policy = {
.maximum_cpu_load_ratio = 1.0,
.maximum_io_pressure_avg10 = 0.0,
.io_slot_capacity = 1,
};
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
&profile,
&policy
);
CHECK(governor);
Lardon3DResourceSnapshot resource_snapshot = {
.memory_available_bytes = UINT64_MAX,
.cpu_load_1m = 0.0,
};
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *reservation;
CHECK(lardon3d_resource_governor_reserve(
governor,
&resource_snapshot,
&estimate,
&decision,
&reservation
));
CHECK(reservation);
WaitRetryContext ctx = {.governor = governor};
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
Lardon3DTask *task = lardon3d_task_create(
"Annulation pendant attente",
&estimate,
wait_retry_callback,
&ctx
);
CHECK(task);
StartContext start = {task, governor, reservation};
pthread_t thread;
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
(void)pthread_mutex_lock(&ctx.sync_mutex);
while (!ctx.in_break) {
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
}
(void)pthread_mutex_unlock(&ctx.sync_mutex);
/* Annuler pendant que la tâche attend les ressources. */
lardon3d_task_request_cancel(task);
CHECK(lardon3d_task_join(task));
CHECK(pthread_join(thread, NULL) == 0);
Lardon3DTaskSnapshot snapshot;
CHECK(lardon3d_task_snapshot(task, &snapshot));
CHECK(snapshot.state == TASK_CANCELLED);
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
lardon3d_task_destroy(task);
(void)pthread_cond_destroy(&ctx.sync_cond);
(void)pthread_mutex_destroy(&ctx.sync_mutex);
lardon3d_resource_governor_destroy(governor);
return true;
}
static bool
run_pause_during_wait_test(void)
{
const Lardon3DResourceEstimate estimate = {
.minimum_batch_size = 1,
.maximum_batch_size = 100,
.desired_cpu_threads = 1,
.desired_io_slots = 1,
};
Lardon3DHardwareProfile profile = {
.logical_cpu_count = 16,
.page_size_bytes = 4096,
.memory_total_bytes = UINT64_MAX,
.cpu_architecture = "test",
};
Lardon3DResourcePolicy policy = {
.maximum_cpu_load_ratio = 1.0,
.maximum_io_pressure_avg10 = 0.0,
.io_slot_capacity = 1,
};
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
&profile,
&policy
);
CHECK(governor);
Lardon3DResourceSnapshot resource_snapshot = {
.memory_available_bytes = UINT64_MAX,
.cpu_load_1m = 0.0,
};
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *reservation;
CHECK(lardon3d_resource_governor_reserve(
governor,
&resource_snapshot,
&estimate,
&decision,
&reservation
));
CHECK(reservation);
WaitRetryContext ctx = {.governor = governor};
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
Lardon3DTask *task = lardon3d_task_create(
"Pause pendant attente",
&estimate,
wait_retry_callback,
&ctx
);
CHECK(task);
StartContext start = {task, governor, reservation};
pthread_t thread;
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
(void)pthread_mutex_lock(&ctx.sync_mutex);
while (!ctx.in_break) {
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
}
(void)pthread_mutex_unlock(&ctx.sync_mutex);
/* Mettre en pause pendant l'attente, puis reprendre. */
CHECK(lardon3d_task_pause(task));
CHECK(wait_for_state(task, TASK_PAUSED));
CHECK(lardon3d_task_resume(task));
CHECK(wait_for_state(task, TASK_RUNNING));
/* Lever la contrainte : la tâche doit reprendre puis réussir. */
Lardon3DResourcePolicy allowed = policy;
allowed.maximum_io_pressure_avg10 = 100.0;
CHECK(lardon3d_resource_governor_set_policy(governor, &allowed));
CHECK(lardon3d_task_join(task));
CHECK(pthread_join(thread, NULL) == 0);
Lardon3DTaskSnapshot snapshot;
CHECK(lardon3d_task_snapshot(task, &snapshot));
CHECK(snapshot.state == TASK_COMPLETED);
CHECK(lardon3d_task_sequence_count(task) == 1);
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
lardon3d_task_destroy(task);
(void)pthread_cond_destroy(&ctx.sync_cond);
(void)pthread_mutex_destroy(&ctx.sync_mutex);
lardon3d_resource_governor_destroy(governor);
return true;
}
static bool
run_reject_test(void)
{
const Lardon3DResourceEstimate valid_estimate = {
.minimum_batch_size = 1,
.maximum_batch_size = 1,
.desired_cpu_threads = 1,
};
const Lardon3DResourceEstimate reject_estimate = {
.memory_fixed_bytes = UINT64_MAX,
.memory_bytes_per_item = 1,
.minimum_batch_size = 1,
.maximum_batch_size = 1,
.desired_cpu_threads = 1,
};
Lardon3DHardwareProfile profile = {
.logical_cpu_count = 16,
.page_size_bytes = 4096,
.memory_total_bytes = UINT64_MAX,
.cpu_architecture = "test",
};
Lardon3DResourcePolicy policy = {
.maximum_cpu_load_ratio = 1.0,
.maximum_io_pressure_avg10 = 100.0,
.io_slot_capacity = 1,
};
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
&profile,
&policy
);
CHECK(governor);
Lardon3DResourceSnapshot resource_snapshot = {
.memory_available_bytes = UINT64_MAX,
.cpu_load_1m = 0.0,
};
Lardon3DResourceDecision decision;
Lardon3DResourceReservation *reservation;
CHECK(lardon3d_resource_governor_reserve(
governor,
&resource_snapshot,
&valid_estimate,
&decision,
&reservation
));
CHECK(reservation);
RejectContext ctx = {.governor = governor};
Lardon3DTask *task = lardon3d_task_create(
"Refus gouverneur",
&reject_estimate,
reject_callback,
&ctx
);
CHECK(task);
@ -303,6 +571,52 @@ run_wait_test(void)
return true;
}
static bool
run_invalid_break_test(void)
{
const Lardon3DResourceEstimate estimate = {
.minimum_batch_size = 1,
.maximum_batch_size = 1,
.desired_cpu_threads = 1,
};
Lardon3DHardwareProfile profile = {
.logical_cpu_count = 4,
.page_size_bytes = 4096,
.memory_total_bytes = UINT64_MAX,
.cpu_architecture = "test",
};
Lardon3DResourcePolicy policy = {
.maximum_cpu_load_ratio = 1.0,
.maximum_io_pressure_avg10 = 100.0,
.io_slot_capacity = 1,
};
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
&profile,
&policy
);
CHECK(governor);
Lardon3DTask *task = lardon3d_task_create(
"Sans réservation",
&estimate,
wait_retry_callback,
NULL
);
CHECK(task);
Lardon3DResourceReservation *reservation = NULL;
Lardon3DTaskExecutionContract contract;
CHECK(!lardon3d_task_sequence_break(task, governor, &reservation, &contract));
CHECK(!lardon3d_task_sequence_break(NULL, governor, &reservation, &contract));
CHECK(!lardon3d_task_sequence_break(task, NULL, &reservation, &contract));
CHECK(!lardon3d_task_sequence_break(task, governor, NULL, &contract));
CHECK(!lardon3d_task_sequence_break(task, governor, &reservation, NULL));
Lardon3DTaskSnapshot snapshot;
CHECK(lardon3d_task_snapshot(task, &snapshot));
CHECK(snapshot.state == TASK_PENDING);
lardon3d_task_destroy(task);
lardon3d_resource_governor_destroy(governor);
return true;
}
static bool
run_cancel_test(void)
{
@ -382,11 +696,23 @@ main(void)
if (!run_sequential_test()) {
return EXIT_FAILURE;
}
if (!run_wait_test()) {
if (!run_wait_retry_test()) {
return EXIT_FAILURE;
}
if (!run_cancel_test()) {
return EXIT_FAILURE;
}
if (!run_cancel_during_wait_test()) {
return EXIT_FAILURE;
}
if (!run_pause_during_wait_test()) {
return EXIT_FAILURE;
}
if (!run_reject_test()) {
return EXIT_FAILURE;
}
if (!run_invalid_break_test()) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}