patch-2.4.7 linux/kernel/fork.c
Next file: linux/kernel/kmod.c
Previous file: linux/init/main.c
Back to the patch index
Back to the overall index
- Lines: 133
- Date:
Tue Jul 17 18:23:28 2001
- Orig file:
v2.4.6/linux/kernel/fork.c
- Orig date:
Mon Apr 30 22:23:29 2001
diff -u --recursive --new-file v2.4.6/linux/kernel/fork.c linux/kernel/fork.c
@@ -18,6 +18,7 @@
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/completion.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -269,11 +270,12 @@
void mm_release(void)
{
struct task_struct *tsk = current;
+ struct completion *vfork_done = tsk->vfork_done;
/* notify parent sleeping on vfork() */
- if (tsk->flags & PF_VFORK) {
- tsk->flags &= ~PF_VFORK;
- up(tsk->p_opptr->vfork_sem);
+ if (vfork_done) {
+ tsk->vfork_done = NULL;
+ complete(vfork_done);
}
}
@@ -536,12 +538,10 @@
{
unsigned long new_flags = p->flags;
- new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU | PF_VFORK);
+ new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU);
new_flags |= PF_FORKNOEXEC;
if (!(clone_flags & CLONE_PTRACE))
p->ptrace = 0;
- if (clone_flags & CLONE_VFORK)
- new_flags |= PF_VFORK;
p->flags = new_flags;
}
@@ -557,18 +557,22 @@
int do_fork(unsigned long clone_flags, unsigned long stack_start,
struct pt_regs *regs, unsigned long stack_size)
{
- int retval = -ENOMEM;
+ int retval;
struct task_struct *p;
- DECLARE_MUTEX_LOCKED(sem);
+ struct completion vfork;
+
+ retval = -EPERM;
+ /*
+ * CLONE_PID is only allowed for the initial SMP swapper
+ * calls
+ */
if (clone_flags & CLONE_PID) {
- /* This is only allowed from the boot up thread */
if (current->pid)
- return -EPERM;
+ goto fork_out;
}
-
- current->vfork_sem = &sem;
+ retval = -ENOMEM;
p = alloc_task_struct();
if (!p)
goto fork_out;
@@ -578,6 +582,7 @@
retval = -EAGAIN;
if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur)
goto bad_fork_free;
+
atomic_inc(&p->user->__count);
atomic_inc(&p->user->processes);
@@ -604,14 +609,13 @@
p->run_list.next = NULL;
p->run_list.prev = NULL;
- if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) {
- p->p_opptr = current;
- if (!(p->ptrace & PT_PTRACED))
- p->p_pptr = current;
- }
p->p_cptr = NULL;
init_waitqueue_head(&p->wait_chldexit);
- p->vfork_sem = NULL;
+ p->vfork_done = NULL;
+ if (clone_flags & CLONE_VFORK) {
+ p->vfork_done = &vfork;
+ init_completion(&vfork);
+ }
spin_lock_init(&p->alloc_lock);
p->sigpending = 0;
@@ -685,11 +689,24 @@
retval = p->pid;
p->tgid = retval;
INIT_LIST_HEAD(&p->thread_group);
+
+ /* Need tasklist lock for parent etc handling! */
write_lock_irq(&tasklist_lock);
+
+ /* CLONE_PARENT and CLONE_THREAD re-use the old parent */
+ p->p_opptr = current->p_opptr;
+ p->p_pptr = current->p_pptr;
+ if (!(clone_flags & (CLONE_PARENT | CLONE_THREAD))) {
+ p->p_opptr = current;
+ if (!(p->ptrace & PT_PTRACED))
+ p->p_pptr = current;
+ }
+
if (clone_flags & CLONE_THREAD) {
p->tgid = current->tgid;
list_add(&p->thread_group, ¤t->thread_group);
}
+
SET_LINKS(p);
hash_pid(p);
nr_threads++;
@@ -700,10 +717,10 @@
wake_up_process(p); /* do this last */
++total_forks;
+ if (clone_flags & CLONE_VFORK)
+ wait_for_completion(&vfork);
fork_out:
- if ((clone_flags & CLONE_VFORK) && (retval > 0))
- down(&sem);
return retval;
bad_fork_cleanup_mm:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)