When I read the Node HTTP module documentation, I noticed the server.timeout property. I wanted to introduce it briefly, but after sorting it out, I found that there is a huge content supporting timeout: server.timout -> node core timers -> uv timers -> linux msleep/hrtimer -> clocksource -> tsc -> cmos rtc -> clock After the end of the timer series, Noder can roughly understand: How clock cycle drives Linux msleep/hrtimer; The relationship between Linux timers and UV timers; Relationship between Node timers and UV timers.

Nodejs’ timer capability is dependent on Libuv’s capabilities. What capabilities does Libuv’s timer provide? What capabilities does Linux rely on?

The data structure

In Linux, the timer-related data structures include red-black tree for high-precision timer and bucket linked list for low-precision timer. The timer-related data structure in Libuv is the minimum heap. In fact, the timer-related data structure in Nodejs is also the minimum heap and two-way linked list.

The characteristic of the minimum heap is that the time complexity of obtaining the minimum value is O(1), which can quickly obtain the minimum value in the total multiple timer. In Linux, you set minimal cycles to APIC, and all you have to do is wait to be called. How does libuv handle this?

The working principle of

Linux provides a synchronous non-blocking system call function called epoll-epoll(fd, type, timeout) that can continue execution after the specified time expires. The general execution principle of Timer in Libuv is as follows:

const minHeap = new MinHeap(); // Timer(timeout, handler) const timer1 = new Timer(10s, () => {print(' time to ')}); // 10 seconds Timer const timer2 = new Timer(100s, () => {print(' time to ')}); // 100 seconds timer minheap.insert (timer1).insert(timer2); While (minheap.isempty ()) {const minTimer = minheap.peek (); // Get the minimum time in the minimum heap epoll(... , minTimer.timeout); // Synchronize a non-blocking call to mintimer.handler (); // Execute the scheduled task minheap.remove (); // Delete the minimum value} // until the timer minimum heap is empty, exit the executionCopy the code

Each loop fetches the minimum value to wait, then calls the synchronous non-blocking system call function, waits for a timeout to resume execution, and then executes a timed callback to enter the loop again. Libuv provides data structures and business logic, while Linux provides synchronous non-blocking system calls. The most mysterious is the epoll call, but how is it implemented?

Debug the uv

In the process of reading the source code, personally debugging once can get twice the result with half the effort, because I also stepped on a lot of holes in the process of compilation, but also simple record, so temporarily put down the epoll black box, first talk about the debugging process.

Prepare program test.c

#include "stdio.h"
#include "uv.h"

static int timer_cb_called;

static void timer_cb(uv_timer_t* handle) {
  timer_cb_called++;
}

int main() {
  uv_loop_t *loop = uv_default_loop();
  uv_timer_t timer_req1;
  uv_timer_t timer_req2;

  uv_timer_init(loop, &timer_req1);
  uv_timer_init(loop, &timer_req2);
  uv_timer_start(&timer_req1, timer_cb, 1e4, 0);
  uv_timer_start(&timer_req2, timer_cb, 1e6, 0);

  uv_run(loop, UV_RUN_DEFAULT);

Copy the code

Compile libuv

  1. ./configure --prefix= Specify the directory where the library files are installed
  2. make
  3. make install

Personally, I find the first step very important in debugging. Do not use the default directory

Compiling user code

GCC test.c -i./include/ -l Specifies the directory to install the library file -luv -g -o test

Test. c was compiled in libuv

GDB debugging

gdb --args test

The mystery of the epoll

How can epoll be so 🐮? Based on the limited knowledge at present, it should also make use of Linux timer, since its accuracy is ms, so it should make use of low precision timer. Due to the limited scope (see), and wait for the next chapter.

Follow my wechat official account “SUNTOPO WLOG”, welcome to leave a comment and discuss, I will reply as much as possible, thank you for reading.