• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# libuv
2
3## Introduction
4
5[libuv](http://libuv.org/) is a cross-platform library that implements asynchronous I/O based on event loops. It applies to network programming and file system operations. It is one of the core libraries of Node.js and has been widely used by other software projects.
6
7## Supported Capabilities
8
9- Event-driven asynchronous I/O across platforms.
10
11- Support for standard library interfaces.
12
13
14## Available APIs
15
16For details, see [API documentation](http://docs.libuv.org/en/v1.x/api.html).
17
18## Background of Introducing libuv to OpenHarmony
19
20OpenHarmony introduced Node-API of Node.js in its earlier versions to facilitate Node.js developers to extend their JavaScript APIs with OpenHarmony. It also introduced libuv of Node.js to implement event loops.
21
22### Evolution Trend
23
24To address the scheduling issues caused when the application main thread has an event loop that contains **uvloop**, we plan to normalize the event loops in the application model to allow only one task queue in the application main loop with task priorities controlled.
25
26Avoid using the NDK of libuv to perform operations on the application main loop obtained by **napi_get_uv_event_loop** (deprecated in API version 12). This may cause various problems and large amount of workload to address compatibility issues.
27
28If you want to implement interaction with the main thread cyclically, for example, inserting a task, use [APIs provided by Node-API](../../napi/napi-data-types-interfaces.md).
29
30OpenHarmony will continue to provide capabilities of interacting with the main thread and extending JS APIs through Node-API for a long period of time, but shields the event loops used in the implementation layer. Although **napi_get_uv_event_loop** is deprecated in API version 12, the main functional APIs of Node-API will be maintained for a long time and provide the same native behavior of Node-API, so that the developers who are familiar with the node.js extension mechanism can easily expand their code to OpenHarmony.
31
32If you are familiar with libuv and can handle memory management and multithreading problems, you can use libuv to develop your services on OpenHarmony. Unless otherwise required, you do not need to import the libuv library to your application project.
33
34### Current Problems and Solutions
35
36According to the existing mechanism, only one event loop can exist in a thread. To ensure proper running of the main event loop of the system application, the main event loop listens for the FD events in the JS environment and executes `uv_run` only when an FD event is reported. As a result, certain functions that depend on **uvloop** cannot take effect.
37
38Common scenarios and solutions are as follows:
39
40#### Scenario 1: The JS main thread throws an async task to a worker thread for execution, and executes the result returned by the JS code.
41
42**Example (incorrect)**
43
44Call **napi_get_uv_event_loop()** to obtain the system loop, and use libuv NDK APIs to implement related functions.
45
46```cpp
47#include "napi/native_api.h"
48#include "uv.h"
49#define LOG_DOMAIN 0X0202
50#define LOG_TAG "MyTag"
51#include <hilog/log.h>
52#include <thread>
53#include <sys/eventfd.h>
54#include <unistd.h>
55
56static void execute(uv_work_t *work) {
57    OH_LOG_INFO(LOG_APP, "ohos in execute");
58}
59
60static void complete(uv_work_t *work, int status) {
61    OH_LOG_INFO(LOG_APP, "ohos in complete");
62    delete work;
63}
64static napi_value Add(napi_env env, napi_callback_info info)
65{
66    napi_value work_name;
67    uv_loop_s *loop = nullptr;
68    /* Obtain the uv_loop of the application JS main thread. */
69    napi_get_uv_event_loop(env, &loop);
70    uv_work_t *work = new uv_work_t;
71    int ret = uv_queue_work(loop, work, execute, complete);
72    if (ret != 0) {
73        OH_LOG_INFO(LOG_APP, "delete work");
74        delete work;
75    }
76    return 0;
77}
78
79EXTERN_C_START
80static napi_value Init(napi_env env, napi_value exports){
81    napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};
82    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
83    return exports;
84EXTERN_C_END
85
86static napi_module demoModule = {
87    .nm_version = 1,
88    .nm_flags = 0,
89    .nm_filename = nullptr,
90    .nm_register_func = Init,
91    .nm_modname = "entry",
92    .nm_priv = ((void *)0),
93    .reserved = {0},
94};
95
96extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
97    napi_module_register(&demoModule);
98}
99```
100
101**Example (correct)**:
102
103Use **napi_create_async_work** and **napi_queue_async_work** together.
104
105```cpp
106#include "napi/native_api.h"
107#include "uv.h"
108#define LOG_DOMAIN 0X0202
109#define LOG_TAG "MyTag"
110#include <hilog/log.h>
111#include <thread>
112#include <sys/eventfd.h>
113#include <unistd.h>
114uv_loop_t *loop;
115napi_value jsCb;
116int fd = -1;
117
118static napi_value Add(napi_env env, napi_callback_info info)
119{
120    napi_value work_name;
121    napi_async_work work;
122    napi_create_string_utf8(env, "ohos", NAPI_AUTO_LENGTH, &work_name);
123    /* The fourth parameter specifies the work task of the asynchronous thread, and the fifth parameter is the callback of the main thread. */
124    napi_create_async_work(env, nullptr, work_name, [](napi_env env, void* data){
125        OH_LOG_INFO(LOG_APP, "ohos in execute");
126    }, [](napi_env env, napi_status status, void *data){
127        /* The specific implementation is skipped. */
128        OH_LOG_INFO(LOG_APP, "ohos in complete");
129        napi_delete_async_work(env, (napi_async_work)data);
130    }, nullptr, &work);
131    /* Call napi_queue_async_work to trigger an async task. */
132    napi_queue_async_work(env, work);
133    return 0;
134}
135
136EXTERN_C_START
137static napi_value Init(napi_env env, napi_value exports){
138    napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};
139    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
140    return exports;
141EXTERN_C_END
142
143static napi_module demoModule = {
144    .nm_version = 1,
145    .nm_flags = 0,
146    .nm_filename = nullptr,
147    .nm_register_func = Init,
148    .nm_modname = "entry",
149    .nm_priv = ((void *)0),
150    .reserved = {0},
151};
152
153extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
154    napi_module_register(&demoModule);
155}
156```
157
158#### Scenario 2: The API does not work when the native side throws an FD event to the main loop of the application.
159
160The main loop of the application receives only FD events, and executes **uv_run** only after **backend_fd** in **uvloop** is triggered. That means **uv_run** will never be executed if no FD event is triggered when **uv** APIs are called in the main loop of the application. As a result, calling libuv APIs does not take effect.
161
162**Example (incorrect)**
163
164In the following example, calling **uv_poll_start** in OpenHarmony in the same way as in native libuv does not take effect.
165
166```cpp
167#include "napi/native_api.h"
168#include "uv.h"
169#define LOG_DOMAIN 0X0202
170#define LOG_TAG "MyTag"
171#include <hilog/log.h>
172#include <thread>
173#include <sys/eventfd.h>
174#include <unistd.h>
175uv_loop_t *loop;
176napi_value jsCb;
177int fd = -1;
178void poll_handler(uv_poll_t* handle,int status, int events){
179    OH_LOG_INFO(LOG_APP, "ohos poll print");
180}
181static napi_value TestClose(napi_env env, napi_callback_info info){
182    std::thread::id this_id = std::this_thread::get_id();
183    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id);
184    size_t argc = 1;
185    napi_value workBname;
186
187    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBname);
188
189    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
190    // Obtain the event loop.
191    napi_get_uv_event_loop(env, &loop);
192    // Create an eventfd.
193    fd = eventfd(0, 0);
194    OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd);
195    uv_poll_t* poll_handle = new uv_poll_t;
196    // Initialize a poll handle and associate it with eventfd.
197    uv_poll_init(loop, poll_handle, fd);
198    // Start to listen for the poll event.
199    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
200    // Create a new thread and write data to eventfd.
201    std::thread mythread([](){
202        for (int i = 0; i < 8; i++){
203            int value = 10;
204            int ret = eventfd_write(fd, value);
205            if (ret == -1){
206                OH_LOG_INFO(LOG_APP, "write failed!\n");
207                continue;
208            }
209        }
210    });
211    mythread.detach();
212    return 0;
213}
214EXTERN_C_START
215static napi_value Init(napi_env env, napi_value exports){
216    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
217    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
218    return exports;
219}
220EXTERN_C_END
221
222static napi_module demoModule = {
223    .nm_version = 1,
224    .nm_flags = 0,
225    .nm_filename = nullptr,
226    .nm_register_func = Init,
227    .nm_modname = "entry",
228    .nm_priv = ((void *)0),
229    .reserved = {0},
230};
231
232extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
233    napi_module_register(&demoModule);
234}
235```
236
237The process is as follows:
238
2391. Use **napi_get_uv_event_loop** to obtain **uvloop** of the application main thread.
2402. Create an **eventfd** instance.
2413. Initialize **uv_poll_t**, and start the handle for it to take effect. Trigger the callback **poll_handler** when the **eventfd** instance is readable.
2424. Create a thread and write data to **eventfd**.
243
244After the preceding code is executed, data cannot be properly printed for **poll_handler**. This is because the main thread of the application executes **uv_run** based on the FD rather than in UV_RUN_DEFAULT mode. Although **event_handler** listens for **backend_fd** in **uvloop**, the FD is not added to **backend_fd** through **epoll_ctl** when **uv_poll_start** is executed. The **epoll_ctl** function is executed only when **uv__io_poll** in **uv_run** is executed the next time. Therefore, if no **backend_fd** event is triggered in the application process, the libuv APIs may not work as expected.
245
246**Workaround**
247
248In the current system version, avoid using **napi_get_uv_event_loop** directly to obtain **uvloop** of the application main thread to develop service logic. If libuv must be used to implement service functions, after **uv_xxx_start** is called, use **uv_async_send** to trigger the main thread of the application to execute **uv_run**. In this way, **uv_xxx_start** can be properly executed.
249
250Modify the code as follows:
251
252```cpp
253#include "napi/native_api.h"
254#include "uv.h"
255#define LOG_DOMAIN 0x0202
256#define LOG_TAG "MyTag"
257#include <hilog/log.h>
258#include <thread>
259#include <sys/eventfd.h>
260#include <unistd.h>
261uv_loop_t *loop;
262napi_value jsCb;
263int fd = -1;
264void poll_handler(uv_poll_t* handle,int status, int events){
265    OH_LOG_INFO(LOG_APP, "ohos poll print");
266}
267static napi_value TestClose(napi_env env, napi_callback_info info){
268    std::thread::id this_id = std::this_thread::get_id();
269    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id);
270    size_t argc = 1;
271    napi_value workBName;
272
273    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBName);
274
275    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
276
277    napi_get_uv_event_loop(env, &loop);
278
279    fd = eventfd(0, 0);
280    OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd);
281    uv_poll_t* poll_handle = new uv_poll_t;
282    uv_poll_init(loop, poll_handle, fd);
283    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
284
285    // Trigger an FD event to enable the main thread to execute uv_run.
286    uv_async_send(&loop->wq_async);
287
288    std::thread mythread([](){
289        for (int i = 0; i < 8; i++){
290            int value = 10;
291            int ret = eventfd_write(fd, value);
292            if (ret == -1){
293                OH_LOG_INFO(LOG_APP, "write failed!\n");
294                continue;
295            }
296        }
297    });
298    mythread.detach();
299    return 0;
300}
301
302EXTERN_C_START
303static napi_value Init(napi_env env, napi_value exports){
304    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
305    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
306    return exports;
307}
308EXTERN_C_END
309
310static napi_module demoModule = {
311    .nm_version = 1,
312    .nm_flags = 0,
313    .nm_filename = nullptr,
314    .nm_register_func = Init,
315    .nm_modname = "entry",
316    .nm_priv = ((void *)0),
317    .reserved = {0},
318};
319
320extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
321    napi_module_register(&demoModule);
322}
323```
324
325## Using libuv
326
327All the APIs that depend on **uv_run** in the libuv NDK do not work as expected in the application main loop of the current system, and may cause freezing or loss of frames. You are advised not to directly use libuv NDK APIs in the JS main thread. You can use Node-API to implement async task execution and communication with the main thread using thread-safe functions.
328
329### Mappings Between libuv APIs and Node-API APIs
330
331Instead of using libuv APIs, you can use the equivalent Node-API provided by OpenHarmony, which includes async work APIs and thread-safe APIs.
332
333#### Asynchronous Work APIs
334
335libuv provides the **uv_queue_work** API to perform a time-consuming operation in an async thread and return the result to the main thread for processing through a callback.
336
337You can use [napi_async_work](../../napi/use-napi-asynchronous-task.md) APIs of Node-API to implement async operations.
338
339The related APIs are as follows:
340
341```cpp
342// Create a work object that executes logic asynchronously.
343// env: pointer to the current execution environment.
344// async_resource: (optional) resource object used to trace async operations.
345// async_resource_name: (optional) name of the resource object. The value is a string.
346// execute: callback invoked to perform an async operation in another thread.
347// complete: callback to be invoked when the async operation is complete.
348// data: pointer to the customized data to be passed to the execute and complete callbacks.
349// result: pointer to the async work object created.
350napi_status napi_create_async_work(napi_env env,
351                                  napi_value async_resource,
352                                  napi_value async_resource_name,
353                                   napi_async_execute_callback execute,
354                                 napi_async_complete_callback complete,
355                                  void* data,
356                                  napi_async_work* result);
357
358// Add an async work object to the queue so that it can be scheduled for execution.
359// env: pointer to the current execution environment.
360// work: pointer to the async work object to add.
361napi_status napi_queue_async_work(napi_env env, napi_async_work work);
362
363// Delete an async work object.
364// env: pointer to the current execution environment.
365// work: pointer to the async work object to delete.
366napi_status napi_delete_async_work(napi_env env, napi_async_work work);
367```
368
369#### Thread-safe APIs for Cross-Thread Sharing and Invocation
370
371When you want to pass a callback to the application main thread, you can use the libuv **uv_async_t** handle, which is used for inter-thread communication, and the following functions:
372
373- uv_async_init()
374- uv_async_send()
375
376The equivalent Node-API APIs are [napi_threadsafe_function](../../napi/use-napi-thread-safety.md) APIs.
377
378
379
380```cpp
381// Create a thread-safe function.
382// env: pointer to the current execution environment.
383// func: pointer to the JavaScript function to create.
384// resource_name: pointer to the resource name.
385// max_queue_size: maximum size of the queue.
386// initial_thread_count: number of initial threads.
387// callback: callback.
388// result: pointer to the operation result.
389napi_status napi_create_threadsafe_function(napi_env env,
390                                           napi_value func,
391                                           const char* resource_name,
392                                            size_t max_queue_size,
393                                           size_t initial_thread_count,
394                                           void* context,
395                                           napi_threadsafe_function_call_js call_js_func,
396                                           napi_threadsafe_function_finalize finalize,
397                                           napi_threadsafe_function* result);
398
399// Acquire a thread-safe function.
400// function: pointer to the thread-safe function to acquire.
401napi_status napi_acquire_threadsafe_function(napi_threadsafe_function function);
402
403// Call a thread-safe function.
404// function: pointer to the thread-safe function to call.
405// data: pointer to the user data.
406napi_status napi_call_threadsafe_function(napi_threadsafe_function function, void* data);
407
408// Release a thread-safe function.
409// function: pointer to the thread-safe function to release.
410napi_status napi_release_threadsafe_function(napi_threadsafe_function function);
411
412```
413
414If you need to use other libuv APIs to implement service functions, read on to discover basic libuv concepts and common APIs to be used in OpenHarmony, which are helpful to prevent application crashes when using libuv APIs. You can also learn about the APIs that can be used in the application main thread and those cannot.
415
416### Available APIs
417
418|  API Type   |  API   |
419| ---- | ---- |
420|  [Loop](#event-loops-in-libuv)  |  uv_loop_init    |
421| [Loop](#event-loops-in-libuv) |   uv_loop_close   |
422| [Loop](#event-loops-in-libuv) |  uv_default_loop    |
423| [Loop](#event-loops-in-libuv) |   uv_run   |
424| [Loop](#event-loops-in-libuv) |    uv_loop_alive  |
425| [Loop](#event-loops-in-libuv) |  uv_stop    |
426|   [Handle](#handles-and-requests-in-libuv)  |  uv_poll\_\* |
427|   [Handle](#handles-and-requests-in-libuv)  |  uv_timer\_\* |
428|   [Handle](#handles-and-requests-in-libuv)  |  uv_async\_\* |
429|   [Handle](#handles-and-requests-in-libuv)  |   uv_signal\_\*   |
430|   [Handle](#handles-and-requests-in-libuv)  |   uv_fs\_\*  |
431|   [Request](#handles-and-requests-in-libuv)  |  uv_random    |
432|   [Request](#handles-and-requests-in-libuv)  |  uv_getaddrinfo    |
433|   [Request](#handles-and-requests-in-libuv)  |  uv_getnameinfo    |
434|   [Request](#handles-and-requests-in-libuv)  |  uv_queue_work    |
435|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_init    |
436|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_send    |
437|   [Thread pool](#thread-pool)  |  uv_queue_work    |
438
439### Thread-Safe Functions
440
441A large number of async works are involved in libuv. Improper use of libuv APIs may cause multithreading issues. The following lists the common thread-safe and non-thread-safe functions in libuv. If a non-thread-safe function is called in multithreading programming, you need to add a lock or ensure correct execution timing of the code. Otherwise, the application may crash.
442
443Thread-safe functions include the following:
444
445- **uv_async_init()**: initializes an async handle, which is used to wake up the main event loop thread from another thread and trigger a callback.
446- **uv_async_send()**: sends a signal to an async handle. This API can be called in any thread.
447- **uv_thread_create()**: creates a thread and executes the specified function. This API can be called in any thread.
448- **uv_fs\_\*()**: performs file system operations (*\** indicates the specific function name.)
449- **uv_poll\_\*()**: performs operations on polling events (*\** indicates the specific function name.)
450- Lock-related APIs, such as **uv\_mutex\_lock()** and **uv\_mutex\_unlock()**.
451
452> **NOTE**
453>
454> - Even if the function like **uv_xxx_init** is implemented in a thread-safe manner, avoid calling it by multiple threads at the same time. Otherwise, resource contention may occur. The best way is to call the function in an event loop thread.
455> - The callback invoked after **uv_async_send()** is triggered asynchronously. If **uv_async_send()** is called multiple times, libuv ensures that at least one callback is executed. As a result, if **uv_async_send()** is called for the same handle for multiple times, the callback processing may be different from your expectations.
456
457
458
459Non-thread-safe functions include the following:
460
461- **uv\_os\_unsetenv()**: deletes an environment variable.
462- **uv\_os\_setenv()**: sets an environment variable.
463- **uv\_os\_getenv()**: obtains an environment variable.
464- **uv\_os\_environ(**): retrieves all environment variables.
465- **uv\_os\_tmpdir()**: obtains the temporary directory.
466- **uv\_os\_homedir()**: obtains the home directory.
467
468### Event Loops in libuv
469
470As a core concept in libuv, an event loop manages all resources of the entire event loop and runs through the lifecycle of the entire event loop. Generally, the thread where **uv_run** is located is the main thread of the event loop.
471
472#### Event Loop Running Modes
473
474- **UV_RUN_DEFAULT**: runs the event loop until there are no active handles or requests. This is the default mode.
475- **UV_RUN_ONCE**: polls for I/O once. If there is a callback in **pending_queue**, execute the callback and then skip **uv__io_poll**. In this mode, there is an event to occur in the loop by default.
476
477- **UV_RUN_NOWAIT**: polls for I/O once but do not block if there are no pending callbacks. In this mode, **uv__io_poll** is executed once and **pending_queue** is not executed.
478
479#### Common APIs
480
481```cpp
482int uv_loop_init(uv_loop_t* loop);
483```
484
485   Initializes a loop.
486
487```cpp
488int uv_loop_close(uv_loop_t* loop);
489```
490
491  Closes a loop. The operation is successful only after all handles and requests in the loop are closed. Otherwise, **UV_EBUSY** is returned.
492
493```cpp
494uv_loop_t* uv_default_loop(void);
495```
496
497  Creates a process-level loop. In OpenHarmony, libuv loops still exist in the application main loop and other JS worker threads. You are not advised to use this API to create loops and implement service functions. When the loop mechanism normalization is complete, you can use this API to create loops.
498
499```cpp
500int uv_run(uv_loop_t* loop, uv_run_mode mode);
501```
502
503  Runs an event loop. For details about the running mode, see [Event Loop Running Modes](#event-loop-running-modes).
504
505```cpp
506int uv_loop_alive(uv_loop_t loop);
507```
508
509  Checks whether a loop is active.
510
511```cpp
512void uv_stop(uv_loop_t* loop);
513```
514
515  Stops an event loop. The event loop stops only in the next iteration of the loop. If this API is called before an I/O operation, **uv__io_poll** will be skipped instead of being blocked.
516
517> **Tips**
518>
519> Pay special attention to the use of **uv_stop**. Before **uv_stop** is called, ensure that the handles of all threads related to the loop are closed.
520
521The sample code is as follows:
522
523```cpp
524int stop_loop(uv_loop_t* loop)
525{
526    uv_stop(loop);
527    auto const ensure_close = [](uv_handle_t* handle, void*) {
528        if (uv_is_closing(handle)) {
529            return;
530        } else {
531            uv_close(handle, nullptr);
532        }
533    };
534    // Traverse all handles. Call ensure_close to close the active handle.
535    uv_walk(loop, ensure_close, nullptr);
536
537    // Continue to run uv_run until there is no active handle or request in the loop.
538    while(true) {
539        if (uv_run(loop, UV_RUN_DEFAULT) == 0) {
540            break;
541        }
542    }
543
544    // Check the loop status.
545    if (uv_loop_alive(loop) != 0) {
546        return -1;
547    }
548    return 0;
549}
550```
551
552### Handles and Requests in libuv
553
554A handle indicates a persistent object, which is usually mounted to the corresponding **handle_queue** in a loop. If a handle is active, **uv_run** will process the callback in the handle each time.
555
556A request indicates a temporary request. A request triggers only one callback.
557
558The commonly used handles and requests in OpenHarmony include the following:
559
560```cpp
561/* Handle types. */
562typedef struct uv_handle_s uv_handle_t;
563typedef struct uv_timer_s uv_timer_t;
564typedef struct uv_async_s uv_async_t;
565typedef struct uv_signal_s uv_signal_t;
566
567/* Request types. */
568typedef struct uv_req_s uv_req_t;
569typedef struct uv_work_s uv_work_t;
570typedef struct uv_fs_s uv_fs_t;
571```
572
573> **NOTE**
574>
575> In handles, **uv_xxx_t** inherits from **uv_handle_t**. In requests, **uv_work_t** inherits from **uv_req_t**.
576
577It is critical to understand the handles in libuv and manage its lifecycle. Observe the following when using a handle:
578
5791. Perform the handle initialization in the event loop thread.
5802. If the handle needs to be initialized in a worker thread due to service requirements, use an atomic variable to check whether the initialization is complete before the handle is used.
5813. For the handle that is no longer used, call **uv_close** to remove it from the loop.
582
583Note that **uv_close** is used to close a handle asynchronously. Its prototype is as follows:
584
585```cpp
586void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
587```
588
589  **handle**: pointer to the handle to close.
590
591 **close_cb**: function used to process the handle. This function is used to perform operations such as memory management.
592
593After **uv_close** is called, the handle to be closed is added to the **closing_handles** queue in the loop, and waits for the loop thread to run **uv__run_closing_handles**. Finally, the **close_cb** callback is executed in the next iteration of the loop. Therefore, operations such as memory release should be performed in **close_cb**. Improper use of the **close** API that is executed asynchronously may cause multithreading issues. You need to ensure correct timing of **uv_close** and ensure that all the handles are closed before **close_cb** is executed.
594
595> **Tips**
596>
597> The following rule of thumb in the official libuv documentation (http://libuv.org/) needs to be observed:
598>
599> If a handle of type **uv_foo_t** has a **uv_foo_start()** function, then it's active from the moment that function is called. Likewise, **uv_foo_stop()** deactivates the handle again.
600
601For the libuv request that is dynamically requested, release it in the callback of the loop thread. The following uses **uv_work_t** as an example.
602
603```cpp
604uv_work_t* work = new uv_work_t;
605uv_queue_work(loop, work, [](uv_work_t* req) {
606    // Asynchronous operation
607}, [](uv_work_t* req, int status) {
608    // Callback
609    delete req;
610});
611```
612
613### Inter-Thread Communication
614
615So far, you have learn about the basic concepts of libuv. Now let's dive into the inter-thread communication in libuv.
616
617The inter-thread communication of libuv is implemented based on the **uv_async_t** handle. The related APIs are as follows:
618
619```cpp
620int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb)
621```
622
623Initializes a handle.
624
625- **loop**: pointer to the event loop.
626- **handle**: pointer to the handle for inter-thread communication.
627- **async_cb**: callback to be invoked.
628
629  The API returns **0** if the operation is successful; returns an error code if the operation fails.
630
631```cpp
632int uv_async_send(uv_async_t* handle)
633```
634
635  Wakes up the event loop and calls the async handle's callback.
636
637   **handle**: pointer to the handle for inter-thread communication.
638
639  The API returns **0** if the operation is successful; returns an error code if the operation fails.
640
641> **NOTE**
642>
643> **uv_async_t** remains active after **uv_async_init** is called till it is closed by **uv_close**.
644> **uv_async_t** is executed in the sequence defined by **uv_async_init** instead of **uv_async_send**. Therefore, it is necessary to manage the timing according to the initialization sequence.
645
646![](./figures/libuv-inter-thread-communication.png)
647
648
649
650Example:
651
652```cpp
653#include <bits/stdc++.h>
654#include "uv.h"
655
656uv_loop_t* loop = nullptr;
657uv_async_t* async = nullptr;
658void async_handler(uv_async_t* handle)
659{
660    printf("ohos async print\n");
661}
662
663int main()
664{
665    loop = uv_default_loop();
666    async = new uv_async_t;
667    uv_async_init(loop, async, async_handler);
668    std::thread subThread([]() {
669        for (int i = 0; i < 10; i++) {
670            usleep(100);
671            printf("%dth: subThread triggered\n", i);
672            uv_async_send(async);
673        }
674        // Call uv_close to close the async handle and release the memory in the main loop.
675        uv_close((uv_handle_t*)async, [](uv_handle_t* handle) {
676            printf("delete async\n");
677            delete (uv_async_t*)handle;
678        });
679        uv_stop(loop);
680    });
681    subThread.detach();
682    return uv_run(loop, UV_RUN_DEFAULT);
683}
684```
685
686The sample code describes only a simple scenario. The procedure is as follows:
687
6881. Initialize the async handle in the main thread.
6892. Create a worker thread and trigger **uv_async_send** every 100 milliseconds. After **uv_async_send** is called 10 times, call **uv_close** to close the async handle.
6903. Run the event loop on the main thread.
691
692As indicated by the following information, each time **uv_async_send** is called, the main thread executes the callback.
693
694```
6950th:subThread triggered
696ohos async print
6971th:subThread triggered
698ohos async print
6992th:subThread triggered
700ohos async print
7013th:subThread triggered
702ohos async print
7034th:subThread triggered
704ohos async print
7055th:subThread triggered
706ohos async print
7076th:subThread triggered
708ohos async print
7097th:subThread triggered
710ohos async print
7118th:subThread triggered
712ohos async print
7139th:subThread triggered
714delete async
715```
716
717### Thread Pool
718
719The thread pool in libuv uses the member variable **wq_async** in **uv_loop_t** to control the communication between the main thread and worker threads. The core API is as follows:
720
721```cpp
722int uv_queue_work(uv_loop_t* loop,
723                  uv_work_t* req,
724                  uv_work_cb work_cb,
725                  uv_after_work_cb after_work_cb)
726```
727
728Initializes a work request which will run the given **work_cb** in a thread from the thread pool.
729
730**work_cb**: task submitted to the worker thread.
731
732**after_work_cb**: callback to be executed by the loop thread.
733
734> **NOTE**
735>
736> **after work_cb** is called after **work_cb** is complete. It is triggered by an FD event triggered by **uv_async_send(loop->wq_async)** and executed in the next iteration of the loop thread. The **uv_work_t** lifecycle ends only when **after_work_cb** is executed.
737
738The following figure illustrates a simplified workflow of the libuv thread pool. The default pending flag of the handle is 1. The number of worker threads is an example only.
739
740![](./figures/libuv-thread-pool.png)
741
742### Use of libuv in OpenHarmony
743
744Currently, libuv threads are used in the main thread, JS Worker thread, TaskWorker thread in the Taskpool, and IPC thread of OpenHarmony. Except the main thread, which uses **eventhandler** as the main loop, other threads use the **UV_RUN_DEFAULT** mode in libuv as the event main loop of the calling thread to execute tasks. In the main thread, **eventhandler** triggers task execution by an FD event. **eventhandler** listens for **backend_fd** in **uv_loop**. Once an FD event is triggered in the loop, **eventhandler** calls **uv_run** to execute tasks in libuv.
745
746As a result, all the uv APIs that are not triggered by an FD event in the main thread are not responded in a timely manner. The uv APIs on the JS worker threads work as expected.
747
748In addition, in the application main thread, all async tasks are eventually executed through libuv. However, in the current system, [the libuv thread pool has been incorporated to the FFRT](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/%20libuv%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%8E%A5%E5%85%A5FFRT%E6%96%B9%E6%A1%88%E5%88%86%E6%9E%90). Any async task thrown to the libuv thread will be scheduled by the FFRT thread. The callbacks of the application main thread are also inserted into the **eventhandler** queue by **PostTask()**. This means that after the async task in an FFRT thread is complete, the callback of the main thread is not triggered by **uv_async_send**.
749
750The following figure shows the process.
751
752![](./figures/libuv-ffrt.png)
753
754The following types of requests can be processed as expected in the application main loop:
755
756- uv_random_t
757
758  Function prototype:
759
760  ```cpp
761  /**
762  * Add a work request to an event loop queue.
763  *
764  * @param loop indicates the pointer to the event loop.
765  * @param req indicates the pointer to the request.
766  * @param buf indicates the buffer for storing the random number.
767  * @param buflen indicates the length of the buffer.
768  * @param flags indicates the options for generating the random number.
769  * @param cb indicates the callback used to return the random number generated.
770  *
771  * @return Returns 0 if the operation is successful; returns an error code otherwise.
772  */
773  int uv_random(uv_loop_t* loop,
774               uv_random_t* req,
775               void* buf,
776               size_t buflen,
777               unsigned flags,
778               uv_random_cb cb);
779  ```
780
781- uv_work_t
782
783    Function prototype:
784
785    ```cpp
786    /**
787    * Add a work request to an event loop queue.
788    *
789    * work_cb will be called by a new thread in the next iteration of the event loop.
790    * When work_cb is complete, after_work_cb will be called on the event loop thread.
791    *
792    * @param loop indicates the pointer to the event loop.
793    * @param req indicates the pointer to the work request.
794    * @param work_cb indicates the callback to be executed on a new thread.
795    * @param after_work_cb indicates the callback to be invoked on the event loop thread.
796    *
797    * @return Returns 0 if the operation is successful; returns -1 otherwise.
798    */
799    int uv_queue_work(uv_loop_t* loop,
800                      uv_work_t* req,
801                      uv_work_cb work_cb,
802                      uv_after_work_cb after_work_cb);
803    ```
804
805- uv_fs_t
806
807    All async APIs provided by the file class can work as expected in the application main thread. Common APIs include the following:
808
809    ```cpp
810    /**
811    * Read a file asynchronously.
812    *
813    * @param loop indicates the pointer to the event loop.
814    * @param req indicates the pointer to the file operation request.
815    * @param file indicates the file descriptor.
816    * @param bufs indicates an array of buffers for storing the data read.
817    * @param nbufs indicates the number of buffers.
818    * @param off indicates the offset in the file from which data is read.
819    * @param cb indicates the callback to be invoked when the read operation is complete.
820    * @return Returns 0 if the operation is successful; returns -1 otherwise.
821    */
822    int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
823                  uv_file file,
824                  const uv_buf_t bufs[],
825                  unsigned int nbufs,
826                  int64_t off,
827                  uv_fs_cb cb);
828
829    /**
830    * Open a file asynchronously.
831    *
832    * @param loop indicates the pointer to the event loop.
833    * @param req indicates the pointer to the file operation request.
834    *  * @param path indicates the pointer to the path of the file to open.
835    * @param flags indicates the modes for opening the file.
836    *  * @param mode indicates the permission on the file.
837    * @param cb indicates the callback to be invoked when the file is opened.
838    *
839    * @return Returns 0 if the operation is successful; returns -1 otherwise.
840    */
841    int uv_fs_open(uv_loop_t* loop,
842                   uv_fs_t* req,
843                   const char* path,
844                   int flags,
845                   int mode,
846                   uv_fs_cb cb);
847
848    /**
849    * Sends data from a file to another asynchronously.
850    *
851    * @param loop indicates the pointer to the event loop.
852    * @param req indicates the pointer to the file operation request.
853    * @param out_fd indicates the file descriptor of the destination file.
854    * @param in_fd indicates the file descriptor of the source file.
855    * @param off indicates the offset in the source file from which data is sent.
856    * @param len indicates the length of the data to be sent.
857    * @param cb indicates the callback to be invoked when the data is sent.
858    *
859    * @return Returns 0 if the operation is successful; returns -1 otherwise.
860    */
861    int uv_fs_sendfile(uv_loop_t* loop,
862                       uv_fs_t* req,
863                       uv_file out_fd,
864                       uv_file in_fd,
865                       int64_t off,
866                       size_t len,
867                       uv_fs_cb cb);
868
869    /**
870    * Write data to a file asynchronously.
871    *
872    * @param loop indicates the pointer to the event loop.
873    * @param req indicates the pointer to the file operation request.
874    * @param file indicates the file descriptor.
875    * * @param data indicates an array of buffers for storing the data to be written.
876    * @param nbufs indicates the number of buffers.
877    * @param off indicates the offset in the file from which data is written.
878    * @param cb indicates the callback to be invoked when the write operation is complete.
879    *
880    * @return Returns 0 if the operation is successful; returns -1 otherwise.
881    */
882    int uv_fs_write(uv_loop_t* loop,
883                    uv_fs_t* req,
884                    uv_file file,
885                    const uv_buf_t bufs[],
886                    unsigned int nbufs,
887                    int64_t off,
888                    uv_fs_cb cb);
889
890    /**
891    * Copy a file asynchronously.
892    *
893    * @param loop indicates the pointer to the event loop.
894    * @param req indicates the pointer to the file operation request.
895    * @param path indicates the pointer to the path of the file to copy.
896    * @param new_path indicates the pointer to the destination path.
897    * @param flags indicates the options for the copy operation.
898    * @param cb indicates the callback to be invoked when the copy operation is complete.
899    *
900    * @return Returns 0 if the operation is successful; returns -1 otherwise.
901    */
902    int uv_fs_copyfile(uv_loop_t* loop,
903                       uv_fs_t* req,
904                       const char* path,
905                       const char* new_path
906                       int flags,
907                       uv_fs_cb cb);
908    ```
909
910- uv_getaddrinfo_t
911
912     Function prototype:
913
914     ```cpp
915     /**
916     * Obtain address information asynchronously.
917     *
918     * @param loop indicates the pointer to the event loop.
919     * @param req indicates the pointer to the request for obtaining address information.
920     * @param cb indicates the callback to be invoked when the address information is obtained.
921     * @param hostname indicates the pointer to the host name to resolve.
922     * @param service indicates the pointer to the service name.
923     * @param hints indicates the pointer to the address information with additional address type constraints.
924     *
925     * @return Returns 0 if the operation is successful; returns -1 otherwise.
926     */
927     int uv_getaddrinfo(uv_loop_t* loop,
928                        uv_getaddrinfo_t* req,
929                        uv_getaddrinfo_cb cb,
930                        const char* hostname,
931                        const char* service,
932                        const struct addrinfo* hints);
933     ```
934
935- uv_getnameinfo_t
936
937     Function prototype:
938
939     ```cpp
940     /**
941     * Obtain name information asynchronously.
942     *
943     * @param loop indicates the pointer to the event loop.
944     * @param req indicates the pointer to the request.
945     * @param cb indicates the callback to be invoked when the name information is obtained.
946     * @param addr indicates the pointer to the address information to resolve.
947     * @param flags indicates the flags for controlling the behavior of the lookup.
948     *
949     * @return Returns 0 if the operation is successful; returns -1 otherwise.
950     */
951     int uv_getnameinfo(uv_loop_t* loop,
952                        uv_getnameinfo_t* req,
953                        uv_getnameinfo_cb getnameinfo_cb,
954                        const struct sockaddr* addr,
955                        int flags);
956     ```
957
958The following APIs do not work as expected in the application main thread:
959
960- **Idle** handle
961- **prepare** handle
962- **check** handle
963- signal-related functions
964- Functions related to TCP and UDP
965
966## Case Study
967
968[Cause of Incorrect Triggering Time of the Timer Callback in the Main Thread of libuv](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/libuv%E4%B8%AD%E4%B8%BB%E7%BA%BF%E7%A8%8Btimer%E5%9B%9E%E8%B0%83%E4%BA%8B%E4%BB%B6%E8%A7%A6%E5%8F%91%E6%97%B6%E9%97%B4%E4%B8%8D%E6%AD%A3%E7%A1%AE%E5%8E%9F%E5%9B%A0)
969
970[Incorporating libuv Worker Threads to the FFRT](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/%20libuv%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%8E%A5%E5%85%A5FFRT%E6%96%B9%E6%A1%88%E5%88%86%E6%9E%90)
971
972[FAQs for QoS-Aware libuv and Node-API Async API Improvements](https://gitee.com/openharmony/third_party_libuv/wikis/06-Wiki-%E6%8A%80%E6%9C%AF%E8%B5%84%E6%BA%90/QoS%E6%84%9F%E7%9F%A5%E7%9A%84libuv%E3%80%81napi%E5%BC%82%E6%AD%A5%E6%8E%A5%E5%8F%A3%E6%95%B4%E6%94%B9FAQ)
973