[PATCH i-g-t 01/15] runner goes brrrrr
Petri Latvala
petri.latvala at intel.com
Mon Mar 1 11:32:44 UTC 2021
---
lib/igt_core.c | 6 +
lib/meson.build | 1 +
lib/runnercomms.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++
lib/runnercomms.h | 210 ++++++++++++++++++++++
runner/executor.c | 134 +++++++++++++-
runner/executor.h | 1 +
6 files changed, 785 insertions(+), 7 deletions(-)
create mode 100644 lib/runnercomms.c
create mode 100644 lib/runnercomms.h
diff --git a/lib/igt_core.c b/lib/igt_core.c
index f9dfaa0d..10b5be27 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -73,6 +73,7 @@
#include "igt_list.h"
#include "igt_device_scan.h"
#include "igt_thread.h"
+#include "runnercomms.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
@@ -860,6 +861,11 @@ static void common_init_env(void)
if (env) {
igt_rc_device = strdup(env);
}
+
+ env = getenv("IGT_RUNNER_SOCKET_FD");
+ if (env) {
+ set_runner_socket(atoi(env));
+ }
}
static int common_init(int *argc, char **argv,
diff --git a/lib/meson.build b/lib/meson.build
index 114eadde..53e9eeaa 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -52,6 +52,7 @@ lib_sources = [
'rendercopy_gen7.c',
'rendercopy_gen8.c',
'rendercopy_gen9.c',
+ 'runnercomms.c',
'sw_sync.c',
'intel_aux_pgtable.c',
'intel_reg_map.c',
diff --git a/lib/runnercomms.c b/lib/runnercomms.c
new file mode 100644
index 00000000..c0716fc7
--- /dev/null
+++ b/lib/runnercomms.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright © 2021 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "runnercomms.h"
+
+static int runner_socket_fd = -1;
+
+/**
+ * set_runner_socket:
+ * @fd: socket connected to runner
+ *
+ * If the passed fd is a valid socket, globally sets it to be the fd
+ * to use to talk to igt_runner.
+ */
+void set_runner_socket(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb))
+ return;
+
+ if (!S_ISSOCK(sb.st_mode))
+ return;
+
+ /*
+ * We only sanity-check that the fd is a socket. We don't
+ * check that it's a datagram socket etc.
+ */
+
+ runner_socket_fd = fd;
+}
+
+/**
+ * runner_connected:
+ *
+ * Returns whether set_runner_socket has been called with a valid
+ * socket fd. Note: Will be true forever after that point. This
+ * function is used to mainly determine whether log strings will be
+ * output to the socket or to stdout/stderr and that cannot be changed
+ * even if the socket is lost midway.
+ */
+bool runner_connected(void)
+{
+ return runner_socket_fd >= 0;
+}
+
+/*
+ * send_to_runner:
+ * @fd: Unix socket connected to igt_runner
+ * @packet: packet to send
+ *
+ * Sends the given communications packet to igt_runner. Calls free()
+ * on the packet, don't reuse it.
+ */
+void send_to_runner(struct runnerpacket *packet)
+{
+ if (runner_connected())
+ write(runner_socket_fd, packet, packet->size);
+ free(packet);
+}
+
+/* If enough data left, copy the data to dst, advance p, reduce size */
+static void read_integer(void* dst, size_t bytes, const char **p, uint32_t *size)
+{
+ if (*size < bytes) {
+ *size = 0;
+ return;
+ }
+
+ memcpy(dst, *p, bytes);
+ *p += bytes;
+ *size -= bytes;
+}
+
+/* If nul-termination can be found, set dststr to point to the cstring, advance p, reduce size */
+static void read_cstring(const char **dststr, const char **p, uint32_t *size)
+{
+ const char *end;
+
+ end = memchr(*p, '\0', *size);
+ if (end == NULL) {
+ *size = 0;
+ return;
+ }
+
+ *dststr = *p;
+ *size -= end - *p + 1;
+ *p = end + 1;
+}
+
+/*
+ * read_runnerpacket:
+ * @packet: runner communications packet to read
+ *
+ * Checks that the internal data of the communications packet is valid
+ * and the contents can safely be inspected without further checking
+ * for out-of-bounds etc. Constructs a runnerpacket_read_helper which
+ * will, for c-style strings, point to various sub-values directly in
+ * the #data field within @packet. Those are valid only as long as
+ * @packet is valid.
+ *
+ * Returns: An appropriately constructed runnerpacket_read_helper. On
+ * data validation errors, the #type of the returned value will be
+ * #PACKETTYPE_INVALID.
+ */
+union runnerpacket_read_helper read_runnerpacket(const struct runnerpacket *packet)
+{
+ union runnerpacket_read_helper ret = {};
+ uint32_t sizeleft;
+ const char *p;
+
+ if (packet->size < sizeof(*packet)) {
+ ret.type = PACKETTYPE_INVALID;
+ return ret;
+ }
+
+ ret.type = packet->type;
+ sizeleft = packet->size - sizeof(*packet);
+ p = packet->data;
+
+ switch (packet->type) {
+ case PACKETTYPE_LOG:
+ read_integer(&ret.log.stream, sizeof(ret.log.stream), &p, &sizeleft);
+ read_integer(&ret.log.level, sizeof(ret.log.level), &p, &sizeleft);
+ read_cstring(&ret.log.text, &p, &sizeleft);
+
+ if (ret.log.text == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_EXEC:
+ read_cstring(&ret.exec.cmdline, &p, &sizeleft);
+
+ if (ret.exec.cmdline == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_EXIT:
+ read_integer(&ret.exit.exitcode, sizeof(ret.exit.exitcode), &p, &sizeleft);
+ read_cstring(&ret.exit.timeused, &p, &sizeleft);
+
+ break;
+ case PACKETTYPE_SUBTEST_START:
+ read_cstring(&ret.subteststart.name, &p, &sizeleft);
+
+ if (ret.subteststart.name == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_SUBTEST_RESULT:
+ read_cstring(&ret.subtestresult.name, &p, &sizeleft);
+ read_cstring(&ret.subtestresult.result, &p, &sizeleft);
+ read_cstring(&ret.subtestresult.timeused, &p, &sizeleft);
+ read_cstring(&ret.subtestresult.reason, &p, &sizeleft);
+
+ if (ret.subtestresult.name == NULL ||
+ ret.subtestresult.result == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_DYNAMIC_SUBTEST_START:
+ read_cstring(&ret.dynamicsubteststart.name, &p, &sizeleft);
+
+ if (ret.dynamicsubteststart.name == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_DYNAMIC_SUBTEST_RESULT:
+ read_cstring(&ret.dynamicsubtestresult.name, &p, &sizeleft);
+ read_cstring(&ret.dynamicsubtestresult.result, &p, &sizeleft);
+ read_cstring(&ret.dynamicsubtestresult.timeused, &p, &sizeleft);
+ read_cstring(&ret.dynamicsubtestresult.reason, &p, &sizeleft);
+
+ if (ret.dynamicsubtestresult.name == NULL ||
+ ret.dynamicsubtestresult.result == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ case PACKETTYPE_VERSIONSTRING:
+ read_cstring(&ret.versionstring.text, &p, &sizeleft);
+
+ if (ret.versionstring.text == NULL)
+ ret.type = PACKETTYPE_INVALID;
+
+ break;
+ default:
+ ret.type = PACKETTYPE_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+struct runnerpacket *runnerpacket_log(uint8_t stream, uint8_t level, const char *text)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ size = sizeof(struct runnerpacket) + sizeof(stream) + sizeof(level) + strlen(text) + 1;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_LOG;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ memcpy(p, &stream, sizeof(stream));
+ p += sizeof(stream);
+
+ memcpy(p, &level, sizeof(level));
+ p += sizeof(level);
+
+ strcpy(p, text);
+ p += strlen(text) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_exec(char **argv)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+ int i;
+
+ size = 0;
+ for (i = 0; argv[i] != NULL; i++)
+ size += strlen(argv[i]) + 1; // followed by a space of \0 so +1 either way for each
+
+ size += sizeof(struct runnerpacket);
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_EXEC;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ for (i = 0; argv[i] != NULL; i++) {
+ strcpy(p, argv[i]);
+ p += strlen(argv[i]);
+ p[0] = ' ';
+ p++;
+ }
+ p[0] = '\0';
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_exit(int32_t exitcode, const char *timeused)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ size = sizeof(struct runnerpacket) + sizeof(exitcode) + strlen(timeused) + 1;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_EXIT;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ memcpy(p, &exitcode, sizeof(exitcode));
+ p += sizeof(exitcode);
+
+ strcpy(p, timeused);
+ p += strlen(timeused) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_subtest_start(const char *name)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ size = sizeof(struct runnerpacket) + strlen(name) + 1;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_SUBTEST_START;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ strcpy(p, name);
+ p += strlen(name) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_subtest_result(const char *name, const char *result,
+ const char *timeused, const char *reason)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ if (reason == NULL)
+ reason = "";
+
+ size = sizeof(struct runnerpacket) + strlen(name) + strlen(result) + strlen(timeused) + strlen(reason) + 4;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_SUBTEST_RESULT;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ strcpy(p, name);
+ p += strlen(name) + 1;
+
+ strcpy(p, result);
+ p += strlen(result) + 1;
+
+ strcpy(p, timeused);
+ p += strlen(timeused) + 1;
+
+ strcpy(p, reason);
+ p += strlen(reason) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_dynamic_subtest_start(const char *name)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ size = sizeof(struct runnerpacket) + strlen(name) + 1;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_DYNAMIC_SUBTEST_START;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ strcpy(p, name);
+ p += strlen(name) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_dynamic_subtest_result(const char *name, const char *result,
+ const char *timeused, const char *reason)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ if (reason == NULL)
+ reason = "";
+
+ size = sizeof(struct runnerpacket) + strlen(name) + strlen(result) + strlen(timeused) + strlen(reason) + 4;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_DYNAMIC_SUBTEST_RESULT;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ strcpy(p, name);
+ p += strlen(name) + 1;
+
+ strcpy(p, result);
+ p += strlen(result) + 1;
+
+ strcpy(p, timeused);
+ p += strlen(timeused) + 1;
+
+ strcpy(p, reason);
+ p += strlen(reason) + 1;
+
+ return packet;
+}
+
+struct runnerpacket *runnerpacket_versionstring(const char *text)
+{
+ struct runnerpacket *packet;
+ uint32_t size;
+ char *p;
+
+ size = sizeof(struct runnerpacket) + strlen(text) + 1;
+ packet = malloc(size);
+
+ packet->size = size;
+ packet->type = PACKETTYPE_VERSIONSTRING;
+ packet->senderpid = getpid();
+ packet->sendertid = gettid();
+
+ p = packet->data;
+
+ strcpy(p, text);
+ p += strlen(text) + 1;
+
+ return packet;
+}
diff --git a/lib/runnercomms.h b/lib/runnercomms.h
new file mode 100644
index 00000000..87d8c771
--- /dev/null
+++ b/lib/runnercomms.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright © 2021 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef IGT_RUNNERCOMMS_H
+#define IGT_RUNNERCOMMS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*
+ * A flat struct that can and will be directly dumped to
+ * disk. Constructed with runnerpacket_<type>() helper functions.
+ */
+struct runnerpacket {
+ uint32_t size; /* Full size of the packet in octets */
+ uint32_t type; /* runnerpacket_type_t, but fixed width */
+ int32_t senderpid;
+ int32_t sendertid;
+
+ char data[];
+};
+
+/*
+ * A helper for reading and parsing runnerpacket structs. Fields will
+ * point directly into the data field of an existing runnerpacket
+ * object. Constructed with read_runnerpacket().
+ *
+ * Some fields can be left as 0 / NULL / some other applicable invalid
+ * value in the case of having older dumps read with binaries that
+ * have extended the data formats.
+ */
+union runnerpacket_read_helper {
+ /*
+ * All other fields must begin with "uint32_t type" so it's a
+ * common initial sequence, safe to read no matter what union
+ * field is active.
+ */
+ uint32_t type;
+
+ struct {
+ uint32_t type;
+
+ uint8_t stream;
+ uint8_t level;
+ const char *text;
+ } log;
+
+ struct {
+ uint32_t type;
+
+ const char *cmdline;
+ } exec;
+
+ struct {
+ uint32_t type;
+
+ int32_t exitcode;
+ const char *timeused;
+ } exit;
+
+ struct {
+ uint32_t type;
+
+ const char *name;
+ } subteststart;
+
+ struct {
+ uint32_t type;
+
+ const char *name;
+ const char *result;
+ const char *timeused;
+ const char *reason;
+ } subtestresult;
+
+ struct {
+ uint32_t type;
+
+ const char *name;
+ } dynamicsubteststart;
+
+ struct {
+ uint32_t type;
+
+ const char *name;
+ const char *result;
+ const char *timeused;
+ const char *reason;
+ } dynamicsubtestresult;
+
+ struct {
+ uint32_t type;
+
+ const char *text;
+ } versionstring;
+};
+
+void set_runner_socket(int fd);
+bool runner_connected(void);
+void send_to_runner(struct runnerpacket *packet);
+
+union runnerpacket_read_helper read_runnerpacket(const struct runnerpacket *packet);
+
+/*
+ * All packet types must document the format of the data[] array. The
+ * notation used is
+ *
+ * Explanation of the packet
+ * type: explanation of values
+ * type2: explanation of values
+ * (etc)
+ *
+ * The type "cstring" can be used to denote that the content is a
+ * nul-terminated string.
+ */
+typedef enum runnerpacket_type {
+ PACKETTYPE_INVALID,
+ /* No data. This type is only used on parse failures and such. */
+
+ PACKETTYPE_LOG,
+ /*
+ * Normal log message.
+ * uint8_t: 1 = stdout, 2 = stderr
+ * uint8_t: Log level
+ * cstring: Log text
+ */
+
+ PACKETTYPE_EXEC,
+ /*
+ * Command line executed. Sent by runner before calling exec().
+ * cstring: command line as one string, argv[0] included, space separated
+ */
+
+ PACKETTYPE_EXIT,
+ /*
+ * Process exit. Written by runner.
+ * int32_t: exitcode
+ * cstring: Time taken by the process from exec to exit, as a floating point value in seconds, as text
+ */
+
+ PACKETTYPE_SUBTEST_START,
+ /*
+ * Subtest begins.
+ * cstring: Name of the subtest
+ */
+
+ PACKETTYPE_SUBTEST_RESULT,
+ /*
+ * Subtest ends. Can appear without a corresponding SUBTEST_START packet.
+ * cstring: Name of the subtest
+ * cstring: Result of the subtest
+ * cstring: Time taken by the subtest, as a floating point value in seconds, as text
+ * cstring: If len > 0, the reason for the subtest result (fail/skip)
+ */
+
+ PACKETTYPE_DYNAMIC_SUBTEST_START,
+ /*
+ * Dynamic subtest begins.
+ * cstring: Name of the dynamic subtest
+ */
+
+ PACKETTYPE_DYNAMIC_SUBTEST_RESULT,
+ /*
+ * Dynamic subtest ends.
+ * cstring: Name of the dynamic subtest
+ * cstring: Result of the dynamic subtest
+ * cstring: Time taken by the dynamic subtest, as a floating point value in seconds, as text
+ * cstring: If len > 0, the reason for the dynamic subtest result (fail/skip)
+ */
+
+ PACKETTYPE_VERSIONSTRING,
+ /*
+ * Version of the running test
+ * cstring: Version string
+ */
+
+} runnerpacket_type_t;
+
+struct runnerpacket *runnerpacket_log(uint8_t stream, uint8_t level, const char *text);
+struct runnerpacket *runnerpacket_exec(char **argv);
+struct runnerpacket *runnerpacket_exit(int32_t exitcode, const char *timeused);
+struct runnerpacket *runnerpacket_subtest_start(const char *name);
+struct runnerpacket *runnerpacket_subtest_result(const char *name, const char *result,
+ const char *timeused, const char *reason);
+struct runnerpacket *runnerpacket_dynamic_subtest_start(const char *name);
+struct runnerpacket *runnerpacket_dynamic_subtest_result(const char *name, const char *result,
+ const char *timeused, const char *reason);
+struct runnerpacket *runnerpacket_versionstring(const char *text);
+
+#endif
diff --git a/runner/executor.c b/runner/executor.c
index 9b582179..a2f29d32 100644
--- a/runner/executor.c
+++ b/runner/executor.c
@@ -27,6 +27,7 @@
#include "igt_taints.h"
#include "executor.h"
#include "output_strings.h"
+#include "runnercomms.h"
#define KMSG_HEADER "[IGT] "
#define KMSG_WARN 4
@@ -445,6 +446,7 @@ static const char *filenames[_F_LAST] = {
[_F_OUT] = "out.txt",
[_F_ERR] = "err.txt",
[_F_DMESG] = "dmesg.txt",
+ [_F_SOCKET] = "comms.txt",
};
static int open_at_end(int dirfd, const char *name)
@@ -476,6 +478,9 @@ bool open_output_files(int dirfd, int *fds, bool write)
for (i = 0; i < _F_LAST; i++) {
if ((fds[i] = openfunc(dirfd, filenames[i])) < 0) {
+ /* Ignore failure to open socket comms */
+ if (i == _F_SOCKET) continue;
+
while (--i >= 0)
close(fds[i]);
return false;
@@ -756,6 +761,11 @@ static int next_kill_signal(int killed)
}
}
+static uint32_t socket_dump_canary(void)
+{
+ return 'I' << 24 | 'G' << 16 | 'T' << 8 | '1';
+}
+
/*
* Returns:
* =0 - Success
@@ -763,7 +773,8 @@ static int next_kill_signal(int killed)
* >0 - Timeout happened, need to recreate from journal
*/
static int monitor_output(pid_t child,
- int outfd, int errfd, int kmsgfd, int sigfd,
+ int outfd, int errfd, int socketfd,
+ int kmsgfd, int sigfd,
int *outputs,
double *time_spent,
struct settings *settings,
@@ -791,6 +802,8 @@ static int monitor_output(pid_t child,
if (errfd > nfds)
nfds = errfd;
+ if (socketfd > nfds)
+ nfds = socketfd;
if (kmsgfd > nfds)
nfds = kmsgfd;
if (sigfd > nfds)
@@ -961,6 +974,87 @@ static int monitor_output(pid_t child,
}
}
+ if (socketfd >= 0 && FD_ISSET(socketfd, &set)) {
+ struct runnerpacket *packet;
+ uint32_t canary = socket_dump_canary();
+
+ time_last_activity = time_now;
+
+ /* Don't need flags, don't need srcaddr */
+ s = read(socketfd, buf, sizeof(buf));
+ if (s <= 0) {
+ if (s < 0) {
+ errf("Error reading from communication socket: %m\n");
+ }
+
+ close(socketfd);
+ socketfd = -1;
+ goto socket_end;
+ }
+
+ packet = (struct runnerpacket *)buf;
+ if (s < sizeof(*packet) || s != packet->size) {
+ errf("Socket communication error: Received %zd bytes, expected %zd\n",
+ s, s >= sizeof(packet->size) ? packet->size : sizeof(*packet));
+ close(socketfd);
+ socketfd = -1;
+ goto socket_end;
+ }
+
+ write(outputs[_F_SOCKET], &canary, sizeof(canary));
+ write(outputs[_F_SOCKET], buf, s);
+ disk_usage += s;
+ if (settings->sync)
+ fdatasync(outputs[_F_SOCKET]);
+
+ if (settings->log_level >= LOG_LEVEL_VERBOSE) {
+ union runnerpacket_read_helper helper = {};
+ const char *time;
+
+ if (packet->type == PACKETTYPE_SUBTEST_START ||
+ packet->type == PACKETTYPE_SUBTEST_RESULT ||
+ packet->type == PACKETTYPE_DYNAMIC_SUBTEST_START ||
+ packet->type == PACKETTYPE_DYNAMIC_SUBTEST_RESULT)
+ helper = read_runnerpacket(packet);
+
+ switch (helper.type) {
+ case PACKETTYPE_SUBTEST_START:
+ if (helper.subteststart.name)
+ outf("Starting subtest: %s\n", helper.subteststart.name);
+ break;
+ case PACKETTYPE_SUBTEST_RESULT:
+ if (helper.subtestresult.name && helper.subtestresult.result) {
+ time = "<unknown>";
+ if (helper.subtestresult.timeused)
+ time = helper.subtestresult.timeused;
+ outf("Subtest %s: %s (%ss)\n",
+ helper.subtestresult.name,
+ helper.subtestresult.result,
+ time);
+ }
+ break;
+ case PACKETTYPE_DYNAMIC_SUBTEST_START:
+ if (helper.dynamicsubteststart.name)
+ outf("Starting dynamic subtest: %s\n", helper.dynamicsubteststart.name);
+ break;
+ case PACKETTYPE_DYNAMIC_SUBTEST_RESULT:
+ if (helper.dynamicsubtestresult.name && helper.dynamicsubtestresult.result) {
+ time = "<unknown>";
+ if (helper.dynamicsubtestresult.timeused)
+ time = helper.dynamicsubtestresult.timeused;
+ outf("Dynamic subtest %s: %s (%ss)\n",
+ helper.dynamicsubtestresult.name,
+ helper.dynamicsubtestresult.result,
+ time);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ socket_end:
+
if (kmsgfd >= 0 && FD_ISSET(kmsgfd, &set)) {
long dmesgwritten;
@@ -1151,6 +1245,7 @@ static int monitor_output(pid_t child,
free(outbuf);
close(outfd);
close(errfd);
+ close(socketfd);
close(kmsgfd);
return -1;
}
@@ -1174,6 +1269,7 @@ static int monitor_output(pid_t child,
free(outbuf);
close(outfd);
close(errfd);
+ close(socketfd);
close(kmsgfd);
if (aborting)
@@ -1183,7 +1279,7 @@ static int monitor_output(pid_t child,
}
static void __attribute__((noreturn))
-execute_test_process(int outfd, int errfd,
+execute_test_process(int outfd, int errfd, int socketfd,
struct settings *settings,
struct job_list_entry *entry)
{
@@ -1235,6 +1331,13 @@ execute_test_process(int outfd, int errfd,
}
}
+ if (socketfd >= 0) {
+ struct runnerpacket *packet;
+
+ packet = runnerpacket_exec(argv);
+ write(socketfd, packet, packet->size);
+ }
+
execv(argv[0], argv);
fprintf(stderr, "Cannot execute %s\n", argv[0]);
exit(IGT_EXIT_INVALID);
@@ -1316,7 +1419,8 @@ static int execute_next_entry(struct execute_state *state,
int kmsgfd;
int outpipe[2] = { -1, -1 };
int errpipe[2] = { -1, -1 };
- int outfd, errfd;
+ int socket[2] = { -1, -1 };
+ int outfd, errfd, socketfd;
char name[32];
pid_t child;
int result;
@@ -1346,6 +1450,12 @@ static int execute_next_entry(struct execute_state *state,
goto out_pipe;
}
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socket)) {
+ errf("Error creating sockets: %m\n");
+ result = -1;
+ goto out_pipe;
+ }
+
if ((kmsgfd = open("/dev/kmsg", O_RDONLY | O_CLOEXEC | O_NONBLOCK)) < 0) {
errf("Warning: Cannot open /dev/kmsg\n");
} else {
@@ -1386,27 +1496,37 @@ static int execute_next_entry(struct execute_state *state,
result = -1;
goto out_kmsgfd;
} else if (child == 0) {
+ char *envstring = NULL;
+
outfd = outpipe[1];
errfd = errpipe[1];
+ socketfd = socket[1];
close(outpipe[0]);
close(errpipe[0]);
+ close(socket[0]);
sigprocmask(SIG_UNBLOCK, sigmask, NULL);
+ if (socketfd >= 0 && asprintf(&envstring, "%d", socketfd) == 1)
+ setenv("IGT_RUNNER_SOCKET_FD", envstring, 1);
setenv("IGT_SENTINEL_ON_STDERR", "1", 1);
- execute_test_process(outfd, errfd, settings, entry);
+ execute_test_process(outfd, errfd, socketfd, settings, entry);
/* unreachable */
}
outfd = outpipe[0];
errfd = errpipe[0];
+ socketfd = socket[0];
close(outpipe[1]);
close(errpipe[1]);
- outpipe[1] = errpipe[1] = -1;
+ close(socket[1]);
+ outpipe[1] = errpipe[1] = socket[1] = -1;
- result = monitor_output(child, outfd, errfd, kmsgfd, sigfd,
- outputs, time_spent, settings, abortreason);
+ result = monitor_output(child, outfd, errfd, socketfd,
+ kmsgfd, sigfd,
+ outputs, time_spent, settings,
+ abortreason);
out_kmsgfd:
close(kmsgfd);
diff --git a/runner/executor.h b/runner/executor.h
index 6c83e649..31f4ac16 100644
--- a/runner/executor.h
+++ b/runner/executor.h
@@ -22,6 +22,7 @@ enum {
_F_OUT,
_F_ERR,
_F_DMESG,
+ _F_SOCKET,
_F_LAST,
};
--
2.29.2
More information about the Intel-gfx-trybot
mailing list