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[libuv](http://libuv.org/) implements event-driven asynchronous I/O across platforms and supports standard library interfaces.
10
11## Including libuv
12
13To use libuv capabilities, include the following header file:
14
15```c
16#include <uv.h>
17```
18
19Add the following dynamic link library to **CMakeLists.txt**:
20
21```
22libuv.so
23```
24
25## Available APIs
26
27For details, see [API documentation](http://docs.libuv.org/en/v1.x/api.html).
28
29## Background of Introducing libuv to OpenHarmony
30
31OpenHarmony introduced Node-API of Node.js in its earlier versions to facilitate Node.js developers to extend their JavaScript (JS) APIs with OpenHarmony. It also introduced libuv of Node.js to implement event loops.
32
33### Evolution Trend
34
35To 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.
36
37Avoid using the libuv NDK 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 increase the workload required to address compatibility issues.
38
39If you want to implement interaction with the main thread cyclically, for example, insert a task, use [Node-API](../../napi/napi-data-types-interfaces.md).
40
41We will continue to provide capabilities of interacting with the main thread and extend JS APIs through Node-API in the future for a long period of time, but shield the event loops 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 behaviors as native Node-API, so that the developers who are familiar with the node.js extension mechanism can easily use their code with OpenHarmony.
42
43If you are familiar with libuv and can handle memory management and multithreading problems, you can still use libuv to develop your services on OpenHarmony. Unless otherwise required, you do not need to import the libuv library to your application project.
44
45### Current Problems and Solutions
46
47According 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.
48
49Common scenarios and solutions are as follows:
50
51#### Scenario 1: The JS main thread throws an asynchronous task to a worker thread for execution and executes the result returned by the JS code.
52
53**Example (incorrect)**
54
55Call **napi_get_uv_event_loop()** to obtain the system loop, and use libuv NDK APIs to implement related functions.
56
57```cpp
58#include "napi/native_api.h"
59#include "uv.h"
60#define LOG_DOMAIN 0X0202
61#define LOG_TAG "MyTag"
62#include <hilog/log.h>
63#include <thread>
64#include <sys/eventfd.h>
65#include <unistd.h>
66
67static void execute(uv_work_t *work) {
68    OH_LOG_INFO(LOG_APP, "ohos in execute");
69}
70
71static void complete(uv_work_t *work, int status) {
72    OH_LOG_INFO(LOG_APP, "ohos in complete");
73    delete work;
74}
75static napi_value Add(napi_env env, napi_callback_info info)
76{
77    napi_value work_name;
78    uv_loop_s *loop = nullptr;
79    /* Obtain the uv_loop of the application JS main thread. */
80    napi_get_uv_event_loop(env, &loop);
81    uv_work_t *work = new uv_work_t;
82    int ret = uv_queue_work(loop, work, execute, complete);
83    if (ret != 0) {
84        OH_LOG_INFO(LOG_APP, "delete work");
85        delete work;
86    }
87    return 0;
88}
89
90EXTERN_C_START
91static napi_value Init(napi_env env, napi_value exports){
92    napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};
93    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
94    return exports;
95}
96EXTERN_C_END
97
98static napi_module demoModule = {
99    .nm_version = 1,
100    .nm_flags = 0,
101    .nm_filename = nullptr,
102    .nm_register_func = Init,
103    .nm_modname = "entry",
104    .nm_priv = ((void *)0),
105    .reserved = {0},
106};
107
108extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
109    napi_module_register(&demoModule);
110}
111```
112
113**Example (correct)**:
114
115Use **napi_create_async_work** and **napi_queue_async_work** together.
116
117```cpp
118#include "napi/native_api.h"
119#include "uv.h"
120#define LOG_DOMAIN 0X0202
121#define LOG_TAG "MyTag"
122#include <hilog/log.h>
123#include <thread>
124#include <sys/eventfd.h>
125#include <unistd.h>
126uv_loop_t *loop;
127napi_value jsCb;
128int fd = -1;
129
130static napi_value Add(napi_env env, napi_callback_info info)
131{
132    napi_value work_name;
133    napi_async_work work;
134    napi_create_string_utf8(env, "ohos", NAPI_AUTO_LENGTH, &work_name);
135    /* The fourth parameter specifies the work task of the asynchronous thread, and the fifth parameter is the callback of the main thread. */
136    napi_create_async_work(env, nullptr, work_name, [](napi_env env, void* data){
137        OH_LOG_INFO(LOG_APP, "ohos in execute");
138    }, [](napi_env env, napi_status status, void *data){
139        /* The specific implementation is skipped. */
140        OH_LOG_INFO(LOG_APP, "ohos in complete");
141        napi_delete_async_work(env, (napi_async_work)data);
142    }, nullptr, &work);
143    /* Call napi_queue_async_work to trigger an async task. */
144    napi_queue_async_work(env, work);
145    return 0;
146}
147
148EXTERN_C_START
149static napi_value Init(napi_env env, napi_value exports){
150    napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};
151    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
152    return exports;
153}
154EXTERN_C_END
155
156static napi_module demoModule = {
157    .nm_version = 1,
158    .nm_flags = 0,
159    .nm_filename = nullptr,
160    .nm_register_func = Init,
161    .nm_modname = "entry",
162    .nm_priv = ((void *)0),
163    .reserved = {0},
164};
165
166extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
167    napi_module_register(&demoModule);
168}
169```
170
171#### Scenario 2: The libuv API does not work when throwing an FD event to the main loop of the application from the native side.
172
173The 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.
174
175**Example (incorrect)**
176
177In the following example, calling **uv_poll_start** in the same way as in native libuv on HarmonyOS does not take effect.
178
179```cpp
180#include "napi/native_api.h"
181#include "uv.h"
182#define LOG_DOMAIN 0X0202
183#define LOG_TAG "MyTag"
184#include <hilog/log.h>
185#include <thread>
186#include <sys/eventfd.h>
187#include <unistd.h>
188uv_loop_t *loop;
189napi_value jsCb;
190int fd = -1;
191void poll_handler(uv_poll_t* handle,int status, int events){
192    OH_LOG_INFO(LOG_APP, "ohos poll print");
193}
194static napi_value TestClose(napi_env env, napi_callback_info info){
195    std::thread::id this_id = std::this_thread::get_id();
196    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id);
197    size_t argc = 1;
198    napi_value workBname;
199
200    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBname);
201
202    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
203    // Obtain the event loop.
204    napi_get_uv_event_loop(env, &loop);
205    // Create an eventfd.
206    fd = eventfd(0, 0);
207    OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd);
208    uv_poll_t* poll_handle = new uv_poll_t;
209    // Initialize a poll handle and associate it with eventfd.
210    uv_poll_init(loop, poll_handle, fd);
211    // Start to listen for the poll event.
212    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
213    // Create a new thread and write data to eventfd.
214    std::thread mythread([](){
215        for (int i = 0; i < 8; i++){
216            int value = 10;
217            int ret = eventfd_write(fd, value);
218            if (ret == -1){
219                OH_LOG_INFO(LOG_APP, "write failed!\n");
220                continue;
221            }
222        }
223    });
224    mythread.detach();
225    return 0;
226}
227EXTERN_C_START
228static napi_value Init(napi_env env, napi_value exports){
229    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
230    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
231    return exports;
232}
233EXTERN_C_END
234
235static napi_module demoModule = {
236    .nm_version = 1,
237    .nm_flags = 0,
238    .nm_filename = nullptr,
239    .nm_register_func = Init,
240    .nm_modname = "entry",
241    .nm_priv = ((void *)0),
242    .reserved = {0},
243};
244
245extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
246    napi_module_register(&demoModule);
247}
248```
249
250The process is as follows:
251
2521. Call **napi_get_uv_event_loop** to obtain **uvloop** of the application main thread.
2532. Create an **eventfd** instance.
2543. Initialize **uv_poll_t**, and start the handle for it to take effect. Invoke the **poll_handler** callback when the **eventfd** instance is readable.
2554. Create a thread and write data to **eventfd**.
256
257After the preceding code is executed, **poll_handler** has no output. This is because the application main thread executes **uv_run** based on the FD rather than looping 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.
258
259**Workaround**
260
261In the current system version, do not use **napi_get_uv_event_loop** 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.
262
263Modify the code as follows:
264
265```cpp
266#include "napi/native_api.h"
267#include "uv.h"
268#define LOG_DOMAIN 0x0202
269#define LOG_TAG "MyTag"
270#include <hilog/log.h>
271#include <thread>
272#include <sys/eventfd.h>
273#include <unistd.h>
274uv_loop_t *loop;
275napi_value jsCb;
276int fd = -1;
277void poll_handler(uv_poll_t* handle,int status, int events){
278    OH_LOG_INFO(LOG_APP, "ohos poll print");
279}
280static napi_value TestClose(napi_env env, napi_callback_info info){
281    std::thread::id this_id = std::this_thread::get_id();
282    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld\n", this_id);
283    size_t argc = 1;
284    napi_value workBName;
285
286    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBName);
287
288    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
289
290    napi_get_uv_event_loop(env, &loop);
291
292    fd = eventfd(0, 0);
293    OH_LOG_INFO(LOG_APP, "fd is %{public}d\n",fd);
294    uv_poll_t* poll_handle = new uv_poll_t;
295    uv_poll_init(loop, poll_handle, fd);
296    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
297
298    // Trigger an FD event to enable the main thread to execute uv_run.
299    uv_async_send(&loop->wq_async);
300
301    std::thread mythread([](){
302        for (int i = 0; i < 8; i++){
303            int value = 10;
304            int ret = eventfd_write(fd, value);
305            if (ret == -1){
306                OH_LOG_INFO(LOG_APP, "write failed!\n");
307                continue;
308            }
309        }
310    });
311    mythread.detach();
312    return 0;
313}
314
315EXTERN_C_START
316static napi_value Init(napi_env env, napi_value exports){
317    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
318    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
319    return exports;
320}
321EXTERN_C_END
322
323static napi_module demoModule = {
324    .nm_version = 1,
325    .nm_flags = 0,
326    .nm_filename = nullptr,
327    .nm_register_func = Init,
328    .nm_modname = "entry",
329    .nm_priv = ((void *)0),
330    .reserved = {0},
331};
332
333extern "C" __attribute__((constructor)) void RegisterEntryModule(void){
334    napi_module_register(&demoModule);
335}
336```
337
338## Using libuv
339
340In the libuv NDK, all the APIs that depend on **uv_run** 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 use libuv NDK APIs in the JS main thread. You can use Node-API to implement asynchronous task execution and communication with the main thread via thread-safe functions.
341
342### Mappings Between libuv APIs and Node-API APIs
343
344Instead of using libuv APIs, you can use the equivalent Node-API provided by OpenHarmony, which includes asynchronous work APIs and thread-safe APIs.
345
346#### Asynchronous Work APIs
347
348libuv provides the **uv_queue_work** API to perform a time-consuming operation in an asynchronous thread and return the result to the main thread for processing through a callback.
349
350You can use [napi_async_work](../../napi/use-napi-asynchronous-task.md) APIs of Node-API to implement asynchronous operations.
351
352The related Node-API interfaces are as follows:
353
354```cpp
355// Creates a work object that executes logic asynchronously.
356// env: pointer to the current execution environment.
357// async_resource: (optional) resource object used to trace asynchronous operations.
358// async_resource_name: (optional) name of the resource object. The value is a string.
359// execute: callback invoked to perform an asynchronous operation in another thread.
360// complete: callback to be invoked when the asynchronous operation is complete.
361// data: pointer to the customized data to be passed to the execute() and complete() callbacks.
362// result: pointer to the asynchronous work object created.
363napi_status napi_create_async_work(napi_env env,
364                                  napi_value async_resource,
365                                  napi_value async_resource_name,
366                                   napi_async_execute_callback execute,
367                                 napi_async_complete_callback complete,
368                                  void* data,
369                                  napi_async_work* result);
370
371// Adds an asynchronous work object to the queue so that it can be scheduled for execution.
372// env: pointer to the current execution environment.
373// work: pointer to the asynchronous work object to add.
374napi_status napi_queue_async_work(napi_env env, napi_async_work work);
375
376// Deletes an asynchronous work object.
377// env: pointer to the current execution environment.
378// work: pointer to the asynchronous work object to delete.
379napi_status napi_delete_async_work(napi_env env, napi_async_work work);
380```
381
382#### Thread-safe APIs for Cross-Thread Sharing and Invocation
383
384When you want to pass a callback to the application main thread, you can use the libuv **uv_async_t** handle for inter-thread communication, and the following functions:
385
386- uv_async_init()
387- uv_async_send()
388
389The equivalent Node-API interfaces are [napi_threadsafe_function](../../napi/use-napi-thread-safety.md) APIs.
390
391 The related Node-API interfaces are as follows:
392
393```cpp
394// Creates a thread-safe function, which can be called in multiple threads without causing data contention or other thread-safe issues.
395// env: pointer to the Node-API environment. It is used to create and operate JS values.
396// func: pointer to the JavaScript function to create.
397// resource_name: pointer to the resource name, which is used for logging and debugging.
398// max_queue_size: an integer specifying the maximum size of a queue. When the queue is full, new calls will be discarded.
399// initial_thread_count: an integer specifying the number of initial threads. These threads will be started when the function is created.
400// context: pointer to the context, which is passed to call_js_func().
401// call_js_func: pointer to the callback to be invoked when the JS function is called.
402// finalize: Pointer to the finalize() function to be called when the thread-safe function is destroyed.
403// result: pointer to the napi_threadsafe_function struct, which will be constructed as the newly created thread-safe function.
404napi_status napi_create_threadsafe_function(napi_env env,
405                                           napi_value func,
406                                           const char* resource_name,
407                                           size_t max_queue_size,
408                                           size_t initial_thread_count,
409                                           void* context,
410                                           napi_threadsafe_function_call_js call_js_func,
411                                           napi_threadsafe_function_finalize finalize,
412                                           napi_threadsafe_function* result);
413
414// Acquires a thread-safe function.
415// function: pointer to the thread-safe function to acquire.
416napi_status napi_acquire_threadsafe_function(napi_threadsafe_function function);
417
418// Calls a thread-safe function.
419// function: pointer to the thread-safe function to call.
420// data: pointer to the user data.
421napi_status napi_call_threadsafe_function(napi_threadsafe_function function, void* data);
422
423// Releases a thread-safe function.
424// function: pointer to the thread-safe function to release.
425napi_status napi_release_threadsafe_function(napi_threadsafe_function function);
426
427```
428
429If 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.  The following also provides information about the APIs that can be used in the application main thread and those cannot.
430
431### Available APIs
432
433|  API Type   |  API   |
434| ---- | ---- |
435|  [Loop](#event-loops-in-libuv)  |  uv_loop_init    |
436| [Loop](#event-loops-in-libuv) |   uv_loop_close   |
437| [Loop](#event-loops-in-libuv) |  uv_default_loop    |
438| [Loop](#event-loops-in-libuv) |   uv_run   |
439| [Loop](#event-loops-in-libuv) |    uv_loop_alive  |
440| [Loop](#event-loops-in-libuv) |  uv_stop    |
441|   [Handle](#handles-and-requests-in-libuv)  |  uv_poll\_\* |
442|   [Handle](#handles-and-requests-in-libuv)  |  uv_timer\_\* |
443|   [Handle](#handles-and-requests-in-libuv)  |  uv_async\_\* |
444|   [Handle](#handles-and-requests-in-libuv)  |   uv_signal\_\*   |
445|   [Handle](#handles-and-requests-in-libuv)  |   uv_fs\_\*  |
446|   [Request](#handles-and-requests-in-libuv)  |  uv_random    |
447|   [Request](#handles-and-requests-in-libuv)  |  uv_getaddrinfo    |
448|   [Request](#handles-and-requests-in-libuv)  |  uv_getnameinfo    |
449|   [Request](#handles-and-requests-in-libuv)  |  uv_queue_work    |
450|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_init    |
451|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_send    |
452|   [Thread pool](#thread-pool)  |  uv_queue_work    |
453
454### Constraints for libuv Single Thread
455
456When using libuv in OpenHarmony, observe to the following:
457
458The thread for calling **uv_run** must be the loop thread (the thread that initializes the loop using **uv_loop_init**), and all non-thread-safe operations of **uvloop** must be performed on the loop thread. Otherwise, the application may crash.
459
460OpenHarmony imposes stricter restrictions on the use of libuv. For non-thread-safe functions, libuv implements the multi-thread check mechanism, which generates warning logs when detecting multi-threading problems. To ensure the check accuracy and prevent incorrect use of uv interfaces, it is recommended that the same thread be used for creating an event loop and executing **uv_run**.
461
462#### Constraints
463
464The constraints vary depending on the source of the loop. Specifically, you can create a loop or obtain a loop from **env**.
465
466##### Creating a Loop
467
468You can call **uv_loop_new** to create a loop or call **uv_loop_init** to initialize a loop. (You need to manage the lifecycle of the loop.) In this case, ensure that **uv_run** is executed on the loop thread, that is, the thread where the loop is created or initialized. In addition, non-thread-safe operations, such as operations related to the timer and handle, must be performed on the loop thread.
469
470If tasks have to be thrown from other threads to the loop thread, use **uv_async_send**. Specifically, register a callback when the **async** handle is initialized. When **uv_async_send** is called, execute the registered callback on the main thread. <br>Example:
471
472```cpp
473#include <napi/native_api.h>
474#include <uv.h>
475#define LOG_DOMAIN 0x0202
476#define LOG_TAG "MyTag"
477#include "hilog/log.h"
478#include <thread>
479#include <unistd.h>
480uv_async_t* async = new uv_async_t;
481
482// Create a timer.
483void timer_cb(uv_async_t* handle) {
484    auto loop = handle->loop;
485    uv_timer_t* timer = new uv_timer_t;
486    uv_timer_init(loop, timer);
487
488    uv_timer_start(timer, [](uv_timer_t* timer){
489        uv_timer_stop(timer);
490    }, 1000, 0);
491    // Close the async handle at appropriate time.
492    if (cond) {
493        uv_close((uv_handle_t*)handle, [](uv_handle_t* handle){
494            delete (uv_async_t*)handle;
495        })
496    }
497}
498
499// Initialize the async handle and bind the corresponding callback.
500static napi_value TestTimerAsync(napi_env env, napi_callback_info info) {
501    std::thread t ([] () { // Thread A, loop thread
502        uv_loop_t* loop = new uv_lppo_t;
503        // Create a loop and manage the loop lifecycle.
504        uv_loop_init(loop);
505        // Initialize an async handle and register a callback.
506        uv_async_init(loop, async, timer_cb);
507        // Start the loop.
508        uv_run(loop, UV_RUN_DEFAULT);
509        // Close all handles.
510        uv_walk(
511            loop,
512            [](uv_handle_t* handle, void* args) {
513                if (!uv_is_closing(handle)) {
514                    uv_close(hendle, [](uv_handle_t* handle){delete handle;});
515                }
516            },
517            nullptr;
518        );
519        while (uv_run(loop, UV_RUN_DEFAULT) != 0);
520        // Release the loop.
521        uv_loop_delete(loop);
522    })
523    t.detach();
524    return 0;
525}
526
527// Call uv_async_send on another thread.
528static napi_value TestTimerAsyncSend(napi_env env, napi_callback_info info) {
529    std::thread t ([] () { // Thread B
530        uv_async_send (async); // Call uv_async_send to instruct the loop thread to call timer_cb bound to the async handle.
531    });
532    t.detach();
533    return 0;
534}
535
536EXTERN_C_START
537static napi_value Init(napi_env env, napi_value exports) {
538    napi_property_descriptor desc[] = {
539        {"testTimerAsync", nullptr, TestTimerAsync, nullptr, nullptr, nullptr, napi_default, nullptr},
540        {"testTimerAsyncSend", nullptr, TestTimerAsyncSend, nullptr, nullptr, nullptr, napi_default, nullptr},
541    };
542    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
543    return exports;
544}
545EXTERN_C_END
546
547static napi_module demoModule = {
548    .nm_version = 1,
549    .nm_flags = 0,
550    .nm_filename = nullptr,
551    .nm_register_func = Init,
552    .nm_modname = "entry",
553    .nm_priv = ((void *)0),
554    .reserved = {0},
555};
556
557extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
558    napi_module_register(&demoModule);
559}
560```
561
562In this example, a global task queue is used and tasks are submitted to the task queue from a non-loop thread. Then, **uv_async_send** is called at appropriate time to return to the loop thread to execute **async_cb**, which traverses and executes all tasks in the task queue. Note that the task queue operations must be thread-safe. A lock-free queue can be used in C++ implementation, and locks must be added in C implementation.
563
564##### Obtaining a Loop from env
565
566Generally, the loop obtained from **env** using **napi_get_uv_event_loop** is an event loop of a JS thread created by the system. Therefore, avoid calling non-thread-safe functions on its child threads.
567
568If a non-thread-safe function has to be called on a non-loop thread due to service requirements, use the thread-safe function **uv_async_send**. Specifically, define a handle of the **uv_async_t*** type. When initializing the handle, add the non-thread-safe function that needs to be called on a child thread in **async_cb**. Then, call **uv_async_send** in a non-loop thread, and execute **async_cb** on the loop thread. For details, see case 2 in [Correct Example](#correct-example).
569
570### Thread-safe Functions
571
572A large number of asynchronous 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 you call a non-thread-safe function in multi-thread programming, you must add a lock for the function or ensure correct code execution sequence. Otherwise, a crash issue may occur.
573
574Thread-safe functions:
575
576- **uv_async_send()**: sends a signal to an asynchronous handle. This API can be called in any thread.
577- **uv_thread_create()**: creates a thread and executes the specified function. This API can be called in any thread.
578- Lock-related APIs, such as **uv\_mutex\_lock()** and **uv\_mutex\_unlock()**.
579
580>  **NOTE**
581>
582> - Even if the function like **uv_xxx_init** is implemented in a thread-safe manner, avoid calling it on multiple threads at the same time. Otherwise, resource contention may occur. The best way is to call the function in an event loop thread.
583> - After **uv_async_send** is called, the callback is invoked asynchronously. libuv only ensures that at least one callback is executed if **uv_async_send** is called multiple times. As a result, if **uv_async_send** is called multiple times for the same handle, the callback processing in libuv may not align with your expectations. However, the native side can ensure that the number of callback execution times matches the number of times that **napi_call_threadsafe_function** is called.
584
585Non-thread-safe functions:
586
587- **uv\_os\_unsetenv()**: deletes an environment variable.
588- **uv\_os\_setenv()**: sets an environment variable.
589- **uv\_os\_getenv()**: obtains an environment variable.
590- **uv\_os\_environ(**): retrieves all environment variables.
591- **uv\_os\_tmpdir()**: obtains the temporary directory.
592- **uv\_os\_homedir()**: obtains the home directory.
593
594### Event Loops in libuv
595
596As 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.
597
598#### Event Loop Running Modes
599
600- **UV_RUN_DEFAULT**: runs the event loop until there are no active handles or requests. This is the default mode.
601- **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.
602
603- **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.
604
605#### Common APIs
606
607```cpp
608int uv_loop_init(uv_loop_t* loop);
609```
610
611 Initializes a loop.
612
613
614
615```cpp
616int uv_loop_close(uv_loop_t* loop);
617```
618
619Closes a loop. The operation is successful only after all handles and requests in the loop are closed. Otherwise, **UV_EBUSY** is returned.
620
621
622
623```cpp
624int uv_loop_delete(uv_loop_t* loop);
625```
626
627Releases a loop. This API calls **uv_loop_close** to release all internal resources associated with the loop and then releases the loop. In OpenHarmony, the **assert()** function does not take effect. Therefore, the loop is released regardless of whether **uv_loop_close** successfully clears the loop resources. When using this API, ensure that the resources associated with the loop can be successfully released when the loop thread exits. That is, all the handles and requests associated with the loop must be closed. Otherwise, resource leaks occur.
628
629> **NOTE**
630>
631> Exercise caution when using this API. You are advised not to use this API unless necessary.
632
633
634
635```cpp
636uv_loop_t* uv_default_loop(void);
637```
638
639Creates 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.
640
641
642
643```cpp
644int uv_run(uv_loop_t* loop, uv_run_mode mode);
645```
646
647  Runs an event loop. For details about the running mode, see [Event Loop Running Modes](#event-loop-running-modes).
648
649
650
651```cpp
652int uv_loop_alive(uv_loop_t loop);
653```
654
655  Checks whether a loop is active.
656
657
658
659```cpp
660void uv_stop(uv_loop_t* loop);
661```
662
663Stops 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.
664
665> **Tips**
666>
667> 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.
668
669Example:
670
671```cpp
672int stop_loop(uv_loop_t* loop)
673{
674    uv_stop(loop);
675    auto const ensure_close = [](uv_handle_t* handle, void*) {
676        if (uv_is_closing(handle)) {
677            return;
678        } else {
679            uv_close(handle, nullptr);
680        }
681    };
682    // Traverse all handles. Call ensure_close to close the active handle.
683    uv_walk(loop, ensure_close, nullptr);
684
685    // Continue to run uv_run until there is no active handle or request in the loop.
686    while(true) {
687        if (uv_run(loop, UV_RUN_DEFAULT) == 0) {
688            break;
689        }
690    }
691
692    // Check the loop status.
693    if (uv_loop_alive(loop) != 0) {
694        return -1;
695    }
696    return 0;
697}
698```
699
700### Handles and Requests in libuv
701
702A 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.
703
704A request indicates a temporary request. A request triggers only one callback.
705
706The commonly used handles and requests in OpenHarmony include the following:
707
708```cpp
709/* Handle types. */
710typedef struct uv_handle_s uv_handle_t;
711typedef struct uv_timer_s uv_timer_t;
712typedef struct uv_async_s uv_async_t;
713typedef struct uv_signal_s uv_signal_t;
714
715/* Request types. */
716typedef struct uv_req_s uv_req_t;
717typedef struct uv_work_s uv_work_t;
718typedef struct uv_fs_s uv_fs_t;
719```
720
721> **NOTE**
722>
723> In handles, **uv_xxx_t** inherits from **uv_handle_t**. In requests, **uv_work_t** inherits from **uv_req_t**.
724
725It is critical to understand the handles in libuv and manage its lifecycle. Observe the following when using a handle:
726
727- Perform the handle initialization in the event loop thread.
728- 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.
729- For the handle that is no longer used, call **uv_close** to remove it from the loop.
730
731Note that **uv_close** is used to close a handle asynchronously. Its prototype is as follows:
732
733```cpp
734void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
735```
736
737  Where:
738
739- **handle**: pointer to the handle to close.
740- **close_cb**: function used to process the handle. This function is used to perform operations such as memory management.
741
742After **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.
743
744> **Tips**<br>The following rule of thumb in the official libuv documentation (http://libuv.org/) needs to be observed.<br>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.
745
746>  **NOTE**
747>
748> - Call **uv_close** before all handles are closed, and all memory operations must be performed in **close_cb** of **uv_close**.
749>
750> - All handle operations cannot be called on non-loop threads by obtaining the loop of other threads.
751
752#### Submitting Asynchronous Tasks
753
754When asynchronous tasks are submitted, the libuv requests that are dynamically acquired must be released in the **complete()** callback executed on the loop thread. The following uses **uv_work_t** as an example.
755
756```cpp
757uv_work_t* work = new uv_work_t;
758uv_queue_work(loop, work, [](uv_work_t* req) {
759    // Asynchronous operation
760}, [](uv_work_t* req, int status) {
761    // Callback
762    delete req;
763});
764```
765
766In special cases, for example, in memory-sensitive cases, the same request can be used repeatedly when:
767
768- The sequence of the same type of tasks is ensured.
769- The request can be successfully released when **uv_queue_work** is called the last time.
770
771```C
772uv_work_t* work = new uv_work_t;
773uv_queue_work(loop, work, [](uv_work_t* work) {
774        // Do something.
775    },
776    [](uv_work_t* work, int status) {
777        // Do something.
778        uv_queue_work(loop, work, [](...) {/* do something*/}, [](...) {
779            // Do something.
780            if (last_task) {  // Release the request after the last task is executed.
781                delete work;
782            }
783        });
784    },
785    )
786```
787
788#### Precautions for Submitting Asynchronous Tasks
789##### uv_queue_work process
790In libuv, **uv_queue_work()** in a UI thread works as follows:
791
7921. Throw **work_cb** to the thread pool of the related priority of Function Flow Runtime (FFRT) and wait for FFRT to schedule and execute the task.
7932. Throw **after_work_cb** to the event queue of **eventhandler**, wait for **eventhandler** to schedule, and return to the loop thread for execution.
794
795> **NOTE**<br>After **uv_queue_work()** is called, it does not mean any task is complete. It only means **work_cb()** is inserted into the thread pool of the related priority of FFRT. The workflow of the taskpool and jsworker threads is the same as that of libuv.
796
797##### Constraints on Using uv_queue_work()
798
799**uv_queue_work()** is only used to throw asynchronous tasks. The **execute()** callback of an asynchronous task added to the thread pool will be scheduled and executed. Therefore, the task execution sequence may be different from the task submission sequence.
800
801**uv_queue_work()** can be called only on the loop thread. This prevents multi-threading issues. Do not use **uv_queue_work()** as a means for inter-thread communication. Specifically, do not use **uv_queue_work** to throw an asynchronous task from thread A to thread B, setting the **execute()** callback to an empty task and executing the **complete()** callback on thread B. This approach is not only inefficient but increases the difficulty in locating faults. To avoid inefficient task submission, use [napi_threadsafe_function](#thread-safe-apis-for-cross-thread-sharing-and-invocation).
802
803#### Using libuv Timers
804
805Observe the following when using the libuv timers:
806
807- Do not use libuv APIs (**uv_timer_start**, **uv_timer_stop**, and **uv_timer_again**) in multiple threads to operate the timer heap of the same loop simultaneously. Otherwise, the application may crash. To use libuv APIs to operate timers, perform the operations on the thread associated with the current **env**'s loop.
808- To throw a timer to a thread, use **uv_async_send**.
809
810##### Incorrect Example
811
812In the following example, operations on the timer heap of the same loop are performed in multiple threads at the same time, which poses a high crash rate.
813
814ArkTS:
815
816```typescript
817import { hilog } from '@kit.PerformanceAnalysisKit';
818import testNapi from 'libentry.so'
819
820function waitforRunner(): number {
821    "use concurrent"
822    hilog.info(0xff, "testTag", "executed");
823    return 0;
824}
825
826@Entry
827@Component
828struct Index {
829  build() {
830    Row() {
831      Column() {
832        Button("TimerTest")
833          .width('40%')
834          .fontSize('14fp')
835          .onClick(() => {
836            let i: number = 20;
837            while (i--) {
838              setTimeout(waitforRunner, 200);
839              testNapi.testTimer();
840          }
841        }).margin(20)
842      }.width('100%')
843    }.height('100%')
844  }
845}
846```
847
848Native C++:
849
850```cpp
851#include <napi/native_api.h>
852#include <uv.h>
853#define LOG_DOMAIN 0x0202
854#define LOG_TAG "MyTag"
855#include "hilog/log.h"
856#include <thread>
857#include <unistd.h>
858
859static napi_value TestTimer(napi_env env, napi_callback_info info) {
860    uv_loop_t* loop = nullptr;
861    uv_timer_t* timer = new uv_timer_t;
862
863    napi_get_uv_event_loop(env, &loop);
864    uv_timer_init(loop, timer);
865    std::thread t1([&loop, &timer](){
866        uv_timer_start(timer, [](uv_timer_t* timer){
867            uv_timer_stop(timer);
868        }, 1000, 0);
869    });
870
871    t1.detach();
872    return 0;
873}
874
875EXTERN_C_START
876static napi_value Init(napi_env env, napi_value exports) {
877    napi_property_descriptor desc[] = {
878        {"testTimer", nullptr, TestTimer, nullptr, nullptr, nullptr, napi_default, nullptr},
879    };
880    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
881    return exports;
882}
883EXTERN_C_END
884
885static napi_module demoModule = {
886    .nm_version = 1,
887    .nm_flags = 0,
888    .nm_filename = nullptr,
889    .nm_register_func = Init,
890    .nm_modname = "entry",
891    .nm_priv = ((void *)0),
892    .reserved = {0},
893};
894
895extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
896    napi_module_register(&demoModule);
897}
898```
899
900Add the following code to **index.d.ts**:
901
902```typescript
903export const testTimer:() => number;
904```
905
906##### Correct Example
907
908**Case 1**: Ensure that timer-related operations are performed on the native main thread. Modify the **TestTimer()** function used in the previous example as follows:
909
910```cpp
911static napi_value TestTimer(napi_env env, napi_callback_info info) {
912    uv_loop_t* loop = nullptr;
913    uv_timer_t* timer = new uv_timer_t;
914
915    napi_get_uv_event_loop(env, &loop);
916    uv_timer_init(loop, timer);
917    uv_timer_start(timer, [](uv_timer_t* timer){
918        uv_timer_stop(timer);
919    }, 1000, 0);
920
921    return 0;
922}
923```
924
925**Case 2**: To throw a timer to a child thread, use the thread-safe function **uv_async_send**.
926
927ArkTS:
928
929```typescript
930import { hilog } from '@kit.PerformanceAnalysisKit';
931import testNapi from 'libentry.so'
932
933function waitforRunner(): number {
934    "use concurrent"
935    hilog.info(0xff, "testTag", "executed");
936    return 0;
937}
938
939@Entry
940@Component
941struct Index {
942  build() {
943    Row() {
944      Column() {
945        Button("TestTimerAsync")
946          .width('40%')
947          .fontSize('14fp')
948          .onClick(() => {
949              testNapi.testTimerAsync (); // Initialize the async handle.
950        }).margin(20)
951
952          Button("TestTimerAsyncSend")
953          .width('40%')
954          .fontSize('14fp')
955          .onClick(() => {
956              testNapi.testTimerAsyncSend (); // The child thread calls uv_async_send to execute timer_cb.
957        }).margin(20)
958      }.width('100%')
959    }.height('100%')
960  }
961}
962```
963
964Native C++:
965
966```c++
967#include <napi/native_api.h>
968#include <uv.h>
969#define LOG_DOMAIN 0x0202
970#define LOG_TAG "MyTag"
971#include "hilog/log.h"
972#include <thread>
973#include <unistd.h>
974uv_async_t* async = new uv_async_t;
975
976// Create a timer.
977void timer_cb(uv_async_t* handle) {
978    auto loop = handle->loop;
979    uv_timer_t* timer = new uv_timer_t;
980    uv_timer_init(loop, timer);
981
982    uv_timer_start(timer, [](uv_timer_t* timer){
983        uv_timer_stop(timer);
984    }, 1000, 0);
985}
986
987// Initialize the async handle and bind the corresponding callback.
988static napi_value TestTimerAsync(napi_env env, napi_callback_info info) {
989    uv_loop_t* loop = nullptr;
990	napi_get_uv_event_loop(env, &loop);
991    uv_async_init(loop, async, timer_cb);
992    return 0;
993}
994
995static napi_value TestTimerAsyncSend(napi_env env, napi_callback_info info) {
996    std::thread t([](){
997        uv_async_send (async); // Call uv_async_send in any child thread to instruct the main thread to call timer_cb associated with async.
998    });
999    t.detach();
1000    return 0;
1001}
1002
1003EXTERN_C_START
1004static napi_value Init(napi_env env, napi_value exports) {
1005    napi_property_descriptor desc[] = {
1006        {"testTimerAsync", nullptr, TestTimerAsync, nullptr, nullptr, nullptr, napi_default, nullptr},
1007        {"testTimerAsyncSend", nullptr, TestTimerAsyncSend, nullptr, nullptr, nullptr, napi_default, nullptr},
1008    };
1009    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
1010    return exports;
1011}
1012EXTERN_C_END
1013
1014static napi_module demoModule = {
1015    .nm_version = 1,
1016    .nm_flags = 0,
1017    .nm_filename = nullptr,
1018    .nm_register_func = Init,
1019    .nm_modname = "entry",
1020    .nm_priv = ((void *)0),
1021    .reserved = {0},
1022};
1023
1024extern "C" __attribute__((constructor)) void RegisterEntryModule(void) {
1025    napi_module_register(&demoModule);
1026}
1027```
1028
1029### Inter-Thread Communication
1030
1031So far, you have learnt about the basic concepts of libuv. Now let's dive into the inter-thread communication in libuv.
1032
1033The inter-thread communication of libuv is implemented based on the **uv_async_t** handle. The related APIs are as follows:
1034
1035```cpp
1036int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb)
1037```
1038
1039**Description**
1040
1041Initializes a handle.
1042
1043**Parameters**
1044
1045- **loop**: pointer to the event loop.
1046-   **handle**: pointer to the handle for inter-thread communication.
1047
1048-   **async_cb**: callback to be invoked.
1049
1050
1051**Return value**
1052
1053This API returns **0** if the operation is successful; returns an error code if the operation fails.
1054
1055
1056
1057```cpp
1058int uv_async_send(uv_async_t* handle)
1059```
1060
1061**Description**
1062
1063Wakes up the event loop and calls the async handle's callback.
1064
1065**Parameters**
1066
1067**handle**: pointer to the handle for inter-thread communication.
1068
1069**Return value**
1070
1071This API returns **0** if the operation is successful; returns an error code if the operation fails.
1072
1073> **NOTE**
1074>
1075> - **uv_async_t** remains active after **uv_async_init** is called till it is closed by **uv_close**.
1076>
1077> - **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.
1078
1079! [](./figures/libuv-inter-thread-communication.png)
1080
1081Example:
1082
1083```cpp
1084#include <bits/stdc++.h>
1085#include "uv.h"
1086
1087uv_loop_t* loop = nullptr;
1088uv_async_t* async = nullptr;
1089int g_counter = 10;
1090void async_handler(uv_async_t* handle)
1091{
1092    printf("ohos async print\n");
1093    if (--g_counter == 0) {
1094        // Call uv_close to close the async handle and release the memory in the main loop.
1095        uv_close((uv_handle_t*)async, [](uv_handle_t* handle) {
1096            printf("delete async\n");
1097            delete (uv_async_t*)handle;
1098        });
1099    }
1100}
1101
1102int main()
1103{
1104    loop = uv_default_loop();
1105    async = new uv_async_t;
1106    uv_async_init(loop, async, async_handler);
1107    std::thread subThread([]() {
1108        for (int i = 0; i < 10; i++) {
1109            usleep (100); // Avoid multiple calls to uv_async_send being executed only once.
1110            printf("%dth: subThread triggered\n", i);
1111            uv_async_send(async);
1112        }
1113    });
1114    subThread.detach();
1115    return uv_run(loop, UV_RUN_DEFAULT);
1116}
1117```
1118
1119The sample code describes only a simple scenario. The procedure is as follows:
1120
11211. Initialize the async handle in the main thread.
11222. 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.
11233. Run the event loop on the main thread.
1124
1125As indicated by the following information, each time **uv_async_send** is called, the main thread executes the callback.
1126
1127```
11280th:subThread triggered
1129ohos async print
11301th:subThread triggered
1131ohos async print
11322th:subThread triggered
1133ohos async print
11343th:subThread triggered
1135ohos async print
11364th:subThread triggered
1137ohos async print
11385th:subThread triggered
1139ohos async print
11406th:subThread triggered
1141ohos async print
11427th:subThread triggered
1143ohos async print
11448th:subThread triggered
1145ohos async print
11469th:subThread triggered
1147ohos async print
1148delete async
1149```
1150
1151### Thread Pool
1152
1153The 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:
1154
1155```cpp
1156int uv_queue_work(uv_loop_t* loop,
1157                  uv_work_t* req,
1158                  uv_work_cb work_cb,
1159                  uv_after_work_cb after_work_cb)
1160```
1161
1162**Description**
1163
1164Initializes a work request which will run the given **work_cb** in a thread from the thread pool.
1165
1166**Parameters**
1167
1168- **work_cb**: task submitted to the worker thread.
1169- **after_work_cb**: callback to be executed by the loop thread.
1170
1171> **NOTE**<br>**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.
1172
1173The 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.
1174
1175! [](./figures/libuv-thread-pool.png)
1176
1177### Use of libuv in OpenHarmony
1178
1179Currently, 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.
1180
1181As 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.
1182
1183In addition, in the application main thread, all asynchronous 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 asynchronous 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 asynchronous task in an FFRT thread is complete, the callback of the main thread is not triggered by **uv_async_send**. The following figure shows the process.
1184
1185![](./figures/libuv-ffrt.png)
1186
1187The following types of requests can be processed as expected in the application main loop:
1188
1189- uv_random_t
1190
1191  Function prototype:
1192
1193```cpp
1194/**
1195* Adds a work request to an event loop queue.
1196*
1197* @param loop indicates the pointer to the event loop.
1198* @param req indicates the pointer to the request.
1199* @param buf indicates the buffer for storing the random number.
1200* @param buflen indicates the length of the buffer.
1201* @param flags Indicates the options for generating a random number. The value is an unsigned integer.
1202* @param cb indicates the callback used to return the random number generated.
1203*
1204* @return Returns 0 if the operation is successful; returns an error code otherwise.
1205*/
1206int uv_random(uv_loop_t* loop,
1207             uv_random_t* req,
1208             void* buf,
1209             size_t buflen,
1210             unsigned flags,
1211             uv_random_cb cb);
1212```
1213
1214- uv_work_t
1215
1216    Function prototype:
1217
1218```cpp
1219/**
1220* Adds a work request to an event loop queue.
1221*
1222* work_cb will be called by a new thread in the next iteration of the event loop.
1223* When work_cb is complete, after_work_cb will be called on the event loop thread.
1224*
1225* @param loop indicates the pointer to the event loop.
1226* @param req indicates the pointer to the work request.
1227* @param work_cb indicates the callback to be executed on a new thread.
1228* @param after_work_cb indicates the callback to be invoked on the event loop thread.
1229*
1230* @return Returns 0 if the operation is successful; returns -1 otherwise.
1231*/
1232int uv_queue_work(uv_loop_t* loop,
1233                  uv_work_t* req,
1234                  uv_work_cb work_cb,
1235                  uv_after_work_cb after_work_cb);
1236```
1237
1238- uv_fs_t
1239
1240    All asynchronous APIs provided by the file class can work as expected in the application main thread. Common APIs include the following:
1241
1242```cpp
1243/**
1244* Reads a file asynchronously.
1245*
1246* @param loop indicates the pointer to the event loop.
1247* @param req indicates the pointer to the file operation request.
1248* @param file indicates the file descriptor.
1249* @param bufs indicates an array of buffers for storing the data read.
1250* @param nbufs indicates the number of buffers.
1251* @param off indicates the offset in the file from which data is read.
1252* @param cb indicates the callback to be invoked when the read operation is complete.
1253* @return Returns 0 if the operation is successful; returns -1 otherwise.
1254*/
1255int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
1256              uv_file file,
1257              const uv_buf_t bufs[],
1258              unsigned int nbufs,
1259              int64_t off,
1260              uv_fs_cb cb);
1261
1262/**
1263* Opens a file asynchronously.
1264*
1265* @param loop indicates the pointer to the event loop.
1266* @param req indicates the pointer to the file operation request.
1267*  * @param path indicates the pointer to the path of the file to open.
1268* @param flags indicates the modes for opening the file.
1269*  * @param mode indicates the permission on the file.
1270* @param cb indicates the callback to be invoked when the file is opened.
1271*
1272* @return Returns 0 if the operation is successful; returns -1 otherwise.
1273*/
1274int uv_fs_open(uv_loop_t* loop,
1275               uv_fs_t* req,
1276               const char* path,
1277               int flags,
1278               int mode,
1279               uv_fs_cb cb);
1280
1281/**
1282* Sends data from a file to another asynchronously.
1283*
1284* @param loop indicates the pointer to the event loop.
1285* @param req indicates the pointer to the file operation request.
1286* @param out_fd indicates the file descriptor of the destination file.
1287* @param in_fd indicates the file descriptor of the source file.
1288* @param off indicates the offset in the source file from which data is sent.
1289* @param len indicates the length of the data to be sent.
1290* @param cb indicates the callback to be invoked when the data is sent.
1291*
1292* @return Returns 0 if the operation is successful; returns -1 otherwise.
1293*/
1294int uv_fs_sendfile(uv_loop_t* loop,
1295                   uv_fs_t* req,
1296                   uv_file out_fd,
1297                   uv_file in_fd,
1298                   int64_t off,
1299                   size_t len,
1300                   uv_fs_cb cb);
1301
1302/**
1303* Writes data to a file asynchronously.
1304*
1305* @param loop indicates the pointer to the event loop.
1306* @param req indicates the pointer to the file operation request.
1307* @param file indicates the file descriptor.
1308* * @param data indicates an array of buffers for storing the data to be written.
1309* @param nbufs indicates the number of buffers.
1310* @param off indicates the offset in the file from which data is written.
1311* @param cb indicates the callback to be invoked when the read operation is complete.
1312*
1313* @return Returns 0 if the operation is successful; returns -1 otherwise.
1314*/
1315int uv_fs_write(uv_loop_t* loop,
1316                uv_fs_t* req,
1317                uv_file file,
1318                const uv_buf_t bufs[],
1319                unsigned int nbufs,
1320                int64_t off,
1321                uv_fs_cb cb);
1322
1323/**
1324* Copies a file asynchronously.
1325*
1326* @param loop indicates the pointer to the event loop.
1327* @param req indicates the pointer to the file operation request.
1328* @param path indicates the pointer to the path of the file to copy.
1329* @param new_path indicates the pointer to the destination path.
1330* @param flags indicates the options for the copy operation.
1331* @param cb indicates the callback to be invoked when the copy operation is complete.
1332*
1333* @return Returns 0 if the operation is successful; returns -1 otherwise.
1334*/
1335int uv_fs_copyfile(uv_loop_t* loop,
1336                   uv_fs_t* req,
1337                   const char* path,
1338                   const char* new_path
1339                   int flags,
1340                   uv_fs_cb cb);
1341```
1342
1343- uv_getaddrinfo_t
1344
1345     Function prototype:
1346
1347```cpp
1348/**
1349* Obtains address information asynchronously.
1350*
1351* @param loop indicates the pointer to the event loop.
1352* @param req indicates the pointer to the request for obtaining address information.
1353* @param cb indicates the callback to be invoked when the address information is obtained.
1354* @param hostname indicates the pointer to the host name to resolve.
1355* @param service indicates the pointer to the service name.
1356* @param hints indicates the pointer to the address information with additional address type constraints.
1357*
1358* @return Returns 0 if the operation is successful; returns -1 otherwise.
1359*/
1360int uv_getaddrinfo(uv_loop_t* loop,
1361                   uv_getaddrinfo_t* req,
1362                   uv_getaddrinfo_cb cb,
1363                   const char* hostname,
1364                   const char* service,
1365                   const struct addrinfo* hints);
1366```
1367
1368- uv_getnameinfo_t
1369
1370     Function prototype:
1371
1372```cpp
1373/**
1374* Obtains name information asynchronously.
1375*
1376* @param loop indicates the pointer to the event loop.
1377* @param req indicates the pointer to the request.
1378* @param cb indicates the callback to be invoked when the name information is obtained.
1379* @param addr indicates the pointer to the address information to resolve.
1380* @param flags indicates the flags for controlling the behavior of the lookup.
1381*
1382* @return Returns 0 if the operation is successful; returns -1 otherwise.
1383*/
1384int uv_getnameinfo(uv_loop_t* loop,
1385                   uv_getnameinfo_t* req,
1386                   uv_getnameinfo_cb getnameinfo_cb,
1387                   const struct sockaddr* addr,
1388                   int flags);
1389```
1390
1391The following APIs do not work as expected in the application main thread:
1392
1393- **Idle** handle
1394- **prepare** handle
1395- **check** handle
1396- signal-related functions
1397- Functions related to TCP and UDP
1398
1399## Case Study
1400
1401[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)
1402
1403[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)
1404
1405[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)
1406