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 -----对应-- ...
随机推荐
- jvm-监视管理控制台-jconsole
命令: jconsole 作用: jvm进程运行状态的实时.可视化工具 效果: 连接远程jvm进程: 1.首先远程jvm进程,开启了jmx服务: -Dcom.sun.management.jmxrem ...
- 修改input type=file 标签默认样式的简单方法
<html><head><title></title></head><body><form id="upload ...
- css的checkbox样式变化
1.CSS body{font-family:'微软简行楷'} ul li{list-style:none; margin:10px;color:#4985d7;} .myCheck { displa ...
- wireshark----教你怎样抓包
wireshark----教你怎样抓包 wireshark是一款强大的抓包工具,走过路过一定不要错过就是了,当你学习TCP/IP协议的时候,学习使用wireshark抓包正是理论联系实际最好的方法,先 ...
- vue-resource基本使用方法
一.vue-resource特点 1.体积小:vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多. 2.支持主流 ...
- NYOJ 1058 部分和问题 【DFS】
部分和问题 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描写叙述 给定整数a1.a2........an,推断能否够从中选出若干数.使它们的和恰好为K. 输入 首先,n和k ...
- 【面试问题】—— 2019.3月前端面试之JS原理&CSS基础&Vue框架
前言:三月中旬面试了两家公司,一家小型公司只有面试,另一家稍大型公司笔试之后一面定夺.笔试部分属于基础类型,网上的复习资料都有. 面试时两位面试官都有考到一些实际工作中会用到,但我还没接触过的知识点. ...
- [Functional Programming] Pull Many Random Numbers in a Single State ADT Transaction
We have the ability to select a single random card from a pile of twelve cards, but we would like to ...
- IT痴汉的工作现状21-Android开发前景论
饭间闲谈 齐天.周权和我是饭搭子.总是边吃边聊一些与技术.汽车和女人相关的话题. "前阵子Nokia裁员之事不知道完没完?这艾洛普挺能作啊."我吃着香喷喷的过桥米线说." ...
- driver: Linux设备模型之input子系统具体解释
本节从总体上解说了输入子系统的框架结构.有助于读者从总体上认识linux的输入子系统.在陷入代码分析的过程中,通过本节的知识可以找准方向,明确原理. 本节重点: 输入子系统的框架结构 各层相应内核中的 ...