aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-11-22 09:55:48 -0500
committerDavid Howells <dhowells@redhat.com>2006-11-22 09:55:48 -0500
commit65f27f38446e1976cc98fd3004b110fedcddd189 (patch)
tree68f8be93feae31dfa018c22db392a05546b63ee1 /drivers/acpi/osl.c
parent365970a1ea76d81cb1ad2f652acb605f06dae256 (diff)
WorkStruct: Pass the work_struct pointer instead of context data
Pass the work_struct pointer to the work function rather than context data. The work function can use container_of() to work out the data. For the cases where the container of the work_struct may go away the moment the pending bit is cleared, it is made possible to defer the release of the structure by deferring the clearing of the pending bit. To make this work, an extra flag is introduced into the management side of the work_struct. This governs auto-release of the structure upon execution. Ordinarily, the work queue executor would release the work_struct for further scheduling or deallocation by clearing the pending bit prior to jumping to the work function. This means that, unless the driver makes some guarantee itself that the work_struct won't go away, the work function may not access anything else in the work_struct or its container lest they be deallocated.. This is a problem if the auxiliary data is taken away (as done by the last patch). However, if the pending bit is *not* cleared before jumping to the work function, then the work function *may* access the work_struct and its container with no problems. But then the work function must itself release the work_struct by calling work_release(). In most cases, automatic release is fine, so this is the default. Special initiators exist for the non-auto-release case (ending in _NAR). Signed-Off-By: David Howells <dhowells@redhat.com>
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c25
1 files changed, 8 insertions, 17 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 068fe4f100b0..02b30ae6a68e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -50,6 +50,7 @@ ACPI_MODULE_NAME("osl")
50struct acpi_os_dpc { 50struct acpi_os_dpc {
51 acpi_osd_exec_callback function; 51 acpi_osd_exec_callback function;
52 void *context; 52 void *context;
53 struct work_struct work;
53}; 54};
54 55
55#ifdef CONFIG_ACPI_CUSTOM_DSDT 56#ifdef CONFIG_ACPI_CUSTOM_DSDT
@@ -564,12 +565,9 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
564 acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number); 565 acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
565} 566}
566 567
567static void acpi_os_execute_deferred(void *context) 568static void acpi_os_execute_deferred(struct work_struct *work)
568{ 569{
569 struct acpi_os_dpc *dpc = NULL; 570 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
570
571
572 dpc = (struct acpi_os_dpc *)context;
573 if (!dpc) { 571 if (!dpc) {
574 printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); 572 printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
575 return; 573 return;
@@ -602,7 +600,6 @@ acpi_status acpi_os_execute(acpi_execute_type type,
602{ 600{
603 acpi_status status = AE_OK; 601 acpi_status status = AE_OK;
604 struct acpi_os_dpc *dpc; 602 struct acpi_os_dpc *dpc;
605 struct work_struct *task;
606 603
607 ACPI_FUNCTION_TRACE("os_queue_for_execution"); 604 ACPI_FUNCTION_TRACE("os_queue_for_execution");
608 605
@@ -615,28 +612,22 @@ acpi_status acpi_os_execute(acpi_execute_type type,
615 612
616 /* 613 /*
617 * Allocate/initialize DPC structure. Note that this memory will be 614 * Allocate/initialize DPC structure. Note that this memory will be
618 * freed by the callee. The kernel handles the tq_struct list in a 615 * freed by the callee. The kernel handles the work_struct list in a
619 * way that allows us to also free its memory inside the callee. 616 * way that allows us to also free its memory inside the callee.
620 * Because we may want to schedule several tasks with different 617 * Because we may want to schedule several tasks with different
621 * parameters we can't use the approach some kernel code uses of 618 * parameters we can't use the approach some kernel code uses of
622 * having a static tq_struct. 619 * having a static work_struct.
623 * We can save time and code by allocating the DPC and tq_structs
624 * from the same memory.
625 */ 620 */
626 621
627 dpc = 622 dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
628 kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
629 GFP_ATOMIC);
630 if (!dpc) 623 if (!dpc)
631 return_ACPI_STATUS(AE_NO_MEMORY); 624 return_ACPI_STATUS(AE_NO_MEMORY);
632 625
633 dpc->function = function; 626 dpc->function = function;
634 dpc->context = context; 627 dpc->context = context;
635 628
636 task = (void *)(dpc + 1); 629 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
637 INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); 630 if (!queue_work(kacpid_wq, &dpc->work)) {
638
639 if (!queue_work(kacpid_wq, task)) {
640 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 631 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
641 "Call to queue_work() failed.\n")); 632 "Call to queue_work() failed.\n"));
642 kfree(dpc); 633 kfree(dpc);