[{"id":2125,"web_url":"https://patchwork.libcamera.org/comment/2125/","msgid":"<a7d3df55-e78f-1b2f-aaae-5cc21a462fcf@ideasonboard.com>","date":"2019-07-02T14:25:53","subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Niklas, / Laurent,\n\nVery minor thing spotted:\n\nOn 02/07/2019 00:23, Laurent Pinchart wrote:\n> From: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> \n> Test that the IPC supports sending data and file descriptors over the\n> IPC medium. To be able to execute the test two parts are needed, one\n> to drive the test and act as the libcamera (master) and a one to act as\n> the IPA (slave).\n> \n> The master drives the testing posting requests to the slave to process\n> and sometimes respond to. A few different tests are performed.\n> \n> - Master sends an array to the slave which responds with a reversed copy\n>   of the array. The master verifies that a reversed array is returned.\n> \n> - Master ties to sends an empty message making sure that the send call\n>   fails.\n> \n> - Master sends a list of file descriptors and ask the slave to calculate\n>   and respond with the sum of the size of the files. The master verifies\n>   that the calculated size is correct.\n> \n> - Master sends a pre-computed size and a list of file descriptors and\n>   asks the slave to verify that the pre-computed size matches the sum of\n>   the size of the file descriptors.\n> \n> - Master sends two file descriptors and asks the salve to join the file\n>   contents in a new file and respond with its file descriptor. The\n>   master then verifies that the content of the returned file descriptor\n>   matches the order of the original two files.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n> Changes since v3:\n> \n> - Use O_TMPFILE instead of shm_open()\n> - Miscellaneous typo and small fixes\n> ---\n>  test/ipc/meson.build    |  12 +\n>  test/ipc/unixsocket.cpp | 502 ++++++++++++++++++++++++++++++++++++++++\n>  test/meson.build        |   1 +\n>  3 files changed, 515 insertions(+)\n>  create mode 100644 test/ipc/meson.build\n>  create mode 100644 test/ipc/unixsocket.cpp\n> \n> diff --git a/test/ipc/meson.build b/test/ipc/meson.build\n> new file mode 100644\n> index 000000000000..ca8375f35df9\n> --- /dev/null\n> +++ b/test/ipc/meson.build\n> @@ -0,0 +1,12 @@\n> +ipc_tests = [\n> +    [ 'unixsocket',  'unixsocket.cpp' ],\n> +]\n> +\n> +foreach t : ipc_tests\n> +    exe = executable(t[0], t[1],\n> +                     dependencies : libcamera_dep,\n> +                     link_with : test_libraries,\n> +                     include_directories : test_includes_internal)\n> +\n> +    test(t[0], exe, suite : 'ipc', is_parallel : false)\n\nAren't IPC tests self contained, and thus suitable for is_parallel :\ntrue?  (which I think is the default if is_parallel is omitted).\n\n\n--\nKieran\n\n\n> +endforeach\n> diff --git a/test/ipc/unixsocket.cpp b/test/ipc/unixsocket.cpp\n> new file mode 100644\n> index 000000000000..eeef64842a75\n> --- /dev/null\n> +++ b/test/ipc/unixsocket.cpp\n> @@ -0,0 +1,502 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * unixsocket.cpp - Unix socket IPC test\n> + */\n> +\n> +#include <algorithm>\n> +#include <fcntl.h>\n> +#include <iostream>\n> +#include <stdlib.h>\n> +#include <string.h>\n> +#include <sys/stat.h>\n> +#include <sys/types.h>\n> +#include <sys/wait.h>\n> +#include <unistd.h>\n> +\n> +#include <libcamera/camera_manager.h>\n> +#include <libcamera/event_dispatcher.h>\n> +#include <libcamera/timer.h>\n> +\n> +#include \"ipc_unixsocket.h\"\n> +#include \"test.h\"\n> +#include \"utils.h\"\n> +\n> +#define CMD_CLOSE\t0\n> +#define CMD_REVERSE\t1\n> +#define CMD_LEN_CALC\t2\n> +#define CMD_LEN_CMP\t3\n> +#define CMD_JOIN\t4\n> +\n> +using namespace std;\n> +using namespace libcamera;\n> +\n> +int calculateLength(int fd)\n> +{\n> +\tlseek(fd, 0, 0);\n> +\tint size = lseek(fd, 0, SEEK_END);\n> +\tlseek(fd, 0, 0);\n> +\n> +\treturn size;\n> +}\n> +\n> +class UnixSocketTestSlave\n> +{\n> +public:\n> +\tUnixSocketTestSlave()\n> +\t\t: exitCode_(EXIT_FAILURE), exit_(false)\n> +\t{\n> +\t\tdispatcher_ = CameraManager::instance()->eventDispatcher();\n> +\t\tipc_.readyRead.connect(this, &UnixSocketTestSlave::readyRead);\n> +\t}\n> +\n> +\tint run(int fd)\n> +\t{\n> +\t\tif (ipc_.bind(fd)) {\n> +\t\t\tcerr << \"Failed to connect to IPC channel\" << endl;\n> +\t\t\treturn EXIT_FAILURE;\n> +\t\t}\n> +\n> +\t\twhile (!exit_)\n> +\t\t\tdispatcher_->processEvents();\n> +\n> +\t\tipc_.close();\n> +\n> +\t\treturn exitCode_;\n> +\t}\n> +\n> +private:\n> +\tvoid readyRead(IPCUnixSocket *ipc)\n> +\t{\n> +\t\tIPCUnixSocket::Payload message, response;\n> +\t\tint ret;\n> +\n> +\t\tret = ipc->receive(&message);\n> +\t\tif (ret) {\n> +\t\t\tcerr << \"Receive message failed: \" << ret << endl;\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tconst uint8_t cmd = message.data[0];\n> +\n> +\t\tswitch (cmd) {\n> +\t\tcase CMD_CLOSE:\n> +\t\t\tstop(0);\n> +\t\t\tbreak;\n> +\n> +\t\tcase CMD_REVERSE: {\n> +\t\t\tresponse.data = message.data;\n> +\t\t\tstd::reverse(response.data.begin() + 1, response.data.end());\n> +\n> +\t\t\tret = ipc_.send(response);\n> +\t\t\tif (ret < 0) {\n> +\t\t\t\tcerr << \"Reverse failed\" << endl;\n> +\t\t\t\tstop(ret);\n> +\t\t\t}\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\tcase CMD_LEN_CALC: {\n> +\t\t\tint size = 0;\n> +\t\t\tfor (int fd : message.fds)\n> +\t\t\t\tsize += calculateLength(fd);\n> +\n> +\t\t\tresponse.data.resize(1 + sizeof(size));\n> +\t\t\tresponse.data[0] = cmd;\n> +\t\t\tmemcpy(response.data.data() + 1, &size, sizeof(size));\n> +\n> +\t\t\tret = ipc_.send(response);\n> +\t\t\tif (ret < 0) {\n> +\t\t\t\tcerr << \"Calc failed\" << endl;\n> +\t\t\t\tstop(ret);\n> +\t\t\t}\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\tcase CMD_LEN_CMP: {\n> +\t\t\tint size = 0;\n> +\t\t\tfor (int fd : message.fds)\n> +\t\t\t\tsize += calculateLength(fd);\n> +\n> +\t\t\tint cmp;\n> +\t\t\tmemcpy(&cmp, message.data.data() + 1, sizeof(cmp));\n> +\n> +\t\t\tif (cmp != size) {\n> +\t\t\t\tcerr << \"Compare failed\" << endl;\n> +\t\t\t\tstop(-ERANGE);\n> +\t\t\t}\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\tcase CMD_JOIN: {\n> +\t\t\tint outfd = open(\"/tmp\", O_TMPFILE | O_RDWR,\n> +\t\t\t\t\t S_IRUSR | S_IWUSR);\n> +\t\t\tif (outfd < 0) {\n> +\t\t\t\tcerr << \"Create out file failed\" << endl;\n> +\t\t\t\tstop(outfd);\n> +\t\t\t\treturn;\n> +\t\t\t}\n> +\n> +\t\t\tfor (int fd : message.fds) {\n> +\t\t\t\twhile (true) {\n> +\t\t\t\t\tchar buf[32];\n> +\t\t\t\t\tssize_t num = read(fd, &buf, sizeof(buf));\n> +\n> +\t\t\t\t\tif (num < 0) {\n> +\t\t\t\t\t\tcerr << \"Read failed\" << endl;\n> +\t\t\t\t\t\tstop(-EIO);\n> +\t\t\t\t\t\treturn;\n> +\t\t\t\t\t} else if (!num)\n> +\t\t\t\t\t\tbreak;\n> +\n> +\t\t\t\t\tif (write(outfd, buf, num) < 0) {\n> +\t\t\t\t\t\tcerr << \"Write failed\" << endl;\n> +\t\t\t\t\t\tstop(-EIO);\n> +\t\t\t\t\t\treturn;\n> +\t\t\t\t\t}\n> +\t\t\t\t}\n> +\n> +\t\t\t\tclose(fd);\n> +\t\t\t}\n> +\n> +\t\t\tlseek(outfd, 0, 0);\n> +\t\t\tresponse.data.push_back(CMD_JOIN);\n> +\t\t\tresponse.fds.push_back(outfd);\n> +\n> +\t\t\tret = ipc_.send(response);\n> +\t\t\tif (ret < 0) {\n> +\t\t\t\tcerr << \"Join failed\" << endl;\n> +\t\t\t\tstop(ret);\n> +\t\t\t}\n> +\n> +\t\t\tclose(outfd);\n> +\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\tdefault:\n> +\t\t\tcerr << \"Unknown command \" << cmd << endl;\n> +\t\t\tstop(-EINVAL);\n> +\t\t\tbreak;\n> +\t\t}\n> +\t}\n> +\n> +\tvoid stop(int code)\n> +\t{\n> +\t\texitCode_ = code;\n> +\t\texit_ = true;\n> +\t}\n> +\n> +\tIPCUnixSocket ipc_;\n> +\tEventDispatcher *dispatcher_;\n> +\tint exitCode_;\n> +\tbool exit_;\n> +};\n> +\n> +class UnixSocketTest : public Test\n> +{\n> +protected:\n> +\tint slaveStart(int fd)\n> +\t{\n> +\t\tpid_ = fork();\n> +\n> +\t\tif (pid_ == -1)\n> +\t\t\treturn TestFail;\n> +\n> +\t\tif (!pid_) {\n> +\t\t\tstd::string arg = std::to_string(fd);\n> +\t\t\texecl(\"/proc/self/exe\", \"/proc/self/exe\",\n> +\t\t\t      arg.c_str(), nullptr);\n> +\n> +\t\t\t/* Only get here if exec fails. */\n> +\t\t\texit(TestFail);\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint slaveStop()\n> +\t{\n> +\t\tint status;\n> +\n> +\t\tif (pid_ < 0)\n> +\t\t\treturn TestFail;\n> +\n> +\t\tif (waitpid(pid_, &status, 0) < 0)\n> +\t\t\treturn TestFail;\n> +\n> +\t\tif (!WIFEXITED(status) || WEXITSTATUS(status))\n> +\t\t\treturn TestFail;\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint testReverse()\n> +\t{\n> +\t\tIPCUnixSocket::Payload message, response;\n> +\t\tint ret;\n> +\n> +\t\tmessage.data = { CMD_REVERSE, 1, 2, 3, 4, 5 };\n> +\n> +\t\tret = call(message, &response);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tstd::reverse(response.data.begin() + 1, response.data.end());\n> +\t\tif (message.data != response.data)\n> +\t\t\treturn TestFail;\n> +\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tint testEmptyFail()\n> +\t{\n> +\t\tIPCUnixSocket::Payload message;\n> +\n> +\t\treturn ipc_.send(message) != -EINVAL;\n> +\t}\n> +\n> +\tint testCalc()\n> +\t{\n> +\t\tIPCUnixSocket::Payload message, response;\n> +\t\tint sizeOut, sizeIn, ret;\n> +\n> +\t\tsizeOut = prepareFDs(&message, 2);\n> +\t\tif (sizeOut < 0)\n> +\t\t\treturn sizeOut;\n> +\n> +\t\tmessage.data.push_back(CMD_LEN_CALC);\n> +\n> +\t\tret = call(message, &response);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tmemcpy(&sizeIn, response.data.data() + 1, sizeof(sizeIn));\n> +\t\tif (sizeOut != sizeIn)\n> +\t\t\treturn TestFail;\n> +\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tint testCmp()\n> +\t{\n> +\t\tIPCUnixSocket::Payload message;\n> +\t\tint size;\n> +\n> +\t\tsize = prepareFDs(&message, 7);\n> +\t\tif (size < 0)\n> +\t\t\treturn size;\n> +\n> +\t\tmessage.data.resize(1 + sizeof(size));\n> +\t\tmessage.data[0] = CMD_LEN_CMP;\n> +\t\tmemcpy(message.data.data() + 1, &size, sizeof(size));\n> +\n> +\t\tif (ipc_.send(message))\n> +\t\t\treturn TestFail;\n> +\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tint testFdOrder()\n> +\t{\n> +\t\tIPCUnixSocket::Payload message, response;\n> +\t\tint ret;\n> +\n> +\t\tstatic const char *strings[2] = {\n> +\t\t\t\"Foo\",\n> +\t\t\t\"Bar\",\n> +\t\t};\n> +\t\tint fds[2];\n> +\n> +\t\tfor (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {\n> +\t\t\tunsigned int len = strlen(strings[i]);\n> +\n> +\t\t\tfds[i] = open(\"/tmp\", O_TMPFILE | O_RDWR,\n> +\t\t\t\t      S_IRUSR | S_IWUSR);\n> +\t\t\tif (fds[i] < 0)\n> +\t\t\t\treturn TestFail;\n> +\n> +\t\t\tret = write(fds[i], strings[i], len);\n> +\t\t\tif (ret < 0)\n> +\t\t\t\treturn TestFail;\n> +\n> +\t\t\tlseek(fds[i], 0, 0);\n> +\t\t\tmessage.fds.push_back(fds[i]);\n> +\t\t}\n> +\n> +\t\tmessage.data.push_back(CMD_JOIN);\n> +\n> +\t\tret = call(message, &response);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tfor (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {\n> +\t\t\tunsigned int len = strlen(strings[i]);\n> +\t\t\tchar buf[len];\n> +\n> +\t\t\tclose(fds[i]);\n> +\n> +\t\t\tif (read(response.fds[0], &buf, len) <= 0)\n> +\t\t\t\treturn TestFail;\n> +\n> +\t\t\tif (memcmp(buf, strings[i], len))\n> +\t\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tclose(response.fds[0]);\n> +\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tint init()\n> +\t{\n> +\t\tcallResponse_ = nullptr;\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tint run()\n> +\t{\n> +\t\tint slavefd = ipc_.create();\n> +\t\tif (slavefd < 0)\n> +\t\t\treturn TestFail;\n> +\n> +\t\tif (slaveStart(slavefd)) {\n> +\t\t\tcerr << \"Failed to start slave\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tipc_.readyRead.connect(this, &UnixSocketTest::readyRead);\n> +\n> +\t\t/* Test reversing a string, this test sending only data. */\n> +\t\tif (testReverse()) {\n> +\t\t\tcerr << \"Reveres array test failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test that an empty message fails. */\n> +\t\tif (testEmptyFail()) {\n> +\t\t\tcerr << \"Empty message test failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test offloading a calculation, this test sending only FDs. */\n> +\t\tif (testCalc()) {\n> +\t\t\tcerr << \"Calc test failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test fire and forget, this tests sending data and FDs. */\n> +\t\tif (testCmp()) {\n> +\t\t\tcerr << \"Cmp test failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Test order of file descriptors. */\n> +\t\tif (testFdOrder()) {\n> +\t\t\tcerr << \"fd order test failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\t/* Close slave connection. */\n> +\t\tIPCUnixSocket::Payload close;\n> +\t\tclose.data.push_back(CMD_CLOSE);\n> +\t\tif (ipc_.send(close)) {\n> +\t\t\tcerr << \"Closing IPC channel failed\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tipc_.close();\n> +\t\tif (slaveStop()) {\n> +\t\t\tcerr << \"Failed to stop slave\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +private:\n> +\tint call(const IPCUnixSocket::Payload &message, IPCUnixSocket::Payload *response)\n> +\t{\n> +\t\tTimer timeout;\n> +\t\tint ret;\n> +\n> +\t\tcallDone_ = false;\n> +\t\tcallResponse_ = response;\n> +\n> +\t\tret = ipc_.send(message);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\ttimeout.start(200);\n> +\t\twhile (!callDone_) {\n> +\t\t\tif (!timeout.isRunning()) {\n> +\t\t\t\tcerr << \"Call timeout!\" << endl;\n> +\t\t\t\tcallResponse_ = nullptr;\n> +\t\t\t\treturn -ETIMEDOUT;\n> +\t\t\t}\n> +\n> +\t\t\tCameraManager::instance()->eventDispatcher()->processEvents();\n> +\t\t}\n> +\n> +\t\tcallResponse_ = nullptr;\n> +\n> +\t\treturn 0;\n> +\t}\n> +\n> +\tvoid readyRead(IPCUnixSocket *ipc)\n> +\t{\n> +\t\tif (!callResponse_) {\n> +\t\t\tcerr << \"Read ready without expecting data, fail.\" << endl;\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tif (ipc->receive(callResponse_)) {\n> +\t\t\tcerr << \"Receive message failed\" << endl;\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tcallDone_ = true;\n> +\t}\n> +\n> +\tint prepareFDs(IPCUnixSocket::Payload *message, unsigned int num)\n> +\t{\n> +\t\tint fd = open(\"/proc/self/exe\", O_RDONLY);\n> +\t\tif (fd < 0)\n> +\t\t\treturn fd;\n> +\n> +\t\tint size = 0;\n> +\t\tfor (unsigned int i = 0; i < num; i++) {\n> +\t\t\tint clone = dup(fd);\n> +\t\t\tif (clone < 0)\n> +\t\t\t\treturn clone;\n> +\n> +\t\t\tsize += calculateLength(clone);\n> +\t\t\tmessage->fds.push_back(clone);\n> +\t\t}\n> +\n> +\t\tclose(fd);\n> +\n> +\t\treturn size;\n> +\t}\n> +\n> +\tpid_t pid_;\n> +\tIPCUnixSocket ipc_;\n> +\tbool callDone_;\n> +\tIPCUnixSocket::Payload *callResponse_;\n> +};\n> +\n> +/*\n> + * Can't use TEST_REGISTER() as single binary needs to act as both proxy\n> + * master and slave.\n> + */\n> +int main(int argc, char **argv)\n> +{\n> +\tif (argc == 2) {\n> +\t\tint ipcfd = std::stoi(argv[1]);\n> +\t\tUnixSocketTestSlave slave;\n> +\t\treturn slave.run(ipcfd);\n> +\t}\n> +\n> +\treturn UnixSocketTest().execute();\n> +}\n> diff --git a/test/meson.build b/test/meson.build\n> index c36ac2479636..3666f6b2385b 100644\n> --- a/test/meson.build\n> +++ b/test/meson.build\n> @@ -2,6 +2,7 @@ subdir('libtest')\n>  \n>  subdir('camera')\n>  subdir('ipa')\n> +subdir('ipc')\n>  subdir('media_device')\n>  subdir('pipeline')\n>  subdir('stream')\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BDEA160B10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Jul 2019 16:25:56 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id DF101524;\n\tTue,  2 Jul 2019 16:25:55 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1562077556;\n\tbh=SV6ydzdSoSeI98yW0E/9IpVuGbvw3n8OoO7WjPVp7PU=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=n/ZiP3F7/coa/3UFCGflpngYHBwVh2kYAW/Cj3syHfy9mspwgDjpkte16+9zV0Egd\n\tw5aFzk+6lhfNY/xD9dpQKbX4EuIecde/JUNkKtyUIPD90pZPl3YKf6mrFmSD2RJjgf\n\tG4gKkr/Y4K++Pcmny/OnkfSFxHxs+iG0WCyIF09M=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190701232339.5191-1-laurent.pinchart@ideasonboard.com>\n\t<20190701232339.5191-3-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tsbsRB8KNNvVXBOVNwko86rQqF9drZuw=","Organization":"Ideas on Board","Message-ID":"<a7d3df55-e78f-1b2f-aaae-5cc21a462fcf@ideasonboard.com>","Date":"Tue, 2 Jul 2019 15:25:53 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.7.1","MIME-Version":"1.0","In-Reply-To":"<20190701232339.5191-3-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 02 Jul 2019 14:25:56 -0000"}},{"id":2128,"web_url":"https://patchwork.libcamera.org/comment/2128/","msgid":"<20190702143646.GD5033@pendragon.ideasonboard.com>","date":"2019-07-02T14:36:46","subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Tue, Jul 02, 2019 at 03:25:53PM +0100, Kieran Bingham wrote:\n> On 02/07/2019 00:23, Laurent Pinchart wrote:\n> > From: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > \n> > Test that the IPC supports sending data and file descriptors over the\n> > IPC medium. To be able to execute the test two parts are needed, one\n> > to drive the test and act as the libcamera (master) and a one to act as\n> > the IPA (slave).\n> > \n> > The master drives the testing posting requests to the slave to process\n> > and sometimes respond to. A few different tests are performed.\n> > \n> > - Master sends an array to the slave which responds with a reversed copy\n> >   of the array. The master verifies that a reversed array is returned.\n> > \n> > - Master ties to sends an empty message making sure that the send call\n> >   fails.\n> > \n> > - Master sends a list of file descriptors and ask the slave to calculate\n> >   and respond with the sum of the size of the files. The master verifies\n> >   that the calculated size is correct.\n> > \n> > - Master sends a pre-computed size and a list of file descriptors and\n> >   asks the slave to verify that the pre-computed size matches the sum of\n> >   the size of the file descriptors.\n> > \n> > - Master sends two file descriptors and asks the salve to join the file\n> >   contents in a new file and respond with its file descriptor. The\n> >   master then verifies that the content of the returned file descriptor\n> >   matches the order of the original two files.\n> > \n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> > Changes since v3:\n> > \n> > - Use O_TMPFILE instead of shm_open()\n> > - Miscellaneous typo and small fixes\n> > ---\n> >  test/ipc/meson.build    |  12 +\n> >  test/ipc/unixsocket.cpp | 502 ++++++++++++++++++++++++++++++++++++++++\n> >  test/meson.build        |   1 +\n> >  3 files changed, 515 insertions(+)\n> >  create mode 100644 test/ipc/meson.build\n> >  create mode 100644 test/ipc/unixsocket.cpp\n> > \n> > diff --git a/test/ipc/meson.build b/test/ipc/meson.build\n> > new file mode 100644\n> > index 000000000000..ca8375f35df9\n> > --- /dev/null\n> > +++ b/test/ipc/meson.build\n> > @@ -0,0 +1,12 @@\n> > +ipc_tests = [\n> > +    [ 'unixsocket',  'unixsocket.cpp' ],\n> > +]\n> > +\n> > +foreach t : ipc_tests\n> > +    exe = executable(t[0], t[1],\n> > +                     dependencies : libcamera_dep,\n> > +                     link_with : test_libraries,\n> > +                     include_directories : test_includes_internal)\n> > +\n> > +    test(t[0], exe, suite : 'ipc', is_parallel : false)\n> \n> Aren't IPC tests self contained, and thus suitable for is_parallel :\n> true?  (which I think is the default if is_parallel is omitted).\n\nI think you're right. Niklas ? Does anyone want to submit a patch ?\n\n> > +endforeach\n> > diff --git a/test/ipc/unixsocket.cpp b/test/ipc/unixsocket.cpp\n> > new file mode 100644\n> > index 000000000000..eeef64842a75\n> > --- /dev/null\n> > +++ b/test/ipc/unixsocket.cpp\n> > @@ -0,0 +1,502 @@\n> > +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> > +/*\n> > + * Copyright (C) 2019, Google Inc.\n> > + *\n> > + * unixsocket.cpp - Unix socket IPC test\n> > + */\n> > +\n> > +#include <algorithm>\n> > +#include <fcntl.h>\n> > +#include <iostream>\n> > +#include <stdlib.h>\n> > +#include <string.h>\n> > +#include <sys/stat.h>\n> > +#include <sys/types.h>\n> > +#include <sys/wait.h>\n> > +#include <unistd.h>\n> > +\n> > +#include <libcamera/camera_manager.h>\n> > +#include <libcamera/event_dispatcher.h>\n> > +#include <libcamera/timer.h>\n> > +\n> > +#include \"ipc_unixsocket.h\"\n> > +#include \"test.h\"\n> > +#include \"utils.h\"\n> > +\n> > +#define CMD_CLOSE\t0\n> > +#define CMD_REVERSE\t1\n> > +#define CMD_LEN_CALC\t2\n> > +#define CMD_LEN_CMP\t3\n> > +#define CMD_JOIN\t4\n> > +\n> > +using namespace std;\n> > +using namespace libcamera;\n> > +\n> > +int calculateLength(int fd)\n> > +{\n> > +\tlseek(fd, 0, 0);\n> > +\tint size = lseek(fd, 0, SEEK_END);\n> > +\tlseek(fd, 0, 0);\n> > +\n> > +\treturn size;\n> > +}\n> > +\n> > +class UnixSocketTestSlave\n> > +{\n> > +public:\n> > +\tUnixSocketTestSlave()\n> > +\t\t: exitCode_(EXIT_FAILURE), exit_(false)\n> > +\t{\n> > +\t\tdispatcher_ = CameraManager::instance()->eventDispatcher();\n> > +\t\tipc_.readyRead.connect(this, &UnixSocketTestSlave::readyRead);\n> > +\t}\n> > +\n> > +\tint run(int fd)\n> > +\t{\n> > +\t\tif (ipc_.bind(fd)) {\n> > +\t\t\tcerr << \"Failed to connect to IPC channel\" << endl;\n> > +\t\t\treturn EXIT_FAILURE;\n> > +\t\t}\n> > +\n> > +\t\twhile (!exit_)\n> > +\t\t\tdispatcher_->processEvents();\n> > +\n> > +\t\tipc_.close();\n> > +\n> > +\t\treturn exitCode_;\n> > +\t}\n> > +\n> > +private:\n> > +\tvoid readyRead(IPCUnixSocket *ipc)\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message, response;\n> > +\t\tint ret;\n> > +\n> > +\t\tret = ipc->receive(&message);\n> > +\t\tif (ret) {\n> > +\t\t\tcerr << \"Receive message failed: \" << ret << endl;\n> > +\t\t\treturn;\n> > +\t\t}\n> > +\n> > +\t\tconst uint8_t cmd = message.data[0];\n> > +\n> > +\t\tswitch (cmd) {\n> > +\t\tcase CMD_CLOSE:\n> > +\t\t\tstop(0);\n> > +\t\t\tbreak;\n> > +\n> > +\t\tcase CMD_REVERSE: {\n> > +\t\t\tresponse.data = message.data;\n> > +\t\t\tstd::reverse(response.data.begin() + 1, response.data.end());\n> > +\n> > +\t\t\tret = ipc_.send(response);\n> > +\t\t\tif (ret < 0) {\n> > +\t\t\t\tcerr << \"Reverse failed\" << endl;\n> > +\t\t\t\tstop(ret);\n> > +\t\t\t}\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\n> > +\t\tcase CMD_LEN_CALC: {\n> > +\t\t\tint size = 0;\n> > +\t\t\tfor (int fd : message.fds)\n> > +\t\t\t\tsize += calculateLength(fd);\n> > +\n> > +\t\t\tresponse.data.resize(1 + sizeof(size));\n> > +\t\t\tresponse.data[0] = cmd;\n> > +\t\t\tmemcpy(response.data.data() + 1, &size, sizeof(size));\n> > +\n> > +\t\t\tret = ipc_.send(response);\n> > +\t\t\tif (ret < 0) {\n> > +\t\t\t\tcerr << \"Calc failed\" << endl;\n> > +\t\t\t\tstop(ret);\n> > +\t\t\t}\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\n> > +\t\tcase CMD_LEN_CMP: {\n> > +\t\t\tint size = 0;\n> > +\t\t\tfor (int fd : message.fds)\n> > +\t\t\t\tsize += calculateLength(fd);\n> > +\n> > +\t\t\tint cmp;\n> > +\t\t\tmemcpy(&cmp, message.data.data() + 1, sizeof(cmp));\n> > +\n> > +\t\t\tif (cmp != size) {\n> > +\t\t\t\tcerr << \"Compare failed\" << endl;\n> > +\t\t\t\tstop(-ERANGE);\n> > +\t\t\t}\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\n> > +\t\tcase CMD_JOIN: {\n> > +\t\t\tint outfd = open(\"/tmp\", O_TMPFILE | O_RDWR,\n> > +\t\t\t\t\t S_IRUSR | S_IWUSR);\n> > +\t\t\tif (outfd < 0) {\n> > +\t\t\t\tcerr << \"Create out file failed\" << endl;\n> > +\t\t\t\tstop(outfd);\n> > +\t\t\t\treturn;\n> > +\t\t\t}\n> > +\n> > +\t\t\tfor (int fd : message.fds) {\n> > +\t\t\t\twhile (true) {\n> > +\t\t\t\t\tchar buf[32];\n> > +\t\t\t\t\tssize_t num = read(fd, &buf, sizeof(buf));\n> > +\n> > +\t\t\t\t\tif (num < 0) {\n> > +\t\t\t\t\t\tcerr << \"Read failed\" << endl;\n> > +\t\t\t\t\t\tstop(-EIO);\n> > +\t\t\t\t\t\treturn;\n> > +\t\t\t\t\t} else if (!num)\n> > +\t\t\t\t\t\tbreak;\n> > +\n> > +\t\t\t\t\tif (write(outfd, buf, num) < 0) {\n> > +\t\t\t\t\t\tcerr << \"Write failed\" << endl;\n> > +\t\t\t\t\t\tstop(-EIO);\n> > +\t\t\t\t\t\treturn;\n> > +\t\t\t\t\t}\n> > +\t\t\t\t}\n> > +\n> > +\t\t\t\tclose(fd);\n> > +\t\t\t}\n> > +\n> > +\t\t\tlseek(outfd, 0, 0);\n> > +\t\t\tresponse.data.push_back(CMD_JOIN);\n> > +\t\t\tresponse.fds.push_back(outfd);\n> > +\n> > +\t\t\tret = ipc_.send(response);\n> > +\t\t\tif (ret < 0) {\n> > +\t\t\t\tcerr << \"Join failed\" << endl;\n> > +\t\t\t\tstop(ret);\n> > +\t\t\t}\n> > +\n> > +\t\t\tclose(outfd);\n> > +\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\n> > +\t\tdefault:\n> > +\t\t\tcerr << \"Unknown command \" << cmd << endl;\n> > +\t\t\tstop(-EINVAL);\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\t}\n> > +\n> > +\tvoid stop(int code)\n> > +\t{\n> > +\t\texitCode_ = code;\n> > +\t\texit_ = true;\n> > +\t}\n> > +\n> > +\tIPCUnixSocket ipc_;\n> > +\tEventDispatcher *dispatcher_;\n> > +\tint exitCode_;\n> > +\tbool exit_;\n> > +};\n> > +\n> > +class UnixSocketTest : public Test\n> > +{\n> > +protected:\n> > +\tint slaveStart(int fd)\n> > +\t{\n> > +\t\tpid_ = fork();\n> > +\n> > +\t\tif (pid_ == -1)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\tif (!pid_) {\n> > +\t\t\tstd::string arg = std::to_string(fd);\n> > +\t\t\texecl(\"/proc/self/exe\", \"/proc/self/exe\",\n> > +\t\t\t      arg.c_str(), nullptr);\n> > +\n> > +\t\t\t/* Only get here if exec fails. */\n> > +\t\t\texit(TestFail);\n> > +\t\t}\n> > +\n> > +\t\treturn TestPass;\n> > +\t}\n> > +\n> > +\tint slaveStop()\n> > +\t{\n> > +\t\tint status;\n> > +\n> > +\t\tif (pid_ < 0)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\tif (waitpid(pid_, &status, 0) < 0)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\tif (!WIFEXITED(status) || WEXITSTATUS(status))\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\treturn TestPass;\n> > +\t}\n> > +\n> > +\tint testReverse()\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message, response;\n> > +\t\tint ret;\n> > +\n> > +\t\tmessage.data = { CMD_REVERSE, 1, 2, 3, 4, 5 };\n> > +\n> > +\t\tret = call(message, &response);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\n> > +\t\tstd::reverse(response.data.begin() + 1, response.data.end());\n> > +\t\tif (message.data != response.data)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tint testEmptyFail()\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message;\n> > +\n> > +\t\treturn ipc_.send(message) != -EINVAL;\n> > +\t}\n> > +\n> > +\tint testCalc()\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message, response;\n> > +\t\tint sizeOut, sizeIn, ret;\n> > +\n> > +\t\tsizeOut = prepareFDs(&message, 2);\n> > +\t\tif (sizeOut < 0)\n> > +\t\t\treturn sizeOut;\n> > +\n> > +\t\tmessage.data.push_back(CMD_LEN_CALC);\n> > +\n> > +\t\tret = call(message, &response);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\n> > +\t\tmemcpy(&sizeIn, response.data.data() + 1, sizeof(sizeIn));\n> > +\t\tif (sizeOut != sizeIn)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tint testCmp()\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message;\n> > +\t\tint size;\n> > +\n> > +\t\tsize = prepareFDs(&message, 7);\n> > +\t\tif (size < 0)\n> > +\t\t\treturn size;\n> > +\n> > +\t\tmessage.data.resize(1 + sizeof(size));\n> > +\t\tmessage.data[0] = CMD_LEN_CMP;\n> > +\t\tmemcpy(message.data.data() + 1, &size, sizeof(size));\n> > +\n> > +\t\tif (ipc_.send(message))\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tint testFdOrder()\n> > +\t{\n> > +\t\tIPCUnixSocket::Payload message, response;\n> > +\t\tint ret;\n> > +\n> > +\t\tstatic const char *strings[2] = {\n> > +\t\t\t\"Foo\",\n> > +\t\t\t\"Bar\",\n> > +\t\t};\n> > +\t\tint fds[2];\n> > +\n> > +\t\tfor (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {\n> > +\t\t\tunsigned int len = strlen(strings[i]);\n> > +\n> > +\t\t\tfds[i] = open(\"/tmp\", O_TMPFILE | O_RDWR,\n> > +\t\t\t\t      S_IRUSR | S_IWUSR);\n> > +\t\t\tif (fds[i] < 0)\n> > +\t\t\t\treturn TestFail;\n> > +\n> > +\t\t\tret = write(fds[i], strings[i], len);\n> > +\t\t\tif (ret < 0)\n> > +\t\t\t\treturn TestFail;\n> > +\n> > +\t\t\tlseek(fds[i], 0, 0);\n> > +\t\t\tmessage.fds.push_back(fds[i]);\n> > +\t\t}\n> > +\n> > +\t\tmessage.data.push_back(CMD_JOIN);\n> > +\n> > +\t\tret = call(message, &response);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\n> > +\t\tfor (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {\n> > +\t\t\tunsigned int len = strlen(strings[i]);\n> > +\t\t\tchar buf[len];\n> > +\n> > +\t\t\tclose(fds[i]);\n> > +\n> > +\t\t\tif (read(response.fds[0], &buf, len) <= 0)\n> > +\t\t\t\treturn TestFail;\n> > +\n> > +\t\t\tif (memcmp(buf, strings[i], len))\n> > +\t\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\tclose(response.fds[0]);\n> > +\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tint init()\n> > +\t{\n> > +\t\tcallResponse_ = nullptr;\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tint run()\n> > +\t{\n> > +\t\tint slavefd = ipc_.create();\n> > +\t\tif (slavefd < 0)\n> > +\t\t\treturn TestFail;\n> > +\n> > +\t\tif (slaveStart(slavefd)) {\n> > +\t\t\tcerr << \"Failed to start slave\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\tipc_.readyRead.connect(this, &UnixSocketTest::readyRead);\n> > +\n> > +\t\t/* Test reversing a string, this test sending only data. */\n> > +\t\tif (testReverse()) {\n> > +\t\t\tcerr << \"Reveres array test failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Test that an empty message fails. */\n> > +\t\tif (testEmptyFail()) {\n> > +\t\t\tcerr << \"Empty message test failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Test offloading a calculation, this test sending only FDs. */\n> > +\t\tif (testCalc()) {\n> > +\t\t\tcerr << \"Calc test failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Test fire and forget, this tests sending data and FDs. */\n> > +\t\tif (testCmp()) {\n> > +\t\t\tcerr << \"Cmp test failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Test order of file descriptors. */\n> > +\t\tif (testFdOrder()) {\n> > +\t\t\tcerr << \"fd order test failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\t/* Close slave connection. */\n> > +\t\tIPCUnixSocket::Payload close;\n> > +\t\tclose.data.push_back(CMD_CLOSE);\n> > +\t\tif (ipc_.send(close)) {\n> > +\t\t\tcerr << \"Closing IPC channel failed\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\tipc_.close();\n> > +\t\tif (slaveStop()) {\n> > +\t\t\tcerr << \"Failed to stop slave\" << endl;\n> > +\t\t\treturn TestFail;\n> > +\t\t}\n> > +\n> > +\t\treturn TestPass;\n> > +\t}\n> > +\n> > +private:\n> > +\tint call(const IPCUnixSocket::Payload &message, IPCUnixSocket::Payload *response)\n> > +\t{\n> > +\t\tTimer timeout;\n> > +\t\tint ret;\n> > +\n> > +\t\tcallDone_ = false;\n> > +\t\tcallResponse_ = response;\n> > +\n> > +\t\tret = ipc_.send(message);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\n> > +\t\ttimeout.start(200);\n> > +\t\twhile (!callDone_) {\n> > +\t\t\tif (!timeout.isRunning()) {\n> > +\t\t\t\tcerr << \"Call timeout!\" << endl;\n> > +\t\t\t\tcallResponse_ = nullptr;\n> > +\t\t\t\treturn -ETIMEDOUT;\n> > +\t\t\t}\n> > +\n> > +\t\t\tCameraManager::instance()->eventDispatcher()->processEvents();\n> > +\t\t}\n> > +\n> > +\t\tcallResponse_ = nullptr;\n> > +\n> > +\t\treturn 0;\n> > +\t}\n> > +\n> > +\tvoid readyRead(IPCUnixSocket *ipc)\n> > +\t{\n> > +\t\tif (!callResponse_) {\n> > +\t\t\tcerr << \"Read ready without expecting data, fail.\" << endl;\n> > +\t\t\treturn;\n> > +\t\t}\n> > +\n> > +\t\tif (ipc->receive(callResponse_)) {\n> > +\t\t\tcerr << \"Receive message failed\" << endl;\n> > +\t\t\treturn;\n> > +\t\t}\n> > +\n> > +\t\tcallDone_ = true;\n> > +\t}\n> > +\n> > +\tint prepareFDs(IPCUnixSocket::Payload *message, unsigned int num)\n> > +\t{\n> > +\t\tint fd = open(\"/proc/self/exe\", O_RDONLY);\n> > +\t\tif (fd < 0)\n> > +\t\t\treturn fd;\n> > +\n> > +\t\tint size = 0;\n> > +\t\tfor (unsigned int i = 0; i < num; i++) {\n> > +\t\t\tint clone = dup(fd);\n> > +\t\t\tif (clone < 0)\n> > +\t\t\t\treturn clone;\n> > +\n> > +\t\t\tsize += calculateLength(clone);\n> > +\t\t\tmessage->fds.push_back(clone);\n> > +\t\t}\n> > +\n> > +\t\tclose(fd);\n> > +\n> > +\t\treturn size;\n> > +\t}\n> > +\n> > +\tpid_t pid_;\n> > +\tIPCUnixSocket ipc_;\n> > +\tbool callDone_;\n> > +\tIPCUnixSocket::Payload *callResponse_;\n> > +};\n> > +\n> > +/*\n> > + * Can't use TEST_REGISTER() as single binary needs to act as both proxy\n> > + * master and slave.\n> > + */\n> > +int main(int argc, char **argv)\n> > +{\n> > +\tif (argc == 2) {\n> > +\t\tint ipcfd = std::stoi(argv[1]);\n> > +\t\tUnixSocketTestSlave slave;\n> > +\t\treturn slave.run(ipcfd);\n> > +\t}\n> > +\n> > +\treturn UnixSocketTest().execute();\n> > +}\n> > diff --git a/test/meson.build b/test/meson.build\n> > index c36ac2479636..3666f6b2385b 100644\n> > --- a/test/meson.build\n> > +++ b/test/meson.build\n> > @@ -2,6 +2,7 @@ subdir('libtest')\n> >  \n> >  subdir('camera')\n> >  subdir('ipa')\n> > +subdir('ipc')\n> >  subdir('media_device')\n> >  subdir('pipeline')\n> >  subdir('stream')","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E692360B10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Jul 2019 16:37:05 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 68A01524;\n\tTue,  2 Jul 2019 16:37:05 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1562078225;\n\tbh=T4gn/BH2We5y1JZefMbBJvUrmZJMRQnMf86oUfES2p0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=kn/HjW+mvoXqxI4ZYogXTn1WK7I89uk1QqdiVJOBPFeOtSahzjwvmH1OX4t3YRibm\n\tTKWCipDvfS1h6vTPWFn55QGJ/P9GvKE7iX0DMeJnUI9yOO6mJeZT8M+d69kyZhZpHW\n\t82rjcyAAy+ihMQEerounYvM9vPN5ubYtASJNEm8o=","Date":"Tue, 2 Jul 2019 17:36:46 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190702143646.GD5033@pendragon.ideasonboard.com>","References":"<20190701232339.5191-1-laurent.pinchart@ideasonboard.com>\n\t<20190701232339.5191-3-laurent.pinchart@ideasonboard.com>\n\t<a7d3df55-e78f-1b2f-aaae-5cc21a462fcf@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<a7d3df55-e78f-1b2f-aaae-5cc21a462fcf@ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 02 Jul 2019 14:37:06 -0000"}},{"id":2146,"web_url":"https://patchwork.libcamera.org/comment/2146/","msgid":"<20190704013247.GA17685@bigcity.dyn.berto.se>","date":"2019-07-04T01:32:47","subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"On 2019-07-02 17:36:46 +0300, Laurent Pinchart wrote:\n\n> > Aren't IPC tests self contained, and thus suitable for is_parallel :\n> > true?  (which I think is the default if is_parallel is omitted).\n> \n> I think you're right. Niklas ? Does anyone want to submit a patch ?\n\nI think both IPA, IPC and Stream tests are self-contained and could be \nran in parallel, patch sent. I also had a crazy idea on how to run all \ntests in \"parallel\", send a RFC patch for this but it might be to crazy \nwhile it cuts down the runtime with 50% ;-P","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lf1-x143.google.com (mail-lf1-x143.google.com\n\t[IPv6:2a00:1450:4864:20::143])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9D0D460BEE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Jul 2019 03:32:48 +0200 (CEST)","by mail-lf1-x143.google.com with SMTP id a9so3055444lff.7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 03 Jul 2019 18:32:48 -0700 (PDT)","from localhost (customer-145-14-112-32.stosn.net. [145.14.112.32])\n\tby smtp.gmail.com with ESMTPSA id\n\tu21sm812066lju.2.2019.07.03.18.32.47\n\t(version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256);\n\tWed, 03 Jul 2019 18:32:47 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=fh5/VUly+UnEE0jVX6aqKXsXDwYxwnQTUfJAnDgqOVw=;\n\tb=GLkPwK76+iD+/VAntCyPNpblk5hzDMRr1pWVfUOawUcA8imNVTRv3m5WOuqa2MKwdD\n\tj2UfmqQeI5yy6UUfXmjEmjMDA+PnL/HuL7L9Ro2mXi3buKzGJHxAHZ7dK05BXPB81udi\n\tT/Tz04K/LixmlGYIpJ0D9Ne2gtCwF2pi8QaWuXKVGoPHtzc3OvFt2WJzXwx402HZcL3E\n\t8KNzXKyeFJBY/fJUZfOvmZO9l5PpMgO6tKQ1S+8mRs+iIkR/cegEF62tjy4OWwjEOAmP\n\tVKsLyqqY+80uPVXCFKb2HJZXHSPlcL51nDKEhv3uQ/zRVXPbwFFn8DIAedgiQeELYOVv\n\tq7YA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=fh5/VUly+UnEE0jVX6aqKXsXDwYxwnQTUfJAnDgqOVw=;\n\tb=odGR25hmysEtl3YZjpp0EgrBuNkBJvHlIZCCxJ3g++jPsvZ5R42dZd+rZCGGm4o6Ix\n\tKOuBqHy6APF7lf5yDjmXzvI6g92L04WuPW/ZMnPzHWNjD5I87vROw/5EgdzMC6ktX5l9\n\tTj6D/+F9f3QhwMx3r1w0fTQgUhn+8+ED+9Z06wAVvTcBJpnqaiVUwT5vt50E4esAggyn\n\tZAw9zx5RCtKf+IvDhzvxMH4SUuNmBVjSxrgfUMa3Blf/eDV9kkTNZ269cuarZa+pepd9\n\tPExhp7R3Ede5/ufRzP3SwaBD8CZOmK4jnFo0M2RnWCVw9HFvN4fuY0OACcWFYiJTZg6A\n\tFALg==","X-Gm-Message-State":"APjAAAVga6hTAHsJc11RoYBdMKYxf67I4Gb9/Ue+R3So0zDdZcs6Awzi\n\thq37QthlZc6js3Rqp6AHPLEGLO1+gZQ=","X-Google-Smtp-Source":"APXvYqxL4j5PQ48CIvWYst4HPq1r4PmesgQq6x/qjeIxPFlPuqa6qYwn5zKi6r6o7AkR2LEIUFrIrQ==","X-Received":"by 2002:ac2:5382:: with SMTP id g2mr18658823lfh.92.1562203968167;\n\tWed, 03 Jul 2019 18:32:48 -0700 (PDT)","Date":"Thu, 4 Jul 2019 03:32:47 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190704013247.GA17685@bigcity.dyn.berto.se>","References":"<20190701232339.5191-1-laurent.pinchart@ideasonboard.com>\n\t<20190701232339.5191-3-laurent.pinchart@ideasonboard.com>\n\t<a7d3df55-e78f-1b2f-aaae-5cc21a462fcf@ideasonboard.com>\n\t<20190702143646.GD5033@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190702143646.GD5033@pendragon.ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH v4 2/3] test: ipc: unix: Add test for\n\tIPCUnixSocket","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 04 Jul 2019 01:32:48 -0000"}}]