浅析signal机制在alarm应用程序和内核程序的交互对应关系和程序设计注意事项
//========================================================
//lib库中的函数
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
__sigrestore_t sa_restorer;
sigset_t sa_mask; /* mask last for extensibility */
};
static __inline__ __sighandler_t signal(int s, __sighandler_t f)
{
return bsd_signal(s,f);
}
__sighandler_t bsd_signal(int signum, __sighandler_t handler)
{
return _signal(signum, handler, SA_RESTART);
}
static __sighandler_t
_signal(int signum, __sighandler_t handler, int flags)
{
struct sigaction sa;
__sighandler_t result = SIG_ERR;
sigemptyset( &sa.sa_mask );
sa.sa_handler = handler;
sa.sa_flags = flags;
if ( !sigaction( signum, &sa, &sa ) )//执行调用号__NR_sigaction对应的系统调用
//对应kernel的sys_sigaction
result = (__sighandler_t) sa.sa_handler;
return result;
}
static __inline__ int sigemptyset(sigset_t *set)
{
memset(set, 0, sizeof *set);
return 0;
}
//========================================================
//arm-kernel中的系统调用具体实现
asmlinkage int
sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
if (act) {
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
return -EFAULT;
__get_user(new_ka.sa.sa_flags, &act->sa_flags);
__get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
__put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
return -EFAULT;
__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
}
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 = ¤t->sighand->action[sig-1];
//这就是我们的用户空间的应用程序对应的内核线程current对应的sighand->action集[luther.gliethttp].
//对于某个signum同时只能有一个k_sigaction来控制,并没有实现为链表方式.
spin_lock_irq(¤t->sighand->siglock);
if (oact)
*oact = *k;
if (act) {
sigdelsetmask(&act->sa.sa_mask,
sigmask(SIGKILL) | sigmask(SIGSTOP));
//不论如何kernel将屏蔽掉用户程序企图设置SIGKILL和SIGSTOP,进而不让kernel杀死自己的设置[luther.gliethttp].
*k = *act;//覆盖current->sighand->action[sig-1]中原有内容,并没有实现为链表方式.
/*
* 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);
t = next_thread(t);
} while (t != current);
}
}
spin_unlock_irq(¤t->sighand->siglock);
return 0;
}
#define SIGALRM 14
好了已经把alarm对应的signal放入了current->sighand->action[SIGALRM-1].
那什么时候会调用current->sighand->action[SIGALRM-1]中的方法呢?让我们继续研究研究,
sys_rt_sigsuspend=>do_signal
do_notify_resume=>do_signal
sys_sigsuspend=>do_signal
=>do_signal
=>handle_signal
handle_signal=>setup_rt_frame=>setup_return
handle_signal=>setup_frame=>setup_return
=>setup_return
=>
arch/arm/kernel/entry-common.S
....
sys_rt_sigsuspend_wrapper:
add r2, sp, #S_OFF
b sys_rt_sigsuspend
....
work_pending:
tst r1, #_TIF_NEED_RESCHED
bne work_resched
tst r1, #_TIF_SIGPENDING
beq no_work_pending
mov r0, sp @ 'regs'
mov r2, why @ 'syscall'
bl do_notify_resume //这里会调用
b ret_slow_syscall @ Check work again
....
sys_sigsuspend_wrapper:
add r3, sp, #S_OFF
b sys_sigsuspend
....
static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
struct pt_regs * regs, int syscall)
{
struct thread_info *thread = current_thread_info();
struct task_struct *tsk = current;
int usig = sig;
int ret;
/*
* If we were from a system call, check for system call restarting...
*/
if (syscall) {
switch (regs->ARM_r0) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->ARM_r0 = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->ARM_r0 = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
restart_syscall(regs);
}
}
/*
* translate the signal
*/
if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
usig = thread->exec_domain->signal_invmap[usig];
/*
* Set up the stack frame
*/
if (ka->sa.sa_flags & SA_SIGINFO)
ret = setup_rt_frame(usig, ka, info, oldset, regs);
else
ret = setup_frame(usig, ka, oldset, regs);
/*
* Check that the resulting registers are actually sane.
*/
ret |= !valid_user_regs(regs);
if (ret != 0) {
force_sigsegv(sig, tsk);
return;
}
/*
* Block the signal if we were successful.
*/
spin_lock_irq(&tsk->sighand->siglock);
sigorsets(&tsk->blocked, &tsk->blocked,
&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(&tsk->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&tsk->sighand->siglock);
}
static int
setup_return(struct pt_regs *regs, struct k_sigaction *ka,
unsigned long __user *rc, void __user *frame, int usig)
{
unsigned long handler = (unsigned long)ka->sa.sa_handler;//这就是我们alarm登记的handler处理函数[luther.gliethttp]
unsigned long retcode;
int thumb = 0;
unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
/*
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
*/
if (ka->sa.sa_flags & SA_THIRTYTWO)
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB
if (elf_hwcap & HWCAP_THUMB) {
/*
* The LSB of the handler determines if we're going to
* be using THUMB or ARM mode for this signal handler.
*/
thumb = handler & 1;
if (thumb)
cpsr |= PSR_T_BIT;
else
cpsr &= ~PSR_T_BIT;
}
#endif
if (ka->sa.sa_flags & SA_RESTORER) {
retcode = (unsigned long)ka->sa.sa_restorer;
} else {
unsigned int idx = thumb << 1;
if (ka->sa.sa_flags & SA_SIGINFO)
idx += 3;
if (__put_user(sigreturn_codes[idx], rc) ||
__put_user(sigreturn_codes[idx+1], rc+1))
return 1;
if (cpsr & MODE32_BIT) {
/*
* 32-bit code can use the new high-page
* signal return code support.
*/
retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
} else {
/*
* Ensure that the instruction cache sees
* the return code written onto the stack.
*/
flush_icache_range((unsigned long)rc,
(unsigned long)(rc + 2));
retcode = ((unsigned long)rc) + thumb;
}
}
regs->ARM_r0 = usig;
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;//这是sa_handler处理函数执行完成之后,返回的地址
regs->ARM_pc = handler;
//这就是本次信号触发之后,从内核空间返回用户空间的地址指针,也就是将会返回到我们的用户程序登记注册的处理函数,
//而不是while()可能执行到的位置了,即便在处理alarm_sa_handler处理函数的时候被kernel schedule出去了,但是因为
//alarm_sa_handler处理函数就是当前用户空间处理所在pc,也就是kernel认为的应用程序执行所到处,故当又被kernel schedule
//回到该用户应用程序之后,会继续执行未执行完的alarm_sa_handler处理函数,
//这也就是直接能够剥夺while主处理流程而去执行alarm_sa_handler处理函数的直接原因所在了[luther.gliethttp].
//所以alarm_sa_handler函数中就不可能采用同步机制mutex,sem之类,与while()处理部分进行同步,因为alarm_sa_handler
//并不是一个独立的thread,所以使用signal进行程序设计时,需要我们大家多多注意,signal的这个特性,
//避免用户空间应用程序出现莫名其妙的问题[luther.gliethttp].
regs->ARM_cpsr = cpsr;
return 0;
}
|