CSDN博客

img thewayma

Linux---signal(usr mode application) 编程

发表于2008/9/30 21:14:00  734人阅读

分类: linux programming

Linux---signal(usr mode application) 编程
#<unistd.h>
#<sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
组ID,有效组ID
uid_t getgid(void);
uid_t getegid(void);
信号
不可靠的signalAPI
#<signal.h>
void (*signal)(int sig,void (*func)(int)))(int)
typedef void (*sig_t)(int);

sig_t signal(int sig,sig_t func);
参数:sig为要为其注册一种操作的信号,func为信号处理函数指针
信号说明:
SIGHUP 终端线已经挂起
SIGINT 终端线已经接收到中断字符
SIGQUIT 终端线已经接收到退出字符
SIGUSR1 用户自定义信号1
SIGUSR2 用户自定义信号2
SIGTERM 正被终止的进程
SIGCHLD 一个子进程已终止
SIGPIPE 半关闭管道的写操作已经发生
SIGALRM Alarm函数的计时器已经到期
信号处理函数取值:
SIG_DEL 默认的信号操作(DEFault)
SIG_IGN 忽略信号(IGNore)
函数指针 信号处理函数
例:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int count=0;
void handler(int signo)
{
//signal(SIGINT,handler);
count++;
printf("Got SIGINT/n");
}
int main(void)
{
signal(SIGINT,handler);
while(count<2)
{
printf("Waiting for SIGINT.../n");
sleep(3);
}
puts("end/n");
return 0;
}
可靠信号API
要使用可靠信号必须使用信号集,构造信号集的数据类型sigset_t
<signal.h>
int sigemptyset(sigset_t *set); 清空信号集,使其成为无信号状态
sigset_t my_sigs;
sigemptyset(&my_sigs);
初始化my_sigs信号集,使其不包含任何信号
int sigfillset(sigset_t *set); 将所有可用信号填充进信号集
sigset_t my_sigs;
sigfillset(&my_sigs);
初始化信号集,以包含每个可用的信号
int sigaddset(sigset_t *set,int signum); 将一个指定的信号添加进信号集
sigset_t my_sigs;
sigemptyset(&my_sigs);
sigaddset(&my_sigs,SIGINT);
sigaddset(&my_sigs,SIGPIPE);
清空信号集再添加两个信号
int sigdelset(sigset_t *set,int signum);从信号集中删除指定的信号
sigset_t my_sigs;
sigfillset(&my_sigs);
sigdelset(&my_sigs,SIGINT);
填充信号集再删除SIGINT信号
int sigismember(const sigset_t *set,int signum);测试一个信号是否属于一个信号集
sigset_t my_sigs;
sigemptyset(&my_sigs);
sigaddset(&my_sigs,SIGINT);
if(sigismember(&my_sigs,SIGINT))
puts("has sigint/n"):
if(sigismember(&my_sigs,SIGPIPE))
puts("has sigpipe/n");
设置信号操作
<signal.h>
struct sigaction
{
viod (*sa_handler)(); //信号处理函数指针可为SIG_DEF/SIG_IGN
sigset_t sa_mask;  //掩码值
int sa_flags; //置0
};
int sigaction(int signum, //信号
const struct sigaction *act; //注册信号结构
struct sigaction *oldact //用于返回已注册的信号结构
);
返回已有信号操作:
struct sigaction sa_old;
sigaction(SIGINT,0,&sa_old);

例:报告SIGINT的当前设置
struct sigaction sa_old;
sigaction(SIGINT,0,&sa_old);
if(sa_old.sa_handler==SIG_DEF)
puts("SIG_DEF"):
else if(sa_old.sa_handler==SIG_IGN)
puts("SIG_IGN");
else
printf("sa_handler=0x%081X;/n",(long)sa_old.sa_handler);

例:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static int count=0;
void handler(int signo)
{
signal(SIGINT,handler);
count++;
printf("Get SIGINT:%d/n",count);
}
int main(void)
{
struct sigaction sa_old;
struct sigaction sa_new;
sa_new.sa_handler=handler;
sigemptyset(&sa_new.sa_mask);
sa_new.sa_flags=0;
sigaction(SIGINT,&sa_new,&sa_old);
while(count<2)
{
puts("Waiting for SIGINT.../n");
sleep(2);
}
sigaction(SIGINT,&sa_old,0); //restore signal actions
puts("end/n");
return 0;
}
阻塞信号
int sigpromask(int how,const sigset_t *set,sigset_t *oldset);
how:
SIG_BLOCK 指定的集合表明要阻塞(禁用)附加的信号
SIG_UNBLOCK 指定的集合表明信号将变为未阻塞态(启用态)
SIG_SETMASK 指定的集合替换当前的掩码
说明:
SIG_BLOCK/SIG_UNBLOCK宏修改了当前的信号掩码
SIG_SETMASK宏允许调用程序完全替换当前的信号掩码

例:如何阻塞SIGINT和SIGPIPE信号的接收
sigset_t blk; //signals to block
sigset_t sigsv; //saved signal mask
sigemptyset(&blk); //clear set
sigaddset(&blk,SIGINT); //add SIGINT
sigaddset(&blk,SIGPIPE); //add SIGPIPE
sigpromask(SIG_BLOCK,&blk,&sigsv); //block sigs
//critical code here
sigpromask(SIG_SETMASK,&sigsv,0); //restore mask
获得等待状态的信号
int sigpending(sigset_t *set);
将等待信号的集合复制到set参数提供的集合中

