本文共 2575 字,大约阅读时间需要 8 分钟。
timerfd是linux为用户提供的基于文件描述符的定时器接口,主要的系统调用有三个。分别如下:timerfd_create -- 新建一个fdtimerfd_settime -- 设置fd的超时时间timerfd_gettime -- 获得fd的超时时间一般用户设置fd的超时时间后就可以通过read来读取fd来poll当前的时间.timerfd 基本就是一个内存文件。这点可以从timerfd_create的实现中看到.可以看道timerfd_create 有两个输入蚕食分别是clockid 和 flagsSYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags){ int ufd; struct timerfd_ctx *ctx; /* Check the TFD_* constants for consistency. */ BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);#这里看到clockid只能去这个if中的固定值 if ((flags & ~TFD_CREATE_FLAGS) || (clockid != CLOCK_MONOTONIC && clockid != CLOCK_REALTIME && clockid != CLOCK_REALTIME_ALARM && clockid != CLOCK_BOOTTIME && clockid != CLOCK_BOOTTIME_ALARM)) return -EINVAL; if ((clockid == CLOCK_REALTIME_ALARM || clockid == CLOCK_BOOTTIME_ALARM) && !capable(CAP_WAKE_ALARM)) return -EPERM; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; init_waitqueue_head(&ctx->wqh); spin_lock_init(&ctx->cancel_lock); ctx->clockid = clockid;#是不是alarm if (isalarm(ctx)) alarm_init(&ctx->t.alarm, ctx->clockid == CLOCK_REALTIME_ALARM ? ALARM_REALTIME : ALARM_BOOTTIME, timerfd_alarmproc); else hrtimer_init(&ctx->t.tmr, clockid, HRTIMER_MODE_ABS); ctx->moffs = ktime_mono_to_real(0);#这里就是timerfd的本质,即是内存中的一个文件 ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); if (ufd < 0) kfree(ctx); return ufd;}当用户通过timerfd_sertime之后就会通过read来poll这个fd,我们看看timerfd的read函数实现如下:static const struct file_operations timerfd_fops = { .release = timerfd_release, .poll = timerfd_poll, .read = timerfd_read, .llseek = noop_llseek, .show_fdinfo = timerfd_show, .unlocked_ioctl = timerfd_ioctl,};可以看到read的实现函数为timerfd_readstatic ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ struct timerfd_ctx *ctx = file->private_data; ssize_t res; u64 ticks = 0; if (count < sizeof(ticks)) return -EINVAL; spin_lock_irq(&ctx->wqh.lock);#这里可以看到在创建timerfd的时候可以选择是否阻塞,如果是非阻塞的话,调用read的函数时候如果时间#没有到的话就直接返回了 if (file->f_flags & O_NONBLOCK) res = -EAGAIN; else#如果是阻塞方式,则调用read的时候,就会通过下面的wait函数阻塞在这里 res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks); /* * If clock has changed, we do not care about the * ticks and we do not rearm the timer. Userspace must * reevaluate anyway. */ if (timerfd_canceled(ctx)) { ctx->ticks = 0; ctx->expired = 0; res = -ECANCELED; } spin_unlock_irq(&ctx->wqh.lock); if (ticks) res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks); return res;}
转载地址:http://wpnmi.baihongyu.com/