libubox组件(3)——uloop
一:uloop概述
- uloop有三个功能: 文件描述符触发事件的监控, timeout定时器处理, 当前进程的子进程的维护
二: uloop的整体框架
1: /**
2: * 初始化事件循环
3: *主要工作是poll_fd = epoll_create(32);/* 创建一个epoll的文件描述符监控句柄。最多监控32个文件描述符
4: **/
5: int uloop_init(void)
6: {
7: if (poll_fd >= 0)
8: return 0;
9:
10: poll_fd = epoll_create(32);/* 创建一个epoll的句柄。最多监控32个文件描述符 */
11: if (poll_fd < 0)
12: return -1;
13:
14: fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); /* fd_cloexecs */
15: return 0;
16: }
17:
18:
19: /**
20: * 事件循环主处理入口
21: *1.当某一个进程第一次调用uloop_run时,注册sigchld和sigint信号
22: *2.循环获取当前时间,把超时的timeout处理掉,有一条timeout链表在维护
23: *3.循环检测是否收到一个sigchld信号,如果收到,删除对应的子进程,有一条process子进程链表在维护
24: *4.循环调用epoll_wait 监相应的触发事件文件描述符fd
25: **/
26: void uloop_run(void)
27: {
28: static int recursive_calls = 0; /* static value */
29: struct timeval tv;
30:
31: /*
32: * Handlers are only updated for the first call to uloop_run() (and restored
33: * when this call is done).
34: */
35: if (!recursive_calls++) /* 第一次运行uloop_run时调用, 注册信号处理函数 */
36: uloop_setup_signals(true);
37:
38: uloop_cancelled = false;
39: while(!uloop_cancelled)
40: {
41: uloop_gettime(&tv); /* 获取当前时间 */
42: uloop_process_timeouts(&tv); /* 把超时的timeout清理掉 */
43: if (uloop_cancelled)
44: break;
45:
46: if (do_sigchld) /* 收到一个sigchld的信号 */
47: uloop_handle_processes(); /* 销毁该进程的uloop_process */
48: uloop_gettime(&tv);
49: uloop_run_events(uloop_get_next_timeout(&tv));/* 处理相应的触发事件fd */
50: }
51:
52: if (!--recursive_calls)
53: uloop_setup_signals(false);
54: }
55:
56:
57: /**
58: * 销毁事件循环
59: * 关闭epoll描述符
60: * 销毁子进程链表
61: * 销毁timeout链表
62: **/
63: void uloop_done(void)
64: {
65: if (poll_fd < 0)
66: return;
67:
68: close(poll_fd);
69: poll_fd = -1;
70:
71: uloop_clear_timeouts();
72: uloop_clear_processes();
73: }
1: #define ULOOP_READ (1 << 0)
2: #define ULOOP_WRITE (1 << 1)
3: #define ULOOP_EDGE_TRIGGER (1 << 2)
4: #define ULOOP_BLOCKING (1 << 3)
5:
6: #define ULOOP_EVENT_MASK (ULOOP_READ | ULOOP_WRITE)
7: /* internal flags */
8: #define ULOOP_EVENT_BUFFERED (1 << 4)
9: #define ULOOP_ERROR_CB (1 << 6)
10: struct uloop_fd
11: {
12: uloop_fd_handler cb; /* 文件描述符对应的处理函数 */
13: int fd; /*文件描述符*/
14: bool eof; /*EOF*/
15: bool error; /*出错*/
16: bool registered; /*是否已经添加到epoll的监控队列*/
17: uint8_t flags; /*ULOOP_READ | ULOOP_WRITE | ULOOP_BLOCKING等*/
18: };
19:
20: /**
21: * 注册一个新描述符到事件处理循环
22: */
23: int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
24:
25: /**
26: * 从事件处理循环中销毁指定描述符
27: */
28: int uloop_fd_delete(struct uloop_fd *sock)
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <unistd.h>
5: #include <sys/types.h> /* See NOTES */
6: #include <sys/stat.h>
7: #include <fcntl.h>
8: #include <sys/socket.h>
9: #include <netinet/in.h>
10: #include <arpa/inet.h>
11: #include <libubox/usock.h>
12: #include <libubox/uloop.h>
13: static void recv_string(struct uloop_fd *u, unsigned int events)
14: {
15: char buf[1024] = {0};
16: if (events & ULOOP_READ) {
17: if ( recv(u->fd, buf, 1024, 0) > 0) {
18: printf("recv_buf: %s\n", buf);
19: send(u->fd, "helloworld from server", strlen("helloworld from server"), 0);
20: }
21: }
22: }
23:
24: static void read_std(struct uloop_fd *u, unsigned int events)
25: {
26: char buf[1024] = {0};
27: if (events & ULOOP_READ) {
28: if ( read(u->fd, buf, 1024) > 0) {
29: printf("read_std: %s\n", buf);
30: }
31: }
32: }
33:
34: int main()
35: {
36: struct sockaddr_in cli_addr;
37: socklen_t len = sizeof(struct sockaddr);
38: int type = USOCK_TCP | USOCK_SERVER | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
39: const char *host = "CarRadio";
40: const char *service = "8000";
41: char recv_buf[1024] = {0};
42: int connect_fd, u_fd = usock(type, host, service);
43: if (u_fd < 0) {
44: perror("usock");
45: return -1;
46: }
47:
48: connect_fd = accept(u_fd, (struct sockaddr *)(&cli_addr), &len);
49: if (connect_fd < 0) {
50: perror("accept");
51: return -1;
52: }
53: struct uloop_fd fd[2] = {
54: {
55: .cb = recv_string,
56: .fd = connect_fd,
57: .registered = false,
58: .flags = ULOOP_READ,
59: },
60: {
61: .cb = read_std,
62: .fd = STDIN_FILENO,
63: .registered = false,
64: .flags = ULOOP_READ,
65: }
66: };
67: uloop_init();
68: /*添加uloop_fd*/
69: uloop_fd_add(&fd[0], ULOOP_READ);
70: uloop_fd_add(&fd[1], ULOOP_READ);
71: uloop_run();
72:
73: uloop_fd_delete(&fd[0]);
74: uloop_done();
75:
76: return 0;
77: }
四:timeout定时器处理
建立一条链表管理所有的timeout节点
1: struct uloop_timeout
2: {
3: struct list_head list; //链表节点
4: bool pending; //添加一个新的timeout pending是true, false删除该节点timeout
5:
6: uloop_timeout_handler cb; //超时处理函数
7: struct timeval time; //超时时间
8: };
9:
10: /**
11: * 注册一个新定时器
12: */
13: int uloop_timeout_add(struct uloop_timeout *timeout);
14:
15: /**
16: * 设置定时器超时时间(毫秒),并添加
17: */
18: int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
19:
20: /**
21: * 销毁指定定时器
22: */
23: int uloop_timeout_cancel(struct uloop_timeout *timeout);
24:
25: /**
26: * 获取定时器还剩多长时间超时
27: */
28: int uloop_timeout_remaining(struct uloop_timeout *timeout);
例子:
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <sys/types.h> /* See NOTES */
5: #include <sys/socket.h>
6: #include <libubox/usock.h>
7: #include <libubox/uloop.h>
8: int g_fd = -1;
9: void send_sock(struct uloop_timeout *t);
10:
11: struct uloop_timeout tm = {
12: .cb = send_sock,
13: };
14: void send_sock(struct uloop_timeout *t)
15: {
16: char buf[1024] = {0};
17: send(g_fd, "hello world from cilent", strlen("hello world from cilent"), 0);
18: if ( recv(g_fd, buf, 1024, 0) > 0) {
19: printf("\nrecv_buf: %s\n", buf);
20: }
21: /* 添加uloop_timeout 实现循环定时 */
22: uloop_timeout_set(&tm, 5000);
23: }
24: int main()
25: {
26: struct sockaddr cli_addr;
27: socklen_t len = sizeof(struct sockaddr);
28: int type = USOCK_TCP | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
29: const char *host = "CarRadio";
30: const char *service = "8000";
31: char recv_buf[1024] = {0};
32: g_fd = usock(type, host, service); /* create a linker socket*/
33: if (g_fd < 0) {
34: perror("usock");
35: return -1;
36: }
37: uloop_init();
38: /*添加uloop_timeout*/
39: uloop_timeout_set(&tm, 5000);
40: uloop_run();
41: uloop_done();
42:
43: close(g_fd);
44: return 0;
45: }
46:
五:当前进程的子进程的维护建立一条process链表管理所有的进程id
1: struct uloop_process {
2: struct list_head list;
3: bool pending;
4: uloop_process_handler cb; /** 文件描述符, 调用者初始化 */
5: pid_t pid; /** 文件描述符, 调用者初始化 */
6: };
7: /* 进程退出时回调函数 */
8: typedef void (*uloop_process_handler)(struct uloop_process *c, int ret) ;
9: /**
10: * 注册新进程到事件处理循环
11: */
12: int uloop_process_add(struct uloop_process *p);
13:
14: /**
15: * 从事件处理循环中销毁指定进程
16: */
17: int uloop_process_delete(struct uloop_process *p);
例子:
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4: #include <sys/types.h> /* See NOTES */
5: #include <unistd.h>
6: #include <libubox/uloop.h>
7:
8: struct uloop_process *u_process = NULL;
9: /*c: 代表推出的进程, ret:代表推出的状态*/
10: void process_exit(struct uloop_process *c, int ret)
11: {
12: printf("child process exit id[%d], status[%#x]\n", c->pid, ret);
13: free(c);
14: }
15:
16: void child_process(int t)
17: {
18: printf(" process pid: %d is runing\n", getpid());
19: if (t > 0)
20: sleep(t);
21: printf("process id[%d] will exit...\n", getpid());
22:
23: exit(t);
24: }
25:
26: int main()
27: {
28: int i;
29: pid_t pid;
30: uloop_init();
31: for (i = 0 ; i < 10; i++) {
32: usleep(500);
33: pid = fork();
34: if (pid == 0) {//子进程
35: child_process( (i+1)*10 ); //子进程休眠(i+1)*10s
36: }
37: else {
38: u_process =
39: (struct uloop_process *)malloc(sizeof(struct uloop_process));
40: if (NULL == u_process) {
41: perror("malloc");
42: exit(-1);
43: }
44: u_process->pid = pid;
45: u_process->cb = process_exit;
46: u_process->pending = false;
47: if (uloop_process_add(u_process) < 0) {
48: printf("uloop_process_add failed...\n");
49: }
50: printf("success create process pid: %d\n", pid);
51: }
52: }
53: printf("uloop_runing....\n");
54: uloop_run();
55: uloop_done();
56:
57: return 0;
58: }
59:
60:
libubox组件(3)——uloop的更多相关文章
- openWrt libubox组件之uloop原理分析
1. libubox概述 libubox是openwrt新版本中的一个基础库,有很多应用是基于libubox开发的,如uhttpd,netifd,ubusd等. libubox主要提供以下两种功 ...
- libubox组件(1)——usock
一:相关API介绍 1.相关源码文件:usocket.h usocket.c 2.类型标志 1: #define USOCK_TCP 0 2: #define USOCK_UDP 1 3: #defi ...
- libubox组件(2)——blob/blobmsg (转载 https://segmentfault.com/a/1190000002391970)
一:blob相关接口 1.数据结构 1: struct blob_attr { 2: uint32_t id_len; /** 高1位为extend标志,高7位存储id, 3: * 低24位存储dat ...
- libubox
lbubox是openwrt的一个核心库,封装了一系列基础实用功能,主要提供事件循环,二进制格式处理,linux链表实现和一些JSON辅助处理. 它的目的是以动态链接库方式来提供可重用的通用功能,给其 ...
- libubox-uloop
参考:libubox组件(3)——uloop uloop是提供事件驱动机制接口,类似libevent事件框架,基于epoll接口来实现的. uloop三大功能:事件管理(uloop_fd).超时管理( ...
- openwrt procd启动流程和脚本分析
Linux内核执行start_kernel函数时会调用kernel_init来启动init进程,流程如下图: graph LR A[start_kernel] -->B(rest_init) B ...
- ExtJS 4.2 评分组件
上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...
- react组件的生命周期
写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...
- react-router 组件式配置与对象式配置小区别
1. react-router 对象式配置 和 组件式配置 组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...
随机推荐
- js之对象(经典)
一.对象的定义: 对象是JavaScript的一个基本数据类型,是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值.即属性的无序集合. 二.对象的创建(多种方法) 1.对象 ...
- 用Qemu模拟vexpress-a9 (五) --- u-boot引导kernel,device tree的使用
环境介绍 Win7 64 + Vmware 11 + ubuntu14.04 32 u-boot 版本:u-boot-2015-04 Linux kernel版本:linux-3.16.y busyb ...
- 修改input type=file 标签默认样式的简单方法
<html><head><title></title></head><body><form id="upload ...
- Docker时间和宿主同步
通过date命令查看时间 查看主机时间 [root@localhost ~]# date 2016年 07月 27日 星期三 22:42:44 CST 查看容器时间 root@b43340ecf5ef ...
- Docker实践2:安装Docker及weblogic镜像
安装Docker 以root登录,运行 vi /etc/yum.repos.d/public-yum-ol6.repo,添加如下段落 [ol6_addons]name=Oracle Linux $re ...
- Linux 内核参数 和 Oracle相关参数调整
Linux 内核参数 和 Oracle相关参数调整 分类: Oracle Basic Knowledge2009-10-14 12:23 9648人阅读 评论(0) 收藏 举报 oraclelinux ...
- Docker核心技术
Docker核心技术 1.cgroup 即controller group,其重要概念是子系统,首先挂载子系统,然后才有control group.例如cpu子系统,挂载至系统之后,创建一个cgrou ...
- selinux 是什么 (Linux)
SElinux是Linux安全加强工具.关闭用setenforce 0或者修改文件vim /etc/sysconfig/selinux 把SELINUX=enforcing 改为 SELINUX=di ...
- 利用forever在Linux上实现Node.js项目自启动
在一台计算机上手动跑Node项目简单,node xx.js就搞定了,想让Node项目后台执行,尽管不能直接用node命令搞定,可是在安装了forever这个包以后.还是非常轻松的.只是要是在远程ser ...
- ssh中使用spring的集成quartz 编写定时任务
之前没有使用框架开发时对于开发定时任务都是 使用java的原声timer类,重写线程的run方法跑要执行的任务.刚刚换的新公司,项目使用ssh2,目前该项目中的定时任务的使用spirng集成的quar ...