[{"id":2645,"web_url":"https://patchwork.libcamera.org/comment/2645/","msgid":"<1eb321f0-88a3-ec43-594b-96e21ba9de76@ideasonboard.com>","date":"2019-09-13T09:14:32","subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 12/09/2019 21:03, Laurent Pinchart wrote:\n> Some media devices, such as V4L2 M2M devices, share the same device node\n> for multiple entities. The udev enumerator used to support this, but\n> commit 6e620349009d (\"libcamera: device_enumerator: fix udev media graph\n> loading dependency\") broke this.\n> \n> To fix the problem, rework the media device to V4L2 devices matching\n> code. A new MediaDeviceDeps internal struct stores unmet device number\n> dependencies for a media device, and is stored in a list of pending\n> media devices. To avoid linear lookups, the dependencies are cached in a\n> reverse map of device number to media device dependencies.\n> \n> Fixes: 6e620349009d (\"libcamera: device_enumerator: fix udev media graph loading dependency\")\n\nThis fixes the issue I reported.\n\nTested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nAnd I can't see anything glaring out at me in the code - so LGTM:\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/libcamera/device_enumerator_udev.cpp      | 100 ++++++++++++------\n>  .../include/device_enumerator_udev.h          |  25 ++++-\n>  2 files changed, 89 insertions(+), 36 deletions(-)\n> \n> diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp\n> index c40770911d3d..ddcd59ea52c1 100644\n> --- a/src/libcamera/device_enumerator_udev.cpp\n> +++ b/src/libcamera/device_enumerator_udev.cpp\n> @@ -170,8 +170,8 @@ done:\n>  \n>  int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice> &media)\n>  {\n> -\tunsigned int pendingNodes = 0;\n> -\tint ret;\n> +\tstd::set<dev_t> children;\n> +\tDependencyMap deps;\n>  \n>  \t/* Associate entities to device node paths. */\n>  \tfor (MediaEntity *entity : media->entities()) {\n> @@ -181,28 +181,50 @@ int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice>\n>  \t\tdev_t devnum = makedev(entity->deviceMajor(),\n>  \t\t\t\t       entity->deviceMinor());\n>  \n> -\t\t/* Take device from orphan list first, if it is in the list. */\n> -\t\tauto orphan = std::find(orphans_.begin(), orphans_.end(), devnum);\n> -\t\tif (orphan != orphans_.end()) {\n> -\t\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> -\t\t\tif (deviceNode.empty())\n> -\t\t\t\treturn -EINVAL;\n> -\n> -\t\t\tret = entity->setDeviceNode(deviceNode);\n> -\t\t\tif (ret)\n> -\t\t\t\treturn ret;\n> -\n> -\t\t\torphans_.erase(orphan);\n> +\t\t/*\n> +\t\t * If the devnum isn't in the orphans list, add it to the unmet\n> +\t\t * dependencies.\n> +\t\t */\n> +\t\tif (orphans_.find(devnum) == orphans_.end()) {\n> +\t\t\tdeps[devnum].push_back(entity);\n>  \t\t\tcontinue;\n>  \t\t}\n>  \n> -\t\tdeps_[media].push_back(devnum);\n> -\t\tdevnumToDevice_[devnum] = media;\n> -\t\tdevnumToEntity_[devnum] = entity;\n> -\t\tpendingNodes++;\n> +\t\t/*\n> +\t\t * Otherwise take it from the orphans list. Don't remove the\n> +\t\t * entry from the list yet as other entities in this media\n> +\t\t * device may need the same device.\n> +\t\t */\n> +\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> +\t\tif (deviceNode.empty())\n> +\t\t\treturn -EINVAL;\n> +\n> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tchildren.insert(devnum);\n> +\t}\n> +\n> +\t/* Remove all found children from the orphans list. */\n> +\tfor (auto it = orphans_.begin(), last = orphans_.end(); it != last;) {\n> +\t\tif (children.find(*it) != children.end())\n> +\t\t\tit = orphans_.erase(it);\n> +\t\telse\n> +\t\t\t++it;\n> +\t}\n> +\n> +\t/*\n> +\t * If the media device has unmet dependencies, add it to the pending\n> +\t * list and update the devnum map accordingly.\n> +\t */\n> +\tif (!deps.empty()) {\n> +\t\tpending_.emplace_back(media, deps);\n> +\t\tfor (const auto &dep : deps)\n> +\t\t\tdevMap_[dep.first] = &pending_.back();\n>  \t}\n>  \n> -\treturn pendingNodes;\n> +\treturn deps.size();\n>  }\n>  \n>  /**\n> @@ -247,28 +269,42 @@ std::string DeviceEnumeratorUdev::lookupDeviceNode(dev_t devnum)\n>   */\n>  int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)\n>  {\n> -\tMediaEntity *entity = devnumToEntity_[devnum];\n> -\tif (!entity) {\n> -\t\torphans_.push_back(devnum);\n> +\t/*\n> +\t * If the devnum doesn't belong to any media device, add it to the\n> +\t * orphans list.\n> +\t */\n> +\tauto it = devMap_.find(devnum);\n> +\tif (it == devMap_.end()) {\n> +\t\torphans_.insert(devnum);\n>  \t\treturn 0;\n>  \t}\n>  \n> +\t/*\n> +\t * Set the device node for all entities matching the devnum. Multiple\n> +\t * entities can share the same device node, for instance for V4L2 M2M\n> +\t * devices.\n> +\t */\n>  \tstd::string deviceNode = lookupDeviceNode(devnum);\n>  \tif (deviceNode.empty())\n>  \t\treturn -EINVAL;\n>  \n> -\tint ret = entity->setDeviceNode(deviceNode);\n> -\tif (ret)\n> -\t\treturn ret;\n> +\tMediaDeviceDeps *deps = it->second;\n> +\tfor (MediaEntity *entity : deps->deps_[devnum]) {\n> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\t}\n>  \n> -\tstd::shared_ptr<MediaDevice> media = devnumToDevice_[devnum];\n> -\tdeps_[media].remove(devnum);\n> -\tdevnumToDevice_.erase(devnum);\n> -\tdevnumToEntity_.erase(devnum);\n> +\t/*\n> +\t * Remove the devnum from the unmet dependencies for this media device.\n> +\t * If no more dependency is unmet, add the media device to the\n> +\t * enumerator.\n> +\t */\n> +\tdeps->deps_.erase(devnum);\n>  \n> -\tif (deps_[media].empty()) {\n> -\t\taddDevice(media);\n> -\t\tdeps_.erase(media);\n> +\tif (deps->deps_.empty()) {\n> +\t\taddDevice(deps->media_);\n> +\t\tpending_.remove(*deps);\n>  \t}\n>  \n>  \treturn 0;\n> diff --git a/src/libcamera/include/device_enumerator_udev.h b/src/libcamera/include/device_enumerator_udev.h\n> index fb7cac8011a1..6d8268620185 100644\n> --- a/src/libcamera/include/device_enumerator_udev.h\n> +++ b/src/libcamera/include/device_enumerator_udev.h\n> @@ -10,6 +10,7 @@\n>  #include <list>\n>  #include <map>\n>  #include <memory>\n> +#include <set>\n>  #include <string>\n>  #include <sys/types.h>\n>  \n> @@ -39,11 +40,27 @@ private:\n>  \tstruct udev_monitor *monitor_;\n>  \tEventNotifier *notifier_;\n>  \n> -\tstd::map<std::shared_ptr<MediaDevice>, std::list<dev_t>> deps_;\n> -\tstd::map<dev_t, std::shared_ptr<MediaDevice>> devnumToDevice_;\n> -\tstd::map<dev_t, MediaEntity *> devnumToEntity_;\n> +\tusing DependencyMap = std::map<dev_t, std::list<MediaEntity *>>;\n>  \n> -\tstd::list<dev_t> orphans_;\n> +\tstruct MediaDeviceDeps {\n> +\t\tMediaDeviceDeps(const std::shared_ptr<MediaDevice> &media,\n> +\t\t\t\tconst DependencyMap &deps)\n> +\t\t\t: media_(media), deps_(deps)\n> +\t\t{\n> +\t\t}\n> +\n> +\t\tbool operator==(const MediaDeviceDeps &other) const\n> +\t\t{\n> +\t\t\treturn media_ == other.media_;\n> +\t\t}\n> +\n> +\t\tstd::shared_ptr<MediaDevice> media_;\n> +\t\tDependencyMap deps_;\n> +\t};\n> +\n> +\tstd::set<dev_t> orphans_;\n> +\tstd::list<MediaDeviceDeps> pending_;\n> +\tstd::map<dev_t, MediaDeviceDeps *> devMap_;\n>  \n>  \tint addUdevDevice(struct udev_device *dev);\n>  \tint populateMediaDevice(const std::shared_ptr<MediaDevice> &media);\n>","headers":{"Return-Path":"<kieran.bingham@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 5032D60BB0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Sep 2019 11:14:38 +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 A786D33A;\n\tFri, 13 Sep 2019 11:14:34 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1568366077;\n\tbh=jsRxsoNbdOR8cZTuLvbtS6L9BySwb3ybIlM4Evb9SXU=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=ojERa0uE0i1bp1eG3PH2sfNwPBPiaf1eV8eNrujhxJ5v8lYM8fLaC7odA5BL5lg4y\n\tLFqiuIBi5c5iTXf/alA5xrgz129W3ld/drMSoI+X/r2IwrRlBsIya9wSgmugY/vtl1\n\tdfqOFunfBbeLXnUHbDU78OXiAwNzRAXI8JwKGbtw=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190912200330.19004-1-laurent.pinchart@ideasonboard.com>\n\t<20190912200330.19004-5-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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","Organization":"Ideas on Board","Message-ID":"<1eb321f0-88a3-ec43-594b-96e21ba9de76@ideasonboard.com>","Date":"Fri, 13 Sep 2019 10:14:32 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.8.0","MIME-Version":"1.0","In-Reply-To":"<20190912200330.19004-5-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","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":"Fri, 13 Sep 2019 09:14:38 -0000"}},{"id":2649,"web_url":"https://patchwork.libcamera.org/comment/2649/","msgid":"<b00d44c3-4507-6d76-70f3-4e343e6b0fe5@ideasonboard.com>","date":"2019-09-13T10:10:23","subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 12/09/2019 21:03, Laurent Pinchart wrote:\n> Some media devices, such as V4L2 M2M devices, share the same device node\n> for multiple entities. The udev enumerator used to support this, but\n> commit 6e620349009d (\"libcamera: device_enumerator: fix udev media graph\n> loading dependency\") broke this.\n> \n> To fix the problem, rework the media device to V4L2 devices matching\n> code. A new MediaDeviceDeps internal struct stores unmet device number\n> dependencies for a media device, and is stored in a list of pending\n> media devices. To avoid linear lookups, the dependencies are cached in a\n> reverse map of device number to media device dependencies.\n> \n> Fixes: 6e620349009d (\"libcamera: device_enumerator: fix udev media graph loading dependency\")\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/libcamera/device_enumerator_udev.cpp      | 100 ++++++++++++------\n>  .../include/device_enumerator_udev.h          |  25 ++++-\n>  2 files changed, 89 insertions(+), 36 deletions(-)\n> \n> diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp\n> index c40770911d3d..ddcd59ea52c1 100644\n> --- a/src/libcamera/device_enumerator_udev.cpp\n> +++ b/src/libcamera/device_enumerator_udev.cpp\n> @@ -170,8 +170,8 @@ done:\n>  \n>  int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice> &media)\n>  {\n> -\tunsigned int pendingNodes = 0;\n> -\tint ret;\n> +\tstd::set<dev_t> children;\n> +\tDependencyMap deps;\n>  \n>  \t/* Associate entities to device node paths. */\n>  \tfor (MediaEntity *entity : media->entities()) {\n> @@ -181,28 +181,50 @@ int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice>\n>  \t\tdev_t devnum = makedev(entity->deviceMajor(),\n>  \t\t\t\t       entity->deviceMinor());\n>  \n> -\t\t/* Take device from orphan list first, if it is in the list. */\n> -\t\tauto orphan = std::find(orphans_.begin(), orphans_.end(), devnum);\n> -\t\tif (orphan != orphans_.end()) {\n> -\t\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> -\t\t\tif (deviceNode.empty())\n> -\t\t\t\treturn -EINVAL;\n> -\n> -\t\t\tret = entity->setDeviceNode(deviceNode);\n> -\t\t\tif (ret)\n> -\t\t\t\treturn ret;\n> -\n> -\t\t\torphans_.erase(orphan);\n> +\t\t/*\n> +\t\t * If the devnum isn't in the orphans list, add it to the unmet\n> +\t\t * dependencies.\n> +\t\t */\n> +\t\tif (orphans_.find(devnum) == orphans_.end()) {\n> +\t\t\tdeps[devnum].push_back(entity);\n>  \t\t\tcontinue;\n>  \t\t}\n>  \n> -\t\tdeps_[media].push_back(devnum);\n> -\t\tdevnumToDevice_[devnum] = media;\n> -\t\tdevnumToEntity_[devnum] = entity;\n> -\t\tpendingNodes++;\n> +\t\t/*\n> +\t\t * Otherwise take it from the orphans list. Don't remove the\n> +\t\t * entry from the list yet as other entities in this media\n> +\t\t * device may need the same device.\n> +\t\t */\n> +\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> +\t\tif (deviceNode.empty())\n> +\t\t\treturn -EINVAL;\n> +\n> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\tchildren.insert(devnum);\n> +\t}\n> +\n> +\t/* Remove all found children from the orphans list. */\n> +\tfor (auto it = orphans_.begin(), last = orphans_.end(); it != last;) {\n\nWhat 'type' is last? Where is it declared? Is this it's only use?\n\nIs it automatically defined as an auto? or an iterator?\n\nAnd is it needed? or can the loop exit check just compare against it  !=\norphans_.end() ?\n\n\n> +\t\tif (children.find(*it) != children.end())\n> +\t\t\tit = orphans_.erase(it);\n> +\t\telse\n> +\t\t\t++it;\n> +\t}\n> +\n> +\t/*\n> +\t * If the media device has unmet dependencies, add it to the pending\n> +\t * list and update the devnum map accordingly.\n> +\t */\n> +\tif (!deps.empty()) {\n> +\t\tpending_.emplace_back(media, deps);\n> +\t\tfor (const auto &dep : deps)\n> +\t\t\tdevMap_[dep.first] = &pending_.back();\n>  \t}\n>  \n> -\treturn pendingNodes;\n> +\treturn deps.size();\n>  }\n>  \n>  /**\n> @@ -247,28 +269,42 @@ std::string DeviceEnumeratorUdev::lookupDeviceNode(dev_t devnum)\n>   */\n>  int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)\n>  {\n> -\tMediaEntity *entity = devnumToEntity_[devnum];\n> -\tif (!entity) {\n> -\t\torphans_.push_back(devnum);\n> +\t/*\n> +\t * If the devnum doesn't belong to any media device, add it to the\n> +\t * orphans list.\n> +\t */\n> +\tauto it = devMap_.find(devnum);\n> +\tif (it == devMap_.end()) {\n> +\t\torphans_.insert(devnum);\n>  \t\treturn 0;\n>  \t}\n>  \n> +\t/*\n> +\t * Set the device node for all entities matching the devnum. Multiple\n> +\t * entities can share the same device node, for instance for V4L2 M2M\n> +\t * devices.\n> +\t */\n>  \tstd::string deviceNode = lookupDeviceNode(devnum);\n>  \tif (deviceNode.empty())\n>  \t\treturn -EINVAL;\n>  \n> -\tint ret = entity->setDeviceNode(deviceNode);\n> -\tif (ret)\n> -\t\treturn ret;\n> +\tMediaDeviceDeps *deps = it->second;\n> +\tfor (MediaEntity *entity : deps->deps_[devnum]) {\n> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\t}\n>  \n> -\tstd::shared_ptr<MediaDevice> media = devnumToDevice_[devnum];\n> -\tdeps_[media].remove(devnum);\n> -\tdevnumToDevice_.erase(devnum);\n> -\tdevnumToEntity_.erase(devnum);\n> +\t/*\n> +\t * Remove the devnum from the unmet dependencies for this media device.\n> +\t * If no more dependency is unmet, add the media device to the\n> +\t * enumerator.\n> +\t */\n> +\tdeps->deps_.erase(devnum);\n>  \n> -\tif (deps_[media].empty()) {\n> -\t\taddDevice(media);\n> -\t\tdeps_.erase(media);\n> +\tif (deps->deps_.empty()) {\n> +\t\taddDevice(deps->media_);\n> +\t\tpending_.remove(*deps);\n>  \t}\n>  \n>  \treturn 0;\n> diff --git a/src/libcamera/include/device_enumerator_udev.h b/src/libcamera/include/device_enumerator_udev.h\n> index fb7cac8011a1..6d8268620185 100644\n> --- a/src/libcamera/include/device_enumerator_udev.h\n> +++ b/src/libcamera/include/device_enumerator_udev.h\n> @@ -10,6 +10,7 @@\n>  #include <list>\n>  #include <map>\n>  #include <memory>\n> +#include <set>\n>  #include <string>\n>  #include <sys/types.h>\n>  \n> @@ -39,11 +40,27 @@ private:\n>  \tstruct udev_monitor *monitor_;\n>  \tEventNotifier *notifier_;\n>  \n> -\tstd::map<std::shared_ptr<MediaDevice>, std::list<dev_t>> deps_;\n> -\tstd::map<dev_t, std::shared_ptr<MediaDevice>> devnumToDevice_;\n> -\tstd::map<dev_t, MediaEntity *> devnumToEntity_;\n> +\tusing DependencyMap = std::map<dev_t, std::list<MediaEntity *>>;\n>  \n> -\tstd::list<dev_t> orphans_;\n> +\tstruct MediaDeviceDeps {\n> +\t\tMediaDeviceDeps(const std::shared_ptr<MediaDevice> &media,\n> +\t\t\t\tconst DependencyMap &deps)\n> +\t\t\t: media_(media), deps_(deps)\n> +\t\t{\n> +\t\t}\n> +\n> +\t\tbool operator==(const MediaDeviceDeps &other) const\n> +\t\t{\n> +\t\t\treturn media_ == other.media_;\n> +\t\t}\n> +\n> +\t\tstd::shared_ptr<MediaDevice> media_;\n> +\t\tDependencyMap deps_;\n> +\t};\n> +\n> +\tstd::set<dev_t> orphans_;\n> +\tstd::list<MediaDeviceDeps> pending_;\n> +\tstd::map<dev_t, MediaDeviceDeps *> devMap_;\n>  \n>  \tint addUdevDevice(struct udev_device *dev);\n>  \tint populateMediaDevice(const std::shared_ptr<MediaDevice> &media);\n>","headers":{"Return-Path":"<kieran.bingham@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 8F494600CA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Sep 2019 12:10:28 +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 EE29633A;\n\tFri, 13 Sep 2019 12:10:27 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1568369428;\n\tbh=OKvX7dKv6zr7PiTYSlKO0y3k9Ppv/HMsIVmhsiziW7g=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=KVAjW+K7zDLoTKozaH13PeOo98ifqMp/7RVs8JBAmE/h6tSYIVRqzuu1Eai/ewua7\n\tiNgM0CyLUIADb5UUBic1R3VI0eUYPYSTzXpRk8ZLy+3F8xbe6E0Yb+ve+DUMkSv0zJ\n\tXGH5OaIgLvCBNz4DhMkP3pw61inJWFBRvOoz6ZZs=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190912200330.19004-1-laurent.pinchart@ideasonboard.com>\n\t<20190912200330.19004-5-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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","Organization":"Ideas on Board","Message-ID":"<b00d44c3-4507-6d76-70f3-4e343e6b0fe5@ideasonboard.com>","Date":"Fri, 13 Sep 2019 11:10:23 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.8.0","MIME-Version":"1.0","In-Reply-To":"<20190912200330.19004-5-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","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":"Fri, 13 Sep 2019 10:10:28 -0000"}},{"id":2650,"web_url":"https://patchwork.libcamera.org/comment/2650/","msgid":"<0b9d2178-efa5-a722-0d72-3574c380d602@ideasonboard.com>","date":"2019-09-13T10:21:33","subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"On 13/09/2019 11:10, Kieran Bingham wrote:\n> Hi Laurent,\n> \n> On 12/09/2019 21:03, Laurent Pinchart wrote:\n>> Some media devices, such as V4L2 M2M devices, share the same device node\n>> for multiple entities. The udev enumerator used to support this, but\n>> commit 6e620349009d (\"libcamera: device_enumerator: fix udev media graph\n>> loading dependency\") broke this.\n>>\n>> To fix the problem, rework the media device to V4L2 devices matching\n>> code. A new MediaDeviceDeps internal struct stores unmet device number\n>> dependencies for a media device, and is stored in a list of pending\n>> media devices. To avoid linear lookups, the dependencies are cached in a\n>> reverse map of device number to media device dependencies.\n>>\n>> Fixes: 6e620349009d (\"libcamera: device_enumerator: fix udev media graph loading dependency\")\n>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>> ---\n>>  src/libcamera/device_enumerator_udev.cpp      | 100 ++++++++++++------\n>>  .../include/device_enumerator_udev.h          |  25 ++++-\n>>  2 files changed, 89 insertions(+), 36 deletions(-)\n>>\n>> diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp\n>> index c40770911d3d..ddcd59ea52c1 100644\n>> --- a/src/libcamera/device_enumerator_udev.cpp\n>> +++ b/src/libcamera/device_enumerator_udev.cpp\n>> @@ -170,8 +170,8 @@ done:\n>>  \n>>  int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice> &media)\n>>  {\n>> -\tunsigned int pendingNodes = 0;\n>> -\tint ret;\n>> +\tstd::set<dev_t> children;\n>> +\tDependencyMap deps;\n>>  \n>>  \t/* Associate entities to device node paths. */\n>>  \tfor (MediaEntity *entity : media->entities()) {\n>> @@ -181,28 +181,50 @@ int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice>\n>>  \t\tdev_t devnum = makedev(entity->deviceMajor(),\n>>  \t\t\t\t       entity->deviceMinor());\n>>  \n>> -\t\t/* Take device from orphan list first, if it is in the list. */\n>> -\t\tauto orphan = std::find(orphans_.begin(), orphans_.end(), devnum);\n>> -\t\tif (orphan != orphans_.end()) {\n>> -\t\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n>> -\t\t\tif (deviceNode.empty())\n>> -\t\t\t\treturn -EINVAL;\n>> -\n>> -\t\t\tret = entity->setDeviceNode(deviceNode);\n>> -\t\t\tif (ret)\n>> -\t\t\t\treturn ret;\n>> -\n>> -\t\t\torphans_.erase(orphan);\n>> +\t\t/*\n>> +\t\t * If the devnum isn't in the orphans list, add it to the unmet\n>> +\t\t * dependencies.\n>> +\t\t */\n>> +\t\tif (orphans_.find(devnum) == orphans_.end()) {\n>> +\t\t\tdeps[devnum].push_back(entity);\n>>  \t\t\tcontinue;\n>>  \t\t}\n>>  \n>> -\t\tdeps_[media].push_back(devnum);\n>> -\t\tdevnumToDevice_[devnum] = media;\n>> -\t\tdevnumToEntity_[devnum] = entity;\n>> -\t\tpendingNodes++;\n>> +\t\t/*\n>> +\t\t * Otherwise take it from the orphans list. Don't remove the\n>> +\t\t * entry from the list yet as other entities in this media\n>> +\t\t * device may need the same device.\n>> +\t\t */\n>> +\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n>> +\t\tif (deviceNode.empty())\n>> +\t\t\treturn -EINVAL;\n>> +\n>> +\t\tint ret = entity->setDeviceNode(deviceNode);\n>> +\t\tif (ret)\n>> +\t\t\treturn ret;\n>> +\n>> +\t\tchildren.insert(devnum);\n>> +\t}\n>> +\n>> +\t/* Remove all found children from the orphans list. */\n>> +\tfor (auto it = orphans_.begin(), last = orphans_.end(); it != last;) {\n> \n> What 'type' is last? Where is it declared? Is this it's only use?\n> \n> Is it automatically defined as an auto? or an iterator?\n\nAh - sorry I was confused reading it, It's the same as :\n\n int a = 1, b = 2;\n\n\n> \n> And is it needed? or can the loop exit check just compare against it  !=\n> orphans_.end() ?\n\n\nAnd I think it's needed because we're modifying the iterators with the\n.erase(it)...\n\n--\nKieran\n\n\n>> +\t\tif (children.find(*it) != children.end())\n>> +\t\t\tit = orphans_.erase(it);\n>> +\t\telse\n>> +\t\t\t++it;\n>> +\t}\n>> +\n>> +\t/*\n>> +\t * If the media device has unmet dependencies, add it to the pending\n>> +\t * list and update the devnum map accordingly.\n>> +\t */\n>> +\tif (!deps.empty()) {\n>> +\t\tpending_.emplace_back(media, deps);\n>> +\t\tfor (const auto &dep : deps)\n>> +\t\t\tdevMap_[dep.first] = &pending_.back();\n>>  \t}\n>>  \n>> -\treturn pendingNodes;\n>> +\treturn deps.size();\n>>  }\n>>  \n>>  /**\n>> @@ -247,28 +269,42 @@ std::string DeviceEnumeratorUdev::lookupDeviceNode(dev_t devnum)\n>>   */\n>>  int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)\n>>  {\n>> -\tMediaEntity *entity = devnumToEntity_[devnum];\n>> -\tif (!entity) {\n>> -\t\torphans_.push_back(devnum);\n>> +\t/*\n>> +\t * If the devnum doesn't belong to any media device, add it to the\n>> +\t * orphans list.\n>> +\t */\n>> +\tauto it = devMap_.find(devnum);\n>> +\tif (it == devMap_.end()) {\n>> +\t\torphans_.insert(devnum);\n>>  \t\treturn 0;\n>>  \t}\n>>  \n>> +\t/*\n>> +\t * Set the device node for all entities matching the devnum. Multiple\n>> +\t * entities can share the same device node, for instance for V4L2 M2M\n>> +\t * devices.\n>> +\t */\n>>  \tstd::string deviceNode = lookupDeviceNode(devnum);\n>>  \tif (deviceNode.empty())\n>>  \t\treturn -EINVAL;\n>>  \n>> -\tint ret = entity->setDeviceNode(deviceNode);\n>> -\tif (ret)\n>> -\t\treturn ret;\n>> +\tMediaDeviceDeps *deps = it->second;\n>> +\tfor (MediaEntity *entity : deps->deps_[devnum]) {\n>> +\t\tint ret = entity->setDeviceNode(deviceNode);\n>> +\t\tif (ret)\n>> +\t\t\treturn ret;\n>> +\t}\n>>  \n>> -\tstd::shared_ptr<MediaDevice> media = devnumToDevice_[devnum];\n>> -\tdeps_[media].remove(devnum);\n>> -\tdevnumToDevice_.erase(devnum);\n>> -\tdevnumToEntity_.erase(devnum);\n>> +\t/*\n>> +\t * Remove the devnum from the unmet dependencies for this media device.\n>> +\t * If no more dependency is unmet, add the media device to the\n>> +\t * enumerator.\n>> +\t */\n>> +\tdeps->deps_.erase(devnum);\n>>  \n>> -\tif (deps_[media].empty()) {\n>> -\t\taddDevice(media);\n>> -\t\tdeps_.erase(media);\n>> +\tif (deps->deps_.empty()) {\n>> +\t\taddDevice(deps->media_);\n>> +\t\tpending_.remove(*deps);\n>>  \t}\n>>  \n>>  \treturn 0;\n>> diff --git a/src/libcamera/include/device_enumerator_udev.h b/src/libcamera/include/device_enumerator_udev.h\n>> index fb7cac8011a1..6d8268620185 100644\n>> --- a/src/libcamera/include/device_enumerator_udev.h\n>> +++ b/src/libcamera/include/device_enumerator_udev.h\n>> @@ -10,6 +10,7 @@\n>>  #include <list>\n>>  #include <map>\n>>  #include <memory>\n>> +#include <set>\n>>  #include <string>\n>>  #include <sys/types.h>\n>>  \n>> @@ -39,11 +40,27 @@ private:\n>>  \tstruct udev_monitor *monitor_;\n>>  \tEventNotifier *notifier_;\n>>  \n>> -\tstd::map<std::shared_ptr<MediaDevice>, std::list<dev_t>> deps_;\n>> -\tstd::map<dev_t, std::shared_ptr<MediaDevice>> devnumToDevice_;\n>> -\tstd::map<dev_t, MediaEntity *> devnumToEntity_;\n>> +\tusing DependencyMap = std::map<dev_t, std::list<MediaEntity *>>;\n>>  \n>> -\tstd::list<dev_t> orphans_;\n>> +\tstruct MediaDeviceDeps {\n>> +\t\tMediaDeviceDeps(const std::shared_ptr<MediaDevice> &media,\n>> +\t\t\t\tconst DependencyMap &deps)\n>> +\t\t\t: media_(media), deps_(deps)\n>> +\t\t{\n>> +\t\t}\n>> +\n>> +\t\tbool operator==(const MediaDeviceDeps &other) const\n>> +\t\t{\n>> +\t\t\treturn media_ == other.media_;\n>> +\t\t}\n>> +\n>> +\t\tstd::shared_ptr<MediaDevice> media_;\n>> +\t\tDependencyMap deps_;\n>> +\t};\n>> +\n>> +\tstd::set<dev_t> orphans_;\n>> +\tstd::list<MediaDeviceDeps> pending_;\n>> +\tstd::map<dev_t, MediaDeviceDeps *> devMap_;\n>>  \n>>  \tint addUdevDevice(struct udev_device *dev);\n>>  \tint populateMediaDevice(const std::shared_ptr<MediaDevice> &media);\n>>\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 5D17A600CA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Sep 2019 12:21:37 +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 A841F33A;\n\tFri, 13 Sep 2019 12:21:36 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1568370096;\n\tbh=SCYVcra+9JpL1O4DAeMAtsRtUdpsRvKd3NEAwqvfWfw=;\n\th=Reply-To:Subject:From:To:References:Date:In-Reply-To:From;\n\tb=Fv8WrViOpXLcby7YbdUqa/KFZvPRgkMsi6rUCRMp/BBr0gRhfSk+uLBXH20EvKl5w\n\t3BH0rKIZliI1FU6q5D4sI7rpWEpJD0vAJ50O7y9q4l1lQz7ncCSEKY2kbss4vULBZe\n\tTMZmGNOvbtiQoppR1TMeEkydJNgeXlg+zy8hwqpw=","Reply-To":"kieran.bingham@ideasonboard.com","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20190912200330.19004-1-laurent.pinchart@ideasonboard.com>\n\t<20190912200330.19004-5-laurent.pinchart@ideasonboard.com>\n\t<b00d44c3-4507-6d76-70f3-4e343e6b0fe5@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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","Organization":"Ideas on Board","Message-ID":"<0b9d2178-efa5-a722-0d72-3574c380d602@ideasonboard.com>","Date":"Fri, 13 Sep 2019 11:21:33 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.8.0","MIME-Version":"1.0","In-Reply-To":"<b00d44c3-4507-6d76-70f3-4e343e6b0fe5@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","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":"Fri, 13 Sep 2019 10:21:37 -0000"}},{"id":2651,"web_url":"https://patchwork.libcamera.org/comment/2651/","msgid":"<20190913112716.GF29992@pendragon.ideasonboard.com>","date":"2019-09-13T11:27:16","subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Fri, Sep 13, 2019 at 11:21:33AM +0100, Kieran Bingham wrote:\n> On 13/09/2019 11:10, Kieran Bingham wrote:\n> > On 12/09/2019 21:03, Laurent Pinchart wrote:\n> >> Some media devices, such as V4L2 M2M devices, share the same device node\n> >> for multiple entities. The udev enumerator used to support this, but\n> >> commit 6e620349009d (\"libcamera: device_enumerator: fix udev media graph\n> >> loading dependency\") broke this.\n> >>\n> >> To fix the problem, rework the media device to V4L2 devices matching\n> >> code. A new MediaDeviceDeps internal struct stores unmet device number\n> >> dependencies for a media device, and is stored in a list of pending\n> >> media devices. To avoid linear lookups, the dependencies are cached in a\n> >> reverse map of device number to media device dependencies.\n> >>\n> >> Fixes: 6e620349009d (\"libcamera: device_enumerator: fix udev media graph loading dependency\")\n> >> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >> ---\n> >>  src/libcamera/device_enumerator_udev.cpp      | 100 ++++++++++++------\n> >>  .../include/device_enumerator_udev.h          |  25 ++++-\n> >>  2 files changed, 89 insertions(+), 36 deletions(-)\n> >>\n> >> diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp\n> >> index c40770911d3d..ddcd59ea52c1 100644\n> >> --- a/src/libcamera/device_enumerator_udev.cpp\n> >> +++ b/src/libcamera/device_enumerator_udev.cpp\n> >> @@ -170,8 +170,8 @@ done:\n> >>  \n> >>  int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice> &media)\n> >>  {\n> >> -\tunsigned int pendingNodes = 0;\n> >> -\tint ret;\n> >> +\tstd::set<dev_t> children;\n> >> +\tDependencyMap deps;\n> >>  \n> >>  \t/* Associate entities to device node paths. */\n> >>  \tfor (MediaEntity *entity : media->entities()) {\n> >> @@ -181,28 +181,50 @@ int DeviceEnumeratorUdev::populateMediaDevice(const std::shared_ptr<MediaDevice>\n> >>  \t\tdev_t devnum = makedev(entity->deviceMajor(),\n> >>  \t\t\t\t       entity->deviceMinor());\n> >>  \n> >> -\t\t/* Take device from orphan list first, if it is in the list. */\n> >> -\t\tauto orphan = std::find(orphans_.begin(), orphans_.end(), devnum);\n> >> -\t\tif (orphan != orphans_.end()) {\n> >> -\t\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> >> -\t\t\tif (deviceNode.empty())\n> >> -\t\t\t\treturn -EINVAL;\n> >> -\n> >> -\t\t\tret = entity->setDeviceNode(deviceNode);\n> >> -\t\t\tif (ret)\n> >> -\t\t\t\treturn ret;\n> >> -\n> >> -\t\t\torphans_.erase(orphan);\n> >> +\t\t/*\n> >> +\t\t * If the devnum isn't in the orphans list, add it to the unmet\n> >> +\t\t * dependencies.\n> >> +\t\t */\n> >> +\t\tif (orphans_.find(devnum) == orphans_.end()) {\n> >> +\t\t\tdeps[devnum].push_back(entity);\n> >>  \t\t\tcontinue;\n> >>  \t\t}\n> >>  \n> >> -\t\tdeps_[media].push_back(devnum);\n> >> -\t\tdevnumToDevice_[devnum] = media;\n> >> -\t\tdevnumToEntity_[devnum] = entity;\n> >> -\t\tpendingNodes++;\n> >> +\t\t/*\n> >> +\t\t * Otherwise take it from the orphans list. Don't remove the\n> >> +\t\t * entry from the list yet as other entities in this media\n> >> +\t\t * device may need the same device.\n> >> +\t\t */\n> >> +\t\tstd::string deviceNode = lookupDeviceNode(devnum);\n> >> +\t\tif (deviceNode.empty())\n> >> +\t\t\treturn -EINVAL;\n> >> +\n> >> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> >> +\t\tif (ret)\n> >> +\t\t\treturn ret;\n> >> +\n> >> +\t\tchildren.insert(devnum);\n> >> +\t}\n> >> +\n> >> +\t/* Remove all found children from the orphans list. */\n> >> +\tfor (auto it = orphans_.begin(), last = orphans_.end(); it != last;) {\n> > \n> > What 'type' is last? Where is it declared? Is this it's only use?\n> > \n> > Is it automatically defined as an auto? or an iterator?\n> \n> Ah - sorry I was confused reading it, It's the same as :\n> \n>  int a = 1, b = 2;\n\nCorrect. I wonder if\n\n\tauto a = 1, b = \"foo\";\n\nwould result in a being an integer and b a string :-)\n\n> > And is it needed? or can the loop exit check just compare against it  !=\n> > orphans_.end() ?\n> \n> And I think it's needed because we're modifying the iterators with the\n> .erase(it)...\n\nFirst of all, it's a bit of an optimisation, as otherwise .end() is\ncalled at every iteration. Then, the optimisation is only allowed\nbecause std::set::erase() says\n\n\"References and iterators to the erased elements are invalidated. Other\nreferences and iterators are not affected.\"\n\nThe .end() iterator isn't invalidated, so we can cache it. However, if\nthe container had been an std::vector, the erase() operation is\ndocumented as\n\n\"Invalidates iterators and references at or after the point of the\nerase, including the end() iterator.\"\n\nso caching .end() wouldn't be allowed.\n\n> >> +\t\tif (children.find(*it) != children.end())\n> >> +\t\t\tit = orphans_.erase(it);\n> >> +\t\telse\n> >> +\t\t\t++it;\n> >> +\t}\n> >> +\n> >> +\t/*\n> >> +\t * If the media device has unmet dependencies, add it to the pending\n> >> +\t * list and update the devnum map accordingly.\n> >> +\t */\n> >> +\tif (!deps.empty()) {\n> >> +\t\tpending_.emplace_back(media, deps);\n> >> +\t\tfor (const auto &dep : deps)\n> >> +\t\t\tdevMap_[dep.first] = &pending_.back();\n> >>  \t}\n> >>  \n> >> -\treturn pendingNodes;\n> >> +\treturn deps.size();\n> >>  }\n> >>  \n> >>  /**\n> >> @@ -247,28 +269,42 @@ std::string DeviceEnumeratorUdev::lookupDeviceNode(dev_t devnum)\n> >>   */\n> >>  int DeviceEnumeratorUdev::addV4L2Device(dev_t devnum)\n> >>  {\n> >> -\tMediaEntity *entity = devnumToEntity_[devnum];\n> >> -\tif (!entity) {\n> >> -\t\torphans_.push_back(devnum);\n> >> +\t/*\n> >> +\t * If the devnum doesn't belong to any media device, add it to the\n> >> +\t * orphans list.\n> >> +\t */\n> >> +\tauto it = devMap_.find(devnum);\n> >> +\tif (it == devMap_.end()) {\n> >> +\t\torphans_.insert(devnum);\n> >>  \t\treturn 0;\n> >>  \t}\n> >>  \n> >> +\t/*\n> >> +\t * Set the device node for all entities matching the devnum. Multiple\n> >> +\t * entities can share the same device node, for instance for V4L2 M2M\n> >> +\t * devices.\n> >> +\t */\n> >>  \tstd::string deviceNode = lookupDeviceNode(devnum);\n> >>  \tif (deviceNode.empty())\n> >>  \t\treturn -EINVAL;\n> >>  \n> >> -\tint ret = entity->setDeviceNode(deviceNode);\n> >> -\tif (ret)\n> >> -\t\treturn ret;\n> >> +\tMediaDeviceDeps *deps = it->second;\n> >> +\tfor (MediaEntity *entity : deps->deps_[devnum]) {\n> >> +\t\tint ret = entity->setDeviceNode(deviceNode);\n> >> +\t\tif (ret)\n> >> +\t\t\treturn ret;\n> >> +\t}\n> >>  \n> >> -\tstd::shared_ptr<MediaDevice> media = devnumToDevice_[devnum];\n> >> -\tdeps_[media].remove(devnum);\n> >> -\tdevnumToDevice_.erase(devnum);\n> >> -\tdevnumToEntity_.erase(devnum);\n> >> +\t/*\n> >> +\t * Remove the devnum from the unmet dependencies for this media device.\n> >> +\t * If no more dependency is unmet, add the media device to the\n> >> +\t * enumerator.\n> >> +\t */\n> >> +\tdeps->deps_.erase(devnum);\n> >>  \n> >> -\tif (deps_[media].empty()) {\n> >> -\t\taddDevice(media);\n> >> -\t\tdeps_.erase(media);\n> >> +\tif (deps->deps_.empty()) {\n> >> +\t\taddDevice(deps->media_);\n> >> +\t\tpending_.remove(*deps);\n> >>  \t}\n> >>  \n> >>  \treturn 0;\n> >> diff --git a/src/libcamera/include/device_enumerator_udev.h b/src/libcamera/include/device_enumerator_udev.h\n> >> index fb7cac8011a1..6d8268620185 100644\n> >> --- a/src/libcamera/include/device_enumerator_udev.h\n> >> +++ b/src/libcamera/include/device_enumerator_udev.h\n> >> @@ -10,6 +10,7 @@\n> >>  #include <list>\n> >>  #include <map>\n> >>  #include <memory>\n> >> +#include <set>\n> >>  #include <string>\n> >>  #include <sys/types.h>\n> >>  \n> >> @@ -39,11 +40,27 @@ private:\n> >>  \tstruct udev_monitor *monitor_;\n> >>  \tEventNotifier *notifier_;\n> >>  \n> >> -\tstd::map<std::shared_ptr<MediaDevice>, std::list<dev_t>> deps_;\n> >> -\tstd::map<dev_t, std::shared_ptr<MediaDevice>> devnumToDevice_;\n> >> -\tstd::map<dev_t, MediaEntity *> devnumToEntity_;\n> >> +\tusing DependencyMap = std::map<dev_t, std::list<MediaEntity *>>;\n> >>  \n> >> -\tstd::list<dev_t> orphans_;\n> >> +\tstruct MediaDeviceDeps {\n> >> +\t\tMediaDeviceDeps(const std::shared_ptr<MediaDevice> &media,\n> >> +\t\t\t\tconst DependencyMap &deps)\n> >> +\t\t\t: media_(media), deps_(deps)\n> >> +\t\t{\n> >> +\t\t}\n> >> +\n> >> +\t\tbool operator==(const MediaDeviceDeps &other) const\n> >> +\t\t{\n> >> +\t\t\treturn media_ == other.media_;\n> >> +\t\t}\n> >> +\n> >> +\t\tstd::shared_ptr<MediaDevice> media_;\n> >> +\t\tDependencyMap deps_;\n> >> +\t};\n> >> +\n> >> +\tstd::set<dev_t> orphans_;\n> >> +\tstd::list<MediaDeviceDeps> pending_;\n> >> +\tstd::map<dev_t, MediaDeviceDeps *> devMap_;\n> >>  \n> >>  \tint addUdevDevice(struct udev_device *dev);\n> >>  \tint populateMediaDevice(const std::shared_ptr<MediaDevice> &media);","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 88211600CA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Sep 2019 13:27:24 +0200 (CEST)","from pendragon.ideasonboard.com (bl10-204-24.dsl.telepac.pt\n\t[85.243.204.24])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C3EDE33A;\n\tFri, 13 Sep 2019 13:27:23 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1568374044;\n\tbh=GLxMBt//1k/O0GncVDDtyPlXxGJSc1scuojIQmOwjrM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=BAwynPOJFczQiBzJZhINjaKjev/ycFBzSIKuYy83GHYYsGm5rJRauaWtv8tp8j2Uy\n\tMrWyEuhJRf1AZ+R2QHfkEdi+ZQHAXsIJu74GSkTzOfgC1dTRcYkDl35ClqoEK4y6IG\n\tPLd61B9yK+uYC7VEr4ll0gRrn2AZfqWGN7e6V6TI=","Date":"Fri, 13 Sep 2019 14:27:16 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190913112716.GF29992@pendragon.ideasonboard.com>","References":"<20190912200330.19004-1-laurent.pinchart@ideasonboard.com>\n\t<20190912200330.19004-5-laurent.pinchart@ideasonboard.com>\n\t<b00d44c3-4507-6d76-70f3-4e343e6b0fe5@ideasonboard.com>\n\t<0b9d2178-efa5-a722-0d72-3574c380d602@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<0b9d2178-efa5-a722-0d72-3574c380d602@ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 4/4] libcamera:\n\tdevice_enumerator_udev: Support entities sharing device nodes","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":"Fri, 13 Sep 2019 11:27:24 -0000"}}]