⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * This must be called with current->sighand->siglock held. * * This should be the path for all ptrace stops. * We always set current->last_siginfo while stopped here. * That makes it a way to test a stopped process for * being ptrace-stopped vs being job-control-stopped. * * If we actually decide not to stop at all because the tracer is gone, * we leave nostop_code in current->exit_code. */static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info){	/*	 * If there is a group stop in progress,	 * we must participate in the bookkeeping.	 */	if (current->signal->group_stop_count > 0)		--current->signal->group_stop_count;	current->last_siginfo = info;	current->exit_code = exit_code;	/* Let the debugger run.  */	set_current_state(TASK_TRACED);	spin_unlock_irq(&current->sighand->siglock);	try_to_freeze();	read_lock(&tasklist_lock);	if (may_ptrace_stop()) {		do_notify_parent_cldstop(current, CLD_TRAPPED);		read_unlock(&tasklist_lock);		schedule();	} else {		/*		 * By the time we got the lock, our tracer went away.		 * Don't stop here.		 */		read_unlock(&tasklist_lock);		set_current_state(TASK_RUNNING);		current->exit_code = nostop_code;	}	/*	 * We are back.  Now reacquire the siglock before touching	 * last_siginfo, so that we are sure to have synchronized with	 * any signal-sending on another CPU that wants to examine it.	 */	spin_lock_irq(&current->sighand->siglock);	current->last_siginfo = NULL;	/*	 * Queued signals ignored us while we were stopped for tracing.	 * So check for any that we should take before resuming user mode.	 * This sets TIF_SIGPENDING, but never clears it.	 */	recalc_sigpending_tsk(current);}void ptrace_notify(int exit_code){	siginfo_t info;	BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);	memset(&info, 0, sizeof info);	info.si_signo = SIGTRAP;	info.si_code = exit_code;	info.si_pid = current->pid;	info.si_uid = current->uid;	/* Let the debugger run.  */	spin_lock_irq(&current->sighand->siglock);	ptrace_stop(exit_code, 0, &info);	spin_unlock_irq(&current->sighand->siglock);}static voidfinish_stop(int stop_count){	/*	 * If there are no other threads in the group, or if there is	 * a group stop in progress and we are the last to stop,	 * report to the parent.  When ptraced, every thread reports itself.	 */	if (stop_count == 0 || (current->ptrace & PT_PTRACED)) {		read_lock(&tasklist_lock);		do_notify_parent_cldstop(current, CLD_STOPPED);		read_unlock(&tasklist_lock);	}	do {		schedule();	} while (try_to_freeze());	/*	 * Now we don't run again until continued.	 */	current->exit_code = 0;}/* * This performs the stopping for SIGSTOP and other stop signals. * We have to stop all threads in the thread group. * Returns nonzero if we've actually stopped and released the siglock. * Returns zero if we didn't stop and still hold the siglock. */static int do_signal_stop(int signr){	struct signal_struct *sig = current->signal;	int stop_count;	if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED))		return 0;	if (sig->group_stop_count > 0) {		/*		 * There is a group stop in progress.  We don't need to		 * start another one.		 */		stop_count = --sig->group_stop_count;	} else {		/*		 * There is no group stop already in progress.		 * We must initiate one now.		 */		struct task_struct *t;		sig->group_exit_code = signr;		stop_count = 0;		for (t = next_thread(current); t != current; t = next_thread(t))			/*			 * Setting state to TASK_STOPPED for a group			 * stop is always done with the siglock held,			 * so this check has no races.			 */			if (!t->exit_state &&			    !(t->state & (TASK_STOPPED|TASK_TRACED))) {				stop_count++;				signal_wake_up(t, 0);			}		sig->group_stop_count = stop_count;	}	if (stop_count == 0)		sig->flags = SIGNAL_STOP_STOPPED;	current->exit_code = sig->group_exit_code;	__set_current_state(TASK_STOPPED);	spin_unlock_irq(&current->sighand->siglock);	finish_stop(stop_count);	return 1;}/* * Do appropriate magic when group_stop_count > 0. * We return nonzero if we stopped, after releasing the siglock. * We return zero if we still hold the siglock and should look * for another signal without checking group_stop_count again. */static int handle_group_stop(void){	int stop_count;	if (current->signal->group_exit_task == current) {		/*		 * Group stop is so we can do a core dump,		 * We are the initiating thread, so get on with it.		 */		current->signal->group_exit_task = NULL;		return 0;	}	if (current->signal->flags & SIGNAL_GROUP_EXIT)		/*		 * Group stop is so another thread can do a core dump,		 * or else we are racing against a death signal.		 * Just punt the stop so we can get the next signal.		 */		return 0;	/*	 * There is a group stop in progress.  We stop	 * without any associated signal being in our queue.	 */	stop_count = --current->signal->group_stop_count;	if (stop_count == 0)		current->signal->flags = SIGNAL_STOP_STOPPED;	current->exit_code = current->signal->group_exit_code;	set_current_state(TASK_STOPPED);	spin_unlock_irq(&current->sighand->siglock);	finish_stop(stop_count);	return 1;}int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,			  struct pt_regs *regs, void *cookie){	sigset_t *mask = &current->blocked;	int signr = 0;	try_to_freeze();relock:	spin_lock_irq(&current->sighand->siglock);	for (;;) {		struct k_sigaction *ka;		if (unlikely(current->signal->group_stop_count > 0) &&		    handle_group_stop())			goto relock;		signr = dequeue_signal(current, mask, info);		if (!signr)			break; /* will return 0 */		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {			ptrace_signal_deliver(regs, cookie);			/* Let the debugger run.  */			ptrace_stop(signr, signr, info);			/* We're back.  Did the debugger cancel the sig?  */			signr = current->exit_code;			if (signr == 0)				continue;			current->exit_code = 0;			/* Update the siginfo structure if the signal has			   changed.  If the debugger wanted something			   specific in the siginfo structure then it should			   have updated *info via PTRACE_SETSIGINFO.  */			if (signr != info->si_signo) {				info->si_signo = signr;				info->si_errno = 0;				info->si_code = SI_USER;				info->si_pid = current->parent->pid;				info->si_uid = current->parent->uid;			}			/* If the (new) signal is now blocked, requeue it.  */			if (sigismember(&current->blocked, signr)) {				specific_send_sig_info(signr, info, current);				continue;			}		}		ka = &current->sighand->action[signr-1];		if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */			continue;		if (ka->sa.sa_handler != SIG_DFL) {			/* Run the handler.  */			*return_ka = *ka;			if (ka->sa.sa_flags & SA_ONESHOT)				ka->sa.sa_handler = SIG_DFL;			break; /* will return non-zero "signr" value */		}		/*		 * Now we are doing the default action for this signal.		 */		if (sig_kernel_ignore(signr)) /* Default is nothing. */			continue;		/*		 * Init of a pid space gets no signals it doesn't want from		 * within that pid space. It can of course get signals from		 * its parent pid space.		 */		if (current == child_reaper(current))			continue;		if (sig_kernel_stop(signr)) {			/*			 * The default action is to stop all threads in			 * the thread group.  The job control signals			 * do nothing in an orphaned pgrp, but SIGSTOP			 * always works.  Note that siglock needs to be			 * dropped during the call to is_orphaned_pgrp()			 * because of lock ordering with tasklist_lock.			 * This allows an intervening SIGCONT to be posted.			 * We need to check for that and bail out if necessary.			 */			if (signr != SIGSTOP) {				spin_unlock_irq(&current->sighand->siglock);				/* signals can be posted during this window */				if (is_current_pgrp_orphaned())					goto relock;				spin_lock_irq(&current->sighand->siglock);			}			if (likely(do_signal_stop(signr))) {				/* It released the siglock.  */				goto relock;			}			/*			 * We didn't actually stop, due to a race			 * with SIGCONT or something like that.			 */			continue;		}		spin_unlock_irq(&current->sighand->siglock);		/*		 * Anything else is fatal, maybe with a core dump.		 */		current->flags |= PF_SIGNALED;		if (sig_kernel_coredump(signr)) {			/*			 * If it was able to dump core, this kills all			 * other threads in the group and synchronizes with			 * their demise.  If we lost the race with another			 * thread getting here, it set group_exit_code			 * first and our do_group_exit call below will use			 * that value and ignore the one we pass it.			 */			do_coredump((long)signr, signr, regs);		}		/*		 * Death signals, no core dump.		 */		do_group_exit(signr);		/* NOTREACHED */	}	spin_unlock_irq(&current->sighand->siglock);	return signr;}EXPORT_SYMBOL(recalc_sigpending);EXPORT_SYMBOL_GPL(dequeue_signal);EXPORT_SYMBOL(flush_signals);EXPORT_SYMBOL(force_sig);EXPORT_SYMBOL(kill_proc);EXPORT_SYMBOL(ptrace_notify);EXPORT_SYMBOL(send_sig);EXPORT_SYMBOL(send_sig_info);EXPORT_SYMBOL(sigprocmask);EXPORT_SYMBOL(block_all_signals);EXPORT_SYMBOL(unblock_all_signals);/* * System call entry points. */asmlinkage long sys_restart_syscall(void){	struct restart_block *restart = &current_thread_info()->restart_block;	return restart->fn(restart);}long do_no_restart_syscall(struct restart_block *param){	return -EINTR;}/* * We don't need to get the kernel lock - this is all local to this * particular thread.. (and that's good, because this is _heavily_ * used by various programs) *//* * This is also useful for kernel threads that want to temporarily * (or permanently) block certain signals. * * NOTE! Unlike the user-mode sys_sigprocmask(), the kernel * interface happily blocks "unblockable" signals like SIGKILL * and friends. */int sigprocmask(int how, sigset_t *set, sigset_t *oldset){	int error;	spin_lock_irq(&current->sighand->siglock);	if (oldset)		*oldset = current->blocked;	error = 0;	switch (how) {	case SIG_BLOCK:		sigorsets(&current->blocked, &current->blocked, set);		break;	case SIG_UNBLOCK:		signandsets(&current->blocked, &current->blocked, set);		break;	case SIG_SETMASK:		current->blocked = *set;		break;	default:		error = -EINVAL;	}	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	return error;}asmlinkage longsys_rt_sigprocmask(int how, sigset_t __user *set, sigset_t __user *oset, size_t sigsetsize){	int error = -EINVAL;	sigset_t old_set, new_set;	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (sigsetsize != sizeof(sigset_t))		goto out;	if (set) {		error = -EFAULT;		if (copy_from_user(&new_set, set, sizeof(*set)))			goto out;		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));		error = sigprocmask(how, &new_set, &old_set);		if (error)			goto out;		if (oset)			goto set_old;	} else if (oset) {		spin_lock_irq(&current->sighand->siglock);		old_set = current->blocked;		spin_unlock_irq(&current->sighand->siglock);	set_old:		error = -EFAULT;		if (copy_to_user(oset, &old_set, sizeof(*oset)))			goto out;	}	error = 0;out:	return error;}long do_sigpending(void __user *set, unsigned long sigsetsize){	long error = -EINVAL;	sigset_t pending;	if (sigsetsize > sizeof(sigset_t))		goto out;	spin_lock_irq(&current->sighand->siglock);	sigorsets(&pending, &current->pending.signal,		  &current->signal->shared_pending.signal);	spin_unlock_irq(&current->sighand->siglock);	/* Outside the lock because only this thread touches it.  */	sigandsets(&pending, &current->blocked, &pending);	error = -EFAULT;	if (!copy_to_user(set, &pending, sigsetsize))		error = 0;out:	return error;}	asmlinkage longsys_rt_sigpending(sigset_t __user *set, size_t sigsetsize){	return do_sigpending(set, sigsetsize);}#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USERint copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from){	int err;	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))		return -EFAULT;	if (from->si_code < 0)		return __copy_to_user(to, from, sizeof(siginfo_t))			? -EFAULT : 0;	/*	 * If you change siginfo_t structure, please be sure	 * this code is fixed accordingly.	 * Please remember to update the signalfd_copyinfo() function	 * inside fs/signalfd.c too, in case siginfo_t changes.	 * It should never copy any pad contained in the structure	 * to avoid security leaks, but must copy the generic	 * 3 ints plus the relevant union member.	 */	err = __put_user(from->si_signo, &to->si_signo);	err |= __put_user(from->si_errno, &to->si_errno);	err |= __put_user((short)from->si_code, &to->si_code);	switch (from->si_code & __SI_MASK) {	case __SI_KILL:		err |= __put_user(from->si_pid, &to->si_pid);		err |= __put_user(from->si_uid, &to->si_uid);		break;	case __SI_TIMER:		 err |= __put_user(from->si_tid, &to->si_tid);		 err |= __put_user(from->si_overrun, &to->si_overrun);		 err |= __put_user(from->si_ptr, &to->si_ptr);		break;	case __SI_POLL:		err |= __put_user(from->si_band, &to->si_band);		err |= __put_user(from->si_fd, &to->si_fd);		break;	case __SI_FAULT:		err |= __put_user(from->si_addr, &to->si_addr);#ifdef __ARCH_SI_TRAPNO		err |= __put_user(from->si_trapno, &to->si_trapno);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -