patch-2.1.36 linux/kernel/exit.c

Next file: linux/kernel/fork.c
Previous file: linux/init/main.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.35/linux/kernel/exit.c linux/kernel/exit.c
@@ -41,18 +41,23 @@
 	 * be handled immediately (ie non-blocked and untraced)
 	 * and that is ignored (either explicitly or by default)
 	 */
+	spin_lock_irq(&p->sig->siglock);
 	if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
 		/* don't bother with ignored signals (but SIGCHLD is special) */
 		if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
-			return;
+			goto out;
 		/* some signals are ignored by default.. (but SIGCONT already did its deed) */
 		if ((sa->sa_handler == SIG_DFL) &&
 		    (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
-			return;
+			goto out;
 	}
+	spin_lock(&p->sigmask_lock);
 	p->signal |= mask;
+	spin_unlock(&p->sigmask_lock);
 	if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
 		wake_up_process(p);
+out:
+	spin_unlock_irq(&p->sig->siglock);
 }
 
 /*
@@ -65,16 +70,23 @@
 	if (p->sig) {
 		unsigned long mask = 1UL << sig;
 		struct sigaction *sa = p->sig->action + sig;
+
+		spin_lock_irq(&p->sig->siglock);
+
+		spin_lock(&p->sigmask_lock);
 		p->signal |= mask;
 		p->blocked &= ~mask;
+		spin_unlock(&p->sigmask_lock);
+
 		if (sa->sa_handler == SIG_IGN)
 			sa->sa_handler = SIG_DFL;
 		if (p->state == TASK_INTERRUPTIBLE)
 			wake_up_process(p);
+
+		spin_unlock_irq(&p->sig->siglock);
 	}
 }
 
-
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
 {
 	if (!p || sig > 32)
@@ -84,24 +96,23 @@
 	    (current->uid ^ p->suid) && (current->uid ^ p->uid) &&
 	    !suser())
 		return -EPERM;
-	if (!sig)
-		return 0;
-	/*
-	 * Forget it if the process is already zombie'd.
-	 */
-	if (!p->sig)
-		return 0;
-	if ((sig == SIGKILL) || (sig == SIGCONT)) {
-		if (p->state == TASK_STOPPED)
-			wake_up_process(p);
-		p->exit_code = 0;
-		p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
-				(1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
-	}
-	if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
-		p->signal &= ~(1<<(SIGCONT-1));
-	/* Actually generate the signal */
-	generate(sig,p);
+
+	if (sig && p->sig) {
+		spin_lock_irq(&p->sigmask_lock);
+		if ((sig == SIGKILL) || (sig == SIGCONT)) {
+			if (p->state == TASK_STOPPED)
+				wake_up_process(p);
+			p->exit_code = 0;
+			p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
+					(1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
+		}
+		if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
+			p->signal &= ~(1<<(SIGCONT-1));
+		spin_unlock_irq(&p->sigmask_lock);
+
+		/* Actually generate the signal */
+		generate(sig,p);
+	}
 	return 0;
 }
 
@@ -125,6 +136,12 @@
 	}
 	for (i=1 ; i<NR_TASKS ; i++)
 		if (task[i] == p) {
+#ifdef __SMP__
+			/* FIXME! Cheesy, but kills the window... -DaveM */
+			while(p->processor != NO_PROC_ID)
+				barrier();
+			spin_unlock_wait(&scheduler_lock);
+#endif
 			nr_tasks--;
 			task[i] = NULL;
 			REMOVE_LINKS(p);
@@ -245,14 +262,18 @@
 	int fallback;
 
 	fallback = -1;
+	read_lock(&tasklist_lock);
 	for_each_task(p) {
  		if (p->session <= 0)
  			continue;
-		if (p->pgrp == pgrp)
-			return p->session;
+		if (p->pgrp == pgrp) {
+			fallback = p->session;
+			break;
+		}
 		if (p->pid == pgrp)
 			fallback = p->session;
 	}
+	read_unlock(&tasklist_lock);
 	return fallback;
 }
 
