当前位置: 首页 > Linux

unix信号:signalfd,eventfd,timerfd

时间:2023-04-07 00:18:38 Linux

signalfd创建一个用于所接收信号的文件描述符intsignalfd(intfd,constsigset_t*mask,intflags);结构signalfd_siginfo{uint32_tssi_signo;/*信号编号*/int32_tssi_errno;/*错误编号(未使用)*/int32_tssi_code;/*信号代码*/uint32_tssi_pid;/*发送者的PID*/uint32_tssi_uid;/*发送者的真实UID*/int32_tssi_fd;/*文件描述符(SIGIO)*/uint32_tssi_tid;/*内核定时器ID(POSIX定时器)*/uint32_tssi_band;/*波段事件(SIGIO)*/uint32_tssi_overrun;/*POSIX定时器溢出计数*/uint32_tssi_trapno;/*引起信号的陷阱编号*/int32_tssi_status;/*退出状态或信号(SIGCHLD)*/int32_tssi_int;/*sigqueue(3)发送的整数*/uint64_tssi_ptr;/*sigqueue(3)发送的指针*/uint64_tssi_utime;/*用户CPU消耗时间(SIGCHLD)*/uint64_tssi_stime;/*系统CPU时间消耗(SIGCHLD)*/uint64_tssi_addr;/*生成信号的地址(对于硬件生成的信号)*/uint8_tpad[X];/*填充大小为128字节(允许将来添加其他字段)*/};intmain(){sigset_t掩码;int信号;结构signalfd_siginfossinfo;sigemptyset(&掩码);sigaddset(&mask,SIGINT);如果(sigprocmask(SIG_BLOCK,&mask,NULL)<0)print_err("sigprocmaskerr");如果((sigfd=signalfd(-1,&mask,0))<0)print_err("signalfderr");while(1){intlen=read(sigfd,&ssinfo,sizeof(ssinfo));if(len<0)print_err("读取错误");如果(ssinfo.ssi_signo==SIGINT)printf("getSIGINT.\n");}return0;}eventfdinteventfd(unsignedintinitval,intflags);内核相关数据结构structeventfd_ctx{structkrefkref;/*文件计数,用于get/put*/wait_queue_head_twqh;/*这用于在用户模式下存储进程等待项,它的通知机制是可能的*//**每次对一个write(2)执行eventfd,正在写入的__u64的*值被添加到“count”,并且在“wqh”上执行*唤醒。read(2)会将“count”*值返回给用户空间,并将“count”重置为零。内核*端eventfd_signal()也添加到“计数”计数器并*发出唤醒。*/__u64计数;/*计算器,读就是取自然后清空,写就是把值加上*/unsignedintflags;/*使用来存储释放阻塞/非阻塞标志或者是O_CLOEXEC之类的东西*/};值得注意的flagEFD_SEMAPHORE(sinceLinux2.6.30)IfEFD_SEMAPHOREwasnotspecifiedandtheeventfdcounterhasanonzerovalue,thenaread(2)返回包含该值的8个字节,并且计数器的值重置为零。如果指定了EFD_SEMAPHORE并且eventfd计数器具有非零值,则read(2)返回包含值1的8个字节,并且计数器的值为减1。如果在调用read(2)时eventfd计数器为零,则调用要么阻塞,直到计数器变为非零(此时,read(2)继续执行上面描述的)或者如果文件描述符被设置为非阻塞则失败并返回错误EAGAIN.voidfun(intevent_fd){intepoll_fd=epoll_create1(EPOLL_CLOEXEC);//EPOLL_NONBLOCK结构epoll_event事件;constintSIZE=1024;结构epoll_eventready_events[SIZE];intready_nums;memset(&event,0,sizeof事件);event.events=EPOLLIN;event.data.fd=event_fd;epoll_ctl(epoll_fd,EPOLL_CTL_ADD,event_fd,&event);for(;;){ready_nums=epoll_wait(epoll_fd,ready_events,SIZE,-1);for(inti=0;i0){睡眠(1);乐趣(event_fd);转到完成;}DONE:返回0;}timerfd结构timespec{time_ttv_sec;/*秒*/longtv_nsec;/*纳秒*/};结构itimerspec{结构timespecit_interval;/*定时器间隔*/structtimespecit_value;/*Initialexpiration*/};如果new_value->it_value指定一个非零值(即,任一子字段非零),则timer_settime()武装(启动)计时器,将其设置为在给定时间初始到期。如果定时器已经启动,则之前的设置将被覆盖。如果new_value->it_value指定零值(即,两个子字段均为零),则定时器被解除。new_value->it_interval字段指定定时器的周期,在秒和纳秒。如果该字段不为零,则每次武装定时器到期时,定时器都会从new_value->it_interval中指定的值重新加载。如果new_value->it_interval指定零值,则计时器仅在it_value指定的时间到期一次。默认情况下,new_value->it_value中指定的初始过期时间被解释为相对于调用时计时器时钟上的当前时间。这可以通过在标志中指定TIMER_ABSTIME来修改,在这种情况下,new_value->it_value被解释为计时器时钟上测量的绝对值;也就是说,当时钟值达到new_value->it_value指定的值时,定时器就会超时。如果指定的绝对时间已经过去,则定时器立即到期,溢出计数(请参阅timer_getoverrun(2))将被正确设置。如果CLOCK_REALTIME时钟的值在调整时被调整absolutetimerbasedonthatclockisarmed,那么定时器的到期时间将被适当调整。对CLOCK_REALTIME时钟的调整对基于该时钟的相关计时器没有影响。如果old_value不为NULL,则它指向一个缓冲区,该缓冲区用于返回计时器的前一个间隔(在old_value->it_interval中)和时间量直到定时器之前已经过期(在old_value->it_value中)。timer_gettime()返回直到下一次过期的时间,以及时间间隔,对于timerid指定的定时器,在curr_value指向的缓冲区中。剩余的时间直到在curr_value->it_value中返回下一个定时器到期时间;这始终是一个相对值,无论在启用计时器时是否使用了TIMER_ABSTIME标志。如果curr_value->it_value中返回的值为零,则定时器当前处于解除状态。定时器间隔在curr_value->it_interval中返回.如果curr_value->it_interval中返回的值为零,那么这是一个“一次性”timer.inttimer_settime(timer_ttimerid,intflags,conststructitimerspec*new_value,structitimerspec*old_value);intmain(){inttimer_fd=timerfd_create(CLOCK_MONOTONIC,0);/*structtimespecbegin_time;结构timespectime_interval={1,0};如果(clock_gettime(CLOCK_MONOTONIC,&begin_time)<0){print_err("clock_gettime错误");}*/结构itimerspec定时器={{0,0},{1,0}};//ifif(timerfd_settime(timer_fd,0,&timer,NULL)<0){print_err("timerfd_settime错误");}while(1){staticuint64_ttime_out_count=0;if(read(timer_fd,&time_out_count,sizeoftime_out_count)<0){print_err("读取错误");}else{printf("time_out_count:=%lu\n",time_out_count);}}返回0;}