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;
}

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 初始化为0loop->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;
}

uv__once_init

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

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);
}

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);}
}

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 systemuv_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();
}

uv__loops_init

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

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);}
}

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哈希结构
}

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 = 4096uv__fd_hash[i].data =uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE; }
}

uv_signals_init

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

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;}}
}

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");}
}

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);
}

Libuv源码解析 - uv_loop整个初始化模块相关推荐

  1. 从源码解析 Bert 的 BertPooler 模块

    前文链接: 从源码层面,深入理解 Bert 框架 从源码解析 Bert 的 Embedding 模块 ​从源码解析 Bert 的 BertEncoder 模块 以上文章解析了Bert的BertEmbe ...

  2. Libuv源码解析 - uv_run

    Libuv源码解析 - uv_run uv_run int uv_run(uv_loop_t *loop, uv_run_mode mode) {DWORD timeout;int r;int ran ...

  3. datax源码解析-JobContainer的初始化阶段解析

    datax源码解析-JobContainer的初始化阶段解析 写在前面 此次源码分析的版本是3.0.因为插件是datax重要的组成部分,源码分析过程中会涉及到插件部分的源码,为了保持一致性,插件都已大 ...

  4. linux内核radeon gpu源码解析3 —— Radeon初始化

    解析DRM代码,以从底层介绍显卡驱动的初始化过程,显卡类型是AMD的radeon r600以后的系列显卡.基本的过程就是驱动载入,硬件初始化,设置硬件独立的模块(如内存管理器),设置显示(分辨率等). ...

  5. Mybatis源码解析之Mybatis初始化过程

    一.搭建一个简单的Mybatis工程 为了了解Mybatis的初始化过程,这里需要搭建一个简单的Mybatis工程操作数据库,工程结构如下: 一个UserBean.java private int i ...

  6. BLAM源码解析(一)—— 模块初始化

    接下来写一个开源SLAM算法系列吧,本期介绍BLAM算法.BLAM算法是伯克利的一位大牛写的,首先名字就很有意思,BLAM表示 B(erkeley) L(localization) A(nd) M(a ...

  7. ORB_SLAM2 源码解析 单目初始化器Initializer(三)

    目录 一.地图点初始化 二.重新记录特征点的匹配关系 1.构建旋转直方图 1.1.在半径窗口内搜索当前帧F2中所有的候选匹配特征点GetFeaturesInArea 1.2.表示一个图像像素相当于多少 ...

  8. jQuery 源码解析(三十一) 动画模块 便捷动画详解

    jquery在$.animate()这个接口上又封装了几个API,用于进行匹配元素的便捷动画,如下: $(selector).show(speed,easing,callback)        ;如 ...

  9. webserver接口_SpringBoot内置源码解析WebServer初始化过程

    WebServer 初始化过程 在上一节中 Spring Boot 初始化了 WebServer 对应的工厂类.同时,我们也知道对应 Web容器的WebServer实现类有:TomcatWebServ ...

最新文章

  1. drawboard pdf拆分文件_电脑在线如何分割PDF页面?免费分割3M以内PDF文件页面的简单方法...
  2. python args kwargs_Python中的args和kwargs
  3. PowerShell 备份sharepoint站点命令
  4. Android项目实战(十五):自定义不可滑动的ListView和GridView
  5. Go vs .NET Core 2.1
  6. mysql严格模式 报错_mysql严格模式
  7. 贵阳龙里计算机培训,贵州省龙里中等职业学校机械加工技术专业
  8. 无线遥控器应用在安防防盗中有怎样作用?
  9. docker容器接入canbus
  10. 计算机信息技术奥赛实践,高中信息技术奥赛一本全
  11. python制作日历并保存成excel_Python+Excel制作精美壁纸日历,任意DIY
  12. C/C++学习笔记(2020.11---2021.5)
  13. org.apache.ibatis.binding.BindingException: Type interface com.java.mapper.UserMapper is not known t
  14. android高仿今日头条,高仿今日头条App
  15. tracepro应用实例详解_腾讯云服务器计费模式包年包月、按量计费和竞价实例选择建议...
  16. 美元指数高位盘整 黄金踩下回落“急刹车”
  17. 新浪大赚,阿里吃亏------剖析阿里巴巴入股新浪微博
  18. c语言 Linux CURL发送Http get请求 带参数
  19. 清华大学计算机学院92届韩松,清华大学计算机科学与技术系2020—2021学年度学生科协主席候选人名单公示...
  20. iOS15.2 注册相册变化通知未给相册权限导致崩溃 [PHPhotoLibrary.sharedPhotoLibrary registerChangeObserver:self]

热门文章

  1. 办公室 VR 黄片,骚操作!微软 HoloLens 之父辞职!
  2. LDMIA、LDMIB、LDMDB、LDMDA、STMIA、LDMFD、LDMFA、LDMED、LDMEA等指令详解
  3. PHP fpdi合并多个PDF文件,取多个PDF特定页数合并以及导出
  4. 如何去除 aspose.cells 水印
  5. 中国医科大学2021年9月《护理研究》作业考核试题
  6. 查看oracle执行计划方法( 一)
  7. #芯片# N25Q128A21BSF40F
  8. win7已经阻止此发行者在您的计算机上运行软件,win7系统打开特定网站提示“控件无法安装,windows已阻止此软件因为无法验证发行者”如何解决...
  9. 9年前,字节跳动第一个安卓工程师是这样工作的
  10. 如何在远程工作中保持企业文化的凝聚力