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
 
root / scripts / sai-jig.service
Author[]Andy Green <andy@warmcat.com> 2025-10-27 11:13 UTC
Committer[]Andy Green <andy@warmcat.com> 2025-10-27 11:14 UTC
Tree09f0229b70f6ee1afc4090aae53b50975e1d5da7   Raw Patch
 
mac: implement suspender
mac: implement suspender

Co-developed-by: Gemini 2.5
diff --git a/src/builder/b-deletion.c b/src/builder/b-deletion.c index 0690e4e..8bfa236 100644 --- a/src/builder/b-deletion.c +++ b/src/builder/b-deletion.c @@ -24,6 +24,7 @@ #include <signal.h> #include <limits.h> #include <stdlib.h> +#include <fcntl.h> #include <sys/types.h> #if !defined(WIN32) @@ -54,10 +55,6 @@ #include "b-private.h" -extern int -saib_suspender_fork(void); -extern struct lws_protocols protocol_suspender_stdxxx; - int sai_deletion_worker(const char *home_dir) { @@ -268,6 +265,9 @@ saib_deletion_init(const char *argv0) return 1; } + fcntl(pfd[0], F_SETFD, FD_CLOEXEC); + fcntl(pfd[1], F_SETFD, FD_CLOEXEC); + pid = fork(); if (pid == -1) { lwsl_err("fork() failed\n"); diff --git a/src/builder/b-power.c b/src/builder/b-power.c index 97b130b..2193de2 100644 --- a/src/builder/b-power.c +++ b/src/builder/b-power.c @@ -195,8 +195,16 @@ LWS_SS_USER_TYPEDEF static lws_ss_state_return_t saib_power_link_rx(void *userobj, const uint8_t *buf, size_t len, int flags) { +#if !defined(WIN32) uint8_t te = 0; ssize_t n; +#if defined(__linux__) + int fd = lws_spawn_get_fd_stdxxx(lsp_suspender, 0); +#endif +#if defined(__APPLE__) + int fd = builder.pipe_suspender_wr; +#endif + if (len < 4 || !(flags & LWSSS_FLAG_SOM)) return 0; @@ -217,10 +225,10 @@ saib_power_link_rx(void *userobj, const uint8_t *buf, size_t len, int flags) * cleanly */ - n = write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1); + n = write(fd, &te, 1); if (n != 1) lwsl_err("%s: unable to request shutdown\n", __func__); - +#endif return LWSSSSRET_OK; } @@ -235,10 +243,16 @@ sul_do_suspend_cb(lws_sorted_usec_list_t *sul) #if !defined(WIN32) uint8_t te = 1; ssize_t n; +#if defined(__linux__) + int fd = lws_spawn_get_fd_stdxxx(lsp_suspender, 0); +#endif +#if defined(__APPLE__) + int fd = builder.pipe_suspender_wr; +#endif lwsl_notice("%s: actioning suspend...\n", __func__); - n = write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1); + n = write(fd, &te, 1); if (n == 1) { #if defined(WIN32) Sleep(2000); @@ -358,3 +372,16 @@ saib_power_init(void) return 0; } + +#if defined(__APPLE__) +void +sul_release_wakelock_cb(lws_sorted_usec_list_t *sul) +{ + lwsl_notice("%s: releasing wakelock (pid %d)\n", __func__, (int)builder.wakelock_pid); + if (builder.wakelock_pid) { + kill(builder.wakelock_pid, SIGTERM); + waitpid(builder.wakelock_pid, NULL, 0); + builder.wakelock_pid = 0; + } +} +#endif diff --git a/src/builder/b-private.h b/src/builder/b-private.h index b02aa51..dec7b4e 100644 --- a/src/builder/b-private.h +++ b/src/builder/b-private.h @@ -104,6 +104,11 @@ struct sai_builder { lws_sorted_usec_list_t sul_stay; lws_sorted_usec_list_t sul_cleanup_jobs; +#if defined(__APPLE__) + lws_sorted_usec_list_t sul_release_wakelock; + pid_t wakelock_pid; +#endif + const char *metrics_uri; const char *metrics_path; const char *metrics_secret; @@ -146,8 +151,10 @@ struct sai_builder { #if !defined(WIN32) int pipe_master_wr; + int pipe_suspender_wr; #else void *pipe_master_wr_win; + void *pipe_suspender_wr; #endif }; @@ -270,3 +277,18 @@ saib_srv_queue_json_fragments_helper(struct lws_ss_handle *h, int saib_queue_task_status_update(sai_plat_t *sp, struct sai_plat_server *spm, const char *rej_task_uuid, unsigned int reason); + + +extern int +saib_suspender_fork(const char *path); +extern int +sai_deletion_worker(const char *home_dir); +extern int +saib_suspender_start(void); +extern int +saib_power_init(void); +extern int +saib_deletion_init(const char *argv0); +extern void +suspender_destroy(void); + diff --git a/src/builder/b-sai.c b/src/builder/b-sai.c index 17d0e7d..bb08103 100644 --- a/src/builder/b-sai.c +++ b/src/builder/b-sai.c @@ -89,7 +89,7 @@ struct active_job_uuid { char uuid[65]; }; -static const char *config_dir = "/etc/sai/builder"; +static const char *config_dir = "/etc/sai/builder", *argv0; static int interrupted; static lws_state_notify_link_t nl; @@ -98,17 +98,6 @@ struct sai_builder builder; extern struct lws_spawn_piped *lsp_suspender; extern struct lws_protocols protocol_stdxxx; extern struct lws_protocols protocol_suspender_stdxxx; - -extern int -saib_suspender_fork(const char *path); -extern int -sai_deletion_worker(const char *home_dir); -extern int -saib_suspender_start(void); -extern int -saib_power_init(void); -extern int -saib_deletion_init(const char *argv0); static const char * const default_ss_policy = "{" @@ -327,6 +316,12 @@ app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link, if (current != LWS_SYSTATE_OPERATIONAL) break; + if (saib_deletion_init(argv0)) + return 1; + + if (saib_suspender_fork(argv0)) + return 1; + /* * The builder JSON conf listed servers we want to connect to, * let's collect the config, make a ss for each and add the @@ -423,6 +418,8 @@ int main(int argc, const char **argv) struct stat sb; const char *p; + argv0 = argv[0]; + if ((p = lws_cmdline_option(argc, argv, "--home"))) /* * This is the deletion worker process being spawned, it only @@ -430,11 +427,14 @@ int main(int argc, const char **argv) */ return sai_deletion_worker(p); - if ((p = lws_cmdline_option(argc, argv, "-s"))) + if ((p = lws_cmdline_option(argc, argv, "-s"))) { + lwsl_notice("%s: starting shutdown worker\n", __func__); + sleep(3000); /* * This is the suspend / shutdown worker process being spawned */ return saib_suspender_start(); + } if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); @@ -591,26 +591,12 @@ int main(int argc, const char **argv) } saib_power_init(); - if (saib_deletion_init(argv[0])) - goto bail; - - if (saib_suspender_fork(argv[0])) - goto bail; while (!lws_service(builder.context, 0) && !interrupted) ; bail: - - if (lsp_suspender) { - uint8_t te = 2; - - /* - * Clean up after the suspend process - */ - - write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1); - } + suspender_destroy(); /* destroy the unique servers */ diff --git a/src/builder/b-suspender.c b/src/builder/b-suspender.c index eb9dce7..16375c7 100644 --- a/src/builder/b-suspender.c +++ b/src/builder/b-suspender.c @@ -24,6 +24,7 @@ #include <signal.h> #include <limits.h> #include <stdlib.h> +#include <fcntl.h> #include <sys/types.h> #if !defined(WIN32) @@ -107,17 +108,34 @@ callback_sai_suspender_stdwsi(struct lws *wsi, enum lws_callback_reasons reason, struct lws_protocols protocol_suspender_stdxxx = { "sai-suspender-stdxxx", callback_sai_suspender_stdwsi, 0, 0 }; +#if !defined(__APPLE__) +static void reap(void *opaque, const lws_spawn_resource_us_t *res, + siginfo_t *si, int we_killed_him) +{ + lwsl_err("%s: reaped suspender fork... %d\n", __func__, si->si_status); +} +#endif int saib_suspender_fork(const char *path) { -#if !defined(WIN32) +#if defined(__linux__) struct lws_spawn_piped_info info; - char rpath[PATH_MAX]; const char * const ea[] = { rpath, "-s", NULL }; +#endif + char rpath[PATH_MAX]; + + if (!realpath(path, rpath)) { + lwsl_err("%s: failed to get realpath for %s: %s\n", __func__, + path, strerror(errno)); + return 1; + } + + lwsl_err("%s: starting %s\n", __func__, rpath); realpath(path, rpath); +#if defined(__linux__) memset(&info, 0, sizeof(info)); memset(&builder.suspend_nspawn, 0, sizeof(builder.suspend_nspawn)); @@ -127,12 +145,49 @@ saib_suspender_fork(const char *path) info.opaque = (void *)&builder.suspend_nspawn; info.protocol_name = "sai-suspender-stdxxx"; info.plsp = &lsp_suspender; + info.reap_cb = reap; lsp_suspender = lws_spawn_piped(&info); if (!lsp_suspender) { lwsl_err("%s: suspend spawn failed\n", __func__); return 1; } +#endif +#if defined(__APPLE__) + { + int pfd[2]; + pid_t pid; + + if (pipe(pfd) == -1) { + lwsl_err("pipe() failed\n"); + return 1; + } + + fcntl(pfd[0], F_SETFD, FD_CLOEXEC); + fcntl(pfd[1], F_SETFD, FD_CLOEXEC); + + pid = fork(); + if (pid == -1) { + lwsl_err("fork() failed\n"); + return 1; + } + + if (!pid) { + close(pfd[1]); /* wr */ + if (dup2(pfd[0], 0) < 0) + return 1; + close(pfd[0]); + + execlp(rpath, rpath, "-s", (char *)NULL); + lwsl_err("execlp failed\n"); + return 1; + } + + /* parent */ + close(pfd[0]); /* rd */ + builder.pipe_suspender_wr = pfd[1]; + } +#endif /* * We start off idle, with no tasks on any platform and doing @@ -142,7 +197,8 @@ saib_suspender_fork(const char *path) lws_sul_schedule(builder.context, 0, &builder.sul_idle, sul_idle_cb, SAI_IDLE_GRACE_US); -#endif + + lwsl_err("%s: done\n", __func__); return 0; } @@ -251,3 +307,23 @@ saib_suspender_start(void) return 0; } + +void +suspender_destroy() +{ +#if defined(__linux__) + int fd = lws_spawn_get_fd_stdxxx(lsp_suspender, 0); +#endif +#if defined(__APPLE__) + int fd = builder.pipe_suspender_wr; +#endif + if (lsp_suspender) { + uint8_t te = 2; + + /* + * Clean up after the suspend process + */ + + write(fd, &te, 1); + } +} diff --git a/src/builder/b-task.c b/src/builder/b-task.c index e72bab5..ced00e9 100644 --- a/src/builder/b-task.c +++ b/src/builder/b-task.c @@ -26,6 +26,12 @@ #include <assert.h> #include <fcntl.h> +#if defined(__APPLE__) +#include <sys/wait.h> +void +sul_release_wakelock_cb(lws_sorted_usec_list_t *sul); +#endif + #include "b-private.h" const char *git_helper_sh = @@ -372,10 +378,19 @@ saib_task_destroy(struct sai_nspawn *ns) * Schedule informing all the servers we're connected to */ - if (!m) + if (!m) { +#if defined(__APPLE__) + lwsl_notice("%s: last task finished, scheduling wakelock release\n", __func__); + lws_sul_schedule(builder.context, 0, + &builder.sul_release_wakelock, + sul_release_wakelock_cb, + 30 * LWS_US_PER_SEC); +#else lws_sul_schedule(builder.context, 0, &builder.sul_idle, sul_idle_cb, SAI_IDLE_GRACE_US); +#endif + } } if (ns->task && ns->task->ac_task_container) { @@ -1069,6 +1084,28 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len) if (saib_queue_task_status_update(sp, spm, task->uuid, SAI_TASK_REASON_ACCEPTED)) goto bail; +#if defined(__APPLE__) + /* + * If we started the first task, acquire a wakelock to prevent + * idle suspend + */ + if (sp->nspawn_owner.count == 1 && !builder.wakelock_pid) { + pid_t pid = fork(); + + if (pid == -1) + lwsl_err("%s: fork for wakelock failed\n", __func__); + else if (!pid) { + execl("/usr/bin/caffeinate", "/usr/bin/caffeinate", "-i", (char *)NULL); + exit(1); /* should not get here */ + } else { + lwsl_notice("%s: acquired wakelock (pid %d)\n", __func__, (int)pid); + builder.wakelock_pid = pid; + } + } + /* if there's a pending wakelock release, cancel it */ + lws_sul_cancel(&builder.sul_release_wakelock); +#endif + break; case SAIB_RX_TASK_CANCEL:
Page fetched 0s ago, creation time: 4ms (vhost etag hits: 0%, cache hits: 0%)