例:假定已阻塞SIGPIPE信号说明了如何测试同一信号是否处理等待状态
sigset_t pendg; //pending signal set
sigpending(&pendg); //inquire of pending signals
if(sigismember(&pendg,SIGPIPE))
puts("SIGPIPE is pending.");
唤醒信号,解除信号的阻塞
int sigsuspend(const sigset_t *mask);
临时使用mask参数中提供的信号掩码然后等待信号出现
例:假定已阻塞SIGPIPE信号
sigset_t pendg;
sigset_t notpipe;
sigfillset(&notpipe);
sigdelset(&notpipe,SIGPIPE);
sigpending(&pendg);
if(sigismember(&pendg,SIGPIPE))
sigsuspend(&notpipe);
调用sigsuspend时就会临时解除SIGPIPE信号的阻塞,并允许处理信号,
然而,当信号处理函数返回时就会恢复原来的信号掩码.
计时器
unsigned int alarm(unsigned int seconds);
创建计时器,在指定的时间到了之后就会唤醒SIGALRM信号
如果在唤醒SIGALRM信号之前调用了alarm就会取消当前计时器并启动新的计时器
给alarm指定0就会取消进行中的计时器
每个进程只能有一个alarm计时器
例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
//sinal catcher
static void catch_sig(int signo)
{
if(signo==SIGINT)
{
alarm(0); //cancel the timer
puts("catch sigint/n");
}else if(signo==SIGALRM)
puts("catch sigalrm/n");
}
int main(void)
{
sigset_t sigs;
struct sigaction sa_old,sa_new;
sa_new.sa_handler=catch_sig;
sigemptyset(&sa_new.sa_mask);
sigaddset(&sa_new.sa_mask,SIGINT);
sigaddset(&sa_new.sa_mask,SiGALRM);
sa_new.sa_flags=0;
sigaction(SIGINT,&sa_new,&sa_old);
sigaction(SIGALRM,&sa_new,0);
sigfillset(&sigs,SIGINT);
sigfillset(&sigs,SIGALRM);
puts("you have 3 seconds to sigint:/n");
alarm(3);
sigsuspend(&sigs); //wait for sigint or sigalrm
puts("done/n");
return 0;
}
唤醒信号
<signal.h>
<sys/types.h>
int kill(pid_t pid,int sig);
唤醒指定进程中的指定信号
例如在自己进程中唤醒SIGUSR1信号
kill(getpid(),SIGUSR1);
sig为0时,kill允许进程检查pid进程是否存在
如:
pid_t PID=1234;
if(kill(PID,0)==-1)
{
if(errno==ESRCH)
puts("process 1234 is not executing./n");
else
perror("kill");
}
else
puts("process 1234 is executing/n");
有效的I/O调度
当进行I/O操作时如果读或写得不到请求,进程就会进入睡眠状态等待条件达到要求.
解决方案:当不能完成I/O操作时系统调用返回一个错误,指明此时它没有成功,这就是非阻塞的I/O.
1.在非阻塞模式下打开文件
<fcntl.h>
int open(const char *path,int flags,...);
指定flags时让它包含O_NONBLOCK标志
2.设置非阻塞模式
<fcntl.h>
int fcntl(int fd,int cmd,...);
cmd取值:
F_GETFL 获得标志
F_SETFL 设置标志
例:
int fd,fl;
f1=fcntl(fd,F_GETFL,0);
if(f1==-1)
{
perror("fcntl(F_GETFL)");
exit(1);
}
if(fcntl(fd,F_SETFL,f1|O_NONBLOCK)==-1)
{
perror("fcntl(F_SETFL)");
exit(1);
}
例:在非阻塞模式下读取FIFO的程序
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main(void)
{
int z;
int fd;
char buf[256];
fd=open("./fifo",O_RDWR|O_NONBLOCK);
if(fd==-1)
{
perror("open");
exit(1);
}
while((z=read(fd,buf,sizeof(buf))==-1&&errno==EAGAIN);
if(z>=0)
{
buf[z]=0;
printf("GotInput:%s/n",buf);
}
else
perror("read");
return 0;
}
I/O调度函数
为了让核心知道什么唤醒进程进行I/O操作,进程就一定要注册它感兴趣的I/O事件
文件描述符集合以及它们的宏
<sys/types.h>
FD_ZERO(fd_set *set);
FD_SET(int fd,fd_set *set);
FD_CLR(int fd,fd_set *set);
int FD_ISSET(int fd,fd_set *set);
FD_SETSIZE
在使用文件描述符集合之前一定要先初始化它:
fd_set fdset1;
FD_ZERO(&fdset1);
由FD_ZERO设置文件描述符的初始值,能够使它包含空集合.
集合中最大序号的文件描述符是FD_SETSIZE,超过该值宏行为未定义
要想给集合添加一个文件描述符,可以使用FD_SET:
int fd=1;
FD_ZERO(&fdset1);
FD_SET(fd,&fdset1);
可以使用FD_CLR从集合中删除一个文件描述符:
FD_CLR(fd,&fdset1);
测试一个文件描述符是否属于一个集合:
if(FD_ISSET(2,&fdset1))
{
puts("Standard error(unit 2) is part of fdset1");
}
else
{
puts("Standard error(unit 2) is not in fdset1");
}
timeval结构定义:
作为select函数的一个重要参数
<sys/time.h>
struct timeval
{
long tv_sec; //seconds
long tv_usec; //microseconds
};
例:把timeout定认为1.25秒
struct timeval timeout;
timeout.tv_sec=1;  //1秒
timeout.tv_usec=250000;  //250000豪秒=0.25秒,10^6
select函数:
<sys/types.h>
<sys/time.h>
<unistd.h>
int select(int nfds, //of file descriptors
fd_set *readfds; //read descriptor set
fd_set *writefds; //write descriptor set
fd_set *exceptfds;  //exception descriptor set
struct timeval *timeout  //timeout value
);

阅读全文
0 0

相关文章推荐

img
取 消
img