diff options
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/fork.c | 2 | ||||
-rw-r--r-- | kernel/sched.c | 53 | ||||
-rw-r--r-- | kernel/workqueue_sched.h | 16 |
4 files changed, 69 insertions, 3 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index f118809c953f..edc3dd168d87 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1696,6 +1696,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * | |||
1696 | #define PF_EXITING 0x00000004 /* getting shut down */ | 1696 | #define PF_EXITING 0x00000004 /* getting shut down */ |
1697 | #define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */ | 1697 | #define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */ |
1698 | #define PF_VCPU 0x00000010 /* I'm a virtual CPU */ | 1698 | #define PF_VCPU 0x00000010 /* I'm a virtual CPU */ |
1699 | #define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */ | ||
1699 | #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ | 1700 | #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ |
1700 | #define PF_MCE_PROCESS 0x00000080 /* process policy on mce errors */ | 1701 | #define PF_MCE_PROCESS 0x00000080 /* process policy on mce errors */ |
1701 | #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ | 1702 | #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ |
diff --git a/kernel/fork.c b/kernel/fork.c index b6cce14ba047..a82a65cef741 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -907,7 +907,7 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p) | |||
907 | { | 907 | { |
908 | unsigned long new_flags = p->flags; | 908 | unsigned long new_flags = p->flags; |
909 | 909 | ||
910 | new_flags &= ~PF_SUPERPRIV; | 910 | new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); |
911 | new_flags |= PF_FORKNOEXEC; | 911 | new_flags |= PF_FORKNOEXEC; |
912 | new_flags |= PF_STARTING; | 912 | new_flags |= PF_STARTING; |
913 | p->flags = new_flags; | 913 | p->flags = new_flags; |
diff --git a/kernel/sched.c b/kernel/sched.c index 96eafd5f345f..edd5a54b95da 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -77,6 +77,7 @@ | |||
77 | #include <asm/irq_regs.h> | 77 | #include <asm/irq_regs.h> |
78 | 78 | ||
79 | #include "sched_cpupri.h" | 79 | #include "sched_cpupri.h" |
80 | #include "workqueue_sched.h" | ||
80 | 81 | ||
81 | #define CREATE_TRACE_POINTS | 82 | #define CREATE_TRACE_POINTS |
82 | #include <trace/events/sched.h> | 83 | #include <trace/events/sched.h> |
@@ -2306,6 +2307,9 @@ static inline void ttwu_post_activation(struct task_struct *p, struct rq *rq, | |||
2306 | rq->idle_stamp = 0; | 2307 | rq->idle_stamp = 0; |
2307 | } | 2308 | } |
2308 | #endif | 2309 | #endif |
2310 | /* if a worker is waking up, notify workqueue */ | ||
2311 | if ((p->flags & PF_WQ_WORKER) && success) | ||
2312 | wq_worker_waking_up(p, cpu_of(rq)); | ||
2309 | } | 2313 | } |
2310 | 2314 | ||
2311 | /** | 2315 | /** |
@@ -2414,6 +2418,37 @@ out: | |||
2414 | } | 2418 | } |
2415 | 2419 | ||
2416 | /** | 2420 | /** |
2421 | * try_to_wake_up_local - try to wake up a local task with rq lock held | ||
2422 | * @p: the thread to be awakened | ||
2423 | * | ||
2424 | * Put @p on the run-queue if it's not alredy there. The caller must | ||
2425 | * ensure that this_rq() is locked, @p is bound to this_rq() and not | ||
2426 | * the current task. this_rq() stays locked over invocation. | ||
2427 | */ | ||
2428 | static void try_to_wake_up_local(struct task_struct *p) | ||
2429 | { | ||
2430 | struct rq *rq = task_rq(p); | ||
2431 | bool success = false; | ||
2432 | |||
2433 | BUG_ON(rq != this_rq()); | ||
2434 | BUG_ON(p == current); | ||
2435 | lockdep_assert_held(&rq->lock); | ||
2436 | |||
2437 | if (!(p->state & TASK_NORMAL)) | ||
2438 | return; | ||
2439 | |||
2440 | if (!p->se.on_rq) { | ||
2441 | if (likely(!task_running(rq, p))) { | ||
2442 | schedstat_inc(rq, ttwu_count); | ||
2443 | schedstat_inc(rq, ttwu_local); | ||
2444 | } | ||
2445 | ttwu_activate(p, rq, false, false, true, ENQUEUE_WAKEUP); | ||
2446 | success = true; | ||
2447 | } | ||
2448 | ttwu_post_activation(p, rq, 0, success); | ||
2449 | } | ||
2450 | |||
2451 | /** | ||
2417 | * wake_up_process - Wake up a specific process | 2452 | * wake_up_process - Wake up a specific process |
2418 | * @p: The process to be woken up. | 2453 | * @p: The process to be woken up. |
2419 | * | 2454 | * |
@@ -3618,10 +3653,24 @@ need_resched_nonpreemptible: | |||
3618 | clear_tsk_need_resched(prev); | 3653 | clear_tsk_need_resched(prev); |
3619 | 3654 | ||
3620 | if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { | 3655 | if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { |
3621 | if (unlikely(signal_pending_state(prev->state, prev))) | 3656 | if (unlikely(signal_pending_state(prev->state, prev))) { |
3622 | prev->state = TASK_RUNNING; | 3657 | prev->state = TASK_RUNNING; |
3623 | else | 3658 | } else { |
3659 | /* | ||
3660 | * If a worker is going to sleep, notify and | ||
3661 | * ask workqueue whether it wants to wake up a | ||
3662 | * task to maintain concurrency. If so, wake | ||
3663 | * up the task. | ||
3664 | */ | ||
3665 | if (prev->flags & PF_WQ_WORKER) { | ||
3666 | struct task_struct *to_wakeup; | ||
3667 | |||
3668 | to_wakeup = wq_worker_sleeping(prev, cpu); | ||
3669 | if (to_wakeup) | ||
3670 | try_to_wake_up_local(to_wakeup); | ||
3671 | } | ||
3624 | deactivate_task(rq, prev, DEQUEUE_SLEEP); | 3672 | deactivate_task(rq, prev, DEQUEUE_SLEEP); |
3673 | } | ||
3625 | switch_count = &prev->nvcsw; | 3674 | switch_count = &prev->nvcsw; |
3626 | } | 3675 | } |
3627 | 3676 | ||
diff --git a/kernel/workqueue_sched.h b/kernel/workqueue_sched.h new file mode 100644 index 000000000000..af040babb742 --- /dev/null +++ b/kernel/workqueue_sched.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * kernel/workqueue_sched.h | ||
3 | * | ||
4 | * Scheduler hooks for concurrency managed workqueue. Only to be | ||
5 | * included from sched.c and workqueue.c. | ||
6 | */ | ||
7 | static inline void wq_worker_waking_up(struct task_struct *task, | ||
8 | unsigned int cpu) | ||
9 | { | ||
10 | } | ||
11 | |||
12 | static inline struct task_struct *wq_worker_sleeping(struct task_struct *task, | ||
13 | unsigned int cpu) | ||
14 | { | ||
15 | return NULL; | ||
16 | } | ||