博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dpdk 中的中断
阅读量:4215 次
发布时间:2019-05-26

本文共 6717 字,大约阅读时间需要 22 分钟。

要在dpdk中使用中断,需要调用rte_eal_intr_init 来进行中断子系统初始化,但是这个函数不用用户调用,会在环境初始化函数rte_eal_init 中被调用,用户只要调用rte_intr_callback_register 来注册callback即可rte_eal_intr_init 源码分析如下:intrte_eal_intr_init(void){	int ret = 0, ret_1 = 0;	char thread_name[RTE_MAX_THREAD_NAME_LEN];	/* init the global interrupt source head */	#初始化全局的中断源head 	TAILQ_INIT(&intr_sources);	/**	 * create a pipe which will be waited by epoll and notified to	 * rebuild the wait list of epoll.	 */	 #新建两个pipe分别用于读和写	if (pipe(intr_pipe.pipefd) < 0) {		rte_errno = errno;		return -1;	}	/* create the host thread to wait/handle the interrupt */	#建立一个thread来polling中断	ret = pthread_create(&intr_thread, NULL,			eal_intr_thread_main, NULL);	if (ret != 0) {		rte_errno = ret;		RTE_LOG(ERR, EAL,			"Failed to create thread for interrupt handling\n");	} else {		/* Set thread_name for aid in debugging. */		snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,			"eal-intr-thread");			#设置中断的名字为eal-intr-thread,这样就可以通过ps -ef 查询到这个name		ret_1 = rte_thread_setname(intr_thread, thread_name);		if (ret_1 != 0)			RTE_LOG(DEBUG, EAL,			"Failed to set thread name for interrupt handling\n");	}	return -ret;}中断线程的回调函数为eal_intr_thread_mainstatic __attribute__((noreturn)) void *eal_intr_thread_main(__rte_unused void *arg){	struct epoll_event ev;	/* host thread, never break out */	for (;;) {		/* build up the epoll fd with all descriptors we are to		 * wait on then pass it to the handle_interrupts function		 */		static struct epoll_event pipe_event = {			.events = EPOLLIN | EPOLLPRI,		};		struct rte_intr_source *src;		unsigned numfds = 0;		/* create epoll fd */		#新建一个新的epoll 用于轮询中断		int pfd = epoll_create(1);		if (pfd < 0)			rte_panic("Cannot create epoll instance\n");		pipe_event.data.fd = intr_pipe.readfd;		/**		 * add pipe fd into wait list, this pipe is used to		 * rebuild the wait list.		 */		 #为epoll添加fd		if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd,						&pipe_event) < 0) {			rte_panic("Error adding fd to %d epoll_ctl, %s\n",					intr_pipe.readfd, strerror(errno));		}		numfds++;		rte_spinlock_lock(&intr_lock);	#下面这段code是为uio 驱动添加epoll的fd		TAILQ_FOREACH(src, &intr_sources, next) {			if (src->callbacks.tqh_first == NULL)				continue; /* skip those with no callbacks */			ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;			ev.data.fd = src->intr_handle.fd;			/**			 * add all the uio device file descriptor			 * into wait list.			 */			if (epoll_ctl(pfd, EPOLL_CTL_ADD,					src->intr_handle.fd, &ev) < 0){				rte_panic("Error adding fd %d epoll_ctl, %s\n",					src->intr_handle.fd, strerror(errno));			}			else				numfds++;		}		rte_spinlock_unlock(&intr_lock);		/* serve the interrupt */		#fd添加完成后开始等待epoll 返回		eal_intr_handle_interrupts(pfd, numfds);		/**		 * when we return, we need to rebuild the		 * list of fds to monitor.		 */		close(pfd);	}}static voideal_intr_handle_interrupts(int pfd, unsigned totalfds){	struct epoll_event events[totalfds];	int nfds = 0;	for(;;) {	#等待epoll返回		nfds = epoll_wait(pfd, events, totalfds,			EAL_INTR_EPOLL_WAIT_FOREVER);		/* epoll_wait fail */		#小于零说明返回failed了		if (nfds < 0) {			if (errno == EINTR)				continue;			RTE_LOG(ERR, EAL,				"epoll_wait returns with fail\n");			return;		}		#等于零说明是timeout了,继续等待		/* epoll_wait timeout, will never happens here */		else if (nfds == 0)			continue;		/* epoll_wait has at least one fd ready to read */		#开始处理fd的read		if (eal_intr_process_interrupts(events, nfds) < 0)			return;	}}static inteal_intr_process_interrupts(struct epoll_event *events, int nfds){	bool call = false;	int n, bytes_read;	struct rte_intr_source *src;	struct rte_intr_callback *cb;	union rte_intr_read_buffer buf;	struct rte_intr_callback active_cb;	for (n = 0; n < nfds; n++) {		/**		 * if the pipe fd is ready to read, return out to		 * rebuild the wait list.		 */		if (events[n].data.fd == intr_pipe.readfd){		#开始读fd结果保存到buf.charbuf			int r = read(intr_pipe.readfd, buf.charbuf,					sizeof(buf.charbuf));			RTE_SET_USED(r);			return -1;		}		if (call) {			/* Finally, call all callbacks. */			TAILQ_FOREACH(cb, &src->callbacks, next) {				/* make a copy and unlock. */				#得到注册中断时注册的callback函数,并传递并调用这个callback函数				active_cb = *cb;				rte_spinlock_unlock(&intr_lock);				/* call the actual callback */				active_cb.cb_fn(active_cb.cb_arg);				/*get the lock back. */				rte_spinlock_lock(&intr_lock);			}		}	}	return 0;}原来中断处理就是等待epoll返回,然后调用注册fd时候的callback函数,下来看看怎么注册中断intrte_intr_callback_register(const struct rte_intr_handle *intr_handle,			rte_intr_callback_fn cb, void *cb_arg){	int ret, wake_thread;	struct rte_intr_source *src;	struct rte_intr_callback *callback;	wake_thread = 0;	/* first do parameter checking */	#这三个参数中任何一个为null,则说明参数不合理,返回error	if (intr_handle == NULL || intr_handle->fd < 0 || cb == NULL) {		RTE_LOG(ERR, EAL,			"Registering with invalid input parameter\n");		return -EINVAL;	}	#申请一个callback函数并赋值	/* allocate a new interrupt callback entity */	callback = rte_zmalloc("interrupt callback list",				sizeof(*callback), 0);	if (callback == NULL) {		RTE_LOG(ERR, EAL, "Can not allocate memory\n");		return -ENOMEM;	}	callback->cb_fn = cb;	callback->cb_arg = cb_arg;	rte_spinlock_lock(&intr_lock);	#检查这个handle对应的fd是否已经被注册过,如果已经注册则退出,说明同一个fd	#不能被重复注册	/* check if there is at least one callback registered for the fd */	TAILQ_FOREACH(src, &intr_sources, next) {		if (src->intr_handle.fd == intr_handle->fd) {			/* we had no interrupts for this */			if TAILQ_EMPTY(&src->callbacks)				wake_thread = 1;			TAILQ_INSERT_TAIL(&(src->callbacks), callback, next);			ret = 0;			break;		}	}	/* no existing callbacks for this - add new source */	if (src == NULL) {		if ((src = rte_zmalloc("interrupt source list",				sizeof(*src), 0)) == NULL) {			RTE_LOG(ERR, EAL, "Can not allocate memory\n");			rte_free(callback);			ret = -ENOMEM;		} else {			src->intr_handle = *intr_handle;			TAILQ_INIT(&src->callbacks);			TAILQ_INSERT_TAIL(&(src->callbacks), callback, next);			#将callback插入到全局变量intr_sources 中			TAILQ_INSERT_TAIL(&intr_sources, src, next);			wake_thread = 1;			ret = 0;		}	}	rte_spinlock_unlock(&intr_lock);	/**	 * check if need to notify the pipe fd waited by epoll_wait to	 * rebuild the wait list.	 */	 #前面成功注册的话,则这里会唤醒处理终端的线程,方法就是给pipe中写一个1	if (wake_thread)		if (write(intr_pipe.writefd, "1", 1) < 0)			return -EPIPE;	return ret;}前面申请intr_pipefds 的结构如下,可以看到明显看到包含读和写fdunion intr_pipefds{	struct {		int pipefd[2];	};	struct {		int readfd;		int writefd;	};};从fd读数据到buffer的结构体如下:可以看到在dpdk中中断分为四类,分别是uio/vfio/timer/otherunion rte_intr_read_buffer {	int uio_intr_count;              /* for uio device */#ifdef VFIO_PRESENT	uint64_t vfio_intr_count;        /* for vfio device */#endif	uint64_t timerfd_num;            /* for timerfd */	char charbuf[16];                /* for others */};

转载地址:http://nnnmi.baihongyu.com/

你可能感兴趣的文章
LoadRunner中Concurrent与Simultaneous的区别
查看>>
SiteScope - Agentless监控
查看>>
欢迎加入【亿能测试快讯】邮件列表!
查看>>
为什么我们的自动化测试“要”这么难
查看>>
LoadRunner性能脚本开发实战训练
查看>>
测试之途,前途?钱途?图何?
查看>>
通过FTP服务的winsockes录制脚本
查看>>
LRwinsocket协议测试AAA服务器
查看>>
Net远程管理实验
查看>>
反病毒专家谈虚拟机技术 面临两大技术难题
查看>>
几种典型的反病毒技术:特征码技术、覆盖法技术等
查看>>
Software Security Testing软件安全测试
查看>>
论文浅尝 | 通过共享表示和结构化预测进行事件和事件时序关系的联合抽取
查看>>
廖雪峰Python教程 学习笔记3 hello.py
查看>>
从内核看epoll的实现(基于5.9.9)
查看>>
python与正则表达式
查看>>
安装.Net Framework 4.7.2时出现“不受信任提供程序信任的根证书中终止”的解决方法
查看>>
input type=“button“与input type=“submit“的区别
查看>>
解决Github代码下载慢问题!
查看>>
LeetCode-栈|双指针-42. 接雨水
查看>>