- 浏览: 157687 次
- 性别:
- 来自: 大连->北京
文章分类
最新评论
-
netkongjian:
不错的界面控件知识,感谢分享!
界面测试 -
Tu_Bie:
赞一个。
servlet实现文件上传 -
心惶惶呀:
...
ORACLE和SQL语法区别归纳 -
ccfangle:
:idea:
我出现的原因是:标签重复了~
The content of element type "struts-config" must match 解决方案 -
zxl10059:
嗯,写的不错可以考虑自己写一个分页类page基本就可以明白是怎 ...
MySQL分页
/*
* fs/timerfd.c
*
* Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
*
*
* Thanks to Thomas Gleixner for code reviews and useful comments.
*
*/
#include <linux/file.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/time.h>
#include <linux/hrtimer.h>
#include <linux/anon_inodes.h>
#include <linux/timerfd.h>
#include <linux/syscalls.h>
struct timerfd_ctx {
struct hrtimer tmr;
ktime_t tintv;
wait_queue_head_t wqh;
u64 ticks;
int expired;
int clockid;
};
//该函数是timerfd的定时器超时函数。在timerfd超时时,该函数会设置定时器
//超时标记位;增加定时器超时次数(在设置定时器循环模式时,可能会出现多//次超时没有被处理的情况);唤醒一个等待队列,从而唤醒可能存在的正被阻//塞的read、select。
static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
{
struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
unsigned long flags;
//spin_lock_irqsave函数的作用是采用锁机制保证变量的正确性,但是在过程
//中可能会出现死锁的情况,所以采用一个中断状态来解决这样的问题,与
//下面的spin_lock_irqrestore相对应。
spin_lock_irqsave(&ctx->wqh.lock, flags);
ctx->expired = 1;// 设置定时器超时标记位
ctx->ticks++; //增加定时器超时次数
wake_up_locked(&ctx->wqh); //唤醒一个等待队列
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return HRTIMER_NORESTART;
}
static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
{
ktime_t remaining;
remaining = hrtimer_expires_remaining(&ctx->tmr);
return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
}
//一些初始化的工作
static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
const struct itimerspec *ktmr)
{
enum hrtimer_mode htmode;
ktime_t texp;
htmode = (flags & TFD_TIMER_ABSTIME) ?
HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
texp = timespec_to_ktime(ktmr->it_value);
ctx->expired = 0;
ctx->ticks = 0;
ctx->tintv = timespec_to_ktime(ktmr->it_interval);
hrtimer_init(&ctx->tmr, ctx->clockid, htmode);
hrtimer_set_expires(&ctx->tmr, texp);
ctx->tmr.function = timerfd_tmrproc;
if (texp.tv64 != 0)
//hrtimer_start函数将一个hrtimer加入到一个按照到期时间排序的红黑树中
hrtimer_start(&ctx->tmr, texp, htmode);
}
//timerfd_release函数释放timerfd_create函数中申请的资源,删除已分配的定时//器。
static int timerfd_release(struct inode *inode, struct file *file)
{
struct timerfd_ctx *ctx = file->private_data;
//hrtimer_cancel函数的作用是删除一个正在排队的定时器。这里分三种情况,一种是定
//时器已到期,并且设置了软中断模式;第二种是没有到期,还在红黑树中;第三种是
//定时器正在执行。
hrtimer_cancel(&ctx->tmr);
kfree(ctx); //释放内核空间
return 0;
}
/*timerfd_poll将timerfd的等待队列登记到一个poll_table,从而在定时器超时时能唤醒select系统调用。
*/
static unsigned int timerfd_poll(struct file *file, poll_table *wait)
{
struct timerfd_ctx *ctx = file->private_data;
unsigned int events = 0;
unsigned long flags;
poll_wait(file, &ctx->wqh, wait); //增加一个等待队列到poll_table
spin_lock_irqsave(&ctx->wqh.lock, flags);
if (ctx->ticks)
events |= POLLIN;
spin_unlock_irqrestore(&ctx->wqh.lock, flags);
return events;
}
/*
*timerfd_read函数是文件操作read的内核实现,读到的是定时器的超时次数。
*该函数在阻塞模式下会把自身挂到timerfd的等待队列中,等待定时器超时时
*被唤醒。
*/
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;
DECLARE_WAITQUEUE(wait, current);
if (count < sizeof(ticks))
return -EINVAL;
spin_lock_irq(&ctx->wqh.lock);
res = -EAGAIN;
if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
__add_wait_queue(&ctx->wqh, &wait);
for (res = 0;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (ctx->ticks) {
res = 0;
break;
}
if (signal_pending(current)) {
res = -ERESTARTSYS;
break;
}
spin_unlock_irq(&ctx->wqh.lock);
schedule();
spin_lock_irq(&ctx->wqh.lock);
}
__remove_wait_queue(&ctx->wqh, &wait);
__set_current_state(TASK_RUNNING);
}
if (ctx->ticks) {
ticks = ctx->ticks;
if (ctx->expired && ctx->tintv.tv64) {
/*
* If tintv.tv64 != 0, this is a periodic timer that
* needs to be re-armed. We avoid doing it in the timer
* callback to avoid DoS attacks specifying a very
* short timer period.
*/
ticks += hrtimer_forward_now(&ctx->tmr,
ctx->tintv) - 1;
hrtimer_restart(&ctx->tmr);
}
ctx->expired = 0;
ctx->ticks = 0;
}
spin_unlock_irq(&ctx->wqh.lock);
if (ticks)
res = put_user(ticks, (u64 __user *) buf) ? -EFAULT: sizeof(ticks);
return res;
}
static const struct file_operations timerfd_fops = {
.release = timerfd_release,
.poll = timerfd_poll,
.read = timerfd_read,
};
//根据文件描述符获得一个file的结构体
static struct file *timerfd_fget(int fd)
{
struct file *file;
file = fget(fd);
if (!file)
return ERR_PTR(-EBADF);
if (file->f_op != &timerfd_fops) {
fput(file);
return ERR_PTR(-EINVAL);
}
return file;
}
/*
*做一些定时器的初始化工作;
*调用hrtimer_init初始化一个hrtimer;
*调用anon_inode_getfd分配一个dentry,并得到一个文件号fd,同时传入timerfd
*的文件操作指针struct file_operations timerfd_fops,anno_inode_getfd是文件系统
*anon_inodefs的一个帮助函数。anon文件系统比较简单,整个文件系统只有一
*个inode节点,其实现代码可以在fs/anon_inodes.c中找到。
*/
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);
if ((flags & ~TFD_CREATE_FLAGS) ||
(clockid != CLOCK_MONOTONIC &&
clockid != CLOCK_REALTIME))
return -EINVAL;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
init_waitqueue_head(&ctx->wqh);
ctx->clockid = clockid;
hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
flags & TFD_SHARED_FCNTL_FLAGS);
if (ufd < 0)
kfree(ctx);
return ufd;
}
//timerfd_settime最终会调用hrtimer_start启动定时器,其超时函数被设置为timerfd_tmrproc。
/*此函数用于设置新的超时时间,并开始计时。
*参数ufd是timerfd_create返回的文件句柄。
*参数flags为1代表设置的是绝对时间;为0代表相对时间。
*参数utmr为需要设置的时间。
*参数otmr为定时器这次设置之前的超时时间。
*函数返回0代表设置成功。
*/
SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
const struct itimerspec __user *, utmr,
struct itimerspec __user *, otmr)
{
struct file *file;
struct timerfd_ctx *ctx;
struct itimerspec ktmr, kotmr;
if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
return -EFAULT;
if ((flags & ~TFD_SETTIME_FLAGS) ||
!timespec_valid(&ktmr.it_value) ||
!timespec_valid(&ktmr.it_interval))
return -EINVAL;
file = timerfd_fget(ufd);
if (IS_ERR(file))
return PTR_ERR(file);
ctx = file->private_data;
/*
* We need to stop the existing timer before reprogramming
* it to the new values.
*/
for (;;) {
spin_lock_irq(&ctx->wqh.lock);
if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
break;
spin_unlock_irq(&ctx->wqh.lock);
cpu_relax();
}
/*
* If the timer is expired and it's periodic, we need to advance it
* because the caller may want to know the previous expiration time.
* We do not update "ticks" and "expired" since the timer will be
* re-programmed again in the following timerfd_setup() call.
*/
if (ctx->expired && ctx->tintv.tv64)
hrtimer_forward_now(&ctx->tmr, ctx->tintv);
kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
kotmr.it_interval = ktime_to_timespec(ctx->tintv);
/*
* Re-program the timer to the new value ...
*/
timerfd_setup(ctx, flags, &ktmr);
spin_unlock_irq(&ctx->wqh.lock);
fput(file);
if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
return -EFAULT;
return 0;
}
//此函数用于获得定时器距离下次超时还剩下的时间。
//如果调用时定时器已经到期,并且该定时器处于循环模式,那么调用此函数之后定时器重新开始计时。
SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
{
struct file *file;
struct timerfd_ctx *ctx;
struct itimerspec kotmr;
file = timerfd_fget(ufd);
if (IS_ERR(file))
return PTR_ERR(file);
ctx = file->private_data;
spin_lock_irq(&ctx->wqh.lock);
if (ctx->expired && ctx->tintv.tv64) {
ctx->expired = 0;
ctx->ticks +=
hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
hrtimer_restart(&ctx->tmr);
}
kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
kotmr.it_interval = ktime_to_timespec(ctx->tintv);
spin_unlock_irq(&ctx->wqh.lock);
fput(file);
return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
}
发表评论
-
为嘛BIOS将MBR读入0x7C00地址处(x86平台下)
2012-11-27 14:06 1735对于很多人来讲0x7C00这个地址是很神秘的,不知道这是 ... -
挖个坑,通过一个bug学习scsi~
2012-10-23 15:55 1324开始来点前期准备的知识,主要关于Linux的I/O 路线 ... -
Solaris下如何查看boot_archive以及制作定制版boot_archive
2012-10-23 15:53 886从标题可以得知,分为两步,首先是查看,继而是修改定制。 ... -
vim系列教程(1)基础操作
2011-11-27 20:49 1059总结下本人平时所使用的各种工具以及语言的快速入门教程以及 ... -
code2pdf
2011-06-29 12:10 968http://www.code2pdf.com http:/ ... -
Perl在vim下的一些基本SYNTAX设置
2010-10-09 13:58 1847perl 的语法高亮有一些 ... -
ubuntu 10.04 电子科技大学源 校园网推荐
2010-06-12 10:59 2223电子科技大学源(校园网推荐,快) deb http:// ... -
Linux环境变量设置--总结
2009-10-20 09:27 30351、引言 在 linux系统 ... -
Linux下的脚本语言--Perl和Python Intro
2009-10-15 10:26 3209到Linux下的脚本语言, ... -
CentOS 5.3配置软件源以及CVS服务器
2009-09-24 20:05 15641 、安装完 CentOS 5.3 之后,首先要保证可以 ... -
Unix 哲学
2009-09-24 09:51 849Unix 哲学: 一:小即是美。 二:让程序只做好一件事 ... -
发一张我的桌面
2009-08-24 11:07 824我的Linux下的桌面,纯属娱乐.... -
Debian/Ubuntu的NFS配置
2009-08-21 17:07 1570Debian/Ubuntu的NFS配置 简介 :NFS(Net ... -
ubuntu 镜像的制作
2009-07-20 16:08 3715Ubuntu Customization Kit 简称 UCK ... -
Linux 由浅入深
2009-07-16 22:44 9141.掌握至少50个以上的常用命令。(GOT) 2.熟悉Gno ... -
Debian 安装Flash插件
2009-07-12 09:15 3725下载install_flash_player_10_linux ... -
Debian 源的设置
2009-07-11 20:57 1606Debian 源的设置 作者:Hily 原始链接:http: ... -
嵌入式Linux游戏开发一
2009-06-22 14:13 14471、引言 Linux由于其具有内核强大且稳定,易于扩展 ... -
ubuntu 9.04更新源
2009-05-06 09:33 126841.sudo gedit /etc/apt/sources.l ... -
Linux 下mysql的卸载
2009-04-15 14:41 2354前段时间安装了Mysql,但是有些问题,就想把他卸载了, ...
相关推荐
使用说明 BD2-AK03X/FS..., BD2-AK03X/L..., BD2-AK03X/L...+BD2-LD0G[手册]pdf,
NULL 博文链接:https://bnmnba.iteye.com/blog/2322332
使用说明 BD2-AK04(05,06) / FS... (LSD..., LSM...)[手册]pdf,
使用说明 BD2-AK04 (05,06) / FS... (LSD..., LSM...) (valid from 07/2013 --->)[手册]pdf,
小雉系统升级包-4.181.1507,系统tcp使用bbr,提升tcp效率;系统增加邮件系统,可收发邮件;详细信息请访问: <a href="http://...
实现任意两个复数的加减乘除运算。通过运算符重载方式实现,加减采用成员运算符方式
有框主程序,可以移动http://page18.ctfile.com/fs/gNL152134545 无框主程序,不能移动http://page18.ctfile.com/fs/WKz152134542 2、再下载分省图资(下载后将2个文件拷入NaviOne目录下就可以了) ...
GPIO模拟I2C的程序实现 #include <linux/module.h> #include <linux/config.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/fcntl.h> #include <linux/init.h> #include <linux/delay...
fs/yaffs2/yaffs_vfs.c:2383:2: error: implicit declaration of function 'get_sb_bdev' fs/yaffs2/yaffs_vfs.c: At top level: fs/yaffs2/yaffs_vfs.c:2390:2: error: unknown field 'get_sb' specified in ...
这是一个简单的基于C语言的防火墙,#include <linux/kernel.h> #include <linux/ip.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #...
linux tcp/ip分析 两台主机建立udp通信所走过的函数列表: | sys_read fs/read_write.c | sock_read net/socket.c | sock_recvmsg net/socket.c | inet_recvmsg net/ipv4/af_inet.c | udp_recvmsg net/ipv4/udp.c | ...
#include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/init.h> #include <linux/poll.h> #include <asm/uaccess.h> #...
免积分下载地址:https://xiaoding.pipipan.com/fs/1927055-239610146 更多免积分电子书:https://xiaoding.pipipan.com/dir/1927055-27864699-a6b34f/ 关注我的简书主页,随时获取最新免费电子书:...
小雉系统升级包-3.165.1460,增加对cloudflare的加速支持,详细信息请访问: <a href="http://www.feitianzhi.com/boke/index.php/ziyuanxiazai.html">http://www.feitianzhi.com/boke/index.php/ziyuanxiazai.html</a>
正泰YBLT-FS/1、YBLT-FS/2、YBLT-FS/3系列脚踏开关pdf,正泰YBLT-FS/1、YBLT-FS/2、YBLT-FS/3系列脚踏开关
精简版cef加炫酷demo.160702,winform C#关于自己的浏览器
Absolute Database v7.05 All in One_FS.rar