diff options
| author | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-06-26 01:31:38 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-06-26 01:31:38 -0400 |
| commit | 4854c7b27f0975a2b629f35ea3996d2968eb7c4f (patch) | |
| tree | 4102bdb70289764a2058aff0f907b13d7cf0e0d1 /kernel/workqueue.c | |
| parent | 3cbd5b32cb625f5c0f1b1476d154fac873dd49ce (diff) | |
| parent | fcc18e83e1f6fd9fa6b333735bf0fcd530655511 (diff) | |
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 880fb415a8f6..565cf7a1febd 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -428,22 +428,34 @@ int schedule_delayed_work_on(int cpu, | |||
| 428 | return ret; | 428 | return ret; |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | int schedule_on_each_cpu(void (*func) (void *info), void *info) | 431 | /** |
| 432 | * schedule_on_each_cpu - call a function on each online CPU from keventd | ||
| 433 | * @func: the function to call | ||
| 434 | * @info: a pointer to pass to func() | ||
| 435 | * | ||
| 436 | * Returns zero on success. | ||
| 437 | * Returns -ve errno on failure. | ||
| 438 | * | ||
| 439 | * Appears to be racy against CPU hotplug. | ||
| 440 | * | ||
| 441 | * schedule_on_each_cpu() is very slow. | ||
| 442 | */ | ||
| 443 | int schedule_on_each_cpu(void (*func)(void *info), void *info) | ||
| 432 | { | 444 | { |
| 433 | int cpu; | 445 | int cpu; |
| 434 | struct work_struct *work; | 446 | struct work_struct *works; |
| 435 | 447 | ||
| 436 | work = kmalloc(NR_CPUS * sizeof(struct work_struct), GFP_KERNEL); | 448 | works = alloc_percpu(struct work_struct); |
| 437 | 449 | if (!works) | |
| 438 | if (!work) | ||
| 439 | return -ENOMEM; | 450 | return -ENOMEM; |
| 451 | |||
| 440 | for_each_online_cpu(cpu) { | 452 | for_each_online_cpu(cpu) { |
| 441 | INIT_WORK(work + cpu, func, info); | 453 | INIT_WORK(per_cpu_ptr(works, cpu), func, info); |
| 442 | __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), | 454 | __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), |
| 443 | work + cpu); | 455 | per_cpu_ptr(works, cpu)); |
| 444 | } | 456 | } |
| 445 | flush_workqueue(keventd_wq); | 457 | flush_workqueue(keventd_wq); |
| 446 | kfree(work); | 458 | free_percpu(works); |
| 447 | return 0; | 459 | return 0; |
| 448 | } | 460 | } |
| 449 | 461 | ||
| @@ -531,11 +543,11 @@ int current_is_keventd(void) | |||
| 531 | static void take_over_work(struct workqueue_struct *wq, unsigned int cpu) | 543 | static void take_over_work(struct workqueue_struct *wq, unsigned int cpu) |
| 532 | { | 544 | { |
| 533 | struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu); | 545 | struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu); |
| 534 | LIST_HEAD(list); | 546 | struct list_head list; |
| 535 | struct work_struct *work; | 547 | struct work_struct *work; |
| 536 | 548 | ||
| 537 | spin_lock_irq(&cwq->lock); | 549 | spin_lock_irq(&cwq->lock); |
| 538 | list_splice_init(&cwq->worklist, &list); | 550 | list_replace_init(&cwq->worklist, &list); |
| 539 | 551 | ||
| 540 | while (!list_empty(&list)) { | 552 | while (!list_empty(&list)) { |
| 541 | printk("Taking work for %s\n", wq->name); | 553 | printk("Taking work for %s\n", wq->name); |
| @@ -578,6 +590,8 @@ static int workqueue_cpu_callback(struct notifier_block *nfb, | |||
| 578 | 590 | ||
| 579 | case CPU_UP_CANCELED: | 591 | case CPU_UP_CANCELED: |
| 580 | list_for_each_entry(wq, &workqueues, list) { | 592 | list_for_each_entry(wq, &workqueues, list) { |
| 593 | if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread) | ||
| 594 | continue; | ||
| 581 | /* Unbind so it can run. */ | 595 | /* Unbind so it can run. */ |
| 582 | kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread, | 596 | kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread, |
| 583 | any_online_cpu(cpu_online_map)); | 597 | any_online_cpu(cpu_online_map)); |
