summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-09-25 07:28:05 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-09-25 07:28:05 -0700
commit2ce067b09aff22fcfe57e805e5abf409d4547dd1 (patch)
treec73baa99b8cedcccfc6f2cd14a006f94160175e3 /kernel
parent56d8b39d50e64ca5f9e20cfcd79870dd4109974f (diff)
parent4ab1a3e6a2904f6265c20ad0b1144092bbd2529a (diff)
Merge bk://ldm.bkbits.net/linux-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c46
-rw-r--r--kernel/fork.c46
-rw-r--r--kernel/ksyms.c8
-rw-r--r--kernel/pid.c9
-rw-r--r--kernel/sched.c17
-rw-r--r--kernel/timer.c14
6 files changed, 109 insertions, 31 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 7189e9bce6d4..6ed07def4c62 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -32,6 +32,7 @@ int getrusage(struct task_struct *, int, struct rusage *);
static struct dentry * __unhash_process(struct task_struct *p)
{
struct dentry *proc_dentry;
+
nr_threads--;
detach_pid(p, PIDTYPE_PID);
detach_pid(p, PIDTYPE_TGID);
@@ -57,31 +58,31 @@ static struct dentry * __unhash_process(struct task_struct *p)
void release_task(struct task_struct * p)
{
struct dentry *proc_dentry;
+ task_t *leader;
- if (p->state != TASK_ZOMBIE)
+ if (p->state < TASK_ZOMBIE)
BUG();
if (p != current)
wait_task_inactive(p);
atomic_dec(&p->user->processes);
security_ops->task_free_security(p);
free_uid(p->user);
- if (unlikely(p->ptrace)) {
- write_lock_irq(&tasklist_lock);
+ write_lock_irq(&tasklist_lock);
+ if (unlikely(p->ptrace))
__ptrace_unlink(p);
- write_unlock_irq(&tasklist_lock);
- }
BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
- write_lock_irq(&tasklist_lock);
__exit_sighand(p);
proc_dentry = __unhash_process(p);
/*
* If we are the last non-leader member of the thread
* group, and the leader is zombie, then notify the
- * group leader's parent process.
+ * group leader's parent process. (if it wants notification.)
*/
- if (p->group_leader != p && thread_group_empty(p))
- do_notify_parent(p->group_leader, p->group_leader->exit_signal);
+ leader = p->group_leader;
+ if (leader != p && thread_group_empty(leader) &&
+ leader->state == TASK_ZOMBIE && leader->exit_signal != -1)
+ do_notify_parent(leader, leader->exit_signal);
p->parent->cutime += p->utime + p->cutime;
p->parent->cstime += p->stime + p->cstime;
@@ -159,7 +160,7 @@ static int __will_become_orphaned_pgrp(int pgrp, task_t *ignored_task)
for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
if (p == ignored_task
- || p->state == TASK_ZOMBIE
+ || p->state >= TASK_ZOMBIE
|| p->real_parent->pid == 1)
continue;
if (p->real_parent->pgrp != pgrp
@@ -435,8 +436,11 @@ void exit_mm(struct task_struct *tsk)
static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper)
{
- /* Make sure we're not reparenting to ourselves. */
- if (p == reaper)
+ /*
+ * Make sure we're not reparenting to ourselves and that
+ * the parent is not a zombie.
+ */
+ if (p == reaper || reaper->state >= TASK_ZOMBIE)
p->real_parent = child_reaper;
else
p->real_parent = reaper;
@@ -774,9 +778,10 @@ static int eligible_child(pid_t pid, int options, task_t *p)
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
{
- int flag, retval;
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
+ unsigned long state;
+ int flag, retval;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
@@ -827,7 +832,15 @@ repeat:
*/
if (ret == 2)
continue;
+ /*
+ * Try to move the task's state to DEAD
+ * only one thread is allowed to do this:
+ */
+ state = xchg(&p->state, TASK_DEAD);
+ if (state != TASK_ZOMBIE)
+ continue;
read_unlock(&tasklist_lock);
+
retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
if (!retval && stat_addr) {
if (p->sig->group_exit)
@@ -835,13 +848,16 @@ repeat:
else
retval = put_user(p->exit_code, stat_addr);
}
- if (retval)
- goto end_wait4;
+ if (retval) {
+ p->state = TASK_ZOMBIE;
+ goto end_wait4;
+ }
retval = p->pid;
if (p->real_parent != p->parent) {
write_lock_irq(&tasklist_lock);
__ptrace_unlink(p);
do_notify_parent(p, SIGCHLD);
+ p->state = TASK_ZOMBIE;
write_unlock_irq(&tasklist_lock);
} else
release_task(p);
diff --git a/kernel/fork.c b/kernel/fork.c
index 062a4d1f9c3e..5880309f3fee 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -103,6 +103,52 @@ void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
spin_unlock_irqrestore(&q->lock, flags);
}
+void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ __set_current_state(state);
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+void
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ __set_current_state(state);
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue_tail(q, wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ unsigned long flags;
+
+ __set_current_state(TASK_RUNNING);
+ if (!list_empty(&wait->task_list)) {
+ spin_lock_irqsave(&q->lock, flags);
+ list_del_init(&wait->task_list);
+ spin_unlock_irqrestore(&q->lock, flags);
+ }
+}
+
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync)
+{
+ int ret = default_wake_function(wait, mode, sync);
+
+ if (ret)
+ list_del_init(&wait->task_list);
+ return ret;
+}
+
void __init fork_init(unsigned long mempages)
{
/* create a slab on which task_structs can be allocated */
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 557ae8f7ded2..0409fc676f29 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -400,6 +400,10 @@ EXPORT_SYMBOL(irq_stat);
EXPORT_SYMBOL(add_wait_queue);
EXPORT_SYMBOL(add_wait_queue_exclusive);
EXPORT_SYMBOL(remove_wait_queue);
+EXPORT_SYMBOL(prepare_to_wait);
+EXPORT_SYMBOL(prepare_to_wait_exclusive);
+EXPORT_SYMBOL(finish_wait);
+EXPORT_SYMBOL(autoremove_wake_function);
/* completion handling */
EXPORT_SYMBOL(wait_for_completion);
@@ -493,7 +497,9 @@ EXPORT_SYMBOL(jiffies_64);
EXPORT_SYMBOL(xtime);
EXPORT_SYMBOL(do_gettimeofday);
EXPORT_SYMBOL(do_settimeofday);
-
+#ifdef CONFIG_DEBUG_KERNEL
+EXPORT_SYMBOL(__might_sleep);
+#endif
#if !defined(__ia64__)
EXPORT_SYMBOL(loops_per_jiffy);
#endif
diff --git a/kernel/pid.c b/kernel/pid.c
index b4da62f0aef2..0005a8cc36cb 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -53,6 +53,8 @@ static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
static pidmap_t *map_limit = pidmap_array + PIDMAP_ENTRIES;
+static spinlock_t pidmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
inline void free_pidmap(int pid)
{
pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
@@ -77,8 +79,13 @@ static inline pidmap_t *next_free_map(pidmap_t *map, int *max_steps)
* Free the page if someone raced with us
* installing it:
*/
- if (cmpxchg(&map->page, NULL, (void *) page))
+ spin_lock(&pidmap_lock);
+ if (map->page)
free_page(page);
+ else
+ map->page = (void *)page;
+ spin_unlock(&pidmap_lock);
+
if (!map->page)
break;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 304f90fd4bdf..9965e5f7549e 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2150,3 +2150,20 @@ void __init sched_init(void)
enter_lazy_tlb(&init_mm, current, smp_processor_id());
}
+#ifdef CONFIG_DEBUG_KERNEL
+void __might_sleep(char *file, int line)
+{
+#if defined(in_atomic)
+ static unsigned long prev_jiffy; /* ratelimiting */
+
+ if (in_atomic()) {
+ if (time_before(jiffies, prev_jiffy + HZ))
+ return;
+ prev_jiffy = jiffies;
+ printk("Sleeping function called from illegal"
+ " context at %s:%d\n", file, line);
+ dump_stack();
+ }
+#endif
+}
+#endif
diff --git a/kernel/timer.c b/kernel/timer.c
index 3b4be840f931..55c14c11c901 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -888,20 +888,6 @@ asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0)
return -EINVAL;
-
- if (t.tv_sec == 0 && t.tv_nsec <= 2000000L &&
- current->policy != SCHED_NORMAL)
- {
- /*
- * Short delay requests up to 2 ms will be handled with
- * high precision by a busy wait for all real-time processes.
- *
- * Its important on SMP not to do this holding locks.
- */
- udelay((t.tv_nsec + 999) / 1000);
- return 0;
- }
-
expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
current->state = TASK_INTERRUPTIBLE;