关闭

Linux 通过信号机制在进程间传递参数中的几个主要函数解析

标签: linuxsignal数据结构structdescriptortimer
4661人阅读 评论(0) 收藏 举报
分类:

1. sigqueue() 用于信号的发送

函数功能:

发送信号给特定的某个进程

使用头文件:

#include <signal.h>

函数原型:

 int sigqueue(pid_t pid, int sig, const union sigval value);

参数:

pid是指定接收信号的进程号;

sig确定即将发送的信号;

value是一个联合数据结构union sigval,指定了信号传递的参数,

返回值:

成功时,返回0;(信号已经成功的排到接收队列中)

失败时,返回-1,并设置相应的errno

可能的错误原因:

EAGAIN:已达到接收队列中允许排队的最大个数;

EINVAL:无效的信号sig;

EPERM:进程没有发送信号到接收队列的权利;

ESRCH:没有与pid匹配的进程;

用到的数据结构:

 union sigval {
               int   sival_int;
               void *sival_ptr;
           };

该数据结构包含传递给pid进程的信息,会拷贝到信号处理函数的siginfo_t结构中

2. sigaction() 用于信号的安装

函数功能:

改变进程接收到特定信号后的响应

使用头文件:

#include <signal.h>

函数原型:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数:

signum为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误);

act是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理

oldact指向的对象用来保存原来对相应信号的处理(输出参数)。一般可指定oldact为NULL。

返回值:

成功则返回0;

失败则返回-1;

错误原因:

1>  EFAULT: act或者oldact指向了进程地址空间外的内存

2> EINVAL:指定了不合理的信号量signum

所用到的数据结构:

(1) struct sigaction {

               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

其中:

1> sa_handler和sa_sigaction是两个函数指针,指向信号关联的函数,即用户指定的信号处理函数(不能为它们同时赋值)

2> sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下,当前信号本身会被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位。(具体操作见信号集的操作函数。)

3> sa_flags中包含了许多标志位,包括刚刚提到的SA_NODEFER及SA_NOMASK标志位。

一个比较重要的标志位是SA_SIGINFO,当设定了该标志位时,表示信号附带的参数才可以被传递到信号处理函数中。

即使为sa_sigaction指定了信号处理函数,如果不设置SA_SIGINFO,信号处理函数同样不能得到信号传递过来的数据,在信号处理函数中对这些信息的访问都将导致段错误(Segmentation fault)。

4>  sa_restorer已经过时,不应该使用;

(2) siginfo_t {
               int      si_signo;    /* Signal number */
               int      si_errno;    /* An errno value */
               int      si_code;     /* Signal code */
               int      si_trapno;   /* Trap number that caused
                                        hardware-generated signal
                                        (unused on most architectures) */
               pid_t    si_pid;      /* Sending process ID */
               uid_t    si_uid;      /* Real user ID of sending process */
               int      si_status;   /* Exit value or signal */
               clock_t  si_utime;    /* User time consumed */
               clock_t  si_stime;    /* System time consumed */
               sigval_t si_value;    /* Signal value */
               int      si_int;      /* POSIX.1b signal */
               void    *si_ptr;      /* POSIX.1b signal */

               int      si_overrun;  /* Timer overrun count; POSIX.1b timers */

               int      si_timerid;  /* Timer ID; POSIX.1b timers */
               void    *si_addr;     /* Memory location which caused fault */
               long     si_band;     /* Band event (was int in
                                        glibc 2.3.2 and earlier) */
               int      si_fd;       /* File descriptor */
               short    si_addr_lsb; /* Least significant bit of address
                                        (since kernel 2.6.32) */
           }

其中:

si_signo,  si_errno and si_code对所有信号都有定义;si_errno通常在linux中不使用;其余的只有部分信息是有用的

对于sigqueue()方法发送的信号,会填充 si_pid(进程号) 和  si_uid(用户号);另外,发送过来的参数会填充si_int和si_ptr

( 发送消息时会用到结构体:union sigval {
               int   sival_int;
               void *sival_ptr;
           };)

3. 信号处理类型:

void     (*sa_sigaction) (int, siginfo_t *, void *);

其中:

第一个参数为信号值;

第二个参数是指向siginfo_t结构的指针;

第三个参数没有使用(posix没有规范使用该参数的标准)

附录:

所有可用的信号(输入命令:kill -l)

kill -l
 1) SIGHUP 2) SIGINT3) SIGQUIT4) SIGILL5) SIGTRAP
 6) SIGABRT 7) SIGBUS8) SIGFPE9) SIGKILL10) SIGUSR1
11) SIGSEGV 12) SIGUSR213) SIGPIPE14) SIGALRM15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD18) SIGCONT19) SIGSTOP20) SIGTSTP
21) SIGTTIN 22) SIGTTOU23) SIGURG24) SIGXCPU25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF28) SIGWINCH29) SIGIO30) SIGPWR
31) SIGSYS 34) SIGRTMIN35) SIGRTMIN+136) SIGRTMIN+237) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+540) SIGRTMIN+641) SIGRTMIN+742) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+1045) SIGRTMIN+1146) SIGRTMIN+1247) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+1550) SIGRTMAX-1451) SIGRTMAX-1352) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-1055) SIGRTMAX-956) SIGRTMAX-857) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-560) SIGRTMAX-461) SIGRTMAX-362) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX

代码示例:

信号发送端发送MYSIG信号,并传递int型参数

信号发送端:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MYSIG SIGRTMIN+1;

int main(int argc, char ** argv)
{
    pid_t pid=(pid_t)atoi(argv[1]);

    //发送的信号值
    int signo=MYSIG;

    //附带在信号上的参数
    union sigval mysigval;
    mysigval.sival_int=8;

    //发送信号
    if(sigqueue(pid, signo, mysigval)==-1)
    {
        printf("发送信号失败\n");
        return -1;
    }

    printf("成功发送信号\n");
    sleep(2);
}

疑问:

在信号发送端, 填充结构体

union sigval {
               int   sival_int;
               void *sival_ptr;
           };

时,设置sival_int参数之后,如果设置sival_ptr参数,会导致整个结构体的内容变乱

调试结果如下:

mysigval.sival_ptr=sendBuf;
(gdb) print mysigval
$1 = {sival_int = 8, sival_ptr = 0x8}
(gdb) n
28    if(sigqueue(pid, signo, mysigval)==-1)
(gdb) print mysigval
$2 = {sival_int = -1073745364, sival_ptr = 0xbffff22c}

这样的话,传递一个字符串之类的想法还是无法实现。。。

信号接收端:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

#define MYSIG SIGRTMIN+1;

//声明信号响应函数
void new_act(int, siginfo_t *, void *);

int main()
{
    //指明对信号响应的设置信息
    struct sigaction myAct;
    //标识指明,信号响应函数可以使用传输过来的参数
    myAct.sa_flags=SA_SIGINFO;
    //指明信号响应函数
    myAct.sa_sigaction=new_act;

    int signo=MYSIG;
    //安装信号,为MYSIG设置响应函数
    if(sigaction(signo, &myAct, NULL)<0)
    {
        printf("安装信号失败\n");
    }

    while(true)
    {
        sleep(2);
        printf("一直循环,直到信号的到来\n");
    }
}

//信号响应函数
void new_act(int signum, siginfo_t * info, void * myact)
{
    printf("接收到信号,信号值为%d\n", signum);
    printf("int参数为%d\n", info->si_int);
}



1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1075788次
    • 积分:11084
    • 等级:
    • 排名:第1438名
    • 原创:187篇
    • 转载:125篇
    • 译文:0篇
    • 评论:76条
    文章分类
    最新评论