Show a patch.

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

{
    "id": 22425,
    "url": "https://patchwork.libcamera.org/api/patches/22425/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/22425/",
    "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": "<20241220145556.3011657-1-julien.vuillaumier@nxp.com>",
    "date": "2024-12-20T14:55:56",
    "name": "libcamera: ipc_unixsocket: Fix sendSync() timeout and hang",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "d852e4de237eb9eb4f30dfef64228d03b4e6abda",
    "submitter": {
        "id": 190,
        "url": "https://patchwork.libcamera.org/api/people/190/?format=api",
        "name": "Julien Vuillaumier",
        "email": "julien.vuillaumier@nxp.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/22425/mbox/",
    "series": [
        {
            "id": 4922,
            "url": "https://patchwork.libcamera.org/api/series/4922/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4922",
            "date": "2024-12-20T14:55:56",
            "name": "libcamera: ipc_unixsocket: Fix sendSync() timeout and hang",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4922/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/22425/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/22425/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id CD023C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 20 Dec 2024 14:55:51 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B061568499;\n\tFri, 20 Dec 2024 15:55:50 +0100 (CET)",
            "from EUR05-VI1-obe.outbound.protection.outlook.com\n\t(mail-vi1eur05on20621.outbound.protection.outlook.com\n\t[IPv6:2a01:111:f403:2613::621])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6503367F24\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 20 Dec 2024 15:55:49 +0100 (CET)",
            "from AM9PR04MB8147.eurprd04.prod.outlook.com\n\t(2603:10a6:20b:3e0::22)\n\tby AM8PR04MB7233.eurprd04.prod.outlook.com (2603:10a6:20b:1df::15)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8272.16;\n\tFri, 20 Dec 2024 14:55:47 +0000",
            "from AM9PR04MB8147.eurprd04.prod.outlook.com\n\t([fe80::eace:e980:28a4:ef8a]) by\n\tAM9PR04MB8147.eurprd04.prod.outlook.com\n\t([fe80::eace:e980:28a4:ef8a%5]) with mapi id 15.20.8272.005;\n\tFri, 20 Dec 2024 14:55:47 +0000"
        ],
        "Authentication-Results": [
            "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"Skd8dR7a\";\n\tdkim-atps=neutral",
            "dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=nxp.com;"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n\tb=NTAN/aQ6iOohH+NGqcrhAkSfh+/lgjfpkv4n9CemuQEPnO3C7Pr+CjviUlxWdwccjXd1lP78wCuDyizu3yfebwkn1qPwaDviAl+1yGfZla/w3WOzVulZpaJMMoWdXS+PQ0CK+7ygFvARWls84BcbzWew7RsfF/77AGBqaXo3L0KkQa6LSqBAyj8LJITb99Sysvjkn7aJ18zg0o5RNmKKYXsQerAk8y7uJunVZdtERd4HuuscKV3AjBt1eBt6BDrHCFyDNhWC5RO2tZxVjdRtx7pB1ybbhrdXZSbf6Y6tId4VLeAMWdvELz7zFHr7ktpertk1XNMPv/DPTu7a5ohbUA==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=arcselector10001;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n\tbh=SHFG78aODsDRWyQz92uOVrJg6IRGX6Aj2c7TGPjglus=;\n\tb=QAgwV5MMZ1cnC0XTiAn6WC1jR6vVNheLPHVEBoddMIIa5hy9rJsq0TVHc7J9CF8uY0asSEP6VgQd7/YoDXm3mxIFErz7J2hzk0QdsE/6EfVDvi9VG1W5elGrC5aP0nGrOL5h5l0TyoKyOIw13fewYzBAMxitZPYliBFX21BYYggHVoLsvfgP9IeuoMmA1d9/A0CAw2kTCNmso7Wsqg5SUUBrgbAF/10mN1y+EnKF8kPBwT2863LrXbWlxk/adj6DdeK3jT0SPHA8UR0clBdmyrOPiXRdPh08dumtAru7aLaAt4Gr2J/Jw4Ad2hNsyCGpU9EVulu7vm9bdTjmtJgr2A==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n\tsmtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com;\n\tdkim=pass header.d=nxp.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=SHFG78aODsDRWyQz92uOVrJg6IRGX6Aj2c7TGPjglus=;\n\tb=Skd8dR7aEa8LlIgjGe5qDfOQiaXa3SemKsQIvVqxi7/WK0X5odsThMUjq5AuIeu7VhUKWRWFMYmxmnTcxytbSpM14FHdGIWQO+Zsz4HDI0SQfcwxF7Ru5hc4MwbQOfUiYXmH5t2K1BKKTIluJyXOR3Hn+tNXAxzvYZbP5i3xBVKnyirvFQCSEpA5fTNFPGspBln68T2Sn2w5pe43tnK9ILB0Gp3oe3azO/fXimpZcr7cAoRTYrJ1KbvB1+M7+Fei1NLq/V6DGe6bTZJc0xsuuDk/umzHtOBRd2nkDbUrY4M49j0BvmchSc/OTOSu4JJbpqnUgPC2kVXEVkDPhVAo8w==",
        "From": "Julien Vuillaumier <julien.vuillaumier@nxp.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Julien Vuillaumier <julien.vuillaumier@nxp.com>",
        "Subject": "[PATCH] libcamera: ipc_unixsocket: Fix sendSync() timeout and hang",
        "Date": "Fri, 20 Dec 2024 15:55:56 +0100",
        "Message-Id": "<20241220145556.3011657-1-julien.vuillaumier@nxp.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "AS4P250CA0028.EURP250.PROD.OUTLOOK.COM\n\t(2603:10a6:20b:5e3::16) To AM9PR04MB8147.eurprd04.prod.outlook.com\n\t(2603:10a6:20b:3e0::22)",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "AM9PR04MB8147:EE_|AM8PR04MB7233:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "5d31faf3-5e38-4c0b-0043-08dd2106632d",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;\n\tARA:13230040|1800799024|376014|52116014|366016|38350700014; ",
        "X-Microsoft-Antispam-Message-Info": "BcT5FUt6mYf5WYOjJpxe/K4sQ503jdEb3ZJiWt57dxbYUFfi9IPKZHs7lZqoAjYaGvf8xJITs+Ea9RlraivT2si8WTgwj1gQWOPU5wPdBoo5iiKMFx31An0gNh/ji8fq2m1YHL8H6uP3iuYjYF04kR7uQ5cxDmivu6SGhaUsL93cnvOoe5Pw3z1xgByRQofNmO6xgWzSwDinTwQSrL/VAVT0FeWUIF22i1daaoB7+8sqWKeH6xSJCfxQOPqREn3LWdx38FH+JNH1fDt4b/k5WjwReT8d7EYErAexfjafv7FoHZAM6HWEUa2qwtHbCU4iciTGzz5bEZDn9rNojypBmdk31FRfJqW4tD1qDdeyz3HPPnacrzDPJEZ0ExK5/O3LwsAy2Aug/LODfnC+lLCgC7vcYiE39vUJN2kQ2n/7NpRdu5NCG0P3xYN0vCzBLaqXy0m8t4ljKxw6Wj+WotbR1OgR2OviuIZnibZvCjGlv9HwOmhJfPFmxAJvMTLLGAd+n4naJ4qWz8/FV7iX4L2M5F/4I+ijH6PtYqIEXIs1akphn3S7U6dDCAuSORLGUghFP9jYrzmuv5FRupt7/EnK2lJw0vDj/igWPkBxc7mm/CiPlpItApaRp/kcTse/Vzto3HlbnyTCOw/De9JYNI6RZue2v5jV6w8x1qvNmcagQn3D6SK3EZkR+H0o/IyKjqekXPxhSpBh2pflBH4cTQ40dMHJ+NMzF6TkKudiWxQBiGNejmV1KoYvv173A83V1wlTQ9f5/SVbWBySmKsnlgPxjNfg2X6DAFrc3oFcxA59Hq6XNDGbj3FTHQv4s0td4W4zvL8NYKOFJJDr7UhYc6PNk64ImTyXMwx+uEKVfJ/+PmoSNXzAR4+flKGIC1f4KqMFh+lyy1fnOhgtUwAhlHk8KYQENh138EfTwomGnTI8kCyjGpboZFr14xYrVCQIK91JbrROAe6OXiUXYaFktVgpqU5l6RkkX+J+sc1lzhbrBx81uwubtdpCYSSQ56ItMTpJQyUsKfq2Jz1GuYr817vcKYh4rByeudpIEQ6sXFca/folEMg0q6I3wOlebaZTUrbZK3J7GNgbOIezLfzm/9nC4w+KKcgEpmbt97FD5N/SL0y9zMvyh7HxpirHYbYxWPesKojo6PofaSvQWFAPFo8OeKyVgJkcLQ4LVGONwgvXuj+9TRpKPzGt3HHQwP+heKCyGgt9XC0hPByRd2n9uNJNYEKvm0+O6Wjqom05d5cqdWDgyebgHd2rTsuyKQ9BYsSX/I+VBxh3JbSszzNwFJojnSRtmKZRUwxhUNOMybRD5kc3mZEX7sAdLWeYiHRACey4DMDYheLE/LQjiRKaF/dNBRmnVFjcmQdnD5AeXZQ14lFqgduiWarhv7PtIuZ8iXMD5GFnLz58jHKHxDHnCpPP5huKFKbrum0yhQP6YcP3TjxnuilToTAZLupMmkFJlpiW",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:AM9PR04MB8147.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230040)(1800799024)(376014)(52116014)(366016)(38350700014);\n\tDIR:OUT; SFP:1101; ",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "cOX5512XW6N2EZQFaptfH6pEsvlhb6YXe/JIOJ4HI+MSsZnPWX/bdJp/oLwHaIap/xOopLOP8NRzE7p6XMr4XIJwy3dJ8BeMuK1YR4WtjGN3HCW0pwbO8c1/DlUgiWwbH83C9aqRvkCLrASN6KSODBxRkuYvltzZyLYMvM1SyD/fgLEWMoAK9OlpmIDQAKrkCyYiA4y4Zb0Mt89FTNXk0uY5n4EgtB4iWuDJuiup9vT8t+tXleZVvAdjtXB4v8DhF63DRUtCEwBeWt37GpqNDBw8puHEXuUCy68fCPLRWP6onX3EySyflOtOw8VlwjNY/rHkFHMFfW1mmQ3vigMXNEyEy9rJKRuqtGdFyBjvXUoN/5sBhSpQhil0lYAMiiCqK7kNjI0gPOoy5NfIVy4j6ugSONMd6Y8JkiBFcH0cYNVBJyG96PgTJqa8uKsek3ANa7/WvuxMe2Y/ALc+dsNY6cqvPGGYdsRUtz6yNLMB+fcawWBcvAYMal3+pFDXb9u9/i2awrgj86ePjmt37xRJMcUSDMPwHGQPrG5GC5lfeaqHEURH8Bs3Pu8MDZmk5LFgDm4PBIHvmoTAAnJVjMnYXrksSsTz0mMPqr2x52/7M1adQ1fk7sN3UJ+n6vBGWHb1yGkERqPI6MYrWel97w/KPfnKCmOkW7WKooVlBNu34d0kY3MwjIxchTQkYmoLtcWnrMiQClHitBaWsFcoTSX/PXNHLS1tf+dEE/bRHiAMGOgeiGllz/gPE5NqhXa1iy7cPBdH1s1KOV7abf+Kithv2i9stinV394hGdnVkXwjll6dygiPtqCA1vPI7qP76BPiCnrm8ElRAEWNxEaEgWGX6zJ0QDnXFenvDqJMe3W7pvDxfmaMFvW3NmhQ/0JpwJrcpRCEGYjQqAxJEXrNHhUDPt9I2cVk1HUltR2GdgdWjuUIPID/Z9jmCvXYmnU15+SJU6Q22UVSo8QT6py7ArSu8TJ/J/Uk9sEqfWkevVIy3h2ekw3zzc9cPjtcVwxJU7lSJcHoyNVI/d10nOJVmLGDboviFOYCq0UanEik5crmLPvlBjk0LZ4z+c72jO+yxJlbb/mSRd3OpsqF4SczOS2Qsa8E/fzANWrIWGlmZ2knoJYBrto6qX8fhTOob/E/GFzVnyGU3QP8oifHc8yXz92xjrDsFyYsFZYTpzAE9jliP3vq0IACXwO7Sy/onnb3KleUAotppkMIc0h8wAbnsB8iuWHyBVl9a1zBBpIvm2nVilW+xTJx6JnKYq/XvMIxKQFTlQh/m/1eMBtHqu1py4zeKFLuWJWx9mUHa3YnQ+UgsKujPR3y4NMHcbD5lZOq26t8BeDkSHq+Ip1VF4kIgq/gD8IlknvG2eUFDhvu8DrI9qYn2zE5YHDyh8EEM89nZHF3qRreNsP17VrIZUKbKptpPd6q5p63EFfSZyuKe66SMfZEwlRjXPkR7U5RhIhsia1OSErEaFRr2rQAGBJHbEpwnzmFn8rq/kS7e2o4C7wnsuPJFXPnSmxTBQIRcspT3ncuzgqLgFZjwrd6bsOYFh8Elfcxa+TEvB3ntemJvCDmhCVOT31tL4+NslOylsauaBckC+yCE8G91y3FwmvbVQo+ZQ==",
        "X-OriginatorOrg": "nxp.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "5d31faf3-5e38-4c0b-0043-08dd2106632d",
        "X-MS-Exchange-CrossTenant-AuthSource": "AM9PR04MB8147.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "20 Dec 2024 14:55:47.5492\n\t(UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "686ea1d3-bc2b-4c6f-a92c-d99c5c301635",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "gJn/pb02YJig3BsgZfhUmJxa07pArSdoXnr2jr4FfE2D5G83VcORD+zAMkeq3+zo09/kXCRvYZN1sHurTGxsUDBhSNsS5yTe8+0uJMWkt9k=",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AM8PR04MB7233",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "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>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Unix-socket based IPC sometimes times out or hangs, typically\nwhen multiple camera are stopped simulaneously. That specific case\ntriggers the concurrent sending by each pipeline handler instance\nof a synchronous stop() message to its peer IPA process.\n\nThere is a dedicated IPC socket per camera. Sockets payload receipt\nsignals all run in the camera manager thread.\nTo send a synchronous message to IPA, pipeline invokes from camera\nthread IPCPipeUnixSocket::sendSync(). This sends the message then blocks\nbusy waiting for the peer acknowledgment. Such busy wait is done by\nblocking on event loop calling dispatchEvent(), until the ack condition\nis detected.\n\nOne issue is that the socket receive slot readyRead() wakes up the\nblocked thread via libcamera::Message receipt. Even though such message\nresumes processEvents(), it may reblock immediately because readyRead()\ndoes not interrupt() explictly the dispatcher.\nMost of the time, an other pending event for the thread unblocks the\nevent dispatcher and the ack condition is detected - in worst case the 2\nsec timeout kicks in. Once unblocked, the dispatcher let the message\nacknowledgment to be detected and the sendSync() completes.\n\nThe other issue is that in case of concurrent synchronous IPC messages\nsent by multiple pipeline handlers, there is a possible recursion\nof sendSync() / processEvents() nested in the camera thread stack. As\ncommented in the source, that is a dangerous construct that can lead to\na hang.\nThe reason is that the last synchronous message sent is the deepest in\nthe stack. It is also the one whose acknowledgment is being busy waited.\nHowever other pending synchronous messages may have been initiated before\nand are upper in the stack. If they timeout, the condition is not\ndetected because of the stack recursion, as the thread is busy waiting\nfor the last message to be acknowledged.\n\nThis change implements a safer mechanism to handle the synchronous\nmessage sending, similar to the one used for non isolated IPA. The\nIPCUnixSocketWrapper class is introduced to handle the IPCUnixSocket\nreceive signal in a dedicated thread.\nDoing so, the sending thread, when emiting a synchronous message, can be\nblocked without event dispatcher's processEvents() usage, which avoids\nthe risky stack recursion.\n\nFixes: 21f1b555b (\"libcamera: Add IPCPipe implementation based on unix socket\")\n\nSigned-off-by: Julien Vuillaumier <julien.vuillaumier@nxp.com>\n---\n .../libcamera/internal/ipc_pipe_unixsocket.h  |  13 +-\n src/libcamera/ipc_pipe_unixsocket.cpp         | 242 +++++++++++++-----\n 2 files changed, 178 insertions(+), 77 deletions(-)",
    "diff": "diff --git a/include/libcamera/internal/ipc_pipe_unixsocket.h b/include/libcamera/internal/ipc_pipe_unixsocket.h\nindex 8c972613..280639d5 100644\n--- a/include/libcamera/internal/ipc_pipe_unixsocket.h\n+++ b/include/libcamera/internal/ipc_pipe_unixsocket.h\n@@ -16,6 +16,7 @@\n namespace libcamera {\n \n class Process;\n+class IPCUnixSocketWrapper;\n \n class IPCPipeUnixSocket : public IPCPipe\n {\n@@ -29,18 +30,8 @@ public:\n \tint sendAsync(const IPCMessage &data) override;\n \n private:\n-\tstruct CallData {\n-\t\tIPCUnixSocket::Payload *response;\n-\t\tbool done;\n-\t};\n-\n-\tvoid readyRead();\n-\tint call(const IPCUnixSocket::Payload &message,\n-\t\t IPCUnixSocket::Payload *response, uint32_t seq);\n-\n \tstd::unique_ptr<Process> proc_;\n-\tstd::unique_ptr<IPCUnixSocket> socket_;\n-\tstd::map<uint32_t, CallData> callData_;\n+\tstd::unique_ptr<IPCUnixSocketWrapper> socketWrap_;\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/ipc_pipe_unixsocket.cpp b/src/libcamera/ipc_pipe_unixsocket.cpp\nindex 668ec73b..eb5408d4 100644\n--- a/src/libcamera/ipc_pipe_unixsocket.cpp\n+++ b/src/libcamera/ipc_pipe_unixsocket.cpp\n@@ -9,10 +9,9 @@\n \n #include <vector>\n \n-#include <libcamera/base/event_dispatcher.h>\n #include <libcamera/base/log.h>\n+#include <libcamera/base/mutex.h>\n #include <libcamera/base/thread.h>\n-#include <libcamera/base/timer.h>\n \n #include \"libcamera/internal/ipc_pipe.h\"\n #include \"libcamera/internal/ipc_unixsocket.h\"\n@@ -24,67 +23,161 @@ namespace libcamera {\n \n LOG_DECLARE_CATEGORY(IPCPipe)\n \n-IPCPipeUnixSocket::IPCPipeUnixSocket(const char *ipaModulePath,\n-\t\t\t\t     const char *ipaProxyWorkerPath)\n-\t: IPCPipe()\n+class IPCUnixSocketWrapper : Thread\n {\n-\tstd::vector<int> fds;\n-\tstd::vector<std::string> args;\n-\targs.push_back(ipaModulePath);\n+public:\n+\tIPCUnixSocketWrapper(Signal<const IPCMessage &> *recv)\n+\t\t: recv_(recv), ready_(false), sendSyncPending_(false),\n+\t\t  sendSyncCookie_(0)\n+\t{\n+\t\tstart();\n+\t}\n \n-\tsocket_ = std::make_unique<IPCUnixSocket>();\n-\tUniqueFD fd = socket_->create();\n-\tif (!fd.isValid()) {\n-\t\tLOG(IPCPipe, Error) << \"Failed to create socket\";\n-\t\treturn;\n+\t~IPCUnixSocketWrapper()\n+\t{\n+\t\texit();\n+\t\twait();\n \t}\n-\tsocket_->readyRead.connect(this, &IPCPipeUnixSocket::readyRead);\n-\targs.push_back(std::to_string(fd.get()));\n-\tfds.push_back(fd.get());\n \n-\tproc_ = std::make_unique<Process>();\n-\tint ret = proc_->start(ipaProxyWorkerPath, args, fds);\n-\tif (ret) {\n-\t\tLOG(IPCPipe, Error)\n-\t\t\t<< \"Failed to start proxy worker process\";\n-\t\treturn;\n+\tvoid run() override\n+\t{\n+\t\t/*\n+\t\t * IPC socket construction and connection to its readyRead\n+\t\t * signal has to be done from the IPC thread so that the\n+\t\t * relevant Object instances (EventNotifier, slot) are bound to\n+\t\t * its context.\n+\t\t */\n+\t\tinit();\n+\t\texec();\n+\t\tdeinit();\n \t}\n \n-\tconnected_ = true;\n-}\n+\tint fd() { return fd_.get(); }\n+\tint sendSync(const IPCMessage &in, IPCMessage *out);\n+\tint sendAsync(const IPCMessage &data);\n+\tbool waitReady();\n \n-IPCPipeUnixSocket::~IPCPipeUnixSocket()\n-{\n-}\n+private:\n+\tvoid init();\n+\tvoid deinit();\n+\tvoid readyRead();\n \n-int IPCPipeUnixSocket::sendSync(const IPCMessage &in, IPCMessage *out)\n+\tUniqueFD fd_;\n+\tSignal<const IPCMessage &> *recv_;\n+\tConditionVariable cv_;\n+\tMutex mutex_;\n+\tbool ready_;\n+\tbool sendSyncPending_;\n+\tuint32_t sendSyncCookie_;\n+\tIPCUnixSocket::Payload *sendSyncResponse_;\n+\n+\t/* Socket shall be constructed and destructed from IPC thread context */\n+\tstd::unique_ptr<IPCUnixSocket> socket_;\n+};\n+\n+int IPCUnixSocketWrapper::sendSync(const IPCMessage &in, IPCMessage *out)\n {\n+\tint ret;\n \tIPCUnixSocket::Payload response;\n \n-\tint ret = call(in.payload(), &response, in.header().cookie);\n+\tmutex_.lock();\n+\tASSERT(!sendSyncPending_);\n+\tsendSyncPending_ = true;\n+\tsendSyncCookie_ = in.header().cookie;\n+\tsendSyncResponse_ = &response;\n+\tmutex_.unlock();\n+\n+\tret = socket_->send(in.payload());\n \tif (ret) {\n-\t\tLOG(IPCPipe, Error) << \"Failed to call sync\";\n-\t\treturn ret;\n+\t\tLOG(IPCPipe, Error) << \"Failed to send sync message\";\n+\t\tgoto cleanup;\n+\t}\n+\n+\tbool complete;\n+\t{\n+\t\tMutexLocker locker(mutex_);\n+\t\tauto syncComplete = ([&]() {\n+\t\t\treturn sendSyncPending_ == false;\n+\t\t});\n+\t\tcomplete = cv_.wait_for(locker, 1000ms, syncComplete);\n+\t}\n+\n+\tif (!complete) {\n+\t\tLOG(IPCPipe, Error) << \"Timeout sending sync message\";\n+\t\tret = -ETIMEDOUT;\n+\t\tgoto cleanup;\n \t}\n \n \tif (out)\n \t\t*out = IPCMessage(response);\n \n \treturn 0;\n+\n+cleanup:\n+\tmutex_.lock();\n+\tsendSyncPending_ = false;\n+\tmutex_.unlock();\n+\n+\treturn ret;\n }\n \n-int IPCPipeUnixSocket::sendAsync(const IPCMessage &data)\n+int IPCUnixSocketWrapper::sendAsync(const IPCMessage &data)\n {\n-\tint ret = socket_->send(data.payload());\n-\tif (ret) {\n-\t\tLOG(IPCPipe, Error) << \"Failed to call async\";\n-\t\treturn ret;\n+\tint ret;\n+\tret = socket_->send(data.payload());\n+\tif (ret)\n+\t\tLOG(IPCPipe, Error) << \"Failed to send sync message\";\n+\treturn ret;\n+}\n+\n+bool IPCUnixSocketWrapper::waitReady()\n+{\n+\tbool ready;\n+\t{\n+\t\tMutexLocker locker(mutex_);\n+\t\tauto isReady = ([&]() {\n+\t\t\treturn ready_;\n+\t\t});\n+\t\tready = cv_.wait_for(locker, 1000ms, isReady);\n \t}\n \n-\treturn 0;\n+\treturn ready;\n+}\n+\n+void IPCUnixSocketWrapper::init()\n+{\n+\t/* Init is to be done from the IPC thread context */\n+\tASSERT(Thread::current() == this);\n+\n+\tsocket_ = std::make_unique<IPCUnixSocket>();\n+\tfd_ = socket_->create();\n+\tif (!fd_.isValid()) {\n+\t\tLOG(IPCPipe, Error) << \"Failed to create socket\";\n+\t\treturn;\n+\t}\n+\n+\tsocket_->readyRead.connect(this, &IPCUnixSocketWrapper::readyRead);\n+\n+\tmutex_.lock();\n+\tready_ = true;\n+\tmutex_.unlock();\n+\tcv_.notify_one();\n }\n \n-void IPCPipeUnixSocket::readyRead()\n+void IPCUnixSocketWrapper::deinit()\n+{\n+\t/* Deinit is to be done from the IPC thread context */\n+\tASSERT(Thread::current() == this);\n+\n+\tsocket_->readyRead.disconnect(this);\n+\tsocket_.reset();\n+\n+\tmutex_.lock();\n+\tready_ = false;\n+\tmutex_.unlock();\n+}\n+\n+void IPCUnixSocketWrapper::readyRead()\n {\n \tIPCUnixSocket::Payload payload;\n \tint ret = socket_->receive(&payload);\n@@ -93,55 +186,72 @@ void IPCPipeUnixSocket::readyRead()\n \t\treturn;\n \t}\n \n-\t/* \\todo Use span to avoid the double copy when callData is found. */\n \tif (payload.data.size() < sizeof(IPCMessage::Header)) {\n \t\tLOG(IPCPipe, Error) << \"Not enough data received\";\n \t\treturn;\n \t}\n \n-\tIPCMessage ipcMessage(payload);\n+\tconst IPCMessage::Header *header =\n+\t\treinterpret_cast<IPCMessage::Header *>(payload.data.data());\n+\tbool syncComplete = false;\n+\tmutex_.lock();\n+\tif (sendSyncPending_ && sendSyncCookie_ == header->cookie) {\n+\t\tsyncComplete = true;\n+\t\tsendSyncPending_ = false;\n+\t\t*sendSyncResponse_ = std::move(payload);\n+\t}\n+\tmutex_.unlock();\n \n-\tauto callData = callData_.find(ipcMessage.header().cookie);\n-\tif (callData != callData_.end()) {\n-\t\t*callData->second.response = std::move(payload);\n-\t\tcallData->second.done = true;\n+\tif (syncComplete) {\n+\t\tcv_.notify_one();\n \t\treturn;\n \t}\n \n \t/* Received unexpected data, this means it's a call from the IPA. */\n-\trecv.emit(ipcMessage);\n+\tIPCMessage ipcMessage(payload);\n+\trecv_->emit(ipcMessage);\n }\n \n-int IPCPipeUnixSocket::call(const IPCUnixSocket::Payload &message,\n-\t\t\t    IPCUnixSocket::Payload *response, uint32_t cookie)\n+IPCPipeUnixSocket::IPCPipeUnixSocket(const char *ipaModulePath,\n+\t\t\t\t     const char *ipaProxyWorkerPath)\n+\t: IPCPipe()\n {\n-\tTimer timeout;\n-\tint ret;\n+\tsocketWrap_ = std::make_unique<IPCUnixSocketWrapper>(&recv);\n+\tif (!socketWrap_->waitReady()) {\n+\t\tLOG(IPCPipe, Error) << \"Failed to create socket\";\n+\t\treturn;\n+\t}\n+\tint fd = socketWrap_->fd();\n \n-\tconst auto result = callData_.insert({ cookie, { response, false } });\n-\tconst auto &iter = result.first;\n+\tstd::vector<int> fds;\n+\tstd::vector<std::string> args;\n+\targs.push_back(ipaModulePath);\n+\targs.push_back(std::to_string(fd));\n+\tfds.push_back(fd);\n \n-\tret = socket_->send(message);\n+\tproc_ = std::make_unique<Process>();\n+\tint ret = proc_->start(ipaProxyWorkerPath, args, fds);\n \tif (ret) {\n-\t\tcallData_.erase(iter);\n-\t\treturn ret;\n+\t\tLOG(IPCPipe, Error)\n+\t\t\t<< \"Failed to start proxy worker process\";\n+\t\treturn;\n \t}\n \n-\t/* \\todo Make this less dangerous, see IPCPipe::sendSync() */\n-\ttimeout.start(2000ms);\n-\twhile (!iter->second.done) {\n-\t\tif (!timeout.isRunning()) {\n-\t\t\tLOG(IPCPipe, Error) << \"Call timeout!\";\n-\t\t\tcallData_.erase(iter);\n-\t\t\treturn -ETIMEDOUT;\n-\t\t}\n+\tconnected_ = true;\n+}\n \n-\t\tThread::current()->eventDispatcher()->processEvents();\n-\t}\n+IPCPipeUnixSocket::~IPCPipeUnixSocket()\n+{\n+}\n \n-\tcallData_.erase(iter);\n+int IPCPipeUnixSocket::sendSync(const IPCMessage &in, IPCMessage *out)\n+{\n+\treturn socketWrap_->sendSync(in, out);\n+}\n \n-\treturn 0;\n+int IPCPipeUnixSocket::sendAsync(const IPCMessage &data)\n+{\n+\treturn socketWrap_->sendAsync(data);\n }\n \n } /* namespace libcamera */\n",
    "prefixes": []
}