It is possible that same device is processed multiple times, leading to multiple `MediaDevice`s being instantiated, mostly likely leading to a fatal error: Trying to register a camera with a duplicated ID xyzw... There is a time window after the `udev_monitor` has been created in `init()` and the first (and only) enumeration done in `enumerate()`. If e.g. a UVC camera is connected in this time frame, then it is possible that it will be processed both by the `udevNotify()` and the initial `enumerate()`, leading to the fatal error. This can be reproduced as follows: 1. $ gdb --args cam -m 2. (gdb) break libcamera::DeviceEnumeratorUdev::enumerate 3. (gdb) run 4. when the breakpoint is hit, connect a usb camera 5. (gdb) continue 6. observe fatal error To address this, keep track of the devnums of all devices reported by udev, and reject devices with already known devnums. This ensures that the same device won't be reported multiple times (assuming that udev reports "add" / "remove" events in the correct order). Closes: https://gitlab.freedesktop.org/camera/libcamera/-/issues/293 Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
81 lines
1.6 KiB
C++
81 lines
1.6 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2018-2019, Google Inc.
|
|
*
|
|
* udev-based device enumerator
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <sys/types.h>
|
|
#include <unordered_set>
|
|
|
|
#include <libcamera/base/class.h>
|
|
|
|
#include "libcamera/internal/device_enumerator.h"
|
|
|
|
struct udev;
|
|
struct udev_device;
|
|
struct udev_monitor;
|
|
|
|
namespace libcamera {
|
|
|
|
class EventNotifier;
|
|
class MediaDevice;
|
|
class MediaEntity;
|
|
|
|
class DeviceEnumeratorUdev final : public DeviceEnumerator
|
|
{
|
|
public:
|
|
DeviceEnumeratorUdev();
|
|
~DeviceEnumeratorUdev();
|
|
|
|
int init();
|
|
int enumerate();
|
|
|
|
private:
|
|
using DependencyMap = std::map<dev_t, std::list<MediaEntity *>>;
|
|
|
|
struct MediaDeviceDeps {
|
|
MediaDeviceDeps(std::unique_ptr<MediaDevice> media,
|
|
DependencyMap deps)
|
|
: media_(std::move(media)), deps_(std::move(deps))
|
|
{
|
|
}
|
|
|
|
bool operator==(const MediaDeviceDeps &other) const
|
|
{
|
|
return media_ == other.media_;
|
|
}
|
|
|
|
std::unique_ptr<MediaDevice> media_;
|
|
DependencyMap deps_;
|
|
};
|
|
|
|
LIBCAMERA_DISABLE_COPY_AND_MOVE(DeviceEnumeratorUdev)
|
|
|
|
int addUdevDevice(struct udev_device *dev);
|
|
void removeUdevDevice(struct udev_device *dev);
|
|
int populateMediaDevice(MediaDevice *media, DependencyMap *deps);
|
|
std::string lookupDeviceNode(dev_t devnum);
|
|
|
|
int addV4L2Device(dev_t devnum);
|
|
void udevNotify();
|
|
|
|
struct udev *udev_;
|
|
struct udev_monitor *monitor_;
|
|
EventNotifier *notifier_;
|
|
|
|
std::set<dev_t> orphans_;
|
|
std::unordered_set<dev_t> devices_;
|
|
std::list<MediaDeviceDeps> pending_;
|
|
std::map<dev_t, MediaDeviceDeps *> devMap_;
|
|
};
|
|
|
|
} /* namespace libcamera */
|