• Libuv源码解析 - uv_loop整个初始化模块


    Libuv源码解析 - uv_loop整个初始化模块

    loop_default_loop

    static uv_loop_t  default_loop_struct;
    static uv_loop_t* default_loop_ptr;
    
    
    //维护一个全局的uv_loop_t结构,使用uv_loop_init进行初始化
    //这个函数不是线程安全的
    uv_loop_t* uv_default_loop(void) {
      if (default_loop_ptr != NULL)
        return default_loop_ptr;
    
      //对uv_loop_t结构体的各个字段进行初始化
      if (uv_loop_init(&default_loop_struct))
        return NULL;
    
      default_loop_ptr = &default_loop_struct;
      return default_loop_ptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    uv_loop_init

    int uv_loop_init(uv_loop_t* loop) {
      uv__loop_internal_fields_t* lfields;
      struct heap* timer_heap;
      int err;
      
      /* Initialize libuv itself first */
      //初始化libuv本身,包括(系统级环境配置):
      //Windows API动态加载、Windows socket环境、文件系统、信号量、控制台相关环境、
      //检测系统性能计数器的频率、系统级生命周期注册等
      uv__once_init();
    
      /* Create an I/O completion port */
      //创建一个I/O完成端口,此时没有跟套接字关联
      loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
      if (loop->iocp == NULL)
        return uv_translate_sys_error(GetLastError());
    
      lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
      if (lfields == NULL)
        return UV_ENOMEM;
      loop->internal_fields = lfields;
    
      err = uv_mutex_init(&lfields->loop_metrics.lock);  //初始化一个互斥量
      if (err)
        goto fail_metrics_mutex_init;
    
      /* To prevent uninitialized memory access, loop->time must be initialized
       * to zero before calling uv_update_time for the first time.
       */
      //为了防止未初始化的内存访问,在第一次调用uv_update_time之前,必须将loop->time 初始化为0
      loop->time = 0;
      uv_update_time(loop);
    
      QUEUE_INIT(&loop->wq);            //初始化wq双向环形队列,线程池的线程处理完任务后把对应的结构体插入到wq队列中
      QUEUE_INIT(&loop->handle_queue);  //初始化handle双向环形队列
      loop->active_reqs.count = 0;      //初始化request个数,主要用于文件操作
      loop->active_handles = 0;         //活跃的handles个数
    
      loop->pending_reqs_tail = NULL;   //初始化pending阶段环形队列队尾
    
      loop->endgame_handles = NULL;     //初始化closing阶段单向队列队头
    
      loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));  //初始化定时器小顶堆结构
      if (timer_heap == NULL) {
        err = UV_ENOMEM;
        goto fail_timers_alloc;
      }
    
      heap_init(timer_heap);            //初始化小顶堆
    
      loop->check_handles = NULL;       //初始化双向check句柄队列
      loop->prepare_handles = NULL;     //初始化双向prepare句柄队列
      loop->idle_handles = NULL;        //初始化双向idle句柄队列
    
      loop->next_prepare_handle = NULL;  //同上
      loop->next_check_handle = NULL;
      loop->next_idle_handle = NULL;
    
      memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); //初始化轮询句柄数组
    
      loop->active_tcp_streams = 0;     //初始化tcp流计数器
      loop->active_udp_streams = 0;     //初始化udp流计数器
    
      loop->timer_counter = 0;          //初始化定时器累加ID计数
      loop->stop_flag = 0;              //事件循环标记位初始化
    
      err = uv_mutex_init(&loop->wq_mutex); //初始化互斥量,控制wq队列的互斥访问
      if (err)
        goto fail_mutex_init;
    
      //与其他句柄初始化不同,它会立即启动句柄
      err = uv_async_init(loop, &loop->wq_async, uv__work_done); //初始化通信量,用于线程池和主线程通信
      if (err)
        goto fail_async_init;
      
      //清除handle flag的UV_HANDLE_REF状态,将loop的活跃句柄个数减一
      uv__handle_unref(&loop->wq_async);
      loop->wq_async.flags |= UV_HANDLE_INTERNAL; //添加UV_HANDLE_INTERNAL状态
    
      //记录所有实例化的loop,放入一个指针数据中(本质是一个二级指针)
      err = uv__loops_add(loop);
      if (err)
        goto fail_async_init;
    
      return 0;
    
    fail_async_init:
      uv_mutex_destroy(&loop->wq_mutex);
    
    fail_mutex_init:
      uv__free(timer_heap);
      loop->timer_heap = NULL;
    
    fail_timers_alloc:
      uv_mutex_destroy(&lfields->loop_metrics.lock);
    
    fail_metrics_mutex_init:
      uv__free(lfields);
      loop->internal_fields = NULL;
      CloseHandle(loop->iocp);
      loop->iocp = INVALID_HANDLE_VALUE;
    
      return err;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    uv__once_init

    void uv__once_init(void) {
      //uv_init:参数化系统级的环境配置
      uv_once(&uv_init_guard_, uv_init);
    }
    
    • 1
    • 2
    • 3
    • 4

    uv_once

    void uv_once(uv_once_t* guard, void (*callback)(void)) {
      /* Fast case - avoid WaitForSingleObject. */   //避免线程处于等待状态
      if (guard->ran) {
        return;
      }         
    
      uv__once_inner(guard, callback);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    uv__once_inner

    static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
      DWORD result;
      HANDLE existing_event, created_event;
    
      //函数将创建一个手动重置事件对象,该对象需要使用 ResetEvent 函数将事件状态设置为非对齐状态
      created_event = CreateEvent(NULL, 1, 0, NULL); //创建或打开命名或未命名的事件对象
      //函数调用成功,则返回事件对象的句柄,
      //如果在函数调用之前存在命名事件对象,该函数将返回现有对象的句柄
      if (created_event == 0) {
        /* Could fail in a low-memory situation? */     //在内存不足的情况下可能失败?
        uv_fatal_error(GetLastError(), "CreateEvent");
      }
    
      //比较两个值(参数1和参数3) 如果参数1和参数3相等,那么就把参数2赋予参数1,
      //返回值为参数1未调用方法之前的值,该方法为原子操作,如果参数1和参数3不相等,那么
      //参数1是不会进行修改的
      existing_event = InterlockedCompareExchangePointer(&guard->event,
                                                         created_event,
                                                         NULL);
    
      //表示参数1在进入InterlockedCompareExchangePointer方法之前就是空的,所以我们赢了
      if (existing_event == NULL) {
        /* We won the race */
        callback();                         //初始化系统级的环境
    
        result = SetEvent(created_event);   //将指定的事件对象设置为有信号状态(有标记)
                                            //由于是手动重置事件,所以该事件会一直保持
                                            //有标记状态,直至调用ResetEvent才结束。
                                            //在libuv中,该event永远有标记不会被重置
        assert(result);
        guard->ran = 1;                     //该标记位只初始化一次,即该方法只会调用一次,
                                            //永远不会被重置
    
      } else {
        /* We lost the race. Destroy the event we created and wait for the existing
         * one to become signaled. */
        //我们输了,销毁我们创建的事件,等待现有事件发出信号
        CloseHandle(created_event);
        //等待事件对象处于无信号状态或者超时间隔已过,即此处可能有多个线程处于等待状态
        result = WaitForSingleObject(existing_event, INFINITE);
        assert(result == WAIT_OBJECT_0);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    uv_init

    static void uv_init(void) {
      /* Tell Windows that we will handle critical errors. */   
      //告诉Windows我们将处理关键错误
      //SEM_FAILCRITICALERRORS:系统不显示严重错误处理程序消息框。相反,系统会将错误发送到调用进程。
                              //为了防止错误模式对话框挂起应用程序。
      //SEM_NOGPFAULTERRORBOX: 系统不显示Windows 错误报告对话框。
      //SEM_NOOPENFILEERRORBOX:OpenFile 函数在找不到文件时不显示消息框。相反,错误将返回到调用方。
      SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
                   SEM_NOOPENFILEERRORBOX);
    
      /* Tell the CRT to not exit the application when an invalid parameter is
       * passed. The main issue is that invalid FDs will trigger this behavior.
       */
      //告诉CRT在传递无效参数时不要退出应用程序,主要是无效的FDs将触发此行为
      //CRT:Microsoft开发的C/C++ Runtime Library
    #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
      _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
    #endif
    
      /* We also need to setup our debug report handler because some CRT
       * functions (eg _get_osfhandle) raise an assert when called with invalid
       * FDs even though they return the proper error code in the release build.
       */
      //我们还需要设置调试报告处理程序,因为一些CRT函数(如_get_osfhandle)在使用无效
      //FDs调用时会引发断言,即使它们在发布版本中返回正确的错误代码
    #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
      _CrtSetReportHook(uv__crt_dbg_report_handler);
    #endif
    
      /* Initialize tracking of all uv loops */
      //初始化一个互斥变量,用于解决同步互斥问题
      uv__loops_init();
    
      /* Fetch winapi function pointers. This must be done first because other
       * initialization code might need these function pointers to be loaded.
       */
      //获取WindowsAPI,赋值我们自定义的函数指针,这个过程必须一开始就初始化完毕,因为其他初始化
      //代码可能需要加载这些函数指针。实际上就是通过dll动态链接库加载相应的模块
      uv_winapi_init();
    
      /* Initialize winsock */
      //加载Windows socket环境
      uv_winsock_init();
    
      /* Initialize FS */
      //FS:file system
      uv_fs_init();
    
      /* Initialize signal stuff */
      //初始化信号量
      uv_signals_init();
    
      /* Initialize console */
      //初始化控制台相关
      uv_console_init();
    
      /* Initialize utilities */
      //检测系统性能计数器的频率
      uv__util_init();
    
      /* Initialize system wakeup detection */
      //初始化系统唤醒检测(主机开机关机生命周期)
      uv__init_detect_system_wakeup();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    uv__loops_init

    static void uv__loops_init(void) {
      //初始化一个互斥变量,该对象不能保证哪个线程能获取到临界资源对象,该系统能公平的对待每一个线程
      uv_mutex_init(&uv__loops_lock); 
    }
    
    • 1
    • 2
    • 3
    • 4

    uv_winsock_init

    void uv_winsock_init(void) {
      WSADATA wsa_data;
      int errorno;
      SOCKET dummy;
      WSAPROTOCOL_INFOW protocol_info;
      int opt_len;
    
      /* Set implicit binding address used by connectEx */
      //让uv_addr_ip4_any_结构与"0.0.0.0"绑定,即监听主机的所有IP地址
      //即作为客户端连接隐式绑定的地址
      if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
        abort();
      }
    
      //同上
      if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
        abort();
      }
    
      /* Skip initialization in safe mode without network support */
      //GetSystemMetrics:通过设置不同的标识符就可以知道系统的不同信息
      //SM_CLEANBOOT:    返回系统的启动方式,0表示正常启动,1表示安全模式启动,2表示网络安全模式启动(连接带宽网络)
      if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
    
      /* Initialize winsock */
      //启动Windows Socket网络dll库
      errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
      if (errorno != 0) {
        uv_fatal_error(errorno, "WSAStartup");
      }
    
      /* Try to detect non-IFS LSPs */
      //尝试检测non-IFS LSPs,LSP分两种:一种是IFS LSPs(制作简单,可以完成大部分数据包监听工作)
      //一种是non-IFS LSPs(制作复杂,可以支持Windows 重叠IO,即overlapped I/O)
      uv_tcp_non_ifs_lsp_ipv4 = 1;
      //创建一个套接字,AF_INET表示为ipv4族,SOCK_STREAM表示采用Tcp协议(流式协议),
      //IPPROTO_IP表示可能的协议类型为TCP协议
      dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
      //创建成功
      if (dummy != INVALID_SOCKET) {
        opt_len = (int) sizeof protocol_info;
        if (getsockopt(dummy,
                       SOL_SOCKET,
                       SO_PROTOCOL_INFOW,
                       (char*) &protocol_info,
                       &opt_len) == 0) {
          //成功设置uv_tcp_non_ifs_lsp_ipv4标记位
          if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
            uv_tcp_non_ifs_lsp_ipv4 = 0;
        }
        closesocket(dummy);
      }
    
      /* Try to detect IPV6 support and non-IFS LSPs */
      uv_tcp_non_ifs_lsp_ipv6 = 1;
      dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
      //创建成功,同上
      if (dummy != INVALID_SOCKET) {
        opt_len = (int) sizeof protocol_info;
        if (getsockopt(dummy,
                       SOL_SOCKET,
                       SO_PROTOCOL_INFOW,
                       (char*) &protocol_info,
                       &opt_len) == 0) {
          if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
            uv_tcp_non_ifs_lsp_ipv6 = 0;
        }
        closesocket(dummy);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    uv_fs_init

    void uv_fs_init(void) {
      SYSTEM_INFO system_info;     //用于接收系统消息,包括处理器的体系结构和类型、系统中的处理器数、页面大小和其他此类信息。
    
      GetSystemInfo(&system_info); //获取系统的有关信息
      uv__allocation_granularity = system_info.dwAllocationGranularity; //可在其中分配虚拟内存的起始地址的粒度
    
      uv__fd_hash_init();         //初始化fd哈希结构
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    uv__fd_hash_init

    INLINE static void uv__fd_hash_init(void) {
      size_t i;
      int err;
    
      err = uv_mutex_init(&uv__fd_hash_mutex);  //初始化互斥锁
      if (err) {
        uv_fatal_error(err, "uv_mutex_init");
      }
    
      for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) {
        uv__fd_hash[i].size = 0;
        //分配静态全局区的空间给256个data,256 * 16 = 4096
        uv__fd_hash[i].data =
            uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE; 
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    uv_signals_init

    void uv_signals_init(void) {
      //初始化一个互斥变量,该对象不能保证哪个线程能获取到临界资源对象,该系统能公平的对待每一个线程
      InitializeCriticalSection(&uv__signal_lock);
      //向系统添加或移除回调方法,利用它可以设置钩子函数,当控制台窗口发生事件时,时间首先发送给钩子函数,可以在钩子函数中对事件进行处理。
      if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
        abort();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    uv_console_init

    void uv_console_init(void) {
      if (uv_sem_init(&uv_tty_output_lock, 1))  //初始化一个新的信号量
        abort();
      //创建打开文件或I/O设备的文件句柄。
      uv__tty_console_handle = CreateFileW(L"CONOUT$",
                                           GENERIC_READ | GENERIC_WRITE,
                                           FILE_SHARE_WRITE,
                                           0,
                                           OPEN_EXISTING,
                                           0,
                                           0);
      //创建成功
      if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
        CONSOLE_SCREEN_BUFFER_INFO sb_info;
        //在线程池中建立多个用户工作项目,它具备同步等机制,
        //第一个参数表示用户定义的异步调用事件,用于在线程池中执行
        //第二个参数表示要传递的参数,NULL表示不给我们的回调事件传递参数
        //第三个参数表示回调函数可以执行长时间等待。 此标志可帮助系统确定它是否应创建新线程。
        QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
                          NULL,
                          WT_EXECUTELONGFUNCTION);
        //参数化一个互斥量
        uv_mutex_init(&uv__tty_console_resize_mutex);
    
        //检索指定控制台屏幕缓冲区的信息
        if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
          uv__tty_console_width = sb_info.dwSize.X;
          uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    uv__util_init

    /*
     * One-time initialization code for functionality defined in util.c.
     */
    void uv__util_init(void) {
      LARGE_INTEGER perf_frequency;
    
      /* Initialize process title access mutex. */
      InitializeCriticalSection(&process_title_lock);   //创建一个互斥量
    
      /* Retrieve high-resolution timer frequency
       * and precompute its reciprocal.
       */
      //检索性能计数器的频率。性能计数器的频率在系统启动时固定,在所有处理器中保持一致。
      //因此,只需在应用程序初始化时查询频率,并且可以缓存结果。
      //CPU上也有一个计数器,以机器人的clock为单位,可以通过rdtsc读取,
      //而不用中断,因此其精度与系统时间相当。
      //精度:计算机获取硬件支持,精度比较高,可以通过它来判断其它时间函数的精度范围。
      if (QueryPerformanceFrequency(&perf_frequency)) {
        hrtime_frequency_ = perf_frequency.QuadPart;
      } else {
        uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    uv__register_system_resume_callback

    static void uv__register_system_resume_callback(void) {
      _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
      _HPOWERNOTIFY registration_handle;
    
      if (pPowerRegisterSuspendResumeNotification == NULL)
        return;
    
      recipient.Callback = uv__system_resume_callback;
      recipient.Context = NULL;
      //注册事件,在系统暂停或恢复时接收通知
      (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
                                                 &recipient,
                                                 &registration_handle);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    Docker学习(4)—— 容器数据卷
    autopoi-web 导出 excel 自定义样式
    《王家视频教程图书馆》
    金仓数据库 KingbaseES V8 GIS数据迁移方案(4. 基于SuperMap平台的数据迁移到KES)
    从零开始深入了解MySQL的Buffer Pool
    LeetCode C++ 28.实现strStr()
    背景图片属性
    HTML学生作业网页 传统端午节节日 学生节日网页设计作业源码(HTML+CSS+JS)
    基于Java的中缀表达式转后缀表达式设计
    基于STM32的智能GPS定位系统(云平台、小程序)
  • 原文地址:https://blog.csdn.net/qq135595696/article/details/127797225