text: On Wed, 6 Dec 2006, Andrew Morton wrote:> > I think so too. But it would be imprudent to hang around waiting for me> to write it :(How about something like this?This (a) depends on the just-merged "struct work" cleanup (b) is totally untested (c) probably kills you slowly and painfully (d) may breed frikken sharks with lasers on their frikken heads! (e) does compile, but I don't guarantee anything else. (f) may, in other words, be totally brokenAnd, btw: it may not work. Just in case that wasn't clear. This is a quick hack from me just sitting down and seeing if I can still do kernel programming, or whether I'm just relegated to merge other peoples code. LinusPS. It might be broken.PPS. David Howells added to participant list, hopefully he can double-check all my assumptions, since he's touched the workqueue code last. Tag, you're it!----diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.cindex 4044bb1..e175f39 100644--- a/drivers/net/phy/phy.c+++ b/drivers/net/phy/phy.c@@ -587,8 +587,7 @@ int phy_stop_interrupts(struct phy_device *phydev) * Finish any pending work; we might have been scheduled * to be called from keventd ourselves, though. */- if (!current_is_keventd())- flush_scheduled_work();+ run_scheduled_work(&phydev->phy_queue); free_irq(phydev->irq, phydev); diff --git a/include/linux/workqueue.h b/include/linux/workqueue.hindex 4a3ea83..a601ed5 100644--- a/include/linux/workqueue.h+++ b/include/linux/workqueue.h@@ -160,6 +160,7 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); extern int FASTCALL(schedule_work(struct work_struct *work));+extern int FASTCALL(run_scheduled_work(struct work_struct *work)); extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay)); extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay);diff --git a/kernel/workqueue.c b/kernel/workqueue.cindex 8d1e7cb..fcacf06 100644--- a/kernel/workqueue.c+++ b/kernel/workqueue.c@@ -103,6 +103,79 @@ static inline void *get_wq_data(struct work_struct *work) return (void *) (work->management & WORK_STRUCT_WQ_DATA_MASK); } +static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)+{+ int ret = 0;+ unsigned long flags;++ spin_lock_irqsave(&cwq->lock, flags);+ /*+ * We need to re-validate the work info after we've gotten+ * the cpu_workqueue lock. We can run the work now iff:+ *+ * - the wq_data still matches the cpu_workqueue_struct+ * - AND the work is still marked pending+ * - AND the work is still on a list (which will be this+ * workqueue_struct list)+ *+ * All these conditions are important, because we+ * need to protect against the work being run right+ * now on another CPU (all but the last one might be+ * true if it's currently running and has not been+ * released yet, for example).+ */+ if (get_wq_data(work) == cwq+ && test_bit(WORK_STRUCT_PENDING, &work->management)+ && !list_empty(&work->entry)) {+ work_func_t f = work->func;+ list_del_init(&work->entry);+ spin_unlock_irqrestore(&cwq->lock, flags);++ if (!test_bit(WORK_STRUCT_NOAUTOREL, &work->management))+ work_release(work);+ f(work);++ spin_lock_irqsave(&cwq->lock, flags);+ cwq->remove_sequence++;+ wake_up(&cwq->work_done);+ ret = 1;+ }+ spin_unlock_irqrestore(&cwq->lock, flags);+ return ret;+}++/**+ * run_scheduled_work - run scheduled work synchronously+ * @work: work to run+ *+ * This checks if the work was pending, and runs it+ * synchronously if so. It returns a boolean to indicate+ * whether it had any scheduled work to run or not.+ *+ * NOTE! This _only_ works for normal work_structs. You+ * CANNOT use this for delayed work, because the wq data+ * for delayed work will not point properly to the per-+ * CPU workqueue struct, but will change!+ */+int fastcall run_scheduled_work(struct work_struct *work)+{+ for (;;) {+ struct cpu_workqueue_struct *cwq;++ if (!test_bit(WORK_STRUCT_PENDING, &work->management))+ return 0;+ if (list_empty(&work->entry))+ return 0;+ /* NOTE! This depends intimately on __queue_work! */+ cwq = get_wq_data(work);+ if (!cwq)+ return 0;+ if (__run_work(cwq, work))+ return 1;+ }+}+EXPORT_SYMBOL(run_scheduled_work);+ /* Preempt must be disabled. */ static void __queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)-To unsubscribe from this list: send the line "unsubscribe linux-kernel" inthe body of a message to majordomo@vger.kernel.orgMore majordomo info at read the FAQ at