Show a patch.

GET /api/patches/1526/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1526,
    "url": "https://patchwork.libcamera.org/api/patches/1526/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/1526/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20190627020955.6166-3-niklas.soderlund@ragnatech.se>",
    "date": "2019-06-27T02:09:55",
    "name": "[libcamera-devel,2/2] test: ipc: unix: Add test for IPCUnixSocket",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "cb0578bb5ada0465dc90e1c406fc83a7ab40a9d2",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/1526/mbox/",
    "series": [
        {
            "id": 379,
            "url": "https://patchwork.libcamera.org/api/series/379/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=379",
            "date": "2019-06-27T02:09:53",
            "name": "libcamera: ipc: unix: Add a IPC mechanism based on Unix sockets",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/379/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/1526/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/1526/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<niklas.soderlund@ragnatech.se>",
        "Received": [
            "from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net\n\t[195.74.38.227])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 10F3D6192A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 27 Jun 2019 04:10:11 +0200 (CEST)",
            "from bismarck.berto.se (unknown [145.14.112.32])\n\tby bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA\n\tid a5e93e1a-9880-11e9-8ab4-005056917a89;\n\tThu, 27 Jun 2019 04:09:52 +0200 (CEST)"
        ],
        "X-Halon-ID": "a5e93e1a-9880-11e9-8ab4-005056917a89",
        "Authorized-sender": "niklas@soderlund.pp.se",
        "From": "=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu, 27 Jun 2019 04:09:55 +0200",
        "Message-Id": "<20190627020955.6166-3-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20190627020955.6166-1-niklas.soderlund@ragnatech.se>",
        "References": "<20190627020955.6166-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH 2/2] 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, 27 Jun 2019 02:10:11 -0000"
    },
    "content": "Test that the IPC supports sending data and file descriptors over the\nIPC medium. To be able execute the test two parts are needed, one\nto drive the test and act as the libcamera (master) and a one to act as\nthe IPA (slave).\n\nThe master drives the testing posting requests to the slave to process\nand sometime respond to. A few different tests are preformed.\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 sends a list of file descriptors and ask the salve to calculate\n  and respond with the sum of the size of the files. The master verifies\n  that the calculate size is correct.\n\n- Master send a pre-computed size and a list of file descriptors and\n  ask the slave to verify that the pre-computed size matches the sum of\n  the size of the file descriptors.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n test/ipc/meson.build    |  12 ++\n test/ipc/unixsocket.cpp | 339 ++++++++++++++++++++++++++++++++++++++++\n test/meson.build        |   1 +\n 3 files changed, 352 insertions(+)\n create mode 100644 test/ipc/meson.build\n create mode 100644 test/ipc/unixsocket.cpp",
    "diff": "diff --git a/test/ipc/meson.build b/test/ipc/meson.build\nnew file mode 100644\nindex 0000000000000000..ca8375f35df91731\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+endforeach\ndiff --git a/test/ipc/unixsocket.cpp b/test/ipc/unixsocket.cpp\nnew file mode 100644\nindex 0000000000000000..c50d7463cee48e75\n--- /dev/null\n+++ b/test/ipc/unixsocket.cpp\n@@ -0,0 +1,339 @@\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 <atomic>\n+#include <fcntl.h>\n+#include <iostream>\n+#include <string.h>\n+#include <sys/wait.h>\n+#include <unistd.h>\n+\n+#include <libcamera/camera_manager.h>\n+#include <libcamera/event_dispatcher.h>\n+\n+#include \"ipc_unixsocket.h\"\n+#include \"test.h\"\n+\n+#define CMD_CLOSE 0\n+#define CMD_REVERSE 1\n+#define CMD_LEN_CALC 2\n+#define CMD_LEN_CMP 3\n+\n+using namespace std;\n+using namespace libcamera;\n+\n+int calcLength(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)\n+\t{\n+\t\tdispatcher_ = CameraManager::instance()->eventDispatcher();\n+\t\texit_.store(false, std::memory_order_release);\n+\t\tipc_.payloadReceived.connect(this, &UnixSocketTestSlave::payloadReceived);\n+\t}\n+\n+\tint run(int fd)\n+\t{\n+\t\tif (ipc_.attach(fd)) {\n+\t\t\tcerr << \"Failed to connect to IPC\" << endl;\n+\t\t\treturn EXIT_FAILURE;\n+\t\t}\n+\n+\t\twhile (!exit_.load(std::memory_order_acquire))\n+\t\t\tdispatcher_->processEvents();\n+\n+\t\tipc_.close();\n+\n+\t\treturn exitCode_;\n+\t}\n+\n+private:\n+\tvoid payloadReceived(const IPCUnixSocket::Payload &payload)\n+\t{\n+\t\tIPCUnixSocket::Payload response;\n+\t\tint ret;\n+\n+\t\tconst uint8_t cmd = payload.data.front();\n+\n+\t\tcout << \"Slave received command \" << static_cast<unsigned int>(cmd) << endl;\n+\n+\t\tswitch (cmd) {\n+\t\tcase CMD_CLOSE:\n+\t\t\tstop(0);\n+\t\t\tbreak;\n+\t\tcase CMD_REVERSE: {\n+\t\t\tstd::vector<uint8_t> raw(payload.data.begin() + 1, payload.data.end());\n+\t\t\tstd::reverse(raw.begin(), raw.end());\n+\t\t\traw.insert(raw.begin(), cmd);\n+\n+\t\t\tresponse.data = raw;\n+\t\t\tret = ipc_.send(response);\n+\t\t\tif (ret < 0) {\n+\t\t\t\tcerr << \"Reverse fail\" << endl;\n+\t\t\t\tstop(ret);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tcase CMD_LEN_CALC: {\n+\t\t\tint size = 0;\n+\t\t\tfor (int fd : payload.fds)\n+\t\t\t\tsize += calcLength(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 fail\" << endl;\n+\t\t\t\tstop(ret);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tcase CMD_LEN_CMP: {\n+\t\t\tint size = 0;\n+\t\t\tfor (int fd : payload.fds)\n+\t\t\t\tsize += calcLength(fd);\n+\n+\t\t\tint cmp;\n+\t\t\tmemcpy(&cmp, payload.data.data() + 1, sizeof(cmp));\n+\n+\t\t\tif (cmp != size) {\n+\t\t\t\tcerr << \"Compare fail\" << endl;\n+\t\t\t\tstop(-ERANGE);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\t}\n+\t\tdefault:\n+\t\t\tcerr << \"Unknown command \" << cmd << endl;\n+\t\t\tstop(-EINVAL);\n+\t\t}\n+\t}\n+\n+\tvoid stop(int code)\n+\t{\n+\t\texitCode_ = code;\n+\t\texit_.store(true, std::memory_order_release);\n+\t}\n+\n+\tIPCUnixSocket ipc_;\n+\tEventDispatcher *dispatcher_;\n+\tint exitCode_;\n+\tstd::atomic<bool> exit_;\n+};\n+\n+static const std::vector<std::string> testPaths = {\n+\t\"/proc/self/exe\",\n+\t\"/proc/self/exe\",\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 reverse;\n+\n+\t\treverse.data = { CMD_REVERSE, 1, 2, 3, 4, 5 };\n+\t\tif (ipc_.send(reverse))\n+\t\t\treturn TestFail;\n+\n+\t\tCameraManager::instance()->eventDispatcher()->processEvents();\n+\n+\t\treturn 0;\n+\t}\n+\n+\tint testCalc()\n+\t{\n+\t\tIPCUnixSocket::Payload payload;\n+\n+\t\tcalcSize_ = 0;\n+\t\tfor (const std::string path : testPaths) {\n+\t\t\tint fd = open(path.c_str(), O_RDONLY);\n+\t\t\tif (fd < 0)\n+\t\t\t\treturn TestFail;\n+\n+\t\t\tcalcSize_ += calcLength(fd);\n+\t\t\tpayload.fds.push_back(fd);\n+\t\t}\n+\n+\t\tpayload.data.push_back(CMD_LEN_CALC);\n+\t\tif (ipc_.send(payload))\n+\t\t\treturn TestFail;\n+\n+\t\tCameraManager::instance()->eventDispatcher()->processEvents();\n+\n+\t\treturn 0;\n+\t}\n+\n+\tint testCmp()\n+\t{\n+\t\tIPCUnixSocket::Payload payload;\n+\n+\t\tint size = 0;\n+\t\tfor (const std::string path : testPaths) {\n+\t\t\tint fd = open(path.c_str(), O_RDONLY);\n+\t\t\tif (fd < 0)\n+\t\t\t\treturn TestFail;\n+\n+\t\t\tsize += calcLength(fd);\n+\t\t\tpayload.fds.push_back(fd);\n+\t\t}\n+\n+\t\tpayload.data.resize(1 + sizeof(size));\n+\t\tpayload.data[0] = CMD_LEN_CMP;\n+\t\tmemcpy(payload.data.data() + 1, &size, sizeof(size));\n+\n+\t\tif (ipc_.send(payload))\n+\t\t\treturn TestFail;\n+\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\treturn TestFail;\n+\n+\t\tipc_.payloadReceived.connect(this, &UnixSocketTest::payloadReceived);\n+\n+\t\t/* Test reversing a string, this test sending only data. */\n+\t\tranRev_ = false;\n+\t\tif (testReverse())\n+\t\t\treturn TestFail;\n+\n+\t\t/* Test offloading a calculation, this test sending only FDs. */\n+\t\tranCalc_ = false;\n+\t\tif (testCalc())\n+\t\t\treturn TestFail;\n+\n+\t\t/* Test fire and forget, this tests sending data and FDs. */\n+\t\tif (testCmp())\n+\t\t\treturn TestFail;\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\treturn TestFail;\n+\n+\t\tipc_.close();\n+\t\tif (slaveStop())\n+\t\t\treturn TestFail;\n+\n+\t\t/* Check that all tests have executed. */\n+\t\tif (!ranRev_ || !ranCalc_) {\n+\t\t\tcerr << \"Not all messages responded to\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\treturn TestPass;\n+\t}\n+\n+private:\n+\tvoid payloadReceived(const IPCUnixSocket::Payload &payload)\n+\t{\n+\t\tconst uint8_t cmd = payload.data.front();\n+\t\tcout << \"Master received command \" << static_cast<unsigned int>(cmd) << endl;\n+\n+\t\tswitch (cmd) {\n+\t\tcase CMD_REVERSE: {\n+\t\t\tstd::vector<uint8_t> raw(payload.data.begin() + 1, payload.data.end());\n+\t\t\tif (raw == std::vector<uint8_t>{ 5, 4, 3, 2, 1 })\n+\t\t\t\tranRev_ = true;\n+\t\t\telse\n+\t\t\t\tcerr << \"Reverse response invalid\" << endl;\n+\n+\t\t\tbreak;\n+\t\t}\n+\t\tcase CMD_LEN_CALC: {\n+\t\t\tint output;\n+\t\t\tmemcpy(&output, payload.data.data() + 1, sizeof(output));\n+\t\t\tif (output == calcSize_)\n+\t\t\t\tranCalc_ = true;\n+\t\t\telse\n+\t\t\t\tcerr << \"Calc response invalid\" << endl;\n+\n+\t\t\tbreak;\n+\t\t}\n+\t\tdefault:\n+\t\t\tcerr << \"Unknown command \" << cmd << endl;\n+\t\t}\n+\t}\n+\n+\tpid_t pid_;\n+\tIPCUnixSocket ipc_;\n+\n+\tbool ranRev_;\n+\tbool ranCalc_;\n+\tint calcSize_;\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+}\ndiff --git a/test/meson.build b/test/meson.build\nindex c36ac24796367501..3666f6b2385bd4ca 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",
    "prefixes": [
        "libcamera-devel",
        "2/2"
    ]
}