libubox组件(3)——uloop

时间:2023-03-09 16:04:55
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:  }
 
 
三: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: