Patch Detail
Show a patch.
GET /api/patches/1580/?format=api
{ "id": 1580, "url": "https://patchwork.libcamera.org/api/patches/1580/?format=api", "web_url": "https://patchwork.libcamera.org/patch/1580/", "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": "<20190701232339.5191-4-laurent.pinchart@ideasonboard.com>", "date": "2019-07-01T23:23:39", "name": "[libcamera-devel,v4,3/3] libcamera: ipc: unix: Make socket operation asynchronous", "commit_ref": "f137451817f47c0bfe59586afe5af7b51f8ccad4", "pull_url": null, "state": "accepted", "archived": false, "hash": "da90fc2b9150f72b7653bad48ea39f6e7f8bebfa", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/1580/mbox/", "series": [ { "id": 389, "url": "https://patchwork.libcamera.org/api/series/389/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=389", "date": "2019-07-01T23:23:36", "name": "libcamera: ipc: unix: Add a IPC mechanism based on Unix sockets", "version": 4, "mbox": "https://patchwork.libcamera.org/series/389/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/1580/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/1580/checks/", "tags": {}, "headers": { "Return-Path": "<laurent.pinchart@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 9E8A96157C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 2 Jul 2019 01:24:04 +0200 (CEST)", "from pendragon.bb.dnainternet.fi\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 3786253B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 2 Jul 2019 01:24:04 +0200 (CEST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1562023444;\n\tbh=TjI7zocRVzBpCg7ppR9TAcE9AoBnfn+yWr7PS48vf9s=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=s/RWXt5wZv6/9Gak2hpnYh1DwB3Vtz1eBi3ciyVUmYUFoM6MaAarHWqT9TzrVLnFN\n\tADpYg2iHgLVtme6ToVa5Un12Kf1rRz4j+sUAdkXq1189ddjZGhddlXAMIeKU8y1yIo\n\tDRQ40IdwOv6lw9VZTox2xtocq4aKWpIN/Pm99tzU=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Tue, 2 Jul 2019 02:23:39 +0300", "Message-Id": "<20190701232339.5191-4-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.21.0", "In-Reply-To": "<20190701232339.5191-1-laurent.pinchart@ideasonboard.com>", "References": "<20190701232339.5191-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v4 3/3] libcamera: ipc: unix: Make socket\n\toperation asynchronous", "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": "Mon, 01 Jul 2019 23:24:04 -0000" }, "content": "Blocking socket operation when receiving messages may lead to long\ndelays, and possibly a complete deadlock, if the remote side delays\nsending of the payload after the header, or doesn't send the payload at\nall. To avoid this, make the socket non-blocking and implement a simple\nstate machine to receive the header synchronously with the socket read\nnotification. The payload read is still synchronous with the receive()\nmethod to avoid data copies.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/libcamera/include/ipc_unixsocket.h | 2 +\n src/libcamera/ipc_unixsocket.cpp | 88 ++++++++++++++++++--------\n 2 files changed, 63 insertions(+), 27 deletions(-)", "diff": "diff --git a/src/libcamera/include/ipc_unixsocket.h b/src/libcamera/include/ipc_unixsocket.h\nindex ef166d742554..03e9fe492bde 100644\n--- a/src/libcamera/include/ipc_unixsocket.h\n+++ b/src/libcamera/include/ipc_unixsocket.h\n@@ -49,6 +49,8 @@ private:\n \tvoid dataNotifier(EventNotifier *notifier);\n \n \tint fd_;\n+\tbool headerReceived_;\n+\tstruct Header header_;\n \tEventNotifier *notifier_;\n };\n \ndiff --git a/src/libcamera/ipc_unixsocket.cpp b/src/libcamera/ipc_unixsocket.cpp\nindex c11f116093c5..def08eef00f8 100644\n--- a/src/libcamera/ipc_unixsocket.cpp\n+++ b/src/libcamera/ipc_unixsocket.cpp\n@@ -7,6 +7,7 @@\n \n #include \"ipc_unixsocket.h\"\n \n+#include <poll.h>\n #include <string.h>\n #include <sys/socket.h>\n #include <unistd.h>\n@@ -49,10 +50,10 @@ LOG_DEFINE_CATEGORY(IPCUnixSocket)\n * transporting entire payloads with guaranteed ordering.\n *\n * The IPC design is asynchronous, a message is queued to a receiver which gets\n- * notified that a message is ready to be consumed by a signal. The queuer of\n- * the message gets no notification when a message is delivered nor processed.\n- * If such interactions are needed a protocol specific to the users use-case\n- * should be implemented on top of the IPC objects.\n+ * notified that a message is ready to be consumed by the \\ref readyRead\n+ * signal. The sender of the message gets no notification when a message is\n+ * delivered nor processed. If such interactions are needed a protocol specific\n+ * to the users use-case should be implemented on top of the IPC objects.\n *\n * Establishment of an IPC channel is asymmetrical. The side that initiates\n * communication first instantiates a local side socket and creates the channel\n@@ -64,7 +65,7 @@ LOG_DEFINE_CATEGORY(IPCUnixSocket)\n */\n \n IPCUnixSocket::IPCUnixSocket()\n-\t: fd_(-1), notifier_(nullptr)\n+\t: fd_(-1), headerReceived_(false), notifier_(nullptr)\n {\n }\n \n@@ -89,7 +90,7 @@ int IPCUnixSocket::create()\n \tint sockets[2];\n \tint ret;\n \n-\tret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets);\n+\tret = socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sockets);\n \tif (ret) {\n \t\tret = -errno;\n \t\tLOG(IPCUnixSocket, Error)\n@@ -142,6 +143,7 @@ void IPCUnixSocket::close()\n \t::close(fd_);\n \n \tfd_ = -1;\n+\theaderReceived_ = false;\n }\n \n /**\n@@ -193,38 +195,38 @@ int IPCUnixSocket::send(const Payload &payload)\n * \\param[out] payload Payload where to write the received message\n *\n * This method receives the message payload from the IPC channel and writes it\n- * to the \\a payload. It blocks until one message is received, if an\n- * asynchronous behavior is desired this method should be called when the\n- * readyRead signal is emitted.\n+ * to the \\a payload. If no message payload is available, it returns\n+ * immediately with -EAGAIN. The \\ref readyRead signal shall be used to receive\n+ * notification of message availability.\n *\n * \\todo Add state machine to make sure we don't block forever and that\n * a header is always followed by a payload.\n *\n * \\return 0 on success or a negative error code otherwise\n+ * \\retval -EAGAIN No message payload is available\n+ * \\retval -ENOTCONN The socket is not connected (neither create() nor bind()\n+ * has been called)\n */\n int IPCUnixSocket::receive(Payload *payload)\n {\n-\tHeader hdr;\n-\tint ret;\n-\n \tif (!isBound())\n \t\treturn -ENOTCONN;\n \n-\tif (!payload)\n-\t\treturn -EINVAL;\n+\tif (!headerReceived_)\n+\t\treturn -EAGAIN;\n \n-\tret = ::recv(fd_, &hdr, sizeof(hdr), 0);\n-\tif (ret < 0) {\n-\t\tret = -errno;\n-\t\tLOG(IPCUnixSocket, Error)\n-\t\t\t<< \"Failed to recv header: \" << strerror(-ret);\n+\tpayload->data.resize(header_.data);\n+\tpayload->fds.resize(header_.fds);\n+\n+\tint ret = recvData(payload->data.data(), header_.data,\n+\t\t\t payload->fds.data(), header_.fds);\n+\tif (ret < 0)\n \t\treturn ret;\n-\t}\n \n-\tpayload->data.resize(hdr.data);\n-\tpayload->fds.resize(hdr.fds);\n+\theaderReceived_ = false;\n+\tnotifier_->setEnabled(true);\n \n-\treturn recvData(payload->data.data(), hdr.data, payload->fds.data(), hdr.fds);\n+\treturn 0;\n }\n \n /**\n@@ -232,7 +234,8 @@ int IPCUnixSocket::receive(Payload *payload)\n * \\brief A Signal emitted when a message is ready to be read\n */\n \n-int IPCUnixSocket::sendData(const void *buffer, size_t length, const int32_t *fds, unsigned int num)\n+int IPCUnixSocket::sendData(const void *buffer, size_t length,\n+\t\t\t const int32_t *fds, unsigned int num)\n {\n \tstruct iovec iov[1];\n \tiov[0].iov_base = const_cast<void *>(buffer);\n@@ -266,7 +269,8 @@ int IPCUnixSocket::sendData(const void *buffer, size_t length, const int32_t *fd\n \treturn 0;\n }\n \n-int IPCUnixSocket::recvData(void *buffer, size_t length, int32_t *fds, unsigned int num)\n+int IPCUnixSocket::recvData(void *buffer, size_t length,\n+\t\t\t int32_t *fds, unsigned int num)\n {\n \tstruct iovec iov[1];\n \tiov[0].iov_base = buffer;\n@@ -291,8 +295,9 @@ int IPCUnixSocket::recvData(void *buffer, size_t length, int32_t *fds, unsigned\n \n \tif (recvmsg(fd_, &msg, 0) < 0) {\n \t\tint ret = -errno;\n-\t\tLOG(IPCUnixSocket, Error)\n-\t\t\t<< \"Failed to recvmsg: \" << strerror(-ret);\n+\t\tif (ret != -EAGAIN)\n+\t\t\tLOG(IPCUnixSocket, Error)\n+\t\t\t\t<< \"Failed to recvmsg: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n \n@@ -303,6 +308,35 @@ int IPCUnixSocket::recvData(void *buffer, size_t length, int32_t *fds, unsigned\n \n void IPCUnixSocket::dataNotifier(EventNotifier *notifier)\n {\n+\tint ret;\n+\n+\tif (!headerReceived_) {\n+\t\t/* Receive the header. */\n+\t\tret = ::recv(fd_, &header_, sizeof(header_), 0);\n+\t\tif (ret < 0) {\n+\t\t\tret = -errno;\n+\t\t\tLOG(IPCUnixSocket, Error)\n+\t\t\t\t<< \"Failed to receive header: \" << strerror(-ret);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\theaderReceived_ = true;\n+\t}\n+\n+\t/*\n+\t * If the payload has arrived, disable the notifier and emit the\n+\t * readyRead signal. The notifier will be reenabled by the receive()\n+\t * method.\n+\t */\n+\tstruct pollfd fds = { fd_, POLLIN, 0 };\n+\tret = poll(&fds, 1, 0);\n+\tif (ret < 0)\n+\t\treturn;\n+\n+\tif (!(fds.revents & POLLIN))\n+\t\treturn;\n+\n+\tnotifier_->setEnabled(false);\n \treadyRead.emit(this);\n }\n \n", "prefixes": [ "libcamera-devel", "v4", "3/3" ] }