@@ -262,21 +283,29 @@
  */
 int kill_pg(int pgrp, int sig, int priv)
 {
-	struct task_struct *p;
-	int err,retval = -ESRCH;
-	int found = 0;
+	int retval;
 
-	if (sig<0 || sig>32 || pgrp<=0)
-		return -EINVAL;
-	for_each_task(p) {
-		if (p->pgrp == pgrp) {
-			if ((err = send_sig(sig,p,priv)) != 0)
-				retval = err;
-			else
-				found++;
+	retval = -EINVAL;
+	if (sig >= 0 && sig <= 32 && pgrp > 0) {
+		struct task_struct *p;
+		int found = 0;
+
+		retval = -ESRCH;
+		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (p->pgrp == pgrp) {
+				int err = send_sig(sig,p,priv);
+				if (err != 0)
+					retval = err;
+				else
+					found++;
+			}
 		}
+		read_unlock(&tasklist_lock);
+		if (found)
+			retval = 0;
 	}
-	return(found ? 0 : retval);
+	return retval;
 }
 
 /*
@@ -286,34 +315,51 @@
  */
 int kill_sl(int sess, int sig, int priv)
 {
-	struct task_struct *p;
-	int err,retval = -ESRCH;
-	int found = 0;
+	int retval;
 
-	if (sig<0 || sig>32 || sess<=0)
-		return -EINVAL;
-	for_each_task(p) {
-		if (p->session == sess && p->leader) {
-			if ((err = send_sig(sig,p,priv)) != 0)
-				retval = err;
-			else
-				found++;
+	retval = -EINVAL;
+	if (sig >= 0 && sig <= 32 && sess > 0) {
+		struct task_struct *p;
+		int found = 0;
+
+		retval = -ESRCH;
+		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (p->leader && p->session == sess) {
+				int err = send_sig(sig,p,priv);
+
+				if (err)
+					retval = err;
+				else
+					found++;
+			}
 		}
+		read_unlock(&tasklist_lock);
+		if (found)
+			retval = 0;
 	}
-	return(found ? 0 : retval);
+	return retval;
 }
 
 int kill_proc(int pid, int sig, int priv)
 {
- 	struct task_struct *p;
+	int retval;
 
-	if (sig<0 || sig>32)
-		return -EINVAL;
-	for_each_task(p) {
-		if (p && p->pid == pid)
-			return send_sig(sig,p,priv);
+	retval = -EINVAL;
+	if (sig >= 0 && sig <= 32) {
+		struct task_struct *p;
+		
+		retval = -ESRCH;
+		read_lock(&tasklist_lock);
+		for_each_task(p) {
+			if (p->pid != pid)
+				continue;
+			retval = send_sig(sig,p,priv);
+			break;
+		}
+		read_unlock(&tasklist_lock);
 	}
-	return(-ESRCH);
+	return retval;
 }
 
 /*
@@ -322,34 +368,30 @@
  */
 asmlinkage int sys_kill(int pid,int sig)
 {
-	int err, retval = 0, count = 0;
+	if (!pid)
+		return kill_pg(current->pgrp,sig,0);
 
-	lock_kernel();
-	if (!pid) {
-		err = kill_pg(current->pgrp,sig,0);
-		goto out;
-	}
 	if (pid == -1) {
+		int retval = 0, count = 0;
 		struct task_struct * p;
+
+		read_lock(&tasklist_lock);
 		for_each_task(p) {
 			if (p->pid > 1 && p != current) {
+				int err;
 				++count;
 				if ((err = send_sig(sig,p,0)) != -EPERM)
 					retval = err;
 			}
 		}
-		err = count ? retval : -ESRCH;
-		goto out;
-	}
-	if (pid < 0) {
-		err = kill_pg(-pid,sig,0);
-		goto out;
+		read_unlock(&tasklist_lock);
+		return count ? retval : -ESRCH;
 	}
+	if (pid < 0)
+		return kill_pg(-pid,sig,0);
+
 	/* Normal kill */
-	err = kill_proc(pid,sig,0);
-out:
-	unlock_kernel();
-	return err;
+	return kill_proc(pid,sig,0);
 }
 
 /*
@@ -364,16 +406,20 @@
 {
 	struct task_struct *p;
 
+	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if ((p == ignored_task) || (p->pgrp != pgrp) ||
 		    (p->state == TASK_ZOMBIE) ||
 		    (p->p_pptr->pid == 1))
 			continue;
 		if ((p->p_pptr->pgrp != pgrp) &&
-		    (p->p_pptr->session == p->session))
-			return 0;
+		    (p->p_pptr->session == p->session)) {
+			read_unlock(&tasklist_lock);
+ 			return 0;
+		}
 	}
-	return(1);	/* (sighing) "Often!" */
+	read_unlock(&tasklist_lock);
+	return 1;	/* (sighing) "Often!" */
 }
 
 int is_orphaned_pgrp(int pgrp)
@@ -383,21 +429,27 @@
 
 static inline int has_stopped_jobs(int pgrp)
 {
+	int retval = 0;
 	struct task_struct * p;
 
+	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (p->pgrp != pgrp)
 			continue;
-		if (p->state == TASK_STOPPED)
-			return(1);
+		if (p->state != TASK_STOPPED)
+			continue;
+		retval = 1;
+		break;
 	}
-	return(0);
+	read_unlock(&tasklist_lock);
+	return retval;
 }
 
 static inline void forget_original_parent(struct task_struct * father)
 {
 	struct task_struct * p;
 
+	read_lock(&tasklist_lock);
 	for_each_task(p) {
 		if (p->p_opptr == father)
 			if (task[smp_num_cpus])	/* init */
@@ -405,6 +457,7 @@
 			else
 				p->p_opptr = task[0];
 	}
+	read_unlock(&tasklist_lock);
 }
 
 static inline void close_files(struct files_struct * files)
@@ -470,9 +523,8 @@
 
 	if (sig) {
 		tsk->sig = NULL;
-		if (!--sig->count) {
+		if (atomic_dec_and_test(&sig->count))
 			kfree(sig);
-		}
 	}
 }
 
