[Libguestfs] [nbdkit PATCH 2/2] sh: Implement .thread_model callback

Eric Blake
2019-05-20T12:30:32Z

Wire up .thread_model to the sh plugin, with a change to test-eflags
to demonstrate the effect of a script that requests the tighter
SERIALIZE_CONNECTIONS.  While at it, fix two swapped tests messed up
in afbcd070.

Signed-off-by: Eric Blake <eblake@redhat.com>
---
 plugins/sh/nbdkit-sh-plugin.pod | 15 ++++++++++
 plugins/sh/sh.c                 | 51 +++++++++++++++++++++++++++++++--
 tests/test-eflags.sh            | 49 ++++++++++++++++++++-----------
 3 files changed, 97 insertions(+), 18 deletions(-)

diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index a5285ed..7ba8830 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -180,6 +180,21 @@ ignored.

  /path/to/script config_complete

+=item C<thread_model>
+
+ /path/to/script thread_model
+
+On success this should print the desired thread model of the script,
+one of C<"serialize_connections">,
C<"serialize_all_requests">,
+C<"serialize_requests">, or C<"parallel">.
+
+This method is I<not> required; if omitted, then the plugin will be
+executed under the default sh thread model (currently
+C<"serialize_all_requests">, which implies this callback only
makes a
+difference with an output of C<"serialize_connections">).  If
an error
+occurs, the script should output an error message and exit with status
+C<1>; unrecognized output is ignored.
+
 =item C<open>

  /path/to/script open <readonly>
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index 862be21..aeb0191 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -257,6 +257,54 @@ sh_config_complete (void)
   }
 }

+#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+
+static int
+sh_thread_model (void)
+{
+  const char *args[] = { script, "thread_model", NULL };
+  CLEANUP_FREE char *s = NULL;
+  size_t slen;
+  int r;
+
+  switch (call_read (&s, &slen, args)) {
+  case OK:
+    if (slen > 0 && s[slen-1] == '\n')
+      s[slen-1] = '\0';
+    if (strcasecmp (s, "parallel") == 0)
+      r = NBDKIT_THREAD_MODEL_PARALLEL;
+    else if (strcasecmp (s, "serialize_requests") == 0 ||
+             strcasecmp (s, "serialize-requests") == 0)
+      r = NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS;
+    else if (strcasecmp (s, "serialize_all_requests") == 0 ||
+             strcasecmp (s, "serialize-all-requests") == 0)
+      r = NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS;
+    else if (strcasecmp (s, "serialize_connections") == 0 ||
+             strcasecmp (s, "serialize-connections") == 0)
+      r = NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS;
+    else {
+      nbdkit_debug ("%s: ignoring unrecognized thread model: %s",
+                    script, s);
+      r = THREAD_MODEL;
+    }
+    return r;
+
+  case MISSING:
+    return THREAD_MODEL;
+
+  case ERROR:
+    return -1;
+
+  case RET_FALSE:
+    nbdkit_error ("%s: %s method returned unexpected code (3/false)",
+                  script, "thread_model");
+    errno = EIO;
+    return -1;
+
+  default: abort ();
+  }
+}
+
 static void *
 sh_open (int readonly)
 {
@@ -865,8 +913,6 @@ sh_cache (void *handle, uint32_t count, uint64_t offset,
uint32_t flags)
   "script=<FILENAME>     (required) The shell script to run.\n"
\
   "[other arguments may be used by the plugin that you load]"

-#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
-
 static struct nbdkit_plugin plugin = {
   .name              = "sh",
   .version           = PACKAGE_VERSION,
@@ -878,6 +924,7 @@ static struct nbdkit_plugin plugin = {
   .config            = sh_config,
   .config_complete   = sh_config_complete,
   .config_help       = sh_config_help,
+  .thread_model      = sh_thread_model,

   .open              = sh_open,
   .close             = sh_close,
diff --git a/tests/test-eflags.sh b/tests/test-eflags.sh
index 8158f75..80816ff 100755
--- a/tests/test-eflags.sh
+++ b/tests/test-eflags.sh
@@ -277,22 +277,6 @@ EOF
 # -r
 # can_multi_conn=true

-late_args="serialize=connections" do_nbdkit -r --filter=noparallel
<<'EOF'
-case "$1" in
-     get_size) echo 1M ;;
-     can_multi_conn) exit 0 ;;
-     *) exit 2 ;;
-esac
-EOF
-
-[ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF )) ] ||
-    fail "expected HAS_FLAGS|READ_ONLY|SEND_DF"
-
-#----------------------------------------------------------------------
-# -r
-# --filter=noparallel serialize=connections
-# can_multi_conn=true
-
 do_nbdkit -r <<'EOF'
 case "$1" in
      get_size) echo 1M ;;
@@ -304,6 +288,39 @@ EOF
 [ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF|CAN_MULTI_CONN )) ] ||
     fail "expected HAS_FLAGS|READ_ONLY|SEND_DF|CAN_MULTI_CONN"

+#----------------------------------------------------------------------
+# -r
+# --filter=noparallel serialize=connections
+# can_multi_conn=true
+
+late_args="serialize=connections" do_nbdkit -r --filter=noparallel
<<'EOF'
+case "$1" in
+     get_size) echo 1M ;;
+     can_multi_conn) exit 0 ;;
+     *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF )) ] ||
+    fail "expected HAS_FLAGS|READ_ONLY|SEND_DF"
+
+#----------------------------------------------------------------------
+# -r
+# thread_model=serialize_connections
+# can_multi_conn=true
+
+do_nbdkit -r <<'EOF'
+case "$1" in
+     get_size) echo 1M ;;
+     can_multi_conn) exit 0 ;;
+     thread_model) echo "serialize_connections" ;;
+     *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY|SEND_DF )) ] ||
+    fail "expected HAS_FLAGS|READ_ONLY|SEND_DF"
+
 #----------------------------------------------------------------------
 # -r
 # can_cache=native
--
2.20.1