linux 信号 结构体,Linux的信号机制(一)

void sigfun(int signum)

{

printf("signal number = %d\n",signum);

(void)

signal(SIGINT,SIG_DFT); //set to default handler

}

int mian()

{

(void)

signal(SIGINT,sigfun); //set sigfun for signal SIGINT's handler

while(1) //wait the signal

{

printf("Signal

test.\n"); sleep(1); //sleep 1 second

}

return

0;

}

#gcc sigtest.c -o sigtest

#./sigtest

#Signal test.

#Signal test.

#signal number =

2 //第一次按Ctrl +

c,主程序捕获该信号,并调用sigfun处理

#signal test.

# //第二次按Ctrl

+ c,程序正常退出

下面我们就要开始看kernel的代码了,首先了解task_struct结构中signal相关的部分

struct

task_struct{

//...

/*signal handlers*/

//typedef

struct {volatile unsigned long lock;}spinlock_t;

spinlock_t sigmask_lock; /*protects signal and

blocked*/

struct signal_struct * sig; //用来保存对于不同信号采取的处理方式,所注册的新的信号处理函数就保存在这里

sigset_t blocked;

struct sigpending

pending; //进程的未决信号集,也就是进程接收到的未来得及处理和屏蔽掉的信号都保存在这里,用链表实现

//...

};

struct

signal_struct{

atomic_t count; //typedef struct

{volatile int couter;} atomic_t;

struct k_sigaction action[_NSIG]; //#define _NSIG

128

spinlock_t siglock;

};

struct

k_signation{

struct sigaction sa;

#ifdef

CONFIG_BINFMT_IRIX

void (*sa_restorer)(void);

#endif

};

struct

sigaction{

unsigned int sa_flags;

//typedef void

(*__sighandler)(int);

信号处理函数,如上例的函数sigfun

__sighandler sa_handler;

//typedef

sturct {unsigned long

sig[_NSIG_WORDS];} sigset_t;

//_NSIG_WORDS = 4

sigset_t sa_mask;

};

struct sigpending{

struct sigqueue * head,**tail;

sigset_t signal;

};

struct sigqueue {

struct sigqueue *next;

siginfo_t info;

};

OK,信号主要涉及的struct差不多都在这了,看程序吧。用户使用signal函数其实是个系统调用,反应到kernel里就是sys_signal,看程序:

unsigned long sys_signal(int

sig,__sighandler 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;

//调用do_sigaction

ret = do_sigaction(sig,&new_sa,&old_sa);

return ret? ret:(unsigned long)old_sa.sa.handler;

}

int do_sigaction(int sig,const struct

k_sigcation * act, struct k_sigaction * oact)

{ struct k_sigaction * k;

// ...

//读取当前进程中老的信号信息

k=&

current->sig->action[sig-1]; //task_struct

current;

if(oact) //将该信号信息保存起来

*oact = *k;

if(act){

*k

= *act; //再将新的信号信息保存到进程的信号列表中

//设置该信号需要屏蔽的信号

//#define sigmask(sig)

(1UL<

//获得SIGKILL和SIGSTOP的屏蔽码sigmask(SIGKILL) |

sigmask(SIGSTOP)

sigdelsetmask(&k->sa.sa_mask,sigmask(SIGKILL)|sigmask(SIGSTOP));

//到这里已经看得很清楚了,用户自己注册的信号处理方式已经存入到当前进程的信号集里,然后就是继续进程调度和等候信号事件发生了。。

//...

return 0;

}

}

static inline void

sigdelsetmask(sigset_t *set, unsigned long

mask)

{

//设置不可屏蔽的信号,比如SIGKILL为9,则~sigmask(SIGKILL)为0xfffeffff

//set->sig[0]为32位unsighed

long类型,刚好可以表示对32个信号是否屏蔽.

//然后通过&=操作,刚好可以将SIGKILL对应的第8个bit设为0.表示SIGKILL不被屏蔽

//对于大于32的信号的屏蔽,则可以用set->sig[1]来实现(struct

sigset_t定义了一个包含四个unsighed

long类型的数组,最大可以表示对128个信号的屏蔽情况).

//看似简单,实则巧妙!#$%

set->sig[0] &= ~mask;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值