* [PATCH 0/2] Deliver ACPI events upon subscription and implement multiple readers for /proc/acpi/event
@ 2006-01-24 23:14 Mattia Dongili
2006-01-24 23:14 ` [PATCH 1/2] Implement ACPI event delivery upon subscription Mattia Dongili
0 siblings, 1 reply; 3+ messages in thread
From: Mattia Dongili @ 2006-01-24 23:14 UTC (permalink / raw)
To: linux-acpi, Dmitry Torokhov; +Cc: Mattia Dongili
Hello.
This patch series revamps an old submission[1] from Dmitry Torokhov that
adds support for multiple readers on /proc/acpi/event.
Due to the code reorganization happened in the last 1.5 years I
re-implemented it a little differently introducing a subscription
mechanism to receive events (it might be used in different context
also). driver/acpi/event.c uses it to register a new listener for each
process opening the /proc/acpi/event file.
I was also wondering if this could fit the recent discussion on
"Untangling the sleep hotkey mess"[2] to allow event deliver through
the input subsystem (yes, a proposed solution was the other way around
but this might still be a viable implementation).
[1]: http://marc.theaimsgroup.com/?l=acpi4linux&m=109333066714671&w=2
[2]: sorry, can't find the beginning of the thread
http://marc.theaimsgroup.com/?l=linux-acpi&m=113676899930391&w=2
Dmitry, I don't know how to apply the signed-off thing correctly here,
in the meantime:
Signed-off-by: Mattia Dongili <malattia@linux.it>
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 1/2] Implement ACPI event delivery upon subscription. 2006-01-24 23:14 [PATCH 0/2] Deliver ACPI events upon subscription and implement multiple readers for /proc/acpi/event Mattia Dongili @ 2006-01-24 23:14 ` Mattia Dongili 2006-01-24 23:14 ` [PATCH 2/2] Support multiple readers for /proc/acpi/event Mattia Dongili 0 siblings, 1 reply; 3+ messages in thread From: Mattia Dongili @ 2006-01-24 23:14 UTC (permalink / raw) To: linux-acpi, Dmitry Torokhov; +Cc: Mattia Dongili [PATCH 1/2] Implement ACPI event delivery upon subscription. Drivers can register their listener to receive events instead of using a single event queue. Limit the number of pending events to 32 so if a reader is stuck it won't consume all memory. Signed-off-by: Mattia Dongili <malattia@linux.it> --- drivers/acpi/bus.c | 92 ++++++++++++++++++++--------------------------- include/acpi/acpi_bus.h | 10 +++++ 2 files changed, 50 insertions(+), 52 deletions(-) 0933a109f7da68a80a9a4137c486db17f8bfb9b6 diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 606f873..c4d5412 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -280,91 +280,79 @@ EXPORT_SYMBOL(acpi_bus_set_power); -------------------------------------------------------------------------- */ static DEFINE_SPINLOCK(acpi_bus_event_lock); - -LIST_HEAD(acpi_bus_event_list); +LIST_HEAD(acpi_event_listener_list); DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue); -extern int event_is_open; - -int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data) +int acpi_bus_register_event_listener(struct acpi_event_listener *listener) { - struct acpi_bus_event *event = NULL; unsigned long flags = 0; - ACPI_FUNCTION_TRACE("acpi_bus_generate_event"); + ACPI_FUNCTION_TRACE("acpi_bus_add_listener"); - if (!device) + if (!listener) return_VALUE(-EINVAL); - /* drop event on the floor if no one's listening */ - if (!event_is_open) - return_VALUE(0); - - event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC); - if (!event) - return_VALUE(-ENOMEM); - - strcpy(event->device_class, device->pnp.device_class); - strcpy(event->bus_id, device->pnp.bus_id); - event->type = type; - event->data = data; - spin_lock_irqsave(&acpi_bus_event_lock, flags); - list_add_tail(&event->node, &acpi_bus_event_list); + list_add_tail(&listener->node, &acpi_event_listener_list); spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - wake_up_interruptible(&acpi_bus_event_queue); - return_VALUE(0); } -EXPORT_SYMBOL(acpi_bus_generate_event); +EXPORT_SYMBOL(acpi_bus_register_event_listener); -int acpi_bus_receive_event(struct acpi_bus_event *event) +int acpi_bus_unregister_event_listener(struct acpi_event_listener *listener) { unsigned long flags = 0; - struct acpi_bus_event *entry = NULL; - DECLARE_WAITQUEUE(wait, current); + ACPI_FUNCTION_TRACE("acpi_bus_remove_listener"); - ACPI_FUNCTION_TRACE("acpi_bus_receive_event"); - - if (!event) + if (!listener) return_VALUE(-EINVAL); - if (list_empty(&acpi_bus_event_list)) { + spin_lock_irqsave(&acpi_bus_event_lock, flags); + list_del(&listener->node); + spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&acpi_bus_event_queue, &wait); + return_VALUE(0); +} - if (list_empty(&acpi_bus_event_list)) - schedule(); +EXPORT_SYMBOL(acpi_bus_unregister_event_listener); - remove_wait_queue(&acpi_bus_event_queue, &wait); - set_current_state(TASK_RUNNING); +int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data) +{ + struct acpi_bus_event *event; + struct acpi_event_listener *listener = NULL; + unsigned long flags = 0; - if (signal_pending(current)) - return_VALUE(-ERESTARTSYS); - } + ACPI_FUNCTION_TRACE("acpi_bus_generate_event"); - spin_lock_irqsave(&acpi_bus_event_lock, flags); - entry = - list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node); - if (entry) - list_del(&entry->node); - spin_unlock_irqrestore(&acpi_bus_event_lock, flags); + if (!device) + return_VALUE(-EINVAL); - if (!entry) - return_VALUE(-ENODEV); + spin_lock_irqsave(&acpi_bus_event_lock, flags); + /* drop event on the floor if no one's listening */ + if (list_empty(&acpi_event_listener_list)) { + spin_unlock_irqrestore(&acpi_bus_event_lock, flags); + return_VALUE(0); + } - memcpy(event, entry, sizeof(struct acpi_bus_event)); + list_for_each_entry(listener, &acpi_event_listener_list, node) { + event = &listener->buffer[listener->head]; + listener->head = (listener->head + 1) & (ACPI_EVENT_BUFFER_SIZE - 1); + strcpy(event->device_class, device->pnp.device_class); + strcpy(event->bus_id, device->pnp.bus_id); + event->type = type; + event->data = data; + } + spin_unlock_irqrestore(&acpi_bus_event_lock, flags); - kfree(entry); + wake_up_interruptible(&acpi_bus_event_queue); return_VALUE(0); } -EXPORT_SYMBOL(acpi_bus_receive_event); +EXPORT_SYMBOL(acpi_bus_generate_event); /* -------------------------------------------------------------------------- Notification Handling diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0b54e9a..4ae8d07 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -313,6 +313,14 @@ struct acpi_bus_event { u32 data; }; +#define ACPI_EVENT_BUFFER_SIZE 32 +struct acpi_event_listener { + struct acpi_bus_event buffer[ACPI_EVENT_BUFFER_SIZE]; + int head; + int tail; + struct list_head node; +}; + extern struct subsystem acpi_subsys; /* @@ -324,6 +332,8 @@ void acpi_bus_data_handler(acpi_handle h int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_get_power(acpi_handle handle, int *state); int acpi_bus_set_power(acpi_handle handle, int state); +int acpi_bus_register_event_listener(struct acpi_event_listener *listener); +int acpi_bus_unregister_event_listener(struct acpi_event_listener *listener); int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event(struct acpi_bus_event *event); int acpi_bus_register_driver(struct acpi_driver *driver); -- 1.1.GIT ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] Support multiple readers for /proc/acpi/event. 2006-01-24 23:14 ` [PATCH 1/2] Implement ACPI event delivery upon subscription Mattia Dongili @ 2006-01-24 23:14 ` Mattia Dongili 0 siblings, 0 replies; 3+ messages in thread From: Mattia Dongili @ 2006-01-24 23:14 UTC (permalink / raw) To: linux-acpi, Dmitry Torokhov; +Cc: Mattia Dongili [PATCH 2/2] Support multiple readers for /proc/acpi/event. Each reader registers itself as an ACPI Event listener to get notified of events. Signed-off-by: Mattia Dongili <malattia@linux.it> --- drivers/acpi/event.c | 83 +++++++++++++++++++++++++++----------------------- 1 files changed, 45 insertions(+), 38 deletions(-) 05c7c439c5c09f3f690144e79824b24329121e91 diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 2dbb1b0..ffb6835 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -15,87 +15,93 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("event") +struct acpi_event_reader { + char str[ACPI_MAX_STRING]; + int chars_remaining; + char *ptr; + struct acpi_event_listener listener; +}; + /* Global vars for handling event proc entry */ -static DEFINE_SPINLOCK(acpi_system_event_lock); -int event_is_open = 0; -extern struct list_head acpi_bus_event_list; extern wait_queue_head_t acpi_bus_event_queue; static int acpi_system_open_event(struct inode *inode, struct file *file) { - spin_lock_irq(&acpi_system_event_lock); + struct acpi_event_reader *reader = + kzalloc(sizeof(struct acpi_event_reader), GFP_KERNEL); - if (event_is_open) - goto out_busy; + if (!reader) + return -ENOMEM; - event_is_open = 1; + acpi_bus_register_event_listener(&reader->listener); + file->private_data = reader; - spin_unlock_irq(&acpi_system_event_lock); return 0; - - out_busy: - spin_unlock_irq(&acpi_system_event_lock); - return -EBUSY; } static ssize_t acpi_system_read_event(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { - int result = 0; - struct acpi_bus_event event; - static char str[ACPI_MAX_STRING]; - static int chars_remaining = 0; - static char *ptr; + int result; + struct acpi_bus_event *event; + struct acpi_event_reader *reader = file->private_data; + struct acpi_event_listener *listener = &reader->listener; ACPI_FUNCTION_TRACE("acpi_system_read_event"); - if (!chars_remaining) { - memset(&event, 0, sizeof(struct acpi_bus_event)); + if (!reader->chars_remaining) { - if ((file->f_flags & O_NONBLOCK) - && (list_empty(&acpi_bus_event_list))) + if (listener->head == listener->tail && + (file->f_flags & O_NONBLOCK)) { return_VALUE(-EAGAIN); + } - result = acpi_bus_receive_event(&event); + result = wait_event_interruptible(acpi_bus_event_queue, + listener->head != listener->tail); if (result) return_VALUE(result); - chars_remaining = sprintf(str, "%s %s %08x %08x\n", - event.device_class ? event. - device_class : "<unknown>", - event.bus_id ? event. - bus_id : "<unknown>", event.type, - event.data); - ptr = str; + event = &listener->buffer[listener->tail]; + listener->tail = (listener->tail + 1) & (ACPI_EVENT_BUFFER_SIZE - 1); + + reader->chars_remaining = sprintf(reader->str, "%s %s %08x %08x\n", + event->device_class ? + event->device_class : "<unknown>", + event->bus_id ? event->bus_id : "<unknown>", + event->type, event->data); + reader->ptr = reader->str; } - if (chars_remaining < count) { - count = chars_remaining; + if (reader->chars_remaining < count) { + count = reader->chars_remaining; } - if (copy_to_user(buffer, ptr, count)) + if (copy_to_user(buffer, reader->ptr, count)) return_VALUE(-EFAULT); *ppos += count; - chars_remaining -= count; - ptr += count; + reader->chars_remaining -= count; + reader->ptr += count; return_VALUE(count); } static int acpi_system_close_event(struct inode *inode, struct file *file) { - spin_lock_irq(&acpi_system_event_lock); - event_is_open = 0; - spin_unlock_irq(&acpi_system_event_lock); + struct acpi_event_reader *reader = file->private_data; + + if (!acpi_bus_unregister_event_listener(&reader->listener)) + kfree(reader); + return 0; } static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) { + struct acpi_event_reader *reader = file->private_data; poll_wait(file, &acpi_bus_event_queue, wait); - if (!list_empty(&acpi_bus_event_list)) + if (reader->listener.head != reader->listener.tail) return POLLIN | POLLRDNORM; return 0; } @@ -131,3 +137,4 @@ static int __init acpi_event_init(void) } subsys_initcall(acpi_event_init); + -- 1.1.GIT ^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2006-01-24 23:13 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-01-24 23:14 [PATCH 0/2] Deliver ACPI events upon subscription and implement multiple readers for /proc/acpi/event Mattia Dongili 2006-01-24 23:14 ` [PATCH 1/2] Implement ACPI event delivery upon subscription Mattia Dongili 2006-01-24 23:14 ` [PATCH 2/2] Support multiple readers for /proc/acpi/event Mattia Dongili
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox