[PATCH libevdev 3/4] Guess the device node based on the sysfs path
David Herrmann
dh.herrmann at gmail.com
Fri Aug 16 05:53:03 PDT 2013
Hi
On Fri, Aug 16, 2013 at 8:44 AM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> On Thu, Aug 15, 2013 at 03:02:24PM +0200, David Herrmann wrote:
>> Hi
>>
>> On Thu, Aug 15, 2013 at 6:12 AM, Peter Hutterer
>> <peter.hutterer at who-t.net> wrote:
>> > The sysfs path contains a eventN file, that corresponds to our
>> > /dev/input/eventN number. Use it so clients can quickly get the device
>> > node, without a libudev dependency.
>> >
>> > Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
>> > ---
>> > libevdev/libevdev-uinput-int.h | 1 +
>> > libevdev/libevdev-uinput.c | 45 ++++++++++++++++++++++++++++++++++++++----
>> > libevdev/libevdev-uinput.h | 15 ++++++++++++++
>> > 3 files changed, 57 insertions(+), 4 deletions(-)
>> >
>> > diff --git a/libevdev/libevdev-uinput-int.h b/libevdev/libevdev-uinput-int.h
>> > index f443984..fbc1c29 100644
>> > --- a/libevdev/libevdev-uinput-int.h
>> > +++ b/libevdev/libevdev-uinput-int.h
>> > @@ -26,5 +26,6 @@ struct libevdev_uinput {
>> > int fd_is_managed; /**< do we need to close it? */
>> > char *name; /**< device name */
>> > char *syspath; /**< /sys path */
>> > + char *devnode; /**< device node */
>> > time_t ctime[2]; /**< before/after UI_DEV_CREATE */
>> > };
>> > diff --git a/libevdev/libevdev-uinput.c b/libevdev/libevdev-uinput.c
>> > index 830d681..2cb9121 100644
>> > --- a/libevdev/libevdev-uinput.c
>> > +++ b/libevdev/libevdev-uinput.c
>> > @@ -220,6 +220,7 @@ void libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev)
>> > if (uinput_dev->fd_is_managed)
>> > close(uinput_dev->fd);
>> > free(uinput_dev->syspath);
>> > + free(uinput_dev->devnode);
>> > free(uinput_dev->name);
>> > free(uinput_dev);
>> > }
>> > @@ -229,19 +230,41 @@ int libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev)
>> > return uinput_dev->fd;
>> > }
>> >
>> > -const char* libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev)
>> > +static char *
>> > +fetch_device_node(const char *path)
>> > {
>> > DIR *dir;
>> > struct dirent *dent;
>> > + char *devnode = NULL;
>> >
>> > - if (uinput_dev->syspath != NULL)
>> > - return uinput_dev->syspath;
>> > + dir = opendir(path);
>> > + if (!dir)
>> > + return NULL;
>> > +
>> > + while ((dent = readdir(dir))) {
>>
>> readdir is not re-entrant. I know readdir_r is ugly as we need to
>> allocate "dirent" on the heap, but this way libevdev stays re-entrant.
>
> good point. I'll fix that up asap.
>
> btw, in one of your emails when this branch was new you mentioned you didn't
> want to block on udev for retrieving the devnode. AIUI, with this
> implementation the syspath and the devnode don't rely on udev anymore, so we
> could fetch this data during create and then make the API calls a simple
> (and signal-safe) getter. Sound like a plan?
I checked the kernel again. The call to UI_DEV_CREATE is synchronous
in that regard. It calls device_add() which itself calls into
kobject_add() to sysfs_create_dir(). So the input-device directory in
sysfs is guaranteed to be available once UI_DEV_CREATE returns. Same
is true for any sub-handlers (like evdev).
Furthermore, device_add() also calls devtmpfs_create_node() which
schedules an asynchronous helper but waits for its completion. So as
long as the system uses devtmpfs (which _every_ system should do),
once UI_DEV_CREATE returns, the device-node is guaranteed to be
accessible.
Long story short: This heuristic to retrieve the device node is
_guaranteed_ to work in a race-free manner. No reason to block on
udev.
Cheers
David
More information about the Input-tools
mailing list