Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
Author[]Andy Green <andy@warmcat.com> 2025-05-10 10:46 UTC
Committer[]Andy Green <andy@warmcat.com> 2025-05-10 10:50 UTC
Treec3b4e5602065864a9cf944dd2cb709eb95447f36   Raw Patch
 
power: handle suspend when idle
power: handle suspend when idle
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1de9f1c..fe0b18f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,12 @@ set (CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES};${LIBWEBSOCKETS_INCLUDE set(requirements 1) require_lws_config(LWS_ROLE_H1 1 requirements) require_lws_config(LWS_ROLE_WS 1 requirements) -require_lws_config(LWS_WITH_JOSE 1 requirements) +if (SAI_SERVER) + require_lws_config(LWS_WITH_JOSE 1 requirements) +endif() +if (SAI_BUILDER) + require_lws_config(LWS_WITH_THREADPOOL 1 requirements) +endif() #require_lws_config(LWS_WITH_PLUGINS_BUILTIN 1 requirements) diff --git a/src/builder/b-conf.c b/src/builder/b-conf.c index f50004e..ef87972 100644 --- a/src/builder/b-conf.c +++ b/src/builder/b-conf.c @@ -35,7 +35,8 @@ static const char * const paths_global[] = { "host", "metrics_uri", "metrics_path", - "metrics_secret" + "metrics_secret", + "power-off" }; enum enum_paths_global { @@ -45,6 +46,7 @@ enum enum_paths_global { LEJPM_METRICS_URI, LEJPM_METRICS_PATH, LEJPM_METRICS_SECRET, + LEJPM_POWER_OFF, }; /* platform-related part */ @@ -285,6 +287,10 @@ saib_conf_global_cb(struct lejp_ctx *ctx, char reason) pp = &a->builder->metrics_secret; break; + case LEJPM_POWER_OFF: + pp = &a->builder->power_off; + break; + default: return 0; } diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c index af510d8..57a4a26 100644 --- a/src/builder/b-nspawn.c +++ b/src/builder/b-nspawn.c @@ -49,7 +49,7 @@ saib_log_chunk_create(struct sai_nspawn *ns, void *buf, size_t len, int channel) { struct ws_capture_chunk *chunk; - if (!ns->spm) + if (!ns || !ns->spm) return NULL; chunk = malloc(sizeof(*chunk) + len); @@ -95,8 +95,6 @@ callback_sai_stdwsi(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_RAW_RX_FILE: - if (!ns->spm) - return -1; #if defined(WIN32) { DWORD rb; @@ -116,7 +114,10 @@ callback_sai_stdwsi(struct lws *wsi, enum lws_callback_reasons reason, len = (unsigned int)ilen; - // printf("(%d) %.*s\n", (int)len, (int)len, buf); + if (!ns->spm) { + printf("%s: (%d) %.*s\n", __func__, (int)lws_spawn_get_stdfd(wsi), (int)len, buf); + return -1; + } if (!saib_log_chunk_create(ns, buf, len, lws_spawn_get_stdfd(wsi))) return -1; diff --git a/src/builder/b-private.h b/src/builder/b-private.h index f80ed28..c481c15 100644 --- a/src/builder/b-private.h +++ b/src/builder/b-private.h @@ -39,6 +39,8 @@ #include <pthread.h> #include <git2.h> +#define SAI_IDLE_GRACE_US (20 * LWS_US_PER_SEC) + typedef enum { PHASE_IDLE, @@ -156,14 +158,20 @@ struct sai_builder { lws_dll2_owner_t sai_plat_server_owner; /* servers we connect to */ lws_dll2_owner_t devices_owner; /* sai_serial_t */ + struct sai_nspawn suspend_nspawn; + struct lwsac *conf_head; struct lws_context *context; struct lws_vhost *vhost; + lws_sorted_usec_list_t sul_idle; + const char *metrics_uri; const char *metrics_path; const char *metrics_secret; + const char *power_off; + const char *home; /* home dir, usually /sai/home */ const char *perms; /* user:group */ @@ -250,6 +258,10 @@ extern const struct lws_protocols protocol_logproxy, protocol_resproxy; void * thread_repo(void *d); +void * +thread_suspend(void *d); + + int saib_create_resproxy_listen_uds(struct lws_context *context, struct sai_plat_server *spm); diff --git a/src/builder/b-sai.c b/src/builder/b-sai.c index 2dc3c0c..1287bfe 100644 --- a/src/builder/b-sai.c +++ b/src/builder/b-sai.c @@ -52,6 +52,7 @@ int getpid(void) { return 0; } static const char *config_dir = "/etc/sai/builder"; static int interrupted; static lws_state_notify_link_t nl; +static struct lws_spawn_piped *lsp_suspender; struct sai_builder builder; @@ -386,6 +387,32 @@ app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link, return 0; } +/* + * The grace time is up, ask for the suspend + */ + +void +sul_idle_cb(lws_sorted_usec_list_t *sul) +{ + ssize_t n; + uint8_t te = 1; + + lwsl_notice("%s: requesting suspend...\n", __func__); + + n = write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1); + if (n == 1) { + sleep(2); + /* + * There were 0 tasks ongoing for us to suspend, start off + * with the same assumption and set the idle grace time + */ + lws_sul_schedule(builder.context, 0, &builder.sul_idle, + sul_idle_cb, SAI_IDLE_GRACE_US); + lwsl_notice("%s: resuming after suspend\n", __func__); + } else + lwsl_err("%s: failed to request suspend\n", __func__); +} + static lws_state_notify_link_t * const app_notifier_list[] = { &nl, NULL }; @@ -428,6 +455,48 @@ int main(int argc, const char **argv) const char *p; void *retval; + + if ((p = lws_cmdline_option(argc, argv, "-s"))) { + ssize_t n = 0; + + printf("%s: Spawn process creation entry...\n", __func__); + + /* + * A new process gets started with this option before we drop + * privs. This allows us to suspend with root privs later. + * + * We just wait until we get a byte on stdin from the main + * process indicating we should suspend. + */ + + while (n >= 0) { + int status; + uint8_t d; + pid_t p; + + n = read(0, &d, 1); + lwsl_notice("%s: suspend process read returned %d\n", __func__, (int)n); + + if (n <= 0) + continue; + + if (n == 1 && d == 2) { + lwsl_warn("%s: suspend process ending\n", __func__); + break; + } + + p = fork(); + if (!p) + execl("/usr/bin/systemctl", "/usr/bin/systemctl", "suspend", NULL); + else + waitpid(p, &status, 0); + } + + lwsl_notice("%s: exiting suspend process\n", __func__); + + return 0; + } + if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); @@ -562,6 +631,31 @@ int main(int argc, const char **argv) goto bail; } + if (!strcmp(builder.power_off, "suspend")) { + struct lws_spawn_piped_info info; + const char * const ea[] = { argv[0], "-s", NULL }; + + memset(&info, 0, sizeof(info)); + memset(&builder.suspend_nspawn, 0, sizeof(builder.suspend_nspawn)); + + info.vh = builder.vhost; + info.exec_array = ea; + info.max_log_lines = 100; + info.opaque = (void *)&builder.suspend_nspawn; + + lsp_suspender = lws_spawn_piped(&info); + if (!lsp_suspender) + lwsl_notice("%s: suspend spawn failed\n", __func__); + + /* + * We start off idle, with no tasks on any platform and doing + * the grace time before suspend + */ + + lws_sul_schedule(builder.context, 0, &builder.sul_idle, + sul_idle_cb, SAI_IDLE_GRACE_US); + } + pthread_mutex_init(&builder.mi.mut, NULL); pthread_cond_init(&builder.mi.cond, NULL); @@ -589,6 +683,16 @@ int main(int argc, const char **argv) bail: + if (!strcmp(builder.power_off, "suspend") && lsp_suspender) { + uint8_t te = 2; + + /* + * Clean up after the suspend process + */ + + write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1); + } + /* destroy the unique servers */ lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, @@ -621,13 +725,15 @@ bail: saib_config_destroy(&builder); + if (!strcmp(builder.power_off, "suspend")) + lws_sul_cancel(&builder.sul_idle); + /* - * Clean up after the threads + * Clean up after the spawn threads */ - builder.mi.finish = 1; - pthread_mutex_lock(&builder.mi.mut); + builder.mi.finish = 1; pthread_cond_broadcast(&builder.mi.cond); pthread_mutex_unlock(&builder.mi.mut); @@ -636,8 +742,6 @@ bail: pthread_mutex_destroy(&builder.mi.mut); pthread_cond_destroy(&builder.mi.cond); - - lws_context_destroy(builder.context); return 0; diff --git a/src/builder/b-task.c b/src/builder/b-task.c index 5bb14fc..3b42437 100644 --- a/src/builder/b-task.c +++ b/src/builder/b-task.c @@ -165,6 +165,32 @@ saib_task_destroy(struct sai_nspawn *ns) ns->sp->ongoing, ns->sp->ongoing - 1); ns->sp->ongoing--; + if (!strcmp(builder.power_off, "suspend") && !ns->sp->ongoing) { + int m = 0; + + /* + * Is it the case that none of the platforms have + * any ongoing jobs then? We don't any more. + * + * If nobody does, start the grace time for suspend. + */ + + lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, + builder.sai_plat_owner.head) { + struct sai_plat *sp = lws_container_of(d, + struct sai_plat, sai_plat_list); + if (sp->ongoing) + m++; + } lws_end_foreach_dll_safe(d, d1); + + if (!m) { + lwsl_notice("%s: scheduling suspend grace time\n", __func__); + lws_sul_schedule(builder.context, 0, + &builder.sul_idle, sul_idle_cb, + SAI_IDLE_GRACE_US); + } + } + /* * Schedule informing all the servers we're connected to */ @@ -692,6 +718,12 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len) sp->ongoing++; ns->task->told_ongoing = 1; + if (!strcmp(builder.power_off, "suspend")) { + /* we're busy, we're not in the mood for suspending */ + lwsl_notice("%s: cancelling suspend grace time\n", __func__); + lws_sul_cancel(&ns->builder->sul_idle); + } + /* * Let the mirror thread get on with things... * diff --git a/src/common/include/private.h b/src/common/include/private.h index 3d114c8..4a024e7 100644 --- a/src/common/include/private.h +++ b/src/common/include/private.h @@ -298,6 +298,7 @@ typedef struct sai_plat { typedef struct sai_plat_owner { lws_dll2_owner_t plat_owner; + } sai_plat_owner_t; typedef struct sai_repo { @@ -357,3 +358,6 @@ saicom_lp_ss_from_env(struct lws_context *context, const char *env_name); int saicom_lp_callback_on_drain(saicom_drain_cb cb, void *opaque); + +void +sul_idle_cb(lws_sorted_usec_list_t *sul);
Page fetched 0s ago, creation time: 4ms (vhost etag hits: 0%, cache hits: 0%)