From 84f2d39f2c44c4384ba15de409abf3ff715a93ad Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 24 Oct 2012 19:53:08 -0700 Subject: [PATCH] kernel - Implement UDEVWAIT ioctl for /dev/udev * Implement an ioctl which interacts with a sequence number and waits for a new event, so callers can avoid polling for events. --- sys/kern/kern_udev.c | 73 +++++++++++++++++++++++++++++++++----------- sys/sys/udev.h | 3 +- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/sys/kern/kern_udev.c b/sys/kern/kern_udev.c index 053fedfd46..64c6d511ef 100644 --- a/sys/kern/kern_udev.c +++ b/sys/kern/kern_udev.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -124,6 +125,9 @@ static struct kqinfo udev_kq; static struct lock udev_lk; static int udev_evqlen; static int udev_initiated_count; +static int udev_open_count; +static int udev_seqwait; +static int udev_seq; static int _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) @@ -418,25 +422,33 @@ udev_event_insert(int ev_type, prop_dictionary_t dict) struct udev_event_kernel *ev; /* Only start queing events after client has initiated properly */ - if (udev_initiated_count == 0) - return; - - /* XXX: use objcache eventually */ - ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK); - ev->ev.ev_dict = prop_dictionary_copy(dict); - if (ev->ev.ev_dict == NULL) { - kfree(ev, M_UDEV); - return; + if (udev_initiated_count) { + /* XXX: use objcache eventually */ + ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK); + ev->ev.ev_dict = prop_dictionary_copy(dict); + if (ev->ev.ev_dict == NULL) { + kfree(ev, M_UDEV); + return; + } + ev->ev.ev_type = ev_type; + + lockmgr(&udev_lk, LK_EXCLUSIVE); + TAILQ_INSERT_TAIL(&udev_evq, ev, link); + ++udev_evqlen; + ++udev_seq; + if (udev_seqwait) + wakeup(&udev_seqwait); + lockmgr(&udev_lk, LK_RELEASE); + wakeup(&udev_evq); + KNOTE(&udev_kq.ki_note, 0); + } else if (udev_open_count) { + lockmgr(&udev_lk, LK_EXCLUSIVE); + ++udev_seq; + if (udev_seqwait) + wakeup(&udev_seqwait); + lockmgr(&udev_lk, LK_RELEASE); + KNOTE(&udev_kq.ki_note, 0); } - ev->ev.ev_type = ev_type; - - lockmgr(&udev_lk, LK_EXCLUSIVE); - TAILQ_INSERT_TAIL(&udev_evq, ev, link); - ++udev_evqlen; - lockmgr(&udev_lk, LK_RELEASE); - - wakeup(&udev_evq); - KNOTE(&udev_kq.ki_note, 0); } static void @@ -597,6 +609,7 @@ udev_dev_open(struct dev_open_args *ap) return EBUSY; } softc->opened = 1; + ++udev_open_count; lockmgr(&udev_lk, LK_RELEASE); return 0; @@ -623,6 +636,7 @@ udev_dev_close(struct dev_close_args *ap) softc->opened = 0; softc->dev = NULL; ap->a_head.a_dev->si_drv1 = NULL; + --udev_open_count; lockmgr(&udev_lk, LK_RELEASE); destroy_dev(ap->a_head.a_dev); @@ -749,6 +763,10 @@ udev_dev_read(struct dev_read_args *ap) break; } } + if (ap->a_ioflag & IO_NDELAY) { + error = EWOULDBLOCK; + break; + } if ((error = lksleep(&udev_evq, &udev_lk, PCATCH, "udevq", 0))) break; } @@ -766,6 +784,7 @@ udev_dev_ioctl(struct dev_ioctl_args *ap) prop_string_t ps; struct plistref *pref; int i, error; + int seq; error = 0; @@ -800,6 +819,24 @@ udev_dev_ioctl(struct dev_ioctl_args *ap) //prop_object_release(po); prop_object_release(dict); break; + case UDEVWAIT: + /* + * Wait for events based on sequence number. Updates + * sequence number for loop. + */ + lockmgr(&udev_lk, LK_EXCLUSIVE); + seq = *(int *)ap->a_data; + ++udev_seqwait; + while (seq == udev_seq) { + error = lksleep(&udev_seqwait, &udev_lk, + PCATCH, "udevw", 0); + if (error) + break; + } + --udev_seqwait; + *(int *)ap->a_data = udev_seq; + lockmgr(&udev_lk, LK_RELEASE); + break; default: error = ENOTTY; /* Inappropriate ioctl for device */ break; diff --git a/sys/sys/udev.h b/sys/sys/udev.h index d47d58a429..5474aa0933 100644 --- a/sys/sys/udev.h +++ b/sys/sys/udev.h @@ -55,7 +55,8 @@ int udev_event_detach(cdev_t dev, char *name, int alias); #endif /* _KERNEL */ -#define UDEVPROP _IOWR('U', 0xBA, struct plistref) +#define UDEVPROP _IOWR('U', 0xBA, struct plistref) +#define UDEVWAIT _IOWR('U', 0xC0, int) #define UDEV_EVENT_NONE 0x00 #define UDEV_EVENT_ATTACH 0x01 #define UDEV_EVENT_DETACH 0x02 -- 2.41.0