Messages in this thread Patch in this message | | | Date | Fri, 1 Oct 1999 21:49:11 +0200 (CEST) | From | Andrea Arcangeli <> | Subject | [patch] wait4 SMP race fix (2.2.* && 2.3.*) |
| |
In wait4(2) there's an SMP race that may lead to an userspace deadlock where the parent miss a wakeup from the child and so then the parent hangs forever in wait4().
The problem can happen only if the parent masked SIGCHLD before calling wait4() (exactly as bash does) so there won't be any signal pending and the wakeup of the parent will be done only through the chldexit wq.
CPU0 CPU1 ---- ---- fork() reschedule the child block SIGCHLD wait4() do_exit() add to wait_chldexit wq check all chids all chids are running so enter the sleep/wait path task->state = TASK_ZOMBIE; wakeup chldexit wq task->state = INTERRUPTIBLE; /* we invalidated the wakeup!! */ schedule() deadlock
Here it is the fix against 2.2.13pre14:
--- 2.2.13pre14/kernel/exit.c Tue Sep 28 18:32:39 1999 +++ /tmp/exit.c Fri Oct 1 20:16:57 1999 @@ -433,6 +433,13 @@ add_wait_queue(¤t->wait_chldexit,&wait); repeat: flag = 0; + + /* The interruptible state must be set before looking at the + childs. This because we want to catch any racy exit from + the childs as do_exit() may run under us. The following + read_lock will enforce SMP ordering at the CPU level. */ + current->state = TASK_INTERRUPTIBLE; + read_lock(&tasklist_lock); for (p = current->p_cptr ; p ; p = p->p_osptr) { if (pid>0) { @@ -499,13 +506,13 @@ retval = -ERESTARTSYS; if (signal_pending(current)) goto end_wait4; - current->state=TASK_INTERRUPTIBLE; schedule(); goto repeat; } retval = -ECHILD; end_wait4: remove_wait_queue(¤t->wait_chldexit,&wait); + current->state = TASK_RUNNING; return retval; } I have not the confirm my above patch fixes the deadlock but I am quite optimistic it will 8).
The patch goes fine on the top of 2.3.18*.
Andrea
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |