summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/process.c')
-rw-r--r--arch/i386/kernel/process.c71
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, &regs);
+}
+
+/*
* sys_execve() executes a new program.
*/
asmlinkage int sys_execve(struct pt_regs regs)