一: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:  }
 
 
三:uloop文件描述符触发事件的监控
   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的更多相关文章

  1. openWrt libubox组件之uloop原理分析

    1.    libubox概述 libubox是openwrt新版本中的一个基础库,有很多应用是基于libubox开发的,如uhttpd,netifd,ubusd等. libubox主要提供以下两种功 ...

  2. libubox组件(1)——usock

    一:相关API介绍 1.相关源码文件:usocket.h usocket.c 2.类型标志 1: #define USOCK_TCP 0 2: #define USOCK_UDP 1 3: #defi ...

  3. 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 ...

  4. libubox

    lbubox是openwrt的一个核心库,封装了一系列基础实用功能,主要提供事件循环,二进制格式处理,linux链表实现和一些JSON辅助处理. 它的目的是以动态链接库方式来提供可重用的通用功能,给其 ...

  5. libubox-uloop

    参考:libubox组件(3)——uloop uloop是提供事件驱动机制接口,类似libevent事件框架,基于epoll接口来实现的. uloop三大功能:事件管理(uloop_fd).超时管理( ...

  6. openwrt procd启动流程和脚本分析

    Linux内核执行start_kernel函数时会调用kernel_init来启动init进程,流程如下图: graph LR A[start_kernel] -->B(rest_init) B ...

  7. ExtJS 4.2 评分组件

    上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...

  8. react组件的生命周期

    写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...

  9. react-router 组件式配置与对象式配置小区别

    1. react-router 对象式配置 和 组件式配置    组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...

随机推荐

  1. jvm-监视管理控制台-jconsole

    命令: jconsole 作用: jvm进程运行状态的实时.可视化工具 效果: 连接远程jvm进程: 1.首先远程jvm进程,开启了jmx服务: -Dcom.sun.management.jmxrem ...

  2. 修改input type=file 标签默认样式的简单方法

    <html><head><title></title></head><body><form id="upload ...

  3. css的checkbox样式变化

    1.CSS body{font-family:'微软简行楷'} ul li{list-style:none; margin:10px;color:#4985d7;} .myCheck { displa ...

  4. wireshark----教你怎样抓包

    wireshark----教你怎样抓包 wireshark是一款强大的抓包工具,走过路过一定不要错过就是了,当你学习TCP/IP协议的时候,学习使用wireshark抓包正是理论联系实际最好的方法,先 ...

  5. vue-resource基本使用方法

    一.vue-resource特点 1.体积小:vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比jQuery的体积要小得多. 2.支持主流 ...

  6. NYOJ 1058 部分和问题 【DFS】

    部分和问题 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描写叙述 给定整数a1.a2........an,推断能否够从中选出若干数.使它们的和恰好为K. 输入 首先,n和k ...

  7. 【面试问题】—— 2019.3月前端面试之JS原理&CSS基础&Vue框架

    前言:三月中旬面试了两家公司,一家小型公司只有面试,另一家稍大型公司笔试之后一面定夺.笔试部分属于基础类型,网上的复习资料都有. 面试时两位面试官都有考到一些实际工作中会用到,但我还没接触过的知识点. ...

  8. [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 ...

  9. IT痴汉的工作现状21-Android开发前景论

    饭间闲谈 齐天.周权和我是饭搭子.总是边吃边聊一些与技术.汽车和女人相关的话题. "前阵子Nokia裁员之事不知道完没完?这艾洛普挺能作啊."我吃着香喷喷的过桥米线说." ...

  10. driver: Linux设备模型之input子系统具体解释

    本节从总体上解说了输入子系统的框架结构.有助于读者从总体上认识linux的输入子系统.在陷入代码分析的过程中,通过本节的知识可以找准方向,明确原理. 本节重点: 输入子系统的框架结构 各层相应内核中的 ...