[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