diff options
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4048e92aa04..d4dc69ddebd 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | * Derived from the taskqueue/keventd code by: | 9 | * Derived from the taskqueue/keventd code by: |
| 10 | * | 10 | * |
| 11 | * David Woodhouse <dwmw2@infradead.org> | 11 | * David Woodhouse <dwmw2@infradead.org> |
| 12 | * Andrew Morton <andrewm@uow.edu.au> | 12 | * Andrew Morton |
| 13 | * Kai Petzke <wpp@marie.physik.tu-berlin.de> | 13 | * Kai Petzke <wpp@marie.physik.tu-berlin.de> |
| 14 | * Theodore Ts'o <tytso@mit.edu> | 14 | * Theodore Ts'o <tytso@mit.edu> |
| 15 | * | 15 | * |
| @@ -62,6 +62,7 @@ struct workqueue_struct { | |||
| 62 | const char *name; | 62 | const char *name; |
| 63 | int singlethread; | 63 | int singlethread; |
| 64 | int freezeable; /* Freeze threads during suspend */ | 64 | int freezeable; /* Freeze threads during suspend */ |
| 65 | int rt; | ||
| 65 | #ifdef CONFIG_LOCKDEP | 66 | #ifdef CONFIG_LOCKDEP |
| 66 | struct lockdep_map lockdep_map; | 67 | struct lockdep_map lockdep_map; |
| 67 | #endif | 68 | #endif |
| @@ -766,6 +767,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu) | |||
| 766 | 767 | ||
| 767 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | 768 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) |
| 768 | { | 769 | { |
| 770 | struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; | ||
| 769 | struct workqueue_struct *wq = cwq->wq; | 771 | struct workqueue_struct *wq = cwq->wq; |
| 770 | const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d"; | 772 | const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d"; |
| 771 | struct task_struct *p; | 773 | struct task_struct *p; |
| @@ -781,7 +783,8 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | |||
| 781 | */ | 783 | */ |
| 782 | if (IS_ERR(p)) | 784 | if (IS_ERR(p)) |
| 783 | return PTR_ERR(p); | 785 | return PTR_ERR(p); |
| 784 | 786 | if (cwq->wq->rt) | |
| 787 | sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m); | ||
| 785 | cwq->thread = p; | 788 | cwq->thread = p; |
| 786 | 789 | ||
| 787 | return 0; | 790 | return 0; |
| @@ -801,6 +804,7 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | |||
| 801 | struct workqueue_struct *__create_workqueue_key(const char *name, | 804 | struct workqueue_struct *__create_workqueue_key(const char *name, |
| 802 | int singlethread, | 805 | int singlethread, |
| 803 | int freezeable, | 806 | int freezeable, |
| 807 | int rt, | ||
| 804 | struct lock_class_key *key, | 808 | struct lock_class_key *key, |
| 805 | const char *lock_name) | 809 | const char *lock_name) |
| 806 | { | 810 | { |
| @@ -822,6 +826,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name, | |||
| 822 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); | 826 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); |
| 823 | wq->singlethread = singlethread; | 827 | wq->singlethread = singlethread; |
| 824 | wq->freezeable = freezeable; | 828 | wq->freezeable = freezeable; |
| 829 | wq->rt = rt; | ||
| 825 | INIT_LIST_HEAD(&wq->list); | 830 | INIT_LIST_HEAD(&wq->list); |
| 826 | 831 | ||
| 827 | if (singlethread) { | 832 | if (singlethread) { |
| @@ -965,6 +970,51 @@ undo: | |||
| 965 | return ret; | 970 | return ret; |
| 966 | } | 971 | } |
| 967 | 972 | ||
| 973 | #ifdef CONFIG_SMP | ||
| 974 | struct work_for_cpu { | ||
| 975 | struct work_struct work; | ||
| 976 | long (*fn)(void *); | ||
| 977 | void *arg; | ||
| 978 | long ret; | ||
| 979 | }; | ||
| 980 | |||
| 981 | static void do_work_for_cpu(struct work_struct *w) | ||
| 982 | { | ||
| 983 | struct work_for_cpu *wfc = container_of(w, struct work_for_cpu, work); | ||
| 984 | |||
| 985 | wfc->ret = wfc->fn(wfc->arg); | ||
| 986 | } | ||
| 987 | |||
| 988 | /** | ||
| 989 | * work_on_cpu - run a function in user context on a particular cpu | ||
| 990 | * @cpu: the cpu to run on | ||
| 991 | * @fn: the function to run | ||
| 992 | * @arg: the function arg | ||
| 993 | * | ||
| 994 | * This will return -EINVAL in the cpu is not online, or the return value | ||
| 995 | * of @fn otherwise. | ||
| 996 | */ | ||
| 997 | long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg) | ||
| 998 | { | ||
| 999 | struct work_for_cpu wfc; | ||
| 1000 | |||
| 1001 | INIT_WORK(&wfc.work, do_work_for_cpu); | ||
| 1002 | wfc.fn = fn; | ||
| 1003 | wfc.arg = arg; | ||
| 1004 | get_online_cpus(); | ||
| 1005 | if (unlikely(!cpu_online(cpu))) | ||
| 1006 | wfc.ret = -EINVAL; | ||
| 1007 | else { | ||
| 1008 | schedule_work_on(cpu, &wfc.work); | ||
| 1009 | flush_work(&wfc.work); | ||
| 1010 | } | ||
| 1011 | put_online_cpus(); | ||
| 1012 | |||
| 1013 | return wfc.ret; | ||
| 1014 | } | ||
| 1015 | EXPORT_SYMBOL_GPL(work_on_cpu); | ||
| 1016 | #endif /* CONFIG_SMP */ | ||
| 1017 | |||
| 968 | void __init init_workqueues(void) | 1018 | void __init init_workqueues(void) |
| 969 | { | 1019 | { |
| 970 | cpu_populated_map = cpu_online_map; | 1020 | cpu_populated_map = cpu_online_map; |
