diff options
Diffstat (limited to 'arch/i386/kernel/process.c')
-rw-r--r-- | arch/i386/kernel/process.c | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 00f39d4ed..00f7e0ba2 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -105,19 +105,24 @@ static void hard_idle(void) */ static int cpu_idle(void *unused) { - unsigned long start_idle = jiffies; + int work = 1; + unsigned long start_idle = 0; /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; for (;;) { + if (work) + start_idle = jiffies; + if (jiffies - start_idle > HARD_IDLE_TIMEOUT) hard_idle(); else { if (boot_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) __asm__("hlt"); } - if (current->need_resched) - start_idle = jiffies; - current->policy = SCHED_YIELD; + + work = current->need_resched; schedule(); check_pgt_cache(); } @@ -131,14 +136,21 @@ static int cpu_idle(void *unused) int cpu_idle(void *unused) { - /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; while(1) { - if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) + if (current_cpu_data.hlt_works_ok && !hlt_counter && + !current->need_resched) __asm__("hlt"); - current->policy = SCHED_YIELD; - schedule(); - check_pgt_cache(); + /* + * although we are an idle CPU, we do not want to + * get into the scheduler unnecessarily. + */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } } } @@ -463,24 +475,27 @@ void free_task_struct(struct task_struct *p) void release_segments(struct mm_struct *mm) { - /* forget local segments */ - __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs" - : /* no outputs */ - : "r" (0)); if (mm->segments) { void * ldt = mm->segments; - - /* - * Get the LDT entry from init_task. - */ - current->tss.ldt = _LDT(0); - load_ldt(0); - mm->segments = NULL; vfree(ldt); } } +void forget_segments(void) +{ + /* forget local segments */ + __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs" + : /* no outputs */ + : "r" (0)); + + /* + * Get the LDT entry from init_task. + */ + current->tss.ldt = _LDT(0); + load_ldt(0); +} + /* * Create a kernel thread */ @@ -579,7 +594,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, *childregs = *regs; childregs->eax = 0; childregs->esp = esp; - childregs->eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */ p->tss.esp = (unsigned long) childregs; p->tss.esp0 = (unsigned long) (childregs+1); @@ -771,6 +785,21 @@ asmlinkage int sys_clone(struct pt_regs regs) } /* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s); +} + +/* * sys_execve() executes a new program. */ asmlinkage int sys_execve(struct pt_regs regs) |