History

kthread: Prevent unpark race which puts threads on the wrong cpu

The smpboot threads rely on the park/unpark mechanism which binds per cpu threads on a particular core. Though the functionality is racy: CPU0 CPU1 CPU2 unpark(T) wake_up_process(T) clear(SHOULD_PARK) T runs leave parkme() due to !SHOULD_PARK bind_to(CPU2) BUG_ON(wrong CPU) We cannot let the tasks move themself to the target CPU as one of those tasks is actually the migration thread itself, which requires that it starts running on the target cpu right away. The solution to this problem is to prevent wakeups in park mode which are not from unpark(). That way we can guarantee that the association of the task to the target cpu is working correctly. Add a new task state (TASK_PARKED) which prevents other wakeups and use this state explicitly for the unpark wakeup. Peter noticed: Also, since the task state is visible to userspace and all the parked tasks are still in the PID space, its a good hint in ps and friends that these tasks aren't really there for the moment. The migration thread has another related issue. CPU0 CPU1 Bring up CPU2 create_thread(T) park(T) wait_for_completion() parkme() complete() sched_set_stop_task() schedule(TASK_PARKED) The sched_set_stop_task() call is issued while the task is on the runqueue of CPU1 and that confuses the hell out of the stop_task class on that cpu. So we need the same synchronizaion before sched_set_stop_task().

Thomas Gleixner committed 13 years ago

Commit f2530dc1 parent cfb63ba5 files · +45 −29Browse files

Showing the changes to include (2 of 5 files). Show all

Unified · Split

2 files
  1. include/linux/sched.h +3 −2
  2. include/trace/events/sched.h +1 −1
include/linux/sched.h+3−2
@@ -163,9 +163,10 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) · 162 unmodified lines
163#define TASK_DEAD 64163#define TASK_DEAD 64
164#define TASK_WAKEKILL 128164#define TASK_WAKEKILL 128
165#define TASK_WAKING 256165#define TASK_WAKING 256
166#define TASK_STATE_MAX 512166#define TASK_PARKED 512
167#define TASK_STATE_MAX 1024
167 168
168#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW"169#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
169 170
170extern char ___assert_task_state[1 - 2*!!(171extern char ___assert_task_state[1 - 2*!!(
171 sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];172 sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];
include/trace/events/sched.h+1−1
@@ -147,7 +147,7 @@ TRACE_EVENT(sched_switch, · 146 unmodified lines
147 __print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",147 __print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",
148 { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },148 { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
149 { 16, "Z" }, { 32, "X" }, { 64, "x" },149 { 16, "Z" }, { 32, "X" }, { 64, "x" },
150 { 128, "W" }) : "R",150 { 128, "K" }, { 256, "W" }, { 512, "P" }) : "R",
151 __entry->prev_state & TASK_STATE_MAX ? "+" : "",151 __entry->prev_state & TASK_STATE_MAX ? "+" : "",
152 __entry->next_comm, __entry->next_pid, __entry->next_prio)152 __entry->next_comm, __entry->next_pid, __entry->next_prio)
153);153);