diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8eef913..338079f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -136,9 +136,6 @@ require_lws_config(LWS_ROLE_WS 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/README.md b/README.md
index ae2822d..60ddec8 100644
--- a/README.md
+++ b/README.md
@@ -329,7 +329,7 @@ Feature|dependency
---|---
either|libwebsockets
server|libsqlite3
-builder|libgit2 pthreads
+builder|pthreads
jig (linux only)|libgpiod
#### Unix / Linux
@@ -346,17 +346,10 @@ $ sudo systemctl enable sai-builder
#### Windows builder only
-Build libgit2 via vcpkg, this takes <10mins
-
-```
-> vcpkg install libgit2:x64-windows
-```
-
You have to make git2.dll and some deps visible, in /windows/system32 or similar
```
> sudo cp "\Users\<user>\vcpkg\installed\x64-windows\bin\pcre.dll" "\windows\system32"
-> sudo cp "\Users\<user>\vcpkg\libgit2_x64-windows\bin\git2.dll" "\windows\system32"
```
Build lws the same way as for unix, except with
@@ -369,7 +362,7 @@ Build lws the same way as for unix, except with
For sai it's also very similar to unix, but with
```
-> cmake .. -DSAI_SERVER=0 -DSAI_LWS_INC_PATH="\Users\<user>\libwebsockets\build\include" -DSAI_LWS_LIB_PATH="\Users\<user>\libwebsockets\build\lib\Debug\websockets.lib" -DSAI_GIT2_INC_PATH="\Users\<user>\vcpkg\packages\libgit2_x64-windows\include" -DSAI_GIT2_LIB_PATH="\Users\<user>\vcpkg\packages\libgit2_x64-windows\lib\git2.lib" -DSAI_EXT_PTHREAD_INCLUDE_DIR="C:\Program Files (x86)\pthreads\include" -DSAI_EXT_PTHREAD_LIBRARIES="C:\Program Files (x86)\pthreads\lib\x64\libpthreadGC2.a"
+> cmake .. -DSAI_SERVER=0 -DSAI_LWS_INC_PATH="\Users\<user>\libwebsockets\build\include" -DSAI_LWS_LIB_PATH="\Users\<user>\libwebsockets\build\lib\Debug\websockets.lib" -DSAI_EXT_PTHREAD_INCLUDE_DIR="C:\Program Files (x86)\pthreads\include" -DSAI_EXT_PTHREAD_LIBRARIES="C:\Program Files (x86)\pthreads\lib\x64\libpthreadGC2.a"
> cmake --build . --config DEBUG
> sudo cmake --install . --config DEBUG
```
diff --git a/src/builder/CMakeLists.txt b/src/builder/CMakeLists.txt
index d5866cd..82eaff7 100644
--- a/src/builder/CMakeLists.txt
+++ b/src/builder/CMakeLists.txt
@@ -37,54 +37,12 @@ if (requirements)
link_directories("/usr/local/lib")
endif()
- #
- # libgit2 paths (builder)
- #
if (SAI_BUILDER)
- #
- # libgit2 paths
- #
- find_path( SAI_GIT2_INC_PATH NAMES "git2.h")
- find_library(SAI_GIT2_LIB_PATH NAMES "git2")
-
- if (SAI_GIT2_INC_PATH AND SAI_GIT2_LIB_PATH)
- set(SAI_DEPLIBS "${SAI_GIT2_LIB_PATH}" ${SAI_DEPLIBS})
- include_directories(BEFORE "${SAI_GIT2_INC_PATH}")
- else()
- message(FATAL_ERROR " Unable to find libgit2")
- endif()
-
- target_link_libraries(${SUB} ${SAI_GIT2_LIB_PATH})
-
if (APPLE)
target_link_libraries(sai-builder "-framework IOKit")
endif()
endif()
- set(CMAKE_REQUIRED_LIBRARIES ${SAI_GIT2_LIB_PATH})
-
- CHECK_C_SOURCE_COMPILES("#include <git2.h>
- int main(void) {
- const git_error *e = git_error_last();
- return !!e->message;
- }" SAI_HAVE_LIBGIT2_GIT_ERROR)
-
- if (SAI_HAVE_LIBGIT2_GIT_ERROR)
- set(CMAKE_C_FLAGS "-DSAI_HAVE_LIBGIT2_GIT_ERROR ${CMAKE_C_FLAGS}")
- endif()
-
- CHECK_C_SOURCE_COMPILES("
- #include <git2.h>
- int main(int argc, char **argv) {
- git_proxy_options o;
- git_proxy_options_init(&o, GIT_PROXY_OPTIONS_VERSION);
- return 0;
- }" LIBGIT2_HAVE_GIT_PROXY_OPTIONS_INIT)
-
- if (LIBGIT2_HAVE_GIT_PROXY_OPTIONS_INIT)
- set(CMAKE_C_FLAGS "-DLIBGIT2_HAVE_GIT_PROXY_OPTIONS_INIT ${CMAKE_C_FLAGS}")
- endif()
-
#configure_file("${PROJECT_SOURCE_DIR}/cmake/sai_config_private.h.in"
# "${PROJECT_BINARY_DIR}/sai_config_private.h")
#
diff --git a/src/builder/b-comms.c b/src/builder/b-comms.c
index aac38f5..8f0fd49 100644
--- a/src/builder/b-comms.c
+++ b/src/builder/b-comms.c
@@ -51,157 +51,6 @@ saib_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
}
/*
- * We come here for every platform's threadpool sync
- */
-
-static int
-tp_sync_check(struct lws_dll2 *d, void *user)
-{
- sai_plat_t *sp = lws_container_of(d, sai_plat_t, sai_plat_list);
- struct sai_plat_server *spm = (struct sai_plat_server *)user;
- struct sai_nspawn *ns;
- int n, soe;
- void *vp;
-
- /*
- * Let's look into every nspawn for each platform then...
- */
-
- lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
- sp->nspawn_owner.head) {
-
- ns = lws_container_of(d, struct sai_nspawn, list);
- soe = ns->state;
-
- /*
- * We can't deal with nspawns bound to a different server or
- * nspawns not with an active threadpool task
- */
-
- if (!ns->tp_task || spm != ns->spm)
- goto next;
-
- /*
- * We may not be the only threadpool task that wants
- * to sync... so bear in mind we want to loop after
- * handling this particular one
- */
-
- // lwsl_notice("%s: tp svc, state %d '%s'\n", __func__,
- // ns->state, ns->pending_mirror_log);
-
- /*
- * We got here by threadpool sync... logify the
- * >saib> message from the thread...
- */
-
- if (ns->pending_mirror_log[0]) {
- lwsl_notice("%s: logging %s\n", __func__,
- ns->pending_mirror_log);
- saib_log_chunk_create(ns, ns->pending_mirror_log,
- strlen(ns->pending_mirror_log), 3);
- ns->pending_mirror_log[0] = 0;
- }
-
- //(soe == NSSTATE_WAIT_REMOTE_MIRROR ||
- // soe == NSSTATE_FAILED ||
- // soe == NSSTATE_CHECKOUT ||
- // soe == NSSTATE_CHECKEDOUT) &&
-
- n = (int)lws_threadpool_task_status(ns->tp_task, &vp);
- lwsl_info("%s: WRITEABLE: ss=%p: "
- "task %p, priv %p, status %d\n", __func__, spm->ss,
- ns->tp_task, vp, n);
- switch (n) {
- case LWS_TP_STATUS_FINISHED:
- case LWS_TP_STATUS_STOPPED:
- case LWS_TP_STATUS_QUEUED:
- case LWS_TP_STATUS_RUNNING:
- case LWS_TP_STATUS_STOPPING:
- goto next;
-
- case LWS_TP_STATUS_SYNCING:
- /*
- * This is what the threadpool thread wants to hear from
- * us in order to continue on. The choice in the second
- * arg is whether to ask the thread to stop or not.
- *
- * MIRROR: let thread continue on to CHECKOUT
- * WAIT_REMOTE_MIRROR: continue to wait
- * CHECKOUT: go back into CHECKOUT
- * FAILED or CHECKEDOUT: we're done, stop the thread
- *
- * This wakes the stalled task, we can't read its
- * state after this
- */
-
- lws_threadpool_task_sync(ns->tp_task,
- soe == NSSTATE_CHECKEDOUT ||
- soe == NSSTATE_FAILED);
-
- if (soe != NSSTATE_CHECKEDOUT &&
- soe != NSSTATE_FAILED) {
- lwsl_notice("%s: task still going, status %d, "
- "sp = %p, sp->ss = %p\n",
- __func__, n, sp, ns->spm->ss);
- goto next;
- }
- /*
- * We asked for the task to stop... let's move on
- * while that's happening
- */
- break;
-
- default:
- return 1;
- }
-
- /*
- * The thread is over... either FAILED...
- */
-
- if (soe == NSSTATE_FAILED) {
- lwsl_notice("%s: thread over with FAILED\n",
- __func__);
- goto failer;
- }
-
- /*
- * ...or we did the mirror and let's spawn the actual task now
- */
-
- lwsl_notice("%s: Destroying checkout thread, spawning task\n",
- __func__);
- ns->tp_task = NULL;
-
- lws_sul_cancel(&ns->sul_task_cancel);
- saib_set_ns_state(ns, NSSTATE_BUILD);
-
- n = saib_spawn(ns);
- if (n) {
- lwsl_err("%s: spawn failed: %d\n", __func__, n);
-failer:
- saib_set_ns_state(ns, NSSTATE_FAILED);
- saib_task_grace(ns);
- saib_queue_task_status_update(ns->sp, ns->spm, NULL);
- }
-
-next:
-
- if (ns->artifact_owner.head) {
- /*
- * This nspawn has an outstanding artifact to upload
- */
- }
-
- lwsl_debug("%s: next tp sync\n", __func__);
-
- } lws_end_foreach_dll_safe(d, d1);
-
- return 0;
-}
-
-/*
* We cover requested tx for any instance of a platform that can takes tasks
* from the same server... it means just by coming here, no particular
* platform / sai_plat is implied...
@@ -223,14 +72,6 @@ saib_m_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
int n = 0;
/*
- * We are the ss / wsi that any threadpool instances on any platform
- * with tasks for this server are trying to sync to. We need to handle
- * and resume them all.
- */
-
- lws_dll2_foreach_safe(&builder.sai_plat_owner, spm, tp_sync_check);
-
- /*
* Any builder state updates / rejections to process?
*/
@@ -436,7 +277,27 @@ saib_m_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
star = walk;
ns = lws_container_of(walk, struct sai_nspawn, list);
- if (spm != ns->spm || !ns->chunk_cache.count || !ns->chunk_cache.tail)
+ if (spm != ns->spm)
+ continue;
+
+ if (ns->state_changed) {
+ ns->state_changed = 0;
+
+ switch (ns->state) {
+ case NSSTATE_CHECKEDOUT:
+ saib_set_ns_state(ns, NSSTATE_BUILD);
+ if (saib_spawn(ns)) {
+ lwsl_err("%s: saib_spawn failed\n",
+ __func__);
+ saib_set_ns_state(ns, NSSTATE_FAILED);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!ns->chunk_cache.count || !ns->chunk_cache.tail)
continue;
/*
@@ -530,12 +391,12 @@ cleanup_on_ss_destroy(struct lws_dll2 *d, void *user)
struct sai_nspawn *ns =
lws_container_of(d, struct sai_nspawn, list);
- if (ns->spm == spm && ns->tp) {
- lwsl_notice("%s: calling threadpool_destroy\n", __func__);
- lws_threadpool_finish(ns->tp);
- lws_threadpool_destroy(ns->tp);
- ns->tp = NULL;
- ns->tp_task = NULL;
+ if (ns->spm == spm) {
+ /*
+ * This pss is about to go away, make sure the ns
+ * can't reference it any more no matter what happens
+ */
+ ns->spm = NULL;
}
} lws_end_foreach_dll_safe(d, d1);
diff --git a/src/builder/b-mirror.c b/src/builder/b-mirror.c
index ac32dc8..5e4e768 100644
--- a/src/builder/b-mirror.c
+++ b/src/builder/b-mirror.c
@@ -1,7 +1,7 @@
/*
* sai-builder com-warmcat-sai client protocol implementation
*
- * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,659 +23,301 @@
#include <string.h>
#include <signal.h>
#include <assert.h>
+#include <fcntl.h>
#include "b-private.h"
-#include <git2.h>
-
-enum {
- SRFS_REQUESTING,
- SRFS_PROCESSING,
- SRFS_FAILED,
- SRFS_SUCCEEDED,
-};
-
-/*
- * Request to do the remote -> local mirror action
- */
-
-typedef struct sai_mirror_req {
- lws_dll2_t list;
-
- struct sai_nspawn *ns;
-
- char path[100]; /* local mirror path */
- char url[100];
- char hash[130];
- char ref[96];
-
- int state;
-} sai_mirror_req_t;
-
-static void
-sai_mirror_req_state_set(sai_mirror_req_t *req, int n)
-{
- lwsl_notice("%s: req %p: %d -> %d\n", __func__, req, req->state, n);
- req->state = n;
-}
-
-enum {
- SAIB_CHECKOUT_OK,
- SAIB_CHECKOUT_NOT_IN_LOCAL_MIRROR,
- SAIB_CHECKOUT_CHECKOUT_FAILED,
-};
-
-static int
-sai_mirror_local_checkout(struct sai_nspawn *ns)
-{
- git_checkout_options co_opts = GIT_CHECKOUT_OPTIONS_INIT;
- git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
- git_repository *git_repo_build_specific = NULL;
- char dp[512], spec[256], *paths[] = { spec }, inp[512];
- git_strarray rfs = { paths, 1 };
- git_object *treeish;
- git_remote *remote;
- int n, tries = 2;
-
- lws_strncpy(inp, ns->inp, sizeof(inp) - 1);
- if (inp[strlen(inp) - 1] == '\\')
- inp[strlen(inp) - 1] = '\0';
-
- /*
- * Remove anything that was already in the build-specific dir
- */
-
- lwsl_notice("%s: rm -rf %s\n", __func__, inp);
- lws_dir(inp, NULL, lws_dir_rm_rf_cb);
-
- /*
- * Make sure the build-specific dir itself is left standing in there.
- *
- * We can only create files and dirs using the global sai:nobody
- * credentials since we have dropped root long ago
- */
-
- if (mkdir(inp, 0755))
- lwsl_notice("%s: mkdir %s failed\n", __func__, ns->inp);
-
- /*
- * Create the build-specific git dir and init it
- */
-
- n = git_repository_init(&git_repo_build_specific, inp, 0);
- if (n) {
-#if defined(SAI_HAVE_LIBGIT2_GIT_ERROR)
- const git_error *e = git_error_last();
-
- lwsl_err("%s: unable to init temp repo %s: %d %s\n",
- __func__, ns->inp, n, e ? e->message : "?");
+static const char * const git_helper_sh =
+ "#!/bin/bash\n"
+#if defined(__APPLE__)
+ "export PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin\n"
#else
- lwsl_err("%s: unable to init temp repo %s: %d\n",
- __func__, ns->inp, n);
+ "export PATH=/usr/local/bin:$PATH\n"
#endif
+ "set -e\n"
+ "echo \"git_helper_sh: starting\"\n"
+ "OPERATION=$1\n"
+ "shift\n"
+ "if [ \"$OPERATION\" == \"mirror\" ]; then\n"
+ " REMOTE_URL=$1\n"
+ " REF=$2\n"
+ " HASH=$3\n"
+ " MIRROR_PATH=$4\n"
+ " mkdir -p \"$MIRROR_PATH\"\n"
+ " if [ ! -d \"$MIRROR_PATH/.git\" ]; then\n"
+ " git init --bare \"$MIRROR_PATH\"\n"
+ " fi\n"
+ " REFSPEC=\"$REF:ref-$HASH\"\n"
+ " git -C \"$MIRROR_PATH\" fetch \"$REMOTE_URL\" \"$REFSPEC\"\n"
+ "elif [ \"$OPERATION\" == \"checkout\" ]; then\n"
+ " MIRROR_PATH=$1\n"
+ " BUILD_DIR=$2\n"
+ " HASH=$3\n"
+ " if [ ! -d \"$BUILD_DIR/.git\" ]; then\n"
+ " rm -rf \"$BUILD_DIR\"\n"
+ " mkdir -p \"$BUILD_DIR\"\n"
+ " git -C \"$BUILD_DIR\" init\n"
+ " fi\n"
+ " if ! git -C \"$BUILD_DIR\" fetch \"$MIRROR_PATH\" \"ref-$HASH\"; then\n"
+ " exit 2\n"
+ " fi\n"
+ " git -C \"$BUILD_DIR\" checkout -f \"$HASH\"\n"
+ " git -C \"$BUILD_DIR\" clean -fdx\n"
+ "else\n"
+ " exit 1\n"
+ "fi\n"
+ "echo \">>> Git helper script finished.\"\n"
+ "exit 0\n";
- return SAIB_CHECKOUT_CHECKOUT_FAILED;
- }
-
- /*
- * Attempt to fetch the ref we are interested in from our local mirror
- *
- * Create a temp remote against the destination repo
- */
-
- if (git_remote_create_anonymous(&remote, git_repo_build_specific,
- ns->path)) {
- lwsl_err("%s: cant find remote %s\n", __func__,
- ns->git_repo_url);
-
- git_repository_free(git_repo_build_specific);
- return SAIB_CHECKOUT_CHECKOUT_FAILED;
- }
+#if defined(WIN32)
+static const char * const git_helper_bat =
+ "@echo on\n"
+ "setlocal EnableDelayedExpansion\n"
+ "echo \"git_helper_bat: starting\"\n"
+ "set \"OPERATION=%~1\"\n"
+ "echo \"OPERATION: !OPERATION!\"\n"
+ "if /i \"!OPERATION!\"==\"mirror\" (\n"
+ " set \"REMOTE_URL=%~2\"\n"
+ " set \"REF=%~3\"\n"
+ " set \"HASH=%~4\"\n"
+ " set \"MIRROR_PATH=%~5\"\n"
+ " echo \"REMOTE_URL: !REMOTE_URL!\"\n"
+ " echo \"REF: !REF!\"\n"
+ " echo \"HASH: !HASH!\"\n"
+ " echo \"MIRROR_PATH: !MIRROR_PATH!\"\n"
+ " if not exist \"!MIRROR_PATH!\\.\" (\n"
+ " mkdir \"!MIRROR_PATH!\"\n"
+ " )\n"
+ " if not exist \"!MIRROR_PATH!\\.git\" (\n"
+ " git init --bare \"!MIRROR_PATH!\"\n"
+ " if errorlevel 1 exit /b 1\n"
+ " )\n"
+ " set \"REFSPEC=!REF!:ref-!HASH!\"\n"
+ " echo \"REFSPEC: !REFSPEC!\"\n"
+ " git -C \"!MIRROR_PATH!\" fetch \"!REMOTE_URL!\" \"!REFSPEC!\" 2>&1\n"
+ " if !ERRORLEVEL! neq 0 (\n"
+ " echo \"git fetch failed with errorlevel !ERRORLEVEL!\"\n"
+ " exit /b 1\n"
+ " )\n"
+ " exit /b 0\n"
+ ")\n"
+ "if /i \"!OPERATION!\"==\"checkout\" (\n"
+ " set \"MIRROR_PATH=%~2\"\n"
+ " set \"BUILD_DIR=%~3\"\n"
+ " set \"HASH=%~4\"\n"
+ " echo \"MIRROR_PATH: !MIRROR_PATH!\"\n"
+ " echo \"BUILD_DIR: !BUILD_DIR!\"\n"
+ " echo \"HASH: !HASH!\"\n"
+ " if not exist \"!BUILD_DIR!\\.git\" (\n"
+ " if exist \"!BUILD_DIR!\\\" rmdir /s /q \"!BUILD_DIR!\"\n"
+ " mkdir \"!BUILD_DIR!\"\n"
+ " git -C \"!BUILD_DIR!\" init\n"
+ " if errorlevel 1 exit /b 1\n"
+ " )\n"
+ " git -C \"!BUILD_DIR!\" fetch \"!MIRROR_PATH!\" \"ref-!HASH!\"\n"
+ " if errorlevel 1 exit /b 2\n"
+ " git -C \"!BUILD_DIR!\" checkout -f \"!HASH!\"\n"
+ " if errorlevel 1 exit /b 1\n"
+ " echo \">>> Git helper script finished.\"\n"
+ " exit /b 0\n"
+ ")\n"
+ "exit /b 1\n";
+#endif
- lws_snprintf(spec, sizeof(spec), "ref-%s:ref-%s", ns->hash, ns->hash);
+static void sai_git_mirror_reap_cb(void *opaque, lws_usec_t *accounting,
+ siginfo_t *si, int we_killed_him);
- lwsl_notice("%s: Attempting to fetch %s from mirror to %s\n",
- __func__, spec, ns->inp);
+static void
+sai_git_checkout_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si,
+ int we_killed_him)
+{
+ struct saib_opaque_spawn *op = (struct saib_opaque_spawn *)opaque;
+ struct sai_nspawn *ns = op->ns;
+ int exit_code = -1;
- /*
- * Fetch the tree from the local mirror to our local build repo
- * This may take an open-ended amount of time
- */
+ lwsl_notice("%s: mirror reap callback started\n", __func__);
-#if defined(LIBGIT2_HAVE_GIT_PROXY_OPTIONS_INIT)
- git_proxy_options_init(&opts.proxy_opts, GIT_PROXY_OPTIONS_VERSION);
-#endif
+ lwsl_warn("%s: reap at %llu: we_killed_him: %d\n",
+ __func__, (unsigned long long)lws_now_usecs(),
+ we_killed_him);
- n = git_remote_fetch(remote, &rfs, &opts, "fetch");
- git_remote_free(remote);
- if (n) {
- lwsl_notice("%s: git_remote_fetch() says %d\n", __func__, n);
-#if defined(SAI_HAVE_LIBGIT2_GIT_ERROR)
- const git_error *e = git_error_last();
+ if (we_killed_him)
+ goto fail;
- lwsl_err("%s: git_remote_fetch libgit err: %d %s\n",
- __func__, n, e ? e->message : "?");
+#if !defined(WIN32)
+ if (si->si_code == CLD_EXITED)
+ exit_code = si->si_status;
+#else
+ exit_code = si->retcode & 0xff;
#endif
- git_repository_free(git_repo_build_specific);
- return SAIB_CHECKOUT_NOT_IN_LOCAL_MIRROR;
- }
- /*
- * Check out the commit we fetched into the ephemeral local build dir...
- * this should be a formality since we already retreived the ref into
- * ephemeral local build dir's repo.
- */
-
- lws_snprintf(spec, sizeof(spec), "ref-%s", ns->hash);
- n = git_revparse_single(&treeish, git_repo_build_specific, spec);
- if (n) {
- lwsl_notice("%s: revparse %s failed: %d\n", __func__, spec, n);
- git_repository_free(git_repo_build_specific);
- return SAIB_CHECKOUT_NOT_IN_LOCAL_MIRROR;
+ if (exit_code == 0) {
+ saib_set_ns_state(ns, NSSTATE_CHECKEDOUT);
+ goto onward;
}
-again:
- co_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
- n = git_checkout_tree(git_repo_build_specific, treeish, &co_opts);
- git_object_free(treeish);
- if (n) {
- if (n == GIT_EUNBORNBRANCH && tries--) {
- lwsl_warn("%s: git checkout says HEAD is empty branch\n",
- __func__);
-
- /*
- * It's telling us we need to delete the local mirror
- * HEAD and retry
- */
-
- lws_snprintf(dp, sizeof(dp), "%s/HEAD", ns->inp);
- unlink(dp);
-
- goto again;
- }
- goto co_failed;
+ if (exit_code == 2) {
+ saib_start_mirror(ns);
+ goto onward;
}
- lws_snprintf(spec, sizeof(spec), "refs/heads/ref-%s", ns->hash);
- git_repository_set_head(git_repo_build_specific, spec);
-
- lwsl_notice("%s: checkout OK\n", __func__);
-
- git_repository_free(git_repo_build_specific);
-
- return SAIB_CHECKOUT_OK;
-
-co_failed:
- lwsl_err("%s: git checkout failed: %d\n", __func__, n);
- git_repository_free(git_repo_build_specific);
-
- return SAIB_CHECKOUT_CHECKOUT_FAILED;
+fail:
+ saib_set_ns_state(ns, NSSTATE_FAILED);
+onward:
+ ns->op = NULL;
+ free(op);
}
-
-/*
- * We are a threadpool thread handling queueing on remote mirror "thread_repo",
- * and afterwards checking out a ref from the local copy.
- *
- * The main git2 process just goes away and does the fetch atomically. Wrapping
- * it in an extra threadpool thread lets us continue to be resposive while we're
- * waiting for the remote mirror fetch.
- */
-
-enum lws_threadpool_task_return
-saib_mirror_task(void *user, enum lws_threadpool_task_status s)
+static void
+sai_git_mirror_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si,
+ int we_killed_him)
{
- struct sai_nspawn *ns = (struct sai_nspawn *)user;
- sai_mirror_instance_t *mi;
- sai_mirror_req_t *req;
- int n, m;
-
- lwsl_warn("%s: entry: state %d\n", __func__, ns->state);
-
- mi = &builder.mi;
-
- if (s == LWS_TP_STATUS_STOPPING)
- return LWS_TP_RETURN_STOPPED;
-
- switch (ns->state) {
- case NSSTATE_INIT:
- case NSSTATE_MOUNTING:
-
- case NSSTATE_STARTING_MIRROR:
- lwsl_notice("%s: NSSTATE_STARTING_MIRROR\n", __func__);
- ns->state = NSSTATE_CHECKOUT_SPEC;
- /* fallthru */
-
- case NSSTATE_CHECKOUT_SPEC:
- /*
- * First attempt to checkout from local mirror, in case we
- * already fetched it to the local mirror for an earlier task
- */
-
- lwsl_notice("%s: NSSTATE_CHECKOUT_SPEC\n", __func__);
- switch (sai_mirror_local_checkout(ns)) {
- case SAIB_CHECKOUT_OK:
- /*
- * oh we have it then... do a final sync and have the
- * foreground handler STOP us when we resume
- */
-
- lwsl_notice("%s: syncing checkout %s done\n", __func__,
- ns->inp);
- ns->state = NSSTATE_CHECKEDOUT;
-
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Local mirror checkout %s\n", ns->hash);
-
- return LWS_TP_RETURN_SYNC;
-
- case SAIB_CHECKOUT_NOT_IN_LOCAL_MIRROR:
- /*
- * Basically it means we have to get it from the remote
- * repo into the local mirror first... clear down the
- * local build dir
- */
-
- lws_dir(ns->inp, NULL, lws_dir_rm_rf_cb);
-
- /*
- * Make sure the dir itself is left standing in there
- */
-
- if (mkdir(ns->inp, 0755))
- lwsl_notice("%s: mkdir %s failed\n", __func__, ns->inp);
-
- /*
- * Form a request, kick the remoting thread and then
- * wait on the condition in the request
- */
-
- req = malloc(sizeof(*req));
- if (!req)
- goto fail;
-
- /*
- * The request needs to exist with a standalone
- * lifetime regardless of what's happening to the ns or
- * threadpool thread while it waits, or proceeds
- * asynchronously
- */
-
- lwsl_notice("%s: NOT_IN_LOCAL_MIRROR %s\n", __func__, ns->ref);
- memset(req, 0, sizeof(*req));
- req->state = SRFS_REQUESTING;
- req->ns = ns;
- lws_strncpy(req->url, ns->git_repo_url, sizeof(req->url));
- lws_strncpy(req->hash, ns->hash, sizeof(req->hash));
- lws_strncpy(req->ref, ns->ref, sizeof(req->ref));
- lws_strncpy(req->path, ns->path, sizeof(req->path));
-
- pthread_mutex_lock(&mi->mut);
- lws_dll2_add_tail(&req->list, &mi->pending_req);
-
- pthread_cond_broadcast(&mi->cond);
- pthread_mutex_unlock(&mi->mut);
-
- ns->state = NSSTATE_WAIT_REMOTE_MIRROR;
- ns->mirror_wait_budget = 600;
-
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Starting REMOTE MIRROR FETCH\n");
-
- return LWS_TP_RETURN_SYNC;
-
- case SAIB_CHECKOUT_CHECKOUT_FAILED:
-
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Checkout failed...\n");
-
- goto fail;
- }
-
- break;
-
- case NSSTATE_CHECKOUT:
- /*
- * We come here after the remote -> local mirror operation
- * seemed to go well, to complete the flow by checking out
- * the newly-fetched commit. We can only go OK or fail.
- */
-
- lwsl_notice("%s: NSSTATE_CHECKOUT\n", __func__);
- m = sai_mirror_local_checkout(ns);
- lwsl_notice("%s: sai_mirror_local_checkout() says %d\n", __func__, m);
- switch (m) {
- case SAIB_CHECKOUT_OK:
- /*
- * oh we have it then... do a final sync and have the
- * foreground handler STOP us when we resume
- */
-
- lwsl_notice("%s: syncing checkout %s done\n", __func__,
- ns->inp);
- ns->state = NSSTATE_CHECKEDOUT;
-
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Remote->Local->Checked out %s\n", ns->hash);
+ struct saib_opaque_spawn *op = (struct saib_opaque_spawn *)opaque;
+ struct sai_nspawn *ns = op->ns;
+ int exit_code = -1;
- return LWS_TP_RETURN_SYNC;
+ // lwsl_warn("%s: reap at %llu: we_killed_him: %d, si_code: %d, si_status: %d\n",
+ // __func__, (unsigned long long)lws_now_usecs(),
+ // we_killed_him, si->si_code, si->si_status);
- case SAIB_CHECKOUT_NOT_IN_LOCAL_MIRROR:
- /* fallthru */
- lwsl_notice("%s: checkout not in local mirror\n", __func__);
- case SAIB_CHECKOUT_CHECKOUT_FAILED:
-
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Checkout failed after mirror...\n");
- lwsl_notice("%s: checkout failed\n", __func__);
+ if (we_killed_him)
+ goto fail;
- goto fail;
- }
- break;
-
- case NSSTATE_CHECKEDOUT:
- case NSSTATE_BUILD:
- case NSSTATE_DONE:
- case NSSTATE_FAILED:
- break;
-
- case NSSTATE_WAIT_REMOTE_MIRROR:
-
- /*
- * We are waiting for our request to be handled... we need to
- * watch the req completed list at intervals. Anything on the
- * completed_req owner has either completed or failed.
- */
-
- lwsl_notice("%s: NSSTATE_WAIT_REMOTE_MIRROR\n", __func__);
- pthread_mutex_lock(&mi->mut);
-
- lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
- mi->completed_req.head) {
- sai_mirror_req_t *r = lws_container_of(d,
- sai_mirror_req_t, list);
-
- if (r->ns == ns) {
-
- /*
- * It's our request that has completed
- */
-
- n = r->state;
-
- lws_dll2_remove(&r->list);
- pthread_mutex_unlock(&mi->mut);
- free(r);
-
- if (n == SRFS_FAILED) {
- lwsl_notice("%s: mirror req failed\n",
- __func__);
- goto fail;
- }
-
- /*
- * Leave in NSSTATE_CHECKOUT and come back to
- * continue with checking out after we have
- * sync'd with comms to server
- */
-
- ns->state = NSSTATE_CHECKOUT;
- lws_snprintf(ns->pending_mirror_log,
- sizeof(ns->pending_mirror_log),
- ">saib> Remote -> Local OK\n");
-
- return LWS_TP_RETURN_SYNC;
- }
-
- } lws_end_foreach_dll_safe(d, d1);
-
- pthread_mutex_unlock(&mi->mut); /* --- mi->mut unlock */
-
-#if defined(WIN32)
- Sleep(1000);
+#if !defined(WIN32)
+ if (si->si_code == CLD_EXITED)
+ exit_code = si->si_status;
#else
- sleep(1);
+ exit_code = si->retcode & 0xff;
#endif
- if (!--ns->mirror_wait_budget) {
- lws_snprintf(ns->pending_mirror_log, sizeof(ns->pending_mirror_log),
- ">saib> timed out waiting for mirror\n");
- lwsl_notice("%s: timed out waiting for mirror\n", __func__);
-
- goto fail;
- }
-
- lws_snprintf(ns->pending_mirror_log, sizeof(ns->pending_mirror_log),
- ">saib> Waiting on MIRROR...\n");
-
- return LWS_TP_RETURN_SYNC;
- }
-
- return LWS_TP_RETURN_SYNC;
+ if (exit_code == 0) {
+ /* mirror succeeded, now try checkout again */
+ lwsl_notice("%s: mirror success, starting checkout\n", __func__);
+ saib_start_checkout(ns);
+ goto onward;
+ } else
+ lwsl_warn("%s: exit code 0x%x == failure\n", __func__, (unsigned int)exit_code);
fail:
-
- /*
- * If we have an incomplete request on the mirror thread, remove it
- */
-
- pthread_mutex_lock(&mi->mut);
- lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
- mi->pending_req.head) {
- sai_mirror_req_t *r = lws_container_of(d,
- sai_mirror_req_t, list);
-
- if (r->ns == ns) {
- lws_dll2_remove(&r->list);
- free(r);
- }
-
- } lws_end_foreach_dll_safe(d, d1);
- pthread_mutex_unlock(&mi->mut);
-
- lwsl_err("%s: failed\n", __func__);
- ns->retcode = SAISPRF_EXIT | 253;
-
- return LWS_TP_RETURN_SYNC;
+ saib_set_ns_state(ns, NSSTATE_FAILED);
+onward:
+ ns->op = NULL;
+ free(op);
}
-/*
- * This thread serially handles requests for remote mirrors, since there's a
- * write lock in the filesystem copy when someone is updating the mirror.
- *
- * It picks takes queued requests from the head
- */
-
-void *
-thread_repo(void *d)
+static int
+saib_spawn_git_helper(struct sai_nspawn *ns, const char *operation)
{
- sai_mirror_instance_t *mi = (sai_mirror_instance_t *)d;
- sai_mirror_req_t *req, rcopy;
- int new_state;
- int n;
-
- lwsl_notice("%s: repo thread start\n", __func__);
-
- git_libgit2_init();
-
- while (!mi->finish) {
- git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
- char spec[96], *paths[] = { spec };
- git_strarray rfs = { paths, 1 };
- git_repository *repo_mirror;
- git_remote *remote;
-
- pthread_mutex_lock(&mi->mut);
-
- /* we sleep if there are no requests pending or ongoing */
-
- while (!mi->pending_req.count && !mi->finish)
- pthread_cond_wait(&mi->cond, &mi->mut);
-
- if (mi->finish) {
- pthread_mutex_unlock(&mi->mut);
- break;
- }
-
- /*
- * Starting from the head, look for the first request that's in
- * a state we should start the remote for it
- */
-
- req = NULL;
- lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
- mi->pending_req.head) {
- sai_mirror_req_t *r = lws_container_of(d,
- sai_mirror_req_t, list);
-
- if (r->state == SRFS_REQUESTING) {
- req = r;
- lwsl_notice("%s: setting processing\n",
- __func__);
- sai_mirror_req_state_set(req, SRFS_PROCESSING);
- break;
- }
-
- } lws_end_foreach_dll_safe(d, d1);
-
- //req = lws_dll2_get_head(&bi->requests);
-
- //lws_dll2_remove(&->overall_list);
-
- /*
- * The request object on the list might be removed and destroyed
- * while we do this long-term mirroring action. So take a temp
- * copy of it to set the action up, before releasing the mutex.
- */
- if (req)
- rcopy = *req;
-
- pthread_mutex_unlock(&mi->mut);
- if (!req)
- continue;
-
- /*
- * ... we cannot dereference req after releasing the mutex.
- * We made a temp copy of it in rcopy, to set the transaction
- * up we can use that so we can be sure it's around for that.
- */
-
- /*
- * git init --bare <path>
- */
-
- new_state = SRFS_FAILED;
- repo_mirror = NULL;
- if (git_repository_init(&repo_mirror, rcopy.path, 1)) {
- fprintf(stderr, "%s: unable to init sticky repo %s, errno %d\n",
- __func__, rcopy.path, errno);
-
- goto fail_out;
- }
-
- /*
- * Fetch over the branch or tag we're interested in from the
- * remote repo and into our local sticky mirror
- *
- * git fetch <remote repo> +<ref>:<ref>
- */
-
- if (git_remote_create_anonymous(&remote, repo_mirror, rcopy.url)) {
- fprintf(stderr, "%s: cant find remote %s\n", __func__,
- rcopy.url);
-
- git_repository_free(repo_mirror);
- goto fail_out;
- }
-
- lws_snprintf(spec, sizeof(spec), "%s:ref-%s", rcopy.ref, rcopy.hash);
- fprintf(stderr, "%s: fetching %s %s\n", __func__, rcopy.url, spec);
-
-#if defined(LIBGIT2_HAVE_GIT_PROXY_OPTIONS_INIT)
- git_proxy_options_init(&opts.proxy_opts, GIT_PROXY_OPTIONS_VERSION);
+ struct lws_spawn_piped_info info;
+ struct saib_opaque_spawn *op;
+ char script_path[1024], inp[512];
+ const char *pargs[9];
+ const char **env = NULL;
+#if defined(__APPLE__)
+ const char *env_array[2];
+ char path_env[256];
+#endif
+ ssize_t n;
+ int fd, count = 0;
+
+#if defined(__APPLE__)
+ lws_snprintf(path_env, sizeof(path_env),
+ "PATH=/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/sbin:/usr/sbin");
+ env_array[0] = path_env;
+ env_array[1] = NULL;
+ env = (const char **)env_array;
#endif
- /*
- * This may take an open-ended amount of time
- */
+#if defined(WIN32)
+ lws_snprintf(script_path, sizeof(script_path), "%s\\sai-git-helper-%d.bat",
+ builder.home, ns->instance_idx);
+#else
+ lws_snprintf(script_path, sizeof(script_path), "%s/sai-git-helper-%d.sh",
+ builder.home, ns->instance_idx);
+#endif
- n = git_remote_fetch(remote, &rfs, &opts, "fetch");
-#if defined(SAI_HAVE_LIBGIT2_GIT_ERROR)
- if (n) {
- const git_error *e = git_error_last();
+ fd = open(script_path, O_CREAT | O_TRUNC | O_WRONLY, 0755);
+ if (fd < 0)
+ return -1;
- if (e)
- fprintf(stderr, "%s: git error %s\n", __func__,
- e->message);
- }
+#if defined(WIN32)
+ n = write(fd, git_helper_bat, strlen(git_helper_bat));
+#else
+ n = write(fd, git_helper_sh, strlen(git_helper_sh));
#endif
-
- git_remote_free(remote);
- git_repository_free(repo_mirror);
-
- if (n) {
- fprintf(stderr, "%s: failed to fetch %s, n: %d\n",
- __func__, spec, n);
- goto fail_out;
- }
-
- fprintf(stderr, "%s: syncing mirror fetch %s %s successful\n",
- __func__, rcopy.url, rcopy.hash);
-
- new_state = SRFS_SUCCEEDED;
-
-fail_out:
- /*
- * We notify the threadpool monitoring thread
- */
-
- pthread_mutex_lock(&mi->mut);
-
- /*
- * The requestor and its request may have gone. And, it's
- * possible we got several queued requests that were actually
- * waiting for the same mirror transaction which has now
- * succeeded or failed the same for all of them.
- *
- * Let's take the approach to lock the queue and tell everybody
- * at once who's asking for the same thing what the outcome was.
- */
- lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
- mi->pending_req.head) {
- sai_mirror_req_t *r = lws_container_of(d,
- sai_mirror_req_t, list);
-
- if ((r->state == SRFS_REQUESTING ||
- r->state == SRFS_PROCESSING) &&
- !strcmp(r->url, rcopy.url) &&
- !strcmp(r->hash, rcopy.hash) &&
- !strcmp(r->path, rcopy.path) &&
- !strcmp(r->ref, rcopy.ref)) {
- /*
- * Change the state of matching guys and put
- * them on to the completed_req list owner
- */
- fprintf(stderr, "%s: setting req state %d\n",
- __func__, new_state);
- sai_mirror_req_state_set(r, new_state);
- lws_dll2_remove(&r->list);
- lws_dll2_add_tail(&r->list, &mi->completed_req);
- }
-
- } lws_end_foreach_dll_safe(d, d1);
-
- pthread_mutex_unlock(&mi->mut);
+ close(fd);
+
+ if (n < 0)
+ return -1;
+
+ pargs[count++] = script_path;
+ pargs[count++] = operation;
+
+ if (!strcmp(operation, "mirror")) {
+ pargs[count++] = ns->git_repo_url;
+ pargs[count++] = ns->ref;
+ pargs[count++] = ns->hash;
+ pargs[count++] = ns->path;
+ } else { /* checkout */
+ lws_strncpy(inp, ns->inp, sizeof(inp) - 1);
+ if (inp[strlen(inp) - 1] == '\\')
+ inp[strlen(inp) - 1] = '\0';
+ pargs[count++] = ns->path;
+ pargs[count++] = inp;
+ pargs[count++] = ns->hash;
+ }
+ pargs[count++] = NULL;
+
+ memset(&info, 0, sizeof(info));
+ info.vh = builder.vhost;
+ info.exec_array = pargs;
+ info.env_array = env;
+ info.protocol_name = "sai-stdxxx";
+ info.timeout_us = 5 * 60 * LWS_US_PER_SEC;
+
+ if (!strcmp(operation, "mirror"))
+ info.reap_cb = sai_git_mirror_reap_cb;
+ else
+ info.reap_cb = sai_git_checkout_reap_cb;
+
+ op = malloc(sizeof(*op));
+ if (!op)
+ return -1;
+ memset(op, 0, sizeof(*op));
+
+ op->ns = ns;
+ ns->op = op;
+
+ info.opaque = op;
+ info.owner = &builder.lsp_owner;
+ info.plsp = &op->lsp;
+
+ // lwsl_warn("%s: spawning git-helper for %s at %llu\n", __func__,
+ // operation, (unsigned long long)lws_now_usecs());
+
+ if (lws_spawn_piped(&info) == NULL) {
+ lwsl_err("%s: lws_spawn_piped for %s failed\n", __func__,
+ operation);
+ ns->op = NULL;
+ /* op is attached to wsi and will be freed later */
+ return -1;
}
- lwsl_notice("%s: repo thread exiting\n", __func__);
+ if (!strcmp(operation, "mirror"))
+ saib_set_ns_state(ns, NSSTATE_WAIT_REMOTE_MIRROR);
- git_libgit2_shutdown();
- pthread_exit(NULL);
+ return 0;
+}
- return NULL;
+int
+saib_start_mirror(struct sai_nspawn *ns)
+{
+ return saib_spawn_git_helper(ns, "mirror");
+}
+
+int
+saib_start_checkout(struct sai_nspawn *ns)
+{
+ lwsl_notice("%s: starting checkout\n", __func__);
+ return saib_spawn_git_helper(ns, "checkout");
}
diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c
index fca417e..70612b4 100644
--- a/src/builder/b-nspawn.c
+++ b/src/builder/b-nspawn.c
@@ -78,22 +78,36 @@ static int
callback_sai_stdwsi(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
- struct sai_nspawn *ns = (struct sai_nspawn *)lws_get_opaque_user_data(wsi);
+ struct saib_opaque_spawn *op =
+ (struct saib_opaque_spawn *)lws_get_opaque_user_data(wsi);
+ struct sai_nspawn *ns = op ? op->ns : NULL;
uint8_t buf[600];
int ilen;
+ // lwsl_warn("%s: reason %d\n", __func__, reason);
+
switch (reason) {
case LWS_CALLBACK_RAW_CLOSE_FILE:
- lwsl_user("%s: RAW_CLOSE_FILE wsi %p: fd: %d, stdfd: %d\n",
- __func__, wsi, lws_get_socket_fd(wsi),
- lws_spawn_get_stdfd(wsi));
+ lwsl_warn("%s: RAW_CLOSE_FILE at %llu, wsi %p: fd: %d, stdfd: %d\n",
+ __func__, (unsigned long long)lws_now_usecs(), wsi,
+ lws_get_socket_fd(wsi), lws_spawn_get_stdfd(wsi));
ilen = lws_snprintf((char *)buf, sizeof(buf), "Stdwsi %d close\n", lws_spawn_get_stdfd(wsi));
- saib_log_chunk_create(ns, buf, (size_t)ilen, 3);
+ if (ns) {
+ saib_log_chunk_create(ns, buf, (size_t)ilen, 3);
+ if (ns->spm)
+ if (lws_ss_request_tx(ns->spm->ss))
+ lwsl_warn("%s: lws_ss_request_tx failed\n",
+ __func__);
+ }
- if (ns->lsp)
- lws_spawn_stdwsi_closed(ns->lsp, wsi);
+ lwsl_wsi_err(wsi, "CLOSING: op %p, op->lsp %p", op, op ? op->lsp : NULL);
+ if (op && op->lsp) {
+ lws_spawn_stdwsi_closed(op->lsp, wsi);
+ if (ns)
+ lws_cancel_service(ns->builder->context);
+ }
break;
case LWS_CALLBACK_RAW_RX_FILE:
@@ -116,15 +130,15 @@ callback_sai_stdwsi(struct lws *wsi, enum lws_callback_reasons reason,
len = (unsigned int)ilen;
- if (!ns->spm) {
+ if (!op || !op->ns || !op->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)))
+ if (!saib_log_chunk_create(op->ns, buf, len, lws_spawn_get_stdfd(wsi)))
return -1;
- return lws_ss_request_tx(ns->spm->ss) ? -1 : 0;
+ return lws_ss_request_tx(op->ns->spm->ss) ? -1 : 0;
default:
break;
@@ -141,7 +155,11 @@ static void
sai_lsp_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si,
int we_killed_him)
{
- struct sai_nspawn *ns = (struct sai_nspawn *)opaque;
+ struct saib_opaque_spawn *op = (struct saib_opaque_spawn *)opaque;
+ struct sai_nspawn *ns = op ? op->ns : NULL;
+
+ // lwsl_warn("%s: reap at %llu: we_killed_him: %d\n", __func__,
+ // (unsigned long long)lws_now_usecs(), we_killed_him);
saib_log_chunk_create(ns, ">saib> Reaping build process\n", 29, 3);
@@ -199,6 +217,10 @@ ok:
lwsl_notice("%s: finished, waiting to drain logs (this ns %d, spm in flight %d)\n",
__func__, ns->chunk_cache.count,
ns->spm ? ns->spm->logs_in_flight : -99);
+
+ if (ns)
+ ns->op = NULL;
+ free(op);
}
#if defined(WIN32)
@@ -211,6 +233,7 @@ static const char * const runscript =
"set SAI_LOGPROXY_TTY1=%s\n"
"set HOME=%s\n"
"cd %s\\jobs\\%s\\%s &&"
+ " rmdir /s /q build & "
"%s"
;
@@ -234,7 +257,7 @@ static const char * const runscript =
"export SAI_LOGPROXY_TTY1=%s\n"
"set -e\n"
"cd %s/jobs/$SAI_OVN/$SAI_PROJECT\n"
-
+ "rm -rf build\n"
"%s\n"
"exit $?\n"
;
@@ -245,6 +268,7 @@ int
saib_spawn(struct sai_nspawn *ns)
{
struct lws_spawn_piped_info info;
+ struct saib_opaque_spawn *op;
char args[290], st[2048], *p;
const char *respath = "unk";
const char * cmd[] = {
@@ -252,7 +276,7 @@ saib_spawn(struct sai_nspawn *ns)
NULL
};
const char *env[] = {
- "PATH=/usr/bin:/bin",
+ "PATH=/usr/local/bin:/usr/bin:/bin",
"LANG=en_US.UTF-8",
NULL
};
@@ -336,20 +360,41 @@ saib_spawn(struct sai_nspawn *ns)
info.max_log_lines = 10000;
info.timeout_us = 30 * 60 * LWS_US_PER_SEC;
info.reap_cb = sai_lsp_reap_cb;
- info.opaque = ns;
- info.plsp = &ns->lsp;
#if defined(__linux__)
info.cgroup_name_suffix = cgroup;
info.p_cgroup_ret = &in_cgroup;
#endif
- ns->lsp = lws_spawn_piped(&info);
- if (!ns->lsp) {
+ op = malloc(sizeof(*op));
+ if (!op)
+ return 1;
+ memset(op, 0, sizeof(*op));
+
+ op->ns = ns;
+ ns->op = op;
+
+ info.opaque = op;
+ info.owner = &builder.lsp_owner;
+ info.plsp = &op->lsp;
+
+ // lwsl_warn("%s: spawning build script at %llu\n", __func__,
+ // (unsigned long long)lws_now_usecs());
+
+ lws_spawn_piped(&info);
+ if (!op->lsp) {
+ /*
+ * op is attached to wsi and will be freed in reap cb,
+ * we can't free it here
+ */
+ ns->op = NULL;
lwsl_err("%s: failed\n", __func__);
return 1;
}
+ // lwsl_warn("%s: build script spawn returned at %llu\n", __func__,
+ // (unsigned long long)lws_now_usecs());
+
#if defined(__linux__)
lwsl_notice("%s: lws_spawn_piped started (cgroup: %d)\n", __func__, in_cgroup);
#endif
diff --git a/src/builder/b-private.h b/src/builder/b-private.h
index 5baa4b3..67d0823 100644
--- a/src/builder/b-private.h
+++ b/src/builder/b-private.h
@@ -31,13 +31,18 @@
#define mkdir(x,y) _mkdir(x)
#define rmdir _rmdir
#define unlink _unlink
-#define HAVE_STRUCT_TIMESPEC
#if defined(pid_t)
#undef pid_t
#endif
#endif
#include <pthread.h>
-#include <git2.h>
+
+struct lws_spawn_piped;
+
+struct saib_opaque_spawn {
+ struct sai_nspawn *ns;
+ struct lws_spawn_piped *lsp;
+};
#define SAI_LOAD_REPORT_US (1 * LWS_US_PER_SEC)
#define SAI_IDLE_GRACE_US (30 * LWS_US_PER_SEC)
@@ -78,19 +83,6 @@ enum {
-typedef struct sai_mirror_instance {
- pthread_mutex_t mut;
- pthread_cond_t cond;
-
- pthread_t repo_thread;
-
- lws_dll2_owner_t pending_req;
- lws_dll2_owner_t completed_req;
-
- uint8_t finish;
-} sai_mirror_instance_t;
-
-
/*
* This represents this builder process as a whole
*/
@@ -99,6 +91,7 @@ struct sai_builder {
lws_dll2_owner_t sai_plat_owner; /* list of platforms we offer */
lws_dll2_owner_t sai_plat_server_owner; /* servers we connect to */
lws_dll2_owner_t devices_owner; /* sai_serial_t */
+ lws_dll2_owner_t lsp_owner; /* list of lws_spawn_piped */
struct lws_ss_handle *ss_stay;
@@ -128,8 +121,6 @@ struct sai_builder {
const char *host; /* prepended before hostname */
- sai_mirror_instance_t mi;
-
char path[256];
#if defined(__linux__) || defined(__APPLE__)
@@ -221,9 +212,6 @@ rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde);
extern const struct lws_protocols protocol_logproxy, protocol_resproxy;
void *
-thread_repo(void *d);
-
-void *
thread_suspend(void *d);
@@ -244,3 +232,6 @@ int
saib_get_system_cpu(struct sai_builder *b);
int saib_get_cpu_count(void);
+
+int saib_start_mirror(struct sai_nspawn *ns);
+int saib_start_checkout(struct sai_nspawn *ns);
diff --git a/src/builder/b-sai.c b/src/builder/b-sai.c
index faf0680..626afcd 100644
--- a/src/builder/b-sai.c
+++ b/src/builder/b-sai.c
@@ -726,7 +726,6 @@ void sigint_handler(int sig)
void
sai_ns_destroy(struct sai_nspawn *ns)
{
-
lws_dll2_remove(&ns->list);
free(ns);
}
@@ -741,7 +740,6 @@ int main(int argc, const char **argv)
#endif
struct stat sb;
const char *p;
- void *retval;
#if !defined(WIN32)
@@ -986,28 +984,6 @@ int main(int argc, const char **argv)
}
#endif
- pthread_mutex_init(&builder.mi.mut, NULL);
- pthread_cond_init(&builder.mi.cond, NULL);
-
-
- /*
- * Our approach is to split off a thread to do the git remote handling
- * in a serialized way blocking the related threadpool threads until it
- * completes, without blocking the main (lws) event loop thread.
- *
- * It has to be segregated because there is a repo write lock with one
- * owner at a time for remote -> local mirror write operation.
- *
- * local mirror -> build-specific checkout doesn't need the write lock
- * and can happen concurrently at the threadpool threads.
- */
-
- if (pthread_create(&builder.mi.repo_thread, NULL, thread_repo,
- &builder.mi)) {
- lwsl_err("%s: repo thread creation failed\n", __func__);
- return 1;
- }
-
while (!lws_service(builder.context, 0) && !interrupted)
;
@@ -1057,20 +1033,6 @@ bail:
lws_sul_cancel(&builder.sul_idle);
- /*
- * Clean up after the spawn threads
- */
-
- pthread_mutex_lock(&builder.mi.mut);
- builder.mi.finish = 1;
- pthread_cond_broadcast(&builder.mi.cond);
- pthread_mutex_unlock(&builder.mi.mut);
-
- pthread_join(builder.mi.repo_thread, &retval);
-
- 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 f7848ff..e479f18 100644
--- a/src/builder/b-task.c
+++ b/src/builder/b-task.c
@@ -153,17 +153,8 @@ saib_task_destroy(struct sai_nspawn *ns)
return;
}
- if (ns->tp) {
- ns->tp_task = NULL;
- lwsl_notice("%s: calling threadpool_finish\n", __func__);
- lws_threadpool_finish(ns->tp);
- lwsl_notice("%s: calling threadpool_destroy\n", __func__);
- lws_threadpool_destroy(ns->tp);
- ns->tp = NULL;
- }
if (ns->task && ns->task->told_ongoing) {
-
/*
* Account that we're not doing this task any more
*/
@@ -423,13 +414,13 @@ saib_sul_task_cancel(struct lws_sorted_usec_list *sul)
char s[64];
int n;
- if (!ns->lsp)
+ if (!ns->op || !ns->op->lsp)
return;
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->lsp);
+ lws_spawn_piped_kill_child_process(ns->op->lsp);
if (!--ns->term_budget)
return;
@@ -440,8 +431,6 @@ saib_sul_task_cancel(struct lws_sorted_usec_list *sul)
int
saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len)
{
- struct lws_threadpool_create_args tca;
- struct lws_threadpool_task_args tpa;
sai_plat_t *sp = NULL;
struct sai_nspawn *ns;
sai_resource_t *reso;
@@ -529,9 +518,13 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len)
sp->nspawn_owner.head) {
struct sai_nspawn *xns = lws_container_of(d,
struct sai_nspawn, list);
+ char found = 0;
n++;
- if (!xns->task) {
+ if (!xns->task)
+ found = 1;
+
+ if (found) {
ns = xns;
break;
}
@@ -556,13 +549,6 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len)
// lwsl_hexdump_warn(task->build, strlen(task->build));
- /* create a taskqueue just for preparing this specific spawn */
-
- memset(&tpa, 0, sizeof(tpa));
- tca.threads = 1;
- tca.max_queue_depth = 1;
- ns->tp = lws_threadpool_create(builder.context, &tca, "nsp-%s",
- task->uuid);
lws_strncpy(ns->fsm.distro, task->platform,
sizeof(ns->fsm.distro));
@@ -692,21 +678,11 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len)
saib_set_ns_state(ns, NSSTATE_STARTING_MIRROR);
- memset(&tpa, 0, sizeof(tpa));
- tpa.ss = spm->ss;
- tpa.user = ns;
- tpa.name = "nsp";
- tpa.task = saib_mirror_task;
-
ns->user_cancel = 0;
ns->spins = 0;
- lwsl_warn("%s: enqueuing mirror thread\n", __func__);
-
- ns->tp_task = lws_threadpool_enqueue(ns->tp, &tpa, "tptask-%s",
- task->uuid);
- if (!ns->tp_task) {
- lwsl_err("%s: threadpool enqueue failed\n", __func__);
+ if (saib_start_mirror(ns)) {
+ lwsl_err("%s: saib_start_mirror failed\n", __func__);
goto bail;
}
@@ -716,8 +692,6 @@ saib_ws_json_rx_builder(struct sai_plat_server *spm, const void *in, size_t len)
* after that needs to adjust sp->ongoing accordingly
*/
- lwsl_warn("%s: enqueued mirror thread, ns->tp_task %p\n", __func__, ns->tp_task);
-
lwsl_notice("%s: ongoing %d -> %d\n", __func__, sp->ongoing,
sp->ongoing + 1);
sp->ongoing++;
diff --git a/src/common/include/private.h b/src/common/include/private.h
index 6d0e62d..0475e3d 100644
--- a/src/common/include/private.h
+++ b/src/common/include/private.h
@@ -21,6 +21,10 @@
* structs common to builder and server
*/
+#if defined(WIN32)
+#define HAVE_STRUCT_TIMESPEC
+#endif
+
//#include <sai_config_private.h>
#if defined(__linux__)
@@ -33,6 +37,7 @@
struct sai_plat;
struct sai_builder;
+struct saib_opaque_spawn;
typedef enum {
SAIES_WAITING = 0,
@@ -155,13 +160,11 @@ struct sai_nspawn {
lws_dll2_t list; /* sai_plat owner lists sai_nspawns */
struct sai_builder *builder;
struct lws_fsmount fsm;
- struct lws_spawn_piped *lsp;
+ struct saib_opaque_spawn *op;
sai_task_t *task;
lws_dll2_owner_t artifact_owner; /* struct artifact_path */
- struct lws_threadpool *tp;
- struct lws_threadpool_task *tp_task;
lws_sorted_usec_list_t sul_cleaner;
lws_sorted_usec_list_t sul_task_cancel;
@@ -191,6 +194,7 @@ struct sai_nspawn {
uint8_t finished_when_logs_drained:1;
uint8_t state_changed:1;
uint8_t user_cancel:1;
+
};
/*
diff --git a/src/server/s-websrv.c b/src/server/s-websrv.c
index f904009..93d63d6 100644
--- a/src/server/s-websrv.c
+++ b/src/server/s-websrv.c
@@ -587,7 +587,7 @@ websrvss_ws_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
*flags = (som ? LWSSS_FLAG_SOM : 0) | (eom ? LWSSS_FLAG_EOM : 0);
*len = (size_t)used;
- lwsl_warn("%s: srv -> web: len %d flags %d\n", __func__, (int)*len, (int)*flags);
+ // lwsl_warn("%s: srv -> web: len %d flags %d\n", __func__, (int)*len, (int)*flags);
if (m->bltx)
return lws_ss_request_tx(m->ss);
diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c
index d9f3cea..7bd2f01 100644
--- a/src/server/s-ws-builder.c
+++ b/src/server/s-ws-builder.c
@@ -1092,7 +1092,7 @@ sais_ws_json_tx_builder(struct vhd *vhd, struct pss *pss, uint8_t *buf,
}
- if (!pss->issue_task_owner.count)
+ if (!pss->issue_task_owner.count || !pss->issue_task_owner.head)
return 0; /* nothing to send */
/*