diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-05 00:12:58 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-05 00:12:58 -0800 |
| commit | 908920b1d370e7a5c301d14cfce10c310be19be3 (patch) | |
| tree | 25606bf2c5215cc0e25c9647612390b88622b279 /kernel/fork.c | |
| parent | d01b7e92c0020f89b4bb33fe61c0dffab7078b42 (diff) | |
v2.5.1.9 -> v2.5.1.10
- Kai Germaschewski: ISDN updates
- Al Viro: start moving buffer cache indexing to "struct block_device *"
- Greg KH: USB update
- Russell King: fix up some ARM merge issues
- Ingo Molnar: scalable scheduler
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 52 |
1 files changed, 40 insertions, 12 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 4c3114eef4c4..3fcaeafeb535 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -29,7 +29,6 @@ /* The idle threads do not count.. */ int nr_threads; -int nr_running; int max_threads; unsigned long total_forks; /* Handle normal Linux uptimes. */ @@ -37,6 +36,8 @@ int last_pid; struct task_struct *pidhash[PIDHASH_SZ]; +rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ + void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) { unsigned long flags; @@ -564,6 +565,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size) { int retval; + unsigned long flags; struct task_struct *p; struct completion vfork; @@ -617,8 +619,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, copy_flags(clone_flags, p); p->pid = get_pid(clone_flags); - p->run_list.next = NULL; - p->run_list.prev = NULL; + INIT_LIST_HEAD(&p->run_list); p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); @@ -644,14 +645,16 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, #ifdef CONFIG_SMP { int i; - p->cpus_runnable = ~0UL; - p->processor = current->processor; + + p->cpu = smp_processor_id(); + /* ?? should we just memset this ?? */ for(i = 0; i < smp_num_cpus; i++) p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; spin_lock_init(&p->sigmask_lock); } #endif + p->array = NULL; p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; @@ -685,15 +688,27 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, p->pdeath_signal = 0; /* - * "share" dynamic priority between parent and child, thus the - * total amount of dynamic priorities in the system doesnt change, - * more scheduling fairness. This is only important in the first - * timeslice, on the long run the scheduling behaviour is unchanged. + * Share the timeslice between parent and child, thus the + * total amount of pending timeslices in the system doesnt change, + * resulting in more scheduling fairness. */ + __save_flags(flags); + __cli(); p->time_slice = (current->time_slice + 1) >> 1; current->time_slice >>= 1; - if (!current->time_slice) - current->need_resched = 1; + if (!current->time_slice) { + /* + * This case is rare, it happens when the parent has only + * a single jiffy left from its timeslice. Taking the + * runqueue lock is not a problem. + */ + current->time_slice = 1; + expire_task(current); + } + p->sleep_timestamp = p->run_timestamp = jiffies; + memset(p->sleep_hist, 0, sizeof(p->sleep_hist[0])*SLEEP_HIST_SIZE); + p->sleep_idx = 0; + __restore_flags(flags); /* * Ok, add it to the run-queues and make it @@ -730,10 +745,23 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); - wake_up_process(p); /* do this last */ +#define RUN_CHILD_FIRST 1 +#if RUN_CHILD_FIRST + wake_up_forked_process(p); /* do this last */ +#else + wake_up_process(p); /* do this last */ +#endif ++total_forks; if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); +#if RUN_CHILD_FIRST + else + /* + * Let the child process run first, to avoid most of the + * COW overhead when the child exec()s afterwards. + */ + current->need_resched = 1; +#endif fork_out: return retval; |
