chiark / gitweb /
@@@ fltfmt mess
[mLib] / test / tvec-remote.c
index 3087d1bf77f1b3e36d4458d98f769475f07c2077..bcbfad0d3af27b380417b1c90621a55633b69916 100644 (file)
 #include "lbuf.h"
 #include "mdup.h"
 #include "quis.h"
+
 #include "tvec.h"
+#include "tvec-adhoc.h"
+#include "tvec-bench.h"
+#include "tvec-output.h"
+#include "tvec-remote.h"
+#include "tvec-types.h"
 
 /*----- Preliminaries -----------------------------------------------------*/
 
@@ -111,7 +117,8 @@ static void close_comms(struct tvec_remotecomms *rc)
 
 /* --- @release_comms@ --- *
  *
- * Arguments:  @struct tvec_remotecomms *rc@ = communication state
+ * Arguments:  @struct tvec_state *tv@ = test-vector state
+ *             @struct tvec_remotecomms *rc@ = communication state
  *
  * Returns:    ---
  *
@@ -120,8 +127,8 @@ static void close_comms(struct tvec_remotecomms *rc)
  *             @close_comms@.
  */
 
-static void release_comms(struct tvec_remotecomms *rc)
-  { close_comms(rc); xfree(rc->bin); DBDESTROY(&rc->bout); }
+static void release_comms(struct tvec_state *tv, struct tvec_remotecomms *rc)
+  { close_comms(rc); x_free(tv->a, rc->bin); DBDESTROY(&rc->bout); }
 
 /* --- @setup_comms@ --- *
  *
@@ -379,7 +386,7 @@ static int receive_buffered(struct tvec_state *tv,
   if (rc->binlen - rc->binoff >= want) return (RECV_OK);
 
   /* If the buffer is too small then we must grow it. */
-  GROWBUF_EXTEND(&arena_stdlib, rc->bin, rc->binsz, want, RECVBUFSZ, 1);
+  GROWBUF_EXTEND(size_t, tv->a, rc->bin, rc->binsz, want, RECVBUFSZ, 1);
 
   /* Shunt the unused existing material to the start of the buffer. */
   memmove(rc->bin, rc->bin + rc->binoff, rc->binlen - rc->binoff);
@@ -493,9 +500,9 @@ static int remote_recv(struct tvec_state *tv, struct tvec_remotecomms *rc,
 #define TVPK_FAIL      0x0108u         /* <-- flag: u8, detail: str16 */
 #define TVPK_DUMPREG   0x010au         /* <-- ri: u16; disp: u16;
                                         *     flag: u8, rv: value */
-#define TVPK_BBENCH    0x010cu         /* <-- ident: str32; unit: u16 */
-#define TVPK_EBENCH    0x010eu         /* <-- ident: str32; unit: u16;
-                                        *     flags: u16; n, t, cy: f64 */
+#define TVPK_BBENCH    0x010cu         /* <-- unit: u16, ident: regs */
+#define TVPK_EBENCH    0x010eu         /* <-- unit: u16; flags: u16;
+                                        *     n, t, cy: f64 */
 
 /*----- Server ------------------------------------------------------------*/
 
@@ -577,7 +584,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
   unsigned i;
   buf b;
   dstr d = DSTR_INIT;
-  const struct tvec_test *t;
+  const struct tvec_test *t, *const *tt;
   void *p; size_t sz;
   const struct tvec_env *env = 0;
   const struct tvec_vardef *vd = 0; void *varctx;
@@ -645,9 +652,11 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        if (BLEFT(&b)) goto bad;
 
        /* Find the group given its name. */
-       for (t = srvtv.cfg.tests; t->name; t++)
+       for (tt = srvtv.cfg.tests; *tt; tt++) {
+         t = *tt;
          if (strlen(t->name) == sz && MEMCMP(t->name, ==, p, sz))
            goto found_group;
+       }
        rc = ioerr(&srvtv, &srvrc, "unknown test group `%.*s'",
                   (int)sz, (char *)p);
        goto end;
@@ -658,7 +667,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        if (env && env->setup == tvec_remotesetup)
          env = ((struct tvec_remoteenv *)env)->r.env;
        if (!env || !env->ctxsz) ctx = 0;
-       else ctx = xmalloc(env->ctxsz);
+       else ctx = x_alloc(srvtv.a, env->ctxsz);
        if (env && env->setup) env->setup(&srvtv, env, 0, ctx);
 
        /* Initialize the registers. */
@@ -707,7 +716,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
              if (vd->regsz <= sizeof(rbuf))
                r = &rbuf;
              else {
-               GROWBUF_REPLACE(&arena_stdlib, r_alloc, rsz, vd->regsz,
+               GROWBUF_REPLACE(size_t, srvtv.a, r_alloc, rsz, vd->regsz,
                                8*sizeof(void *), 1);
                r = r_alloc;
              }
@@ -731,7 +740,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
 
              /* Parse the packet payload. */
              if (tvec_deserialize(srvtv.in, &b, srvtv.test->regs,
-                                  srvtv.cfg.nreg, srvtv.cfg.regsz))
+                                  0, 0, srvtv.cfg.nreg, srvtv.cfg.regsz))
                goto bad;
              if (BLEFT(&b)) goto bad;
 