@@ -635,24 +687,22 @@
 	struct wait_queue wait = { current, NULL };
 	struct task_struct *p;
 
-	lock_kernel();
 	if (stat_addr) {
-		retval = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr));
-		if (retval)
-			goto out;
+		if(verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr)))
+			return -EFAULT;
 	}
 	if (ru) {
-		retval = verify_area(VERIFY_WRITE, ru, sizeof(*ru));
-		if (retval)
-			goto out;
+		if(verify_area(VERIFY_WRITE, ru, sizeof(*ru)))
+			return -EFAULT;
 	}
-	retval = -EINVAL;
+
 	if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
-	    goto out;
+		return -EINVAL;
 
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
-	flag=0;
+	flag = 0;
+	read_lock(&tasklist_lock);
  	for (p = current->p_cptr ; p ; p = p->p_osptr) {
 		if (pid>0) {
 			if (p->pid != pid)
@@ -674,23 +724,28 @@
 					continue;
 				if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
 					continue;
+				read_unlock(&tasklist_lock);
 				if (ru != NULL)
 					getrusage(p, RUSAGE_BOTH, ru);
 				if (stat_addr)
-					put_user((p->exit_code << 8) | 0x7f,
-						stat_addr);
+					__put_user((p->exit_code << 8) | 0x7f,
+						   stat_addr);
 				p->exit_code = 0;
 				retval = p->pid;
 				goto end_wait4;
 			case TASK_ZOMBIE:
 				current->cutime += p->utime + p->cutime;
 				current->cstime += p->stime + p->cstime;
+				read_unlock(&tasklist_lock);
 				if (ru != NULL)
 					getrusage(p, RUSAGE_BOTH, ru);
 				if (stat_addr)
-					put_user(p->exit_code, stat_addr);
+					__put_user(p->exit_code, stat_addr);
 				retval = p->pid;
 				if (p->p_opptr != p->p_pptr) {
+					/* Note this grabs tasklist_lock
+					 * as a writer... (twice!)
+					 */
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
 					SET_LINKS(p);
@@ -705,6 +760,7 @@
 				continue;
 		}
 	}
+	read_unlock(&tasklist_lock);
 	if (flag) {
 		retval = 0;
 		if (options & WNOHANG)
@@ -719,8 +775,6 @@
 	retval = -ECHILD;
 end_wait4:
 	remove_wait_queue(&current->wait_chldexit,&wait);
-out:
-	unlock_kernel();
 	return retval;
 }
 
@@ -732,12 +786,7 @@
  */
 asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options)
 {
-	int ret;
-
-	lock_kernel();
-	ret = sys_wait4(pid, stat_addr, options, NULL);
-	unlock_kernel();
-	return ret;
+	return sys_wait4(pid, stat_addr, options, NULL);
 }
 
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov