ARM Linux对signal的处理过程

// 本文部分内容来自网络

// 基于内核版本3.4

一.整体流程

Linux 用户进程不能处理信号,操作系统也不会为了处理一个信号而把当前正在运行的进程挂起,而是选择在内核态切换回用户态的时候(一般都是中断或者系统调用返回)处理信号。

所以处理信号的整个过程是这样的:进程由于 系统调用或者中断 进入内核,完成相应任务返回用户空间的前夕,检查信号队列,如果有信号,则根据信号向量表找到信号处理函数,设置好“堆栈”后,跳到用户态执行信号处理函数。信号处理函数执行完毕后,返回内核态,设置“堆栈”,再返回到用户态继续执行程序。

具体步骤:

      1、用户为某信号注册一个信号处理函数sighandler

      2、当前正在执行主程序,这时候因为中断、异常或系统调用进入内核态。

      3、在处理完异常要返回用户态的主程序之前,检查到有信号未处理,并发现该信号需要按照用户自定义的函数来处理。

      4、内核决定返回用户态执行sighandler函数,而不是恢复main函数的上下文继续执行!(sighandlermain函数使用的是不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程)

      5、sighandler函数返回后,执行特殊的系统调用sigreturn从用户态回到内核态

      6、检查是否还有其它信号需要递达,如果没有 则返回用户态并恢复主程序的上下文信息继续执行。

 

二.代码分析

ARM Linux中,内核态返回用户态通常接口是ret_fast_syscall(系统调用)和ret_to_user(中断),所以signal的处理流程:ret_to_user()/ret_fast_syscall–>work_pending()–>do_notify_resume()–>do_signal

 

 ret_fast_syscall为例分析具体实现,代码位于 archarmkernelentry-common.S

ret_fast_syscall:
 UNWIND(.fnstart    )
 UNWIND(.cantunwind    )
    disable_irq                @ disable interrupts
    ldr    r1, [tsk, #TI_FLAGS]
    tst    r1, #_TIF_WORK_MASK
    bne    fast_work_pending
#if defined(CONFIG_IRQSOFF_TRACER)
    asm_trace_hardirqs_on
#endif

    /* perform architecture specific actions before user return */
    arch_ret_to_user r1, lr

    restore_user_regs fast = 1, offset = S_OFF
 UNWIND(.fnend        )

 

ldr r1, [tsk, #TI_FLAGS]:

 TI_FLAGS表示thread_info结构体中的flags变量,相关宏定义位于archarmkernelAsm-offsets.c

  DEFINE(TI_FLAGS,        offsetof(struct thread_info, flags));
  DEFINE(TI_PREEMPT,        offsetof(struct thread_info, preempt_count));
  DEFINE(TI_ADDR_LIMIT,        offsetof(struct thread_info, addr_limit));
  DEFINE(TI_TASK,        offsetof(struct thread_info, task));
  DEFINE(TI_EXEC_DOMAIN,    offsetof(struct thread_info, exec_domain));
  DEFINE(TI_CPU,        offsetof(struct thread_info, cpu));
  DEFINE(TI_CPU_DOMAIN,        offsetof(struct thread_info, cpu_domain));
  DEFINE(TI_CPU_SAVE,        offsetof(struct thread_info, cpu_context));
  DEFINE(TI_USED_CP,        offsetof(struct thread_info, used_cp));
  DEFINE(TI_TP_VALUE,        offsetof(struct thread_info, tp_value));
  DEFINE(TI_FPSTATE,        offsetof(struct thread_info, fpstate));
  DEFINE(TI_VFPSTATE,        offsetof(struct thread_info, vfpstate));

flags变量表示了该线程基本状态,例如是否有信号pending,是否需要调度等,其可能的值定义位于/arch/arm/include/asm/thread_info.h

/*
 * thread information flags:
 *  TIF_SYSCALL_TRACE    - syscall trace active
 *  TIF_SYSCAL_AUDIT    - syscall auditing active
 *  TIF_SIGPENDING    - signal pending
 *  TIF_NEED_RESCHED    - rescheduling necessary
 *  TIF_NOTIFY_RESUME    - callback before returning to user
 *  TIF_USEDFPU        - FPU was used by this task this quantum (SMP)
 *  TIF_POLLING_NRFLAG    - true if poll_idle() is polling TIF_NEED_RESCHED
 */
#define TIF_SIGPENDING        0
#define TIF_NEED_RESCHED    1
#define TIF_NOTIFY_RESUME    2    /* callback before returning to user */
#define TIF_SYSCALL_TRACE    8
#define TIF_SYSCALL_AUDIT    9
#define TIF_POLLING_NRFLAG    16
#define TIF_USING_IWMMXT    17
#define TIF_MEMDIE        18    /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK    20
#define TIF_SECCOMP        21
#define TIF_SWITCH_MM        22    /* deferred switch_mm */

#define _TIF_SIGPENDING        (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED    (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME    (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACE    (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT    (1 << TIF_SYSCALL_AUDIT)
#define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
#define _TIF_USING_IWMMXT    (1 << TIF_USING_IWMMXT)
#define _TIF_RESTORE_SIGMASK    (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SECCOMP        (1 << TIF_SECCOMP)

/* Checks for any syscall work in entry-common.S */
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)

例如flags=1,表示_TIF_SIGPENDING即有信号pending;flags=2,表示__TIF_NEED_RESCHED即线程需要调度;

tst r1, #_TIF_WORK_MASK

bne fast_work_pending

_TIF_WORK_MASK的值定于同样位于/arch/arm/include/asm/thread_info.h,值为0xff;这两条指令比较了flags值是否为0,如果不为0,则跳转到fast_work_pending函数。

fast_work_pending根据flags的具体值,跳转到work_resched/do_notify_resume等具体接口继续处理:

fast_work_pending:
    str    r0, [sp, #S_R0+S_OFF]!        @ returned r0
work_pending:
    tst    r1, #_TIF_NEED_RESCHED
    bne    work_resched
    tst    r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
    beq    no_work_pending
    mov    r0, sp                @ 'regs'
    mov    r2, why                @ 'syscall'
    tst    r1, #_TIF_SIGPENDING        @ delivering a signal?
    movne    why, #0                @ prevent further restarts
    bl    do_notify_resume
    b    ret_slow_syscall        @ Check work again

// to be continued......

原文地址:https://www.cnblogs.com/DF11G/p/9012498.html