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

📄 signal.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif		break;	case __SI_CHLD:		err |= __put_user(from->si_pid, &to->si_pid);		err |= __put_user(from->si_uid, &to->si_uid);		err |= __put_user(from->si_status, &to->si_status);		err |= __put_user(from->si_utime, &to->si_utime);		err |= __put_user(from->si_stime, &to->si_stime);		break;	case __SI_RT: /* This is not generated by the kernel as of now. */	case __SI_MESGQ: /* But this is */		err |= __put_user(from->si_pid, &to->si_pid);		err |= __put_user(from->si_uid, &to->si_uid);		err |= __put_user(from->si_ptr, &to->si_ptr);		break;	default: /* this is just in case for now ... */		err |= __put_user(from->si_pid, &to->si_pid);		err |= __put_user(from->si_uid, &to->si_uid);		break;	}	return err;}#endifasmlinkage longsys_rt_sigtimedwait(const sigset_t __user *uthese,		    siginfo_t __user *uinfo,		    const struct timespec __user *uts,		    size_t sigsetsize){	int ret, sig;	sigset_t these;	struct timespec ts;	siginfo_t info;	long timeout = 0;	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (sigsetsize != sizeof(sigset_t))		return -EINVAL;	if (copy_from_user(&these, uthese, sizeof(these)))		return -EFAULT;			/*	 * Invert the set of allowed signals to get those we	 * want to block.	 */	sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));	signotset(&these);	if (uts) {		if (copy_from_user(&ts, uts, sizeof(ts)))			return -EFAULT;		if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0		    || ts.tv_sec < 0)			return -EINVAL;	}	spin_lock_irq(&current->sighand->siglock);	sig = dequeue_signal(current, &these, &info);	if (!sig) {		timeout = MAX_SCHEDULE_TIMEOUT;		if (uts)			timeout = (timespec_to_jiffies(&ts)				   + (ts.tv_sec || ts.tv_nsec));		if (timeout) {			/* None ready -- temporarily unblock those we're			 * interested while we are sleeping in so that we'll			 * be awakened when they arrive.  */			current->real_blocked = current->blocked;			sigandsets(&current->blocked, &current->blocked, &these);			recalc_sigpending();			spin_unlock_irq(&current->sighand->siglock);			timeout = schedule_timeout_interruptible(timeout);			spin_lock_irq(&current->sighand->siglock);			sig = dequeue_signal(current, &these, &info);			current->blocked = current->real_blocked;			siginitset(&current->real_blocked, 0);			recalc_sigpending();		}	}	spin_unlock_irq(&current->sighand->siglock);	if (sig) {		ret = sig;		if (uinfo) {			if (copy_siginfo_to_user(uinfo, &info))				ret = -EFAULT;		}	} else {		ret = -EAGAIN;		if (timeout)			ret = -EINTR;	}	return ret;}asmlinkage longsys_kill(int pid, int sig){	struct siginfo info;	info.si_signo = sig;	info.si_errno = 0;	info.si_code = SI_USER;	info.si_pid = current->tgid;	info.si_uid = current->uid;	return kill_something_info(sig, &info, pid);}static int do_tkill(int tgid, int pid, int sig){	int error;	struct siginfo info;	struct task_struct *p;	error = -ESRCH;	info.si_signo = sig;	info.si_errno = 0;	info.si_code = SI_TKILL;	info.si_pid = current->tgid;	info.si_uid = current->uid;	read_lock(&tasklist_lock);	p = find_task_by_pid(pid);	if (p && (tgid <= 0 || p->tgid == tgid)) {		error = check_kill_permission(sig, &info, p);		/*		 * The null signal is a permissions and process existence		 * probe.  No signal is actually delivered.		 */		if (!error && sig && p->sighand) {			spin_lock_irq(&p->sighand->siglock);			handle_stop_signal(sig, p);			error = specific_send_sig_info(sig, &info, p);			spin_unlock_irq(&p->sighand->siglock);		}	}	read_unlock(&tasklist_lock);	return error;}/** *  sys_tgkill - send signal to one specific thread *  @tgid: the thread group ID of the thread *  @pid: the PID of the thread *  @sig: signal to be sent * *  This syscall also checks the @tgid and returns -ESRCH even if the PID *  exists but it's not belonging to the target process anymore. This *  method solves the problem of threads exiting and PIDs getting reused. */asmlinkage long sys_tgkill(int tgid, int pid, int sig){	/* This is only valid for single tasks */	if (pid <= 0 || tgid <= 0)		return -EINVAL;	return do_tkill(tgid, pid, sig);}/* *  Send a signal to only one task, even if it's a CLONE_THREAD task. */asmlinkage longsys_tkill(int pid, int sig){	/* This is only valid for single tasks */	if (pid <= 0)		return -EINVAL;	return do_tkill(0, pid, sig);}asmlinkage longsys_rt_sigqueueinfo(int pid, int sig, siginfo_t __user *uinfo){	siginfo_t info;	if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))		return -EFAULT;	/* Not even root can pretend to send signals from the kernel.	   Nor can they impersonate a kill(), which adds source info.  */	if (info.si_code >= 0)		return -EPERM;	info.si_signo = sig;	/* POSIX.1b doesn't mention process groups.  */	return kill_proc_info(sig, &info, pid);}int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact){	struct k_sigaction *k;	sigset_t mask;	if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))		return -EINVAL;	k = &current->sighand->action[sig-1];	spin_lock_irq(&current->sighand->siglock);	if (signal_pending(current)) {		/*		 * If there might be a fatal signal pending on multiple		 * threads, make sure we take it before changing the action.		 */		spin_unlock_irq(&current->sighand->siglock);		return -ERESTARTNOINTR;	}	if (oact)		*oact = *k;	if (act) {		sigdelsetmask(&act->sa.sa_mask,			      sigmask(SIGKILL) | sigmask(SIGSTOP));		*k = *act;		/*		 * POSIX 3.3.1.3:		 *  "Setting a signal action to SIG_IGN for a signal that is		 *   pending shall cause the pending signal to be discarded,		 *   whether or not it is blocked."		 *		 *  "Setting a signal action to SIG_DFL for a signal that is		 *   pending and whose default action is to ignore the signal		 *   (for example, SIGCHLD), shall cause the pending signal to		 *   be discarded, whether or not it is blocked"		 */		if (act->sa.sa_handler == SIG_IGN ||		   (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) {			struct task_struct *t = current;			sigemptyset(&mask);			sigaddset(&mask, sig);			rm_from_queue_full(&mask, &t->signal->shared_pending);			do {				rm_from_queue_full(&mask, &t->pending);				recalc_sigpending_and_wake(t);				t = next_thread(t);			} while (t != current);		}	}	spin_unlock_irq(&current->sighand->siglock);	return 0;}int do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp){	stack_t oss;	int error;	if (uoss) {		oss.ss_sp = (void __user *) current->sas_ss_sp;		oss.ss_size = current->sas_ss_size;		oss.ss_flags = sas_ss_flags(sp);	}	if (uss) {		void __user *ss_sp;		size_t ss_size;		int ss_flags;		error = -EFAULT;		if (!access_ok(VERIFY_READ, uss, sizeof(*uss))		    || __get_user(ss_sp, &uss->ss_sp)		    || __get_user(ss_flags, &uss->ss_flags)		    || __get_user(ss_size, &uss->ss_size))			goto out;		error = -EPERM;		if (on_sig_stack(sp))			goto out;		error = -EINVAL;		/*		 *		 * Note - this code used to test ss_flags incorrectly		 *  	  old code may have been written using ss_flags==0		 *	  to mean ss_flags==SS_ONSTACK (as this was the only		 *	  way that worked) - this fix preserves that older		 *	  mechanism		 */		if (ss_flags != SS_DISABLE && ss_flags != SS_ONSTACK && ss_flags != 0)			goto out;		if (ss_flags == SS_DISABLE) {			ss_size = 0;			ss_sp = NULL;		} else {			error = -ENOMEM;			if (ss_size < MINSIGSTKSZ)				goto out;		}		current->sas_ss_sp = (unsigned long) ss_sp;		current->sas_ss_size = ss_size;	}	if (uoss) {		error = -EFAULT;		if (copy_to_user(uoss, &oss, sizeof(oss)))			goto out;	}	error = 0;out:	return error;}#ifdef __ARCH_WANT_SYS_SIGPENDINGasmlinkage longsys_sigpending(old_sigset_t __user *set){	return do_sigpending(set, sizeof(*set));}#endif#ifdef __ARCH_WANT_SYS_SIGPROCMASK/* Some platforms have their own version with special arguments others   support only sys_rt_sigprocmask.  */asmlinkage longsys_sigprocmask(int how, old_sigset_t __user *set, old_sigset_t __user *oset){	int error;	old_sigset_t old_set, new_set;	if (set) {		error = -EFAULT;		if (copy_from_user(&new_set, set, sizeof(*set)))			goto out;		new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));		spin_lock_irq(&current->sighand->siglock);		old_set = current->blocked.sig[0];		error = 0;		switch (how) {		default:			error = -EINVAL;			break;		case SIG_BLOCK:			sigaddsetmask(&current->blocked, new_set);			break;		case SIG_UNBLOCK:			sigdelsetmask(&current->blocked, new_set);			break;		case SIG_SETMASK:			current->blocked.sig[0] = new_set;			break;		}		recalc_sigpending();		spin_unlock_irq(&current->sighand->siglock);		if (error)			goto out;		if (oset)			goto set_old;	} else if (oset) {		old_set = current->blocked.sig[0];	set_old:		error = -EFAULT;		if (copy_to_user(oset, &old_set, sizeof(*oset)))			goto out;	}	error = 0;out:	return error;}#endif /* __ARCH_WANT_SYS_SIGPROCMASK */#ifdef __ARCH_WANT_SYS_RT_SIGACTIONasmlinkage longsys_rt_sigaction(int sig,		 const struct sigaction __user *act,		 struct sigaction __user *oact,		 size_t sigsetsize){	struct k_sigaction new_sa, old_sa;	int ret = -EINVAL;	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (sigsetsize != sizeof(sigset_t))		goto out;	if (act) {		if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa)))			return -EFAULT;	}	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);	if (!ret && oact) {		if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa)))			return -EFAULT;	}out:	return ret;}#endif /* __ARCH_WANT_SYS_RT_SIGACTION */#ifdef __ARCH_WANT_SYS_SGETMASK/* * For backwards compatibility.  Functionality superseded by sigprocmask. */asmlinkage longsys_sgetmask(void){	/* SMP safe */	return current->blocked.sig[0];}asmlinkage longsys_ssetmask(int newmask){	int old;	spin_lock_irq(&current->sighand->siglock);	old = current->blocked.sig[0];	siginitset(&current->blocked, newmask & ~(sigmask(SIGKILL)|						  sigmask(SIGSTOP)));	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	return old;}#endif /* __ARCH_WANT_SGETMASK */#ifdef __ARCH_WANT_SYS_SIGNAL/* * For backwards compatibility.  Functionality superseded by sigaction. */asmlinkage unsigned longsys_signal(int sig, __sighandler_t handler){	struct k_sigaction new_sa, old_sa;	int ret;	new_sa.sa.sa_handler = handler;	new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;	sigemptyset(&new_sa.sa.sa_mask);	ret = do_sigaction(sig, &new_sa, &old_sa);	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;}#endif /* __ARCH_WANT_SYS_SIGNAL */#ifdef __ARCH_WANT_SYS_PAUSEasmlinkage longsys_pause(void){	current->state = TASK_INTERRUPTIBLE;	schedule();	return -ERESTARTNOHAND;}#endif#ifdef __ARCH_WANT_SYS_RT_SIGSUSPENDasmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize){	sigset_t newset;	/* XXX: Don't preclude handling different sized sigset_t's.  */	if (sigsetsize != sizeof(sigset_t))		return -EINVAL;	if (copy_from_user(&newset, unewset, sizeof(newset)))		return -EFAULT;	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));	spin_lock_irq(&current->sighand->siglock);	current->saved_sigmask = current->blocked;	current->blocked = newset;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);	current->state = TASK_INTERRUPTIBLE;	schedule();	set_thread_flag(TIF_RESTORE_SIGMASK);	return -ERESTARTNOHAND;}#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma){	return NULL;}void __init signals_init(void){	sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);}

⌨️ 快捷键说明

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