Linux 新的API signalfd、timerfd、eventfd使用说明
Linux 新的API signalfd、timerfd、eventfd使用说明
三种新的fd加入linux内核的的版本:
signalfd:2.6.22
timerfd:2.6.25
eventfd:2.6.22
三种fd的意义:
lsignalfd
传统的处理信号的方式是注册信号处理函数;由于信号是异步发生的,要解决数据的并发访问,可重入问题。signalfd可以将信号抽象为一个文件描述符,当有信号发生时可以对其read,这样可以将信号的监听放到select、poll、epoll等监听队列中。
ltimerfd
可以实现定时器的功能,将定时器抽象为文件描述符,当定时器到期时可以对其read,这样也可以放到监听队列的主循环中。
leventfd
实现了线程之间事件通知的方式,也可以用于用户态和内核通信。eventfd的缓冲区大小是sizeof(uint64_t);向其write可以递增这个计数器,read操作可以读取,并进行清零;eventfd也可以放到监听队列中,当计数器不是0时,有可读事件发生,可以进行读取。
三种新的fd都可以进行监听,当有事件触发时,有可读事件发生。
signalfd涉及API:
- #include
- int signalfd(int fd, const sigset_t *mask, int flags);
参数fd:如果是-1则表示新建一个,如果是一个已经存在的则表示修改signalfd所关联的信号;
参数mask:信号集合;
参数flag:内核版本2.6.27以后支持SFD_NONBLOCK、SFD_CLOEXEC;
成功返回文件描述符,返回的fd支持以下操作:read、select(poll、epoll)、close
l例子
- #include
- #include
- #include
- #include
- #include
- #define handle_error(msg) \
- do { perror(msg); exit(EXIT_FAILURE); } while (0)
- int main(int argc, char *argv[])
- {
- sigset_t mask;
- int sfd;
- struct signalfd_siginfo fdsi;
- ssize_t s;
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGQUIT);
- if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
- handle_error("sigprocmask");
- sfd = signalfd(-1, &mask, 0);
- if (sfd == -1)
- handle_error("signalfd");
- for (;;) {
- s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
- if (s != sizeof(struct signalfd_siginfo))
- handle_error("read");
- if (fdsi.ssi_signo == SIGINT) {
- printf("Got SIGINT\n");
- } else if (fdsi.ssi_signo == SIGQUIT) {
- printf("Got SIGQUIT\n");
- exit(EXIT_SUCCESS);
- } else {
- printf("Read unexpected signal\n");
- }
- }
- }
L17-L21:将感兴趣的信号加入到sigset_t中;
L24:调用signalfd,把信号集与fd关联起来,第一个参数为-1表示新建一个signalfd,不是-1并且是一个合法的signalfd表示向其添加新的信号。
L29:阻塞等待信号的发生并读取。根据读取的结果可以知道发生了什么信号。
timerfd涉及的API
- #include
- int timerfd_create(int clockid, int flags);
- int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,struct itimerspec *old_value);
- int timerfd_gettime(int fd, struct itimerspec *curr_value);
timerfd_create:创建一个timerfd;返回的fd可以进行如下操作:read、select(poll、epoll)、close
timerfd_settime:设置timer的周期,以及起始间隔
timerfd_gettime:获取到期时间。
- //函数参数中数据结构如下:
- struct timespec
- {
- time_t tv_sec; /* Seconds */
- long tv_nsec; /* Nanoseconds */
- };
- struct itimerspec
- {
- struct timespec it_interval; /* Interval for periodic timer */
- struct timespec it_value; /* Initial expiration */
- };
l例子
- #include
- #include
- #include
- #include
- #include
- #include
- #include
/* Definition of uint64_t */ - #define handle_error(msg) \
- do { perror(msg); exit(EXIT_FAILURE); } while (0)
- void printTime()
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- printf("printTime: current time:%ld.%ld ", tv.tv_sec, tv.tv_usec);
- }
- int main(int argc, char *argv[])
- {
- struct timespec now;
- if (clock_gettime(CLOCK_REALTIME, &now) == -1)
- handle_error("clock_gettime");
- struct itimerspec new_value;
- new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
- new_value.it_value.tv_nsec = now.tv_nsec;
- new_value.it_interval.tv_sec = atoi(argv[2]);
- new_value.it_interval.tv_nsec = 0;
- int fd = timerfd_create(CLOCK_REALTIME, 0);
- if (fd == -1)
- handle_error("timerfd_create");
- if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
- handle_error("timerfd_settime");
- printTime();
- printf("timer started\n");
- for (uint64_t tot_exp = 0; tot_exp < atoi(argv[3]);)
- {
- uint64_t exp;
- ssize_t s = read(fd, &exp, sizeof(uint64_t));
- if (s != sizeof(uint64_t))
- handle_error("read");