input子系统事件处理层(evdev)的环形缓冲区

在事件处理层()中结构体evdev_client定义了一个环形缓冲区(circular buffer),其原理是用数组的方式实现了一个先进先出的循环队列(circular queue),用以缓存内核驱动上报给用户层的input_event事件。

struct evdev_client {
	unsigned int head;//头指针
	unsigned int tail;//尾指针
	unsigned int packet_head; /* [future] position of the first element of next packet *//包指针
	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
	struct wake_lock wake_lock;
	bool use_wake_lock;
	char name[28];
	struct fasync_struct *fasync;
	struct evdev *evdev;
	struct list_head node;
	int clkid;
	bool revoked;
	unsigned int bufsize;//循环队列大小
	struct input_event buffer[];//循环队列数组
};
packet_head  
内核驱动处理一次输入,可能上报一到多个input_event事件,为表示处理完成,会在上报这些input_event事件后再上报一次同步事件。头指针head以input_event事件为单位,记录缓冲区的入口偏移量,而包指针packet_head则以“数据包”(一到多个input_event事件)为单位,记录缓冲区的入口偏移量。

circular buffer



以上内容参照
http://blog.csdn.net/zifehng/article/details/70169512
另外,这里也有一个很好的例子。
http://blog.csdn.net/u013904227/article/details/51168398
这个buffer的作用是,上层OPEN了此节点,但是没有读取此节点的数据的时候,循环buffer会保存128个事件。
如下的代码是进入到事件传输,先入队列head++,如果head == tail 则为满。此时将会把tail往后面移动2个位置(input event,
input sync),填充sync事件。P_head =tail, 初始的状态。
正常情况下入队列,队列没有满,就把head++,最终受到sync信号,并把p_head指向head的位置。
static void __pass_event(struct evdev_client *client,
			 const struct input_event *event)
{
	client->buffer[client->head++] = *event;
	client->head &= client->bufsize - 1;
	printk("====%s,head=%d,tail=%d,packet_head=%d,%s/n",__func__,client->head,client->tail,client->packet_head,client->name);
	if (unlikely(client->head == client->tail)) {
		/*
		 * This effectively "drops" all unconsumed events, leaving
		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
		 */
		client->tail = (client->head - 2) & (client->bufsize - 1);

		client->buffer[client->tail].time = event->time;
		client->buffer[client->tail].type = EV_SYN;
		client->buffer[client->tail].code = SYN_DROPPED;
		client->buffer[client->tail].value = 0;

		client->packet_head = client->tail;
		if (client->use_wake_lock)
			wake_unlock(&client->wake_lock);
	}

	if (event->type == EV_SYN && event->code == SYN_REPORT) {
		printk("enter the SYN\n");
		client->packet_head = client->head;
		if (client->use_wake_lock)
			wake_lock(&client->wake_lock);
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}
}


这个是注册的读函数,当上层打开对应的event的时候,底层就会不断判断是否有数据,如果有数据的话,就出队列,当tail不断自加等于 P_head的时候,证明空间已经清空,如果空间为空并且使用休眠锁的话,这时候释放休眠锁。这里的休眠锁,可以通过ioctl来控制。

所以可以在读的操作和写的操作,在条件都为head=tail的情况下,分别为空和满。最终读取完数据初始状态是,

client->packet_head=8,client->tail=8,client->head=8。经过log分析应该是同一个数字。

static int evdev_fetch_next_event(struct evdev_client *client,
				  struct input_event *event)
{
	int have_event;

	spin_lock_irq(&client->buffer_lock);

	have_event = client->packet_head != client->tail;
	if (have_event) {
		*event = client->buffer[client->tail++];
		client->tail &= client->bufsize - 1;
		if (client->use_wake_lock &&
		    client->packet_head == client->tail){
		    printk("=====client->packet_head=%d,client->tail=%d,client->head\n",client->packet_head,client->tail,client->head);
			wake_unlock(&client->wake_lock);
			}
	}

	spin_unlock_irq(&client->buffer_lock);

	return have_event;
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值