@@ -794,7 +803,7 @@ int tvec_remoteserver(int infd, int outfd, const struct tvec_config *config)
        /* Tear down the environment and release other resources. */
        if (env && env->teardown) env->teardown(&srvtv, ctx);
        tvec_releaseregs(&srvtv);
-       xfree(ctx); srvtv.test = 0; env = 0; ctx = 0;
+       x_free(srvtv.a, ctx); srvtv.test = 0; env = 0; ctx = 0;
 
        /* Report completion. */
        QUEUEPK(&srvtv, &srvrc, QF_FORCE, TVPK_EGROUP | TVPF_ACK);
@@ -812,9 +821,9 @@ end:
   /* Clean up and return. */
   if (env && env->teardown) env->teardown(&srvtv, ctx);
   if (vd) vd->def.ty->release(&r->v, &vd->def);
-  xfree(ctx); xfree(r_alloc);
+  x_free(srvtv.a, ctx); x_free(srvtv.a, r_alloc);
   if (srvtv.test) tvec_releaseregs(&srvtv);
-  release_comms(&srvrc); tvec_end(&srvtv);
+  release_comms(&srvtv, &srvrc); tvec_end(&srvtv);
   return (rc ? 2 : 0);
 
 bad:
@@ -1008,11 +1017,41 @@ found:
 static void remote_etest(struct tvec_output *o, unsigned outcome)
   { ; }
 
