timerfd机制

timerfd是linux为用户提供的基于文件描述符的定时器接口,主要的系统调用有三个。分别如下:
timerfd_create -- 新建一个fd
timerfd_settime -- 设置fd的超时时间
timerfd_gettime -- 获得fd的超时时间
一般用户设置fd的超时时间后就可以通过read来读取fd来poll当前的时间.
timerfd 基本就是一个内存文件。这点可以从timerfd_create的实现中看到.
可以看道timerfd_create 有两个输入蚕食分别是clockid 和 flags
SYSCALL_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_read
static 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;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在C语言中,timerfd是一个用于创建定时器的系统调用。它可以与epoll结合使用,以实现定时任务的功能。timerfd_settime接口用于启动和停止定时器。通过设置it_interval和it_value字段的值来指定定时器的周期和首次超时时间。其中it_interval.tv_sec和it_interval.tv_nsec用于设置定时器的周期,单位是秒和纳秒;it_value.tv_sec和it_value.tv_nsec用于设置定时器的首次超时时间。例如,如果想要定时器每50毫秒超时一次,可以将it_interval.tv_nsec设置为50 * 1000 * 1000,并将it_value.tv_sec设置为2。这样定时器会在2秒后首次超时,并且之后每50毫秒超时一次。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [linux c++ 利用timerfd和epoll封装计时器(Timer)类](https://blog.csdn.net/hjwang1/article/details/120387987)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【用示例学习与理解C++系列】timerfd与epoll的使用](https://blog.csdn.net/SCHOLAR_II/article/details/127445837)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值