diff --git a/assets/sai.js b/assets/sai.js
index 0370d72..eb43d7a 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -3735,6 +3735,15 @@ window.addEventListener("load", function() {
}));
}
});
+ menuItems.push({
+ label: "Kill task",
+ callback: () => {
+ sai.send(JSON.stringify({
+ schema: "com.warmcat.sai.taskkill",
+ uuid: taskUuid
+ }));
+ }
+ });
}
}
diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c
index 56c9ed9..6e06f27 100644
--- a/src/builder/b-nspawn.c
+++ b/src/builder/b-nspawn.c
@@ -246,6 +246,14 @@ sai_lsp_reap_cb(void *opaque, const lws_spawn_resource_us_t *res, siginfo_t *si,
saib_log_chunk_create(ns, ">saib> <=== Reaping build process\n", 34, 3);
+ if (ns->user_killed) {
+ lwsl_notice("%s: Process killed manually by user\n", __func__);
+ exit_code = -1;
+ ns->retcode = SAISPRF_EXIT | 1;
+ ns->retcode_set = 1;
+ goto fail;
+ }
+
#if !defined(WIN32)
if (we_killed_him & 1) {
diff --git a/src/builder/b-task.c b/src/builder/b-task.c
index 7b21222..5ef375c 100644
--- a/src/builder/b-task.c
+++ b/src/builder/b-task.c
@@ -736,7 +736,10 @@ saib_sul_task_cancel(struct lws_sorted_usec_list *sul)
if (!ns->op || !ns->op->lsp)
return;
- n = lws_snprintf(s, sizeof(s), ">saib> Cancelling...\n");
+ if (ns->user_killed)
+ n = lws_snprintf(s, sizeof(s), "\xe2\x96\xa0 >saib> Build was manually killed\n");
+ else
+ n = lws_snprintf(s, sizeof(s), ">saib> Cancelling...\n");
saib_log_chunk_create(ns, s, (size_t)n, 3);
lws_spawn_piped_kill_child_process(ns->op->lsp);
diff --git a/src/builder/b-ws-server.c b/src/builder/b-ws-server.c
index df02747..29a36d4 100644
--- a/src/builder/b-ws-server.c
+++ b/src/builder/b-ws-server.c
@@ -237,7 +237,10 @@ saib_m_rx(void *userobj, const uint8_t *in, size_t len, int flags)
* We're going to send a few signals
* at 500ms intervals
*/
- ns->user_cancel = 1;
+ if (can->killed)
+ ns->user_killed = 1;
+ else
+ ns->user_cancel = 1;
ns->term_budget = 5;
lws_sul_schedule(ns->builder->context, 0,
diff --git a/src/common/include/private.h b/src/common/include/private.h
index 55d8fc4..91dcd59 100644
--- a/src/common/include/private.h
+++ b/src/common/include/private.h
@@ -309,6 +309,7 @@ struct sai_nspawn {
uint8_t retcode_set:1;
uint8_t state_changed:1;
uint8_t user_cancel:1;
+ uint8_t user_killed:1;
uint8_t reap_cb_called:1;
};
@@ -345,6 +346,7 @@ typedef struct sai_cancel {
struct lws_dll2 list;
char task_uuid[65];
unsigned int erase;
+ unsigned int killed;
} sai_cancel_t;
/*
@@ -866,7 +868,7 @@ extern const lws_struct_map_t
lsm_plat_list[1],
lsm_schema_map_plat[1],
lsm_task_rej[4],
- lsm_task_cancel[2],
+ lsm_task_cancel[3],
lsm_schema_json_map_can[1],
lsm_schema_json_map_task[1],
lsm_schema_json_map_event[1],
diff --git a/src/common/struct-metadata.c b/src/common/struct-metadata.c
index 41fb8c8..f4c840d 100644
--- a/src/common/struct-metadata.c
+++ b/src/common/struct-metadata.c
@@ -223,6 +223,7 @@ const lws_struct_map_t lsm_schema_json_task_rej[] = {
const lws_struct_map_t lsm_task_cancel[] = {
LSM_CARRAY (sai_cancel_t, task_uuid, "task_uuid"),
LSM_UNSIGNED (sai_cancel_t, erase, "erase"),
+ LSM_UNSIGNED (sai_cancel_t, killed, "killed"),
};
const lws_struct_map_t lsm_openshell[] = {
diff --git a/src/server/s-central.c b/src/server/s-central.c
index e782e5e..0c71519 100644
--- a/src/server/s-central.c
+++ b/src/server/s-central.c
@@ -262,7 +262,7 @@ sais_central_gc_deleted_events_cb(lws_sorted_usec_list_t *sul)
lws_strncpy(tu, u, sizeof(tu));
lws_sql_purify(esc, tu, sizeof(esc));
- sais_task_cancel(vhd, tu, 1);
+ sais_task_cancel(vhd, tu, 1, 0);
lws_snprintf(q, sizeof(q), "DELETE FROM logs WHERE task_uuid='%s'", esc);
sqlite3_exec(pdb, q, NULL, NULL, NULL);
diff --git a/src/server/s-private.h b/src/server/s-private.h
index f1aaa6d..d4c8e7e 100644
--- a/src/server/s-private.h
+++ b/src/server/s-private.h
@@ -323,7 +323,7 @@ int
sais_config_watchers(struct vhd *vhd, const char *config_dir);
int
-sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase);
+sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase, int killed);
int
sais_allocate_task(struct vhd *vhd, struct pss *pss, sai_plat_t *cb,
@@ -425,10 +425,10 @@ void
sais_get_task_metrics_estimates(struct vhd *vhd, sai_task_t *task);
int
-sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase);
+sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase, int killed);
int
-sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid);
+sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid, int killed);
sai_db_result_t
sais_task_clear_build_and_logs(struct vhd *vhd, const char *task_uuid, int from_rejection);
diff --git a/src/server/s-task-helpers.c b/src/server/s-task-helpers.c
index 91319a4..32a08f1 100644
--- a/src/server/s-task-helpers.c
+++ b/src/server/s-task-helpers.c
@@ -410,7 +410,7 @@ sais_task_pause(struct vhd *vhd, const char *task_uuid)
build_step, esc_uuid, esc_uuid);
sqlite3_exec(pdb, q, NULL, NULL, NULL);
}
- sais_task_stop_on_builders(vhd, task_uuid);
+ sais_task_stop_on_builders(vhd, task_uuid, 0);
}
sai_event_db_close(&vhd->sqlite3_cache, &pdb);
@@ -419,7 +419,7 @@ sais_task_pause(struct vhd *vhd, const char *task_uuid)
}
int
-sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase)
+sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase, int killed)
{
sai_cancel_t *can;
@@ -440,6 +440,7 @@ sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase)
lws_strncpy(can->task_uuid, task_uuid, sizeof(can->task_uuid));
can->erase = (unsigned int)erase;
+ can->killed = (unsigned int)killed;
lws_dll2_add_tail(&can->list, &pss->task_cancel_owner);
@@ -459,7 +460,7 @@ sais_task_cancel(struct vhd *vhd, const char *task_uuid, int erase)
}
int
-sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid)
+sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid, int killed)
{
char event_uuid[33], builder_name[128], esc_uuid[129], q[128];
struct pss *pss_match = NULL;
@@ -529,6 +530,7 @@ sais_task_stop_on_builders(struct vhd *vhd, const char *task_uuid)
lws_strncpy(can->task_uuid, task_uuid, sizeof(can->task_uuid));
can->erase = 0;
+ can->killed = (unsigned int)killed;
lws_dll2_add_tail(&can->list, &pss_match->task_cancel_owner);
lws_callback_on_writable(pss_match->wsi);
@@ -602,7 +604,7 @@ sais_task_clear_build_and_logs(struct vhd *vhd, const char *task_uuid, int from_
sais_set_task_state(vhd, task_uuid, SAIES_WAITING, 0, 0);
- sais_task_stop_on_builders(vhd, task_uuid);
+ sais_task_stop_on_builders(vhd, task_uuid, 0);
/*
* Reassess now if there's a builder we can match to a pending task,
@@ -648,7 +650,7 @@ sais_task_remove_all_tries(struct vhd *vhd, const char *task_uuid)
lws_sql_purify(esc, task_uuid, sizeof(esc));
- sais_task_stop_on_builders(vhd, task_uuid);
+ sais_task_stop_on_builders(vhd, task_uuid, 0);
lws_snprintf(cmd, sizeof(cmd), "DELETE FROM logs WHERE task_uuid='%s'", esc);
sqlite3_exec(pdb, cmd, NULL, NULL, NULL);
@@ -737,7 +739,7 @@ sais_task_rebuild_last_step(struct vhd *vhd, const char *task_uuid)
sais_set_task_state(vhd, task_uuid, SAIES_WAITING, 0, 0);
- sais_task_stop_on_builders(vhd, task_uuid);
+ sais_task_stop_on_builders(vhd, task_uuid, 0);
lwsl_err("%s: scheduling sul_central to find a new task\n", __func__);
lws_sul_schedule(vhd->context, 0, &vhd->sul_central, sais_central_cb, 1);
diff --git a/src/server/s-webops.c b/src/server/s-webops.c
index 22f68ec..cc03fd3 100644
--- a/src/server/s-webops.c
+++ b/src/server/s-webops.c
@@ -323,7 +323,7 @@ sais_event_delete(struct vhd *vhd, const char *event_uuid)
while (sqlite3_step(sm) == SQLITE_ROW) {
const unsigned char *task_uuid = sqlite3_column_text(sm, 0);
if (task_uuid)
- sais_task_cancel(vhd, (const char *)task_uuid, 0);
+ sais_task_cancel(vhd, (const char *)task_uuid, 0, 1);
}
sqlite3_finalize(sm);
}
diff --git a/src/server/s-ws-web.c b/src/server/s-ws-web.c
index 2a6fb96..210ac53 100644
--- a/src/server/s-ws-web.c
+++ b/src/server/s-ws-web.c
@@ -112,6 +112,8 @@ static const lws_struct_map_t lsm_schema_json_map[] = {
/* shares struct */ "com.warmcat.sai.taskpause"),
LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
/* shares struct */ "com.warmcat.sai.taskresume"),
+ LSM_SCHEMA (sai_browse_rx_evinfo_t, NULL, lsm_browser_taskreset,
+ /* shares struct */ "com.warmcat.sai.taskkill"),
LSM_SCHEMA (sai_browse_rx_builderdelete_t, NULL, lsm_browser_builderdelete,
"com.warmcat.sai.builderdelete"),
LSM_SCHEMA (sai_openshell_t, NULL, lsm_openshell,
@@ -137,6 +139,7 @@ enum {
SAIS_WS_WEBSRV_RX_TASKINFO,
SAIS_WS_WEBSRV_RX_TASKPAUSE,
SAIS_WS_WEBSRV_RX_TASKRESUME,
+ SAIS_WS_WEBSRV_RX_TASKKILL,
SAIS_WS_WEBSRV_RX_BUILDERDELETE,
SAIS_WS_WEBSRV_RX_OPENSHELL,
SAIS_WS_WEBSRV_RX_CLOSESHELL,
@@ -517,6 +520,16 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
sais_platforms_with_tasks_pending(m->vhd);
break;
+ case SAIS_WS_WEBSRV_RX_TASKKILL:
+ ei = (sai_browse_rx_evinfo_t *)a.dest;
+ if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN))
+ goto soft_error;
+
+ lwsl_ss_warn(m->ss, "SAIS_WS_WEBSRV_RX_TASKKILL: %s: received", ei->event_hash);
+ if (sais_task_stop_on_builders(m->vhd, ei->event_hash, 1))
+ lwsl_ss_err(m->ss, "taskkill failed");
+ break;
+
case SAIS_WS_WEBSRV_RX_TASKREBUILDLASTSTEP:
ei = (sai_browse_rx_evinfo_t *)a.dest;
if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN))
@@ -601,7 +614,7 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
if (sais_validate_id(ei->event_hash, SAI_TASKID_LEN))
goto soft_error;
- sais_task_cancel(m->vhd, ei->event_hash, 0);
+ sais_task_cancel(m->vhd, ei->event_hash, 0, 0);
break;
@@ -762,7 +775,7 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
}
} lws_end_foreach_dll_safe(d, d1);
- sais_task_cancel(m->vhd, cs->task_uuid, 0);
+ sais_task_cancel(m->vhd, cs->task_uuid, 0, 0);
sais_platforms_with_tasks_pending(m->vhd);
lwsac_free(&a.ac);