+/* --- @remote_report@ --- *
+ *
+ * Arguments:  @struct tvec_output *o@ = output sink (ignored)
+ *             @unsigned level@ = message level (@TVLEV_...@)
+ *             @const char *msg@, @va_list *ap@ = format string and
+ *                     arguments
+ *
+ * Returns:    ---
+ *
+ * Use:                Report a message to the user.
+ *
+ *             The remote driver sends a @TVPK_REPORT@ packet to its
+ *             client.  If its attempt to transmit the packet fails, then
+ *             the message is written to the standard error stream instead,
+ *             in the hope that this will help it be noticed.
+ */
+
+static void remote_report(struct tvec_output *o, unsigned level,
+                         const char *msg, va_list *ap)
+{
+  QUEUEPK(&srvtv, &srvrc, 0, TVPK_REPORT) {
+    dbuf_putu16l(&srvrc.bout, level);
+    dbuf_vputstrf16l(&srvrc.bout, msg, ap);
+  } else {
+    fprintf(stderr, "%s %s: ", QUIS, tvec_strlevel(level));
+    vfprintf(stderr, msg, *ap);
+    fputc('\n', stderr);
+  }
+}
+
 /* --- @remote_bbench@ --- *
  *
  * Arguments:  @struct tvec_output *o@ = output sink (ignored)
- *             @const char *ident@ = identifying register values
- *             @unsigned unit@ = measurement unit (@TVBU_...@)
+ *             @const char *desc@ = adhoc test description, must be null
+ *             @unsigned unit@ = measurement unit (@BTU_...@)
  *
  * Returns:    ---
  *
@@ -1022,34 +1061,36 @@ static void remote_etest(struct tvec_output *o, unsigned outcome)
  */
 
 static void remote_bbench(struct tvec_output *o,
-                         const char *ident, unsigned unit)
+                         const char *desc, unsigned unit)
 {
+  assert(!desc);
   QUEUEPK(&srvtv, &srvrc, 0, TVPK_BBENCH) {
-    dbuf_putstr32l(&srvrc.bout, ident);
     dbuf_putu16l(&srvrc.bout, unit);
+    tvec_serialize(srvtv.in, DBUF_BUF(&srvrc.bout), srvtv.test->regs,
+                  TVRF_ID, TVRF_ID, srvtv.cfg.nreg, srvtv.cfg.regsz);
   }
 }
 
 /* --- @remote_ebench@ --- *
  *
  * Arguments:  @struct tvec_output *o@ = output sink (ignored)
- *             @const char *ident@ = identifying register values
- *             @unsigned unit@ = measurement unit (@TVBU_...@)
- *             @const struct bench_timing *tm@ = measurement
+ *             @const char *desc@ = adhoc test description, must be null
+ *             @unsigned unit@ = measurement unit (@BTU_...@)
+ *             @const struct bench_timing *t@ = measurement
  *
  * Returns:    ---
  *
- * Use:                Report a benchmark's results
+ * Use:                Report a benchmark's results.
  *
  *             The remote driver sends a @TVPK_EBENCH@ packet to its client.
  */
 
 static void remote_ebench(struct tvec_output *o,
-                         const char *ident, unsigned unit,
+                         const char *desc, unsigned unit,
                          const struct bench_timing *t)
 {
+  assert(!desc);
   QUEUEPK(&srvtv, &srvrc, 0, TVPK_EBENCH) {
-    dbuf_putstr32l(&srvrc.bout, ident);
     dbuf_putu16l(&srvrc.bout, unit);
     if (!t || !(t->f&BTF_ANY))
       dbuf_putu16l(&srvrc.bout, 0);
@@ -1062,34 +1103,21 @@ static void remote_ebench(struct tvec_output *o,
   }
 }
 
-/* --- @remote_report@ --- *
+static const struct tvec_benchoutops remote_benchops =
+  { remote_bbench, remote_ebench };
+
+/* --- @remote_extend@ --- *
  *
  * Arguments:  @struct tvec_output *o@ = output sink (ignored)
- *             @unsigned level@ = message level (@TVLEV_...@)
- *             @const char *msg@, @va_list *ap@ = format string and
- *                     arguments
- *
- * Returns:    ---
- *
- * Use:                Report a message to the user.
+ *             @const char *name@ = extension name
  *
- *             The remote driver sends a @TVPK_REPORT@ packet to its
- *             client.  If its attempt to transmit the packet fails, then
- *             the message is written to the standard error stream instead,
- *             in the hope that this will help it be noticed.
+ * Returns:    A pointer to the extension implementation, or null.
  */
 
-static void remote_report(struct tvec_output *o, unsigned level,
-                         const char *msg, va_list *ap)
+static const void *remote_extend(struct tvec_output *o, const char *name)
 {
-  QUEUEPK(&srvtv, &srvrc, 0, TVPK_REPORT) {
-    dbuf_putu16l(&srvrc.bout, level);
-    dbuf_vputstrf16l(&srvrc.bout, msg, ap);
-  } else {
-    fprintf(stderr, "%s %s: ", QUIS, tvec_strlevel(level));
-    vfprintf(stderr, msg, *ap);
-    fputc('\n', stderr);
-  }
+  if (STRCMP(name, ==, TVEC_BENCHOUTEXT)) return (&remote_benchops);
+  else return (0);
 }
 
 /* --- @remote_destroy@ --- *
@@ -1110,9 +1138,7 @@ static const struct tvec_outops remote_ops = {
   remote_bsession, remote_esession,
   remote_bgroup, remote_skipgroup, remote_egroup,
   remote_btest, remote_skip, remote_fail, remote_dumpreg, remote_etest,
-  remote_bbench, remote_ebench,
-  remote_report,
-  remote_destroy
+  remote_report, remote_extend, remote_destroy
 };
 
 /*----- Pseudoregister definitions ----------------------------------------*/
@@ -1354,13 +1380,15 @@ enum {
 static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
                          unsigned f, uint16 end, buf *b_out)
 {
-  struct tvec_output *o = tv->output;
+  struct tvec_output *o;
   uint16 pk, u, v;
   const char *p; size_t n;
   dstr d = DSTR_INIT;
   buf *b = b_out;
   const struct tvec_regdef *rd;
   struct bench_timing bt;
+  const struct tvec_benchoutops *bo;
+  struct tvec_fallbackoutput fo;
   struct tvec_reg *reg = 0; size_t rsz = 0;
   unsigned i;
   int rc;
@@ -1476,7 +1504,7 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
        if (!rc)
          tvec_dumpreg(tv, v, 0, rd);
        else {
-         GROWBUF_REPLACE(&arena_stdlib, reg, rsz, tv->cfg.regsz,
+         GROWBUF_REPLACE(size_t, tv->a, reg, rsz, tv->cfg.regsz,
                          8*sizeof(void *), 1);
          rd->ty->init(&reg->v, rd);
          rc = rd->ty->frombuf(b, &reg->v, rd);
@@ -1490,24 +1518,26 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
       case TVPK_BBENCH:
        /* A report that we're starting a benchmark.  Pass this along. */
 
-       p = buf_getmem32l(b, &n); if (!p) goto bad;
        if (buf_getu16l(b, &u)) goto bad;
+       if (tvec_deserialize(tv->in, b, tv->test->regs,
+                            TVRF_ID, TVRF_ID, tv->cfg.nreg, tv->cfg.regsz))
+         goto bad;
        if (BLEFT(b)) goto bad;
-       if (u >= TVBU_LIMIT) {
+       if (u >= BTU_LIMIT) {
          rc = ioerr(tv, &r->rc, "unit code %u out of range", u);
          goto end;
        }
 
-       DRESET(&d); DPUTM(&d, p, n); DPUTZ(&d);
-       o->ops->bbench(o, d.buf, u);
+       bo = tvec_outputext(tv, &o, &fo,
+                           TVEC_BENCHOUTEXT, &tvec_benchoutputfallback);
+       bo->bbench(o, 0, u);
        break;
 
       case TVPK_EBENCH:
        /* A report that a benchmark completed.  Pass this along. */
 
-       p = buf_getmem32l(b, &n); if (!p) goto bad;
        if (buf_getu16l(b, &u) || buf_getu16l(b, &v)) goto bad;
-       if (u >= TVBU_LIMIT) {
+       if (u >= BTU_LIMIT) {
          rc = ioerr(tv, &r->rc, "unit code %u out of range", u);
          goto end;
        }
@@ -1515,9 +1545,11 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
        if ((v&BTF_TIMEOK) && buf_getf64l(b, &bt.t)) goto bad;
        if ((v&BTF_CYOK) && buf_getf64l(b, &bt.cy)) goto bad;
        if (BLEFT(b)) goto bad;
+       bt.f = v;
 
-       DRESET(&d); DPUTM(&d, p, n); DPUTZ(&d);
-       o->ops->ebench(o, d.buf, u, v&BTF_ANY ? &bt : 0);
+       bo = tvec_outputext(tv, &o, &fo,
+                           TVEC_BENCHOUTEXT, &tvec_benchoutputfallback);
+       bo->ebench(o, 0, u, v&BTF_ANY ? &bt : 0);
        break;
 
       default:
@@ -1530,7 +1562,7 @@ static int handle_packets(struct tvec_state *tv, struct tvec_remotectx *r,
 
 end:
   DDESTROY(&d);
-  xfree(reg);
+  x_free(tv->a, reg);
   return (rc);
 bad:
   rc = malformed(tv, &r->rc); goto end;
@@ -1707,12 +1739,27 @@ end:
  */
 
 #define DCF_KILL 0x0100u
+#define DCF_QUITOK 0200u
 static void disconnect_remote(struct tvec_state *tv,
                              struct tvec_remotectx *r, unsigned f)
 {
+  union tvec_regval rv;
+  dstr d = DSTR_INIT;
+
   if (r->kid > 0 && (f&DCF_KILL)) kill(r->kid, SIGTERM);
   close_comms(&r->rc);
-  drain_errfd(tv, r, f | ERF_CLOSE); reap_kid(tv, r);
+  drain_errfd(tv, r, f | ERF_CLOSE);
+  if (r->kid >= 0) {
+    reap_kid(tv, r);
+    if (!(f&ERF_SILENT) &&
+       (!(f&DCF_QUITOK) || (r->exit != TVXST_EXIT &&
+                            r->exit != TVXST_DISCONN))) {
+      rv.u = r->exit;
+      tvty_flags.dump(&rv, &exit_var.def, TVSF_COMPACT, &dstr_printops, &d);
+      tvec_error(tv, "remote connection closed with status %s", d.buf);
+    }
+  }
+  dstr_destroy(&d);
 }
 
 /* --- @connect_remote@ --- *
@@ -1892,7 +1939,7 @@ void tvec_remotesetup(struct tvec_state *tv, const struct tvec_env *env,
   if (connect_remote(tv, r))
     tvec_skipgroup(tv, "failed to connect to test backend");
   reset_vars(r);
-  if (subenv && subenv->ctxsz) r->subctx = xmalloc(subenv->ctxsz);
+  if (subenv && subenv->ctxsz) r->subctx = x_alloc(tv->a, subenv->ctxsz);
   else r->subctx = 0;
   if (subenv && subenv->setup) subenv->setup(tv, subenv, r, r->subctx);
 }
@@ -2046,8 +2093,8 @@ void tvec_remoterun(struct tvec_state *tv, tvec_testfn *fn, void *ctx)
 
   /* Send the command to the server and handle output. */
   QUEUEPK(tv, &r->rc, QF_FORCE, TVPK_TEST)
-    tvec_serialize(tv->in, DBUF_BUF(&r->rc.bout),
-                  tv->test->regs, tv->cfg.nreg, tv->cfg.regsz);
+    tvec_serialize(tv->in, DBUF_BUF(&r->rc.bout), tv->test->regs,
+                  0, 0, tv->cfg.nreg, tv->cfg.regsz);
   else { goto fail; }
   rc = handle_packets(tv, r, RCVF_ALLOWEOF, TVPK_TEST | TVPF_ACK, &b);
 
@@ -2165,13 +2212,13 @@ void tvec_remoteteardown(struct tvec_state *tv, void *ctx)
   buf b;
 
   if (subenv && subenv->teardown) subenv->teardown(tv, r->subctx);
-  xfree(r->subctx);
+  x_free(tv->a, r->subctx);
   if (r->rc.outfd >= 0) {
     QUEUEPK(tv, &r->rc, QF_FORCE, TVPK_EGROUP);
     if (!handle_packets(tv, r, RCVF_ALLOWEOF, TVPK_EGROUP | TVPF_ACK, &b))
       if (BLEFT(&b)) malformed(tv, &r->rc);
   }
-  disconnect_remote(tv, r, 0); release_comms(&r->rc);
+  disconnect_remote(tv, r, DCF_QUITOK); release_comms(tv, &r->rc);
   DDESTROY(&r->prgwant); DDESTROY(&r->progress);
 }