• 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[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
37You are advised not to use libuv NDK on the main loop of the application obtained by calling napi_get_uv_event_loop. Otherwise, various problems may occur, and a large amount of workload will be brought to future compatibility changes.
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. 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.
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 the **uvloop** event 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
57ArkTS side:
58```typescript
59import { hilog } from '@kit.PerformanceAnalysisKit';
60import testNapi from 'libentry.so'
61
62@Entry
63@Component
64struct Index {
65  build() {
66    Row() {
67      Column() {
68        Button("test")
69          .width('40%')
70          .fontSize('14fp')
71          .onClick(() => {
72              testNapi.test();
73        }).margin(20)
74      }.width('100%')
75    }.height('100%')
76  }
77}
78```
79Native side:
80```cpp
81#include "napi/native_api.h"
82#include "uv.h"
83#define LOG_DOMAIN 0X0202
84#define LOG_TAG "MyTag"
85#include <hilog/log.h>
86
87static void execute(uv_work_t* work)
88{
89    OH_LOG_INFO(LOG_APP, "ohos in execute");
90}
91
92static void complete(uv_work_t* work, int status)
93{
94    OH_LOG_INFO(LOG_APP, "ohos in complete");
95    delete work;
96}
97static napi_value Test(napi_env env, napi_callback_info info)
98{
99    uv_loop_s* loop = nullptr;
100    /* Obtain the uv_loop of the application JS main thread. */
101    napi_get_uv_event_loop(env, &loop);
102    uv_work_t* work = new uv_work_t;
103    int ret = uv_queue_work(loop, work, execute, complete);
104    if (ret != 0) {
105        OH_LOG_INFO(LOG_APP, "delete work");
106        delete work;
107    }
108    return 0;
109}
110
111EXTERN_C_START
112static napi_value Init(napi_env env, napi_value exports)
113{
114    napi_property_descriptor desc[] = {{"test", nullptr, Test, nullptr, nullptr, nullptr, napi_default, nullptr}};
115    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
116    return exports;
117}
118EXTERN_C_END
119
120static napi_module demoModule = {
121    .nm_version = 1,
122    .nm_flags = 0,
123    .nm_filename = nullptr,
124    .nm_register_func = Init,
125    .nm_modname = "entry",
126    .nm_priv = ((void *)0),
127    .reserved = {0},
128};
129
130extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
131{
132    napi_module_register(&demoModule);
133}
134```
135
136Add the following code to the **index.d.ts** file:
137```
138export const test:() => number;
139```
140
141**Example (correct)**:
142
143Use **napi_create_async_work** and **napi_queue_async_work** together.
144
145ArkTS side:
146```typescript
147import { hilog } from '@kit.PerformanceAnalysisKit';
148import testNapi from 'libentry.so'
149
150@Entry
151@Component
152struct Index {
153  build() {
154    Row() {
155      Column() {
156        Button("test")
157          .width('40%')
158          .fontSize('14fp')
159          .onClick(() => {
160              testNapi.test();
161        }).margin(20)
162      }.width('100%')
163    }.height('100%')
164  }
165}
166```
167Native side:
168```cpp
169#include "napi/native_api.h"
170#include "uv.h"
171#define LOG_DOMAIN 0X0202
172#define LOG_TAG "MyTag"
173#include <hilog/log.h>
174uv_loop_t* loop = nullptr;
175napi_value jsCb;
176int fd = -1;
177
178static napi_value Test(napi_env env, napi_callback_info info)
179{
180    napi_value work_name;
181    napi_async_work work;
182    napi_create_string_utf8(env, "ohos", NAPI_AUTO_LENGTH, &work_name);
183    /* The fourth parameter specifies the work task of the asynchronous thread, and the fifth parameter is the callback of the main thread. */
184    napi_create_async_work(
185        env, nullptr, work_name, [](napi_env env, void* data){OH_LOG_INFO(LOG_APP, "ohos in execute"); },
186        [](napi_env env, napi_status status, void* data){
187            /* The specific implementation is skipped. */
188            OH_LOG_INFO(LOG_APP, "ohos in complete");
189            napi_delete_async_work(env, (napi_async_work)data);
190        },
191        nullptr, &work);
192    /* Call napi_queue_async_work to trigger an async task. */
193    napi_queue_async_work(env, work);
194    return 0;
195}
196
197EXTERN_C_START
198static napi_value Init(napi_env env, napi_value exports)
199{
200    napi_property_descriptor desc[] = {{"test", nullptr, Test, nullptr, nullptr, nullptr, napi_default, nullptr}};
201    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
202    return exports;
203}
204EXTERN_C_END
205
206static napi_module demoModule = {
207    .nm_version = 1,
208    .nm_flags = 0,
209    .nm_filename = nullptr,
210    .nm_register_func = Init,
211    .nm_modname = "entry",
212    .nm_priv = ((void *)0),
213    .reserved = {0},
214};
215
216extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
217{
218    napi_module_register(&demoModule);
219}
220```
221Add the following code to the **index.d.ts** file:
222```index.d.ts
223export const test:() => number;
224```
225
226#### Scenario 2: The libuv API does not work when throwing an FD event to the main loop of the application from the native side.
227
228The 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.
229
230**Example (incorrect)**
231
232In the following example, calling **uv_poll_start** in the same way as in native libuv on HarmonyOS does not take effect.
233
234ArkTS side:
235```typescript
236import { hilog } from '@kit.PerformanceAnalysisKit';
237import testNapi from 'libentry.so'
238
239@Entry
240@Component
241struct Index {
242  build() {
243    Row() {
244      Column() {
245        Button("testClose")
246          .width('40%')
247          .fontSize('14fp')
248          .onClick(() => {
249              testNapi.testClose();
250        }).margin(20)
251      }.width('100%')
252    }.height('100%')
253  }
254}
255```
256Native side:
257```cpp
258#include "napi/native_api.h"
259#include "uv.h"
260#define LOG_DOMAIN 0X0202
261#define LOG_TAG "MyTag"
262#include <hilog/log.h>
263#include <thread>
264#include <sys/eventfd.h>
265
266uv_loop_t* loop = nullptr;
267napi_value jsCb;
268int fd = -1;
269
270void poll_handler(uv_poll_t* handle,int status, int events)
271{
272    OH_LOG_INFO(LOG_APP, "ohos poll print");
273}
274
275static napi_value TestClose(napi_env env, napi_callback_info info)
276{
277    std::thread::id this_id = std::this_thread::get_id();
278    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld", this_id);
279    size_t argc = 1;
280    napi_value workBname;
281
282    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBname);
283
284    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
285    // Obtain the event loop.
286    napi_get_uv_event_loop(env, &loop);
287    // Create an eventfd.
288    fd = eventfd(0, 0);
289    OH_LOG_INFO(LOG_APP, "fd is %{public}d",fd);
290    uv_poll_t* poll_handle = new uv_poll_t;
291    // Initialize a poll handle and associate it with eventfd.
292    uv_poll_init(loop, poll_handle, fd);
293    // Start to listen for the poll event.
294    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
295    // Create a new thread and write data to eventfd.
296    std::thread mythread([](){
297        for (int i = 0; i < 8; i++){
298            int value = 10;
299            int ret = eventfd_write(fd, value);
300            if (ret == -1){
301                OH_LOG_INFO(LOG_APP, "write failed!");
302                continue;
303            }
304        }
305    });
306    mythread.detach();
307    return 0;
308}
309
310EXTERN_C_START
311static napi_value Init(napi_env env, napi_value exports)
312{
313    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
314    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
315    return exports;
316}
317EXTERN_C_END
318
319static napi_module demoModule = {
320    .nm_version = 1,
321    .nm_flags = 0,
322    .nm_filename = nullptr,
323    .nm_register_func = Init,
324    .nm_modname = "entry",
325    .nm_priv = ((void *)0),
326    .reserved = {0},
327};
328
329extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
330{
331    napi_module_register(&demoModule);
332}
333```
334
335Add the following code to **index.d.ts**:
336
337```
338export const testClose:() => number;
339```
340
341The process is as follows:
342
3431. Call **napi_get_uv_event_loop** to obtain **uvloop** of the application main thread.
3442. Create an **eventfd** instance.
3453. Initialize **uv_poll_t**, and start the handle for it to take effect. Invoke the **poll_handler** callback when the **eventfd** instance is readable.
3464. Create a thread and write data to **eventfd**.
347
348After 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.
349
350**Workaround**
351
352In 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.
353
354Modify the code as follows:
355
356ArkTS side:
357```typescript
358import { hilog } from '@kit.PerformanceAnalysisKit';
359import testNapi from 'libentry.so'
360
361@Entry
362@Component
363struct Index {
364  build() {
365    Row() {
366      Column() {
367        Button("testClose")
368          .width('40%')
369          .fontSize('14fp')
370          .onClick(() => {
371              testNapi.testClose();
372        }).margin(20)
373      }.width('100%')
374    }.height('100%')
375  }
376}
377```
378Native side:
379```cpp
380#include "napi/native_api.h"
381#include "uv.h"
382#define LOG_DOMAIN 0x0202
383#define LOG_TAG "MyTag"
384#include <hilog/log.h>
385#include <thread>
386#include <sys/eventfd.h>
387
388uv_loop_t* loop = nullptr;
389napi_value jsCb;
390int fd = -1;
391
392void poll_handler(uv_poll_t* handle,int status, int events)
393{
394    OH_LOG_INFO(LOG_APP, "ohos poll print");
395}
396
397static napi_value TestClose(napi_env env, napi_callback_info info)
398{
399    std::thread::id this_id = std::this_thread::get_id();
400    OH_LOG_INFO(LOG_APP, "ohos thread id : %{public}ld", this_id);
401    size_t argc = 1;
402    napi_value workBName;
403
404    napi_create_string_utf8(env, "test", NAPI_AUTO_LENGTH, &workBName);
405
406    napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr);
407
408    napi_get_uv_event_loop(env, &loop);
409
410    fd = eventfd(0, 0);
411    OH_LOG_INFO(LOG_APP, "fd is %{public}d",fd);
412    uv_poll_t* poll_handle = new uv_poll_t;
413    uv_poll_init(loop, poll_handle, fd);
414    uv_poll_start(poll_handle, UV_READABLE, poll_handler);
415
416    // Trigger an FD event to enable the main thread to execute uv_run.
417    uv_async_send(&loop->wq_async);
418
419    std::thread mythread([](){
420        for (int i = 0; i < 8; i++){
421            int value = 10;
422            int ret = eventfd_write(fd, value);
423            if (ret == -1){
424                OH_LOG_INFO(LOG_APP, "write failed!");
425                continue;
426            }
427        }
428    });
429    mythread.detach();
430    return 0;
431}
432
433EXTERN_C_START
434static napi_value Init(napi_env env, napi_value exports)
435{
436    napi_property_descriptor desc[] = {{"testClose", nullptr, TestClose, nullptr, nullptr, nullptr, napi_default, nullptr}};
437    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
438    return exports;
439}
440EXTERN_C_END
441
442static napi_module demoModule = {
443    .nm_version = 1,
444    .nm_flags = 0,
445    .nm_filename = nullptr,
446    .nm_register_func = Init,
447    .nm_modname = "entry",
448    .nm_priv = ((void *)0),
449    .reserved = {0},
450};
451
452extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
453{
454    napi_module_register(&demoModule);
455}
456```
457Add the following code to **index.d.ts**:
458
459```
460export const testClose:() => number;
461```
462
463## Using libuv
464
465In 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 directly 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.
466
467### Mappings Between libuv APIs and Node-APIs
468
469Instead of using libuv APIs, you can use the equivalent Node-API provided by OpenHarmony, which includes asynchronous work APIs and thread-safe APIs.
470
471#### Asynchronous Work APIs
472
473libuv 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.
474
475You can use [napi_async_work](../../napi/use-napi-asynchronous-task.md) APIs of Node-API to implement asynchronous operations.
476
477The related Node-API interfaces are as follows:
478
479```cpp
480/**
481* @brief Creates a work object that executes logic asynchronously.
482*
483* @param env Pointer to the current execution environment.
484* @param async_resource (Optional) Resource object used to trace asynchronous operations.
485* @param async_resource_name (Optional) Name of the resource object. The value is a string.
486* @param execute Callback invoked to perform an asynchronous operation in another thread.
487* @param execute Callback to be invoked when the asynchronous operation is complete.
488* @param data Pointer to the customized data to be passed to the execute() and complete() callbacks.
489* @param result Pointer to the asynchronous work object created.
490*/
491napi_status napi_create_async_work(napi_env env,
492                                  napi_value async_resource,
493                                  napi_value async_resource_name,
494                                  napi_async_execute_callback execute,
495                                  napi_async_complete_callback complete,
496                                  void* data,
497                                  napi_async_work* result);
498
499/**
500* @brief Adds an asynchronous work object to the queue so that it can be scheduled for execution.
501*
502* @param env Pointer to the current execution environment.
503* @param work Pointer to the asynchronous work object to add.
504*/
505napi_status napi_queue_async_work(napi_env env, napi_async_work work);
506
507/**
508* @brief Deletes an asynchronous work object.
509*
510* @param env Pointer to the current execution environment.
511* @param work Pointer to the asynchronous work object to delete.
512*/
513napi_status napi_delete_async_work(napi_env env, napi_async_work work);
514```
515
516#### Thread-safe APIs for Cross-Thread Sharing and Invocation
517
518When you want to pass a callback from any child thread to the application main thread for execution, you can use the libuv **uv_async_t** handle for inter-thread communication, and the following functions:
519
520- uv_async_init()
521- uv_async_send()
522
523The equivalent Node-API interfaces are [napi_threadsafe_function](../../napi/use-napi-thread-safety.md) APIs.
524
525 The related Node-API interfaces are as follows:
526
527```cpp
528/**
529* @brief Creates a thread-safe function, which can be called in multiple threads without causing data contention or other thread-safe issues.
530*
531* @param env Pointer to the Node-API environment. It is used to create and operate JS values.
532* @param func Pointer to the JavaScript function to create.
533* @param async_resource Asynchronous resource, which is usually an object that indicates an asynchronous operation.
534* @param async_resource_name Pointer to the resource name, which is used for logging and debugging.
535* @param max_queue_size An integer specifying the maximum size of a queue. When the queue is full, new calls will be discarded.
536* @param initial_thread_count An unsigned integer indicating the initial number of threads when a thread-safe function is created.
537* @param thread_finalize_data Data to be cleared before all threads are created.
538* @param napi_finalize Callback function thread_finalize_cb, which is called when all threads are complete and is used to clear resources
539* @param context Pointer to the context, which is passed to call_js_func().
540* @param call_js_cb Pointer to the callback to be invoked when the JS function is called.
541* @param result Pointer to the napi_threadsafe_function struct, which will be constructed as the thread-safe function created.
542*/
543napi_status napi_create_threadsafe_function(napi_env env,
544                                            napi_value func,
545                                            napi_value async_resource,
546                                            napi_value async_resource_name,
547                                            size_t max_queue_size,
548                                            size_t initial_thread_count,
549                                            void* thread_finalize_data,
550                                            napi_finalize thread_finalize_cb,
551                                            void* context,
552                                            napi_threadsafe_function_call_js call_js_cb,
553                                            napi_threadsafe_function* result);
554
555/**
556* @brief Acquires a thread-safe function.
557*
558* @param function Pointer to the thread-safe function to release.
559*/
560napi_status napi_acquire_threadsafe_function(napi_threadsafe_function function);
561
562/**
563* @brief Calls a thread-safe function.
564* @param function Pointer to the thread-safe function to release.
565* @param data Pointer to the user data.
566* @param is_blocking Enumerated value that determines whether the JavaScript function call is blocking or non-blocking.
567*/
568napi_status napi_call_threadsafe_function(napi_threadsafe_function function,
569                                          void* data,
570                                          napi_threadsafe_function_call_mode is_blocking);
571/**
572* @brief Releases a thread-safe function.
573*
574* @param function Pointer to the thread-safe function to release.
575* @param is_blocking Enumerated value that determines whether the JavaScript function call is blocking or non-blocking.
576*/
577napi_status napi_release_threadsafe_function(napi_threadsafe_function function,
578                                             napi_threadsafe_function_call_mode is_blocking);
579
580```
581
582If 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.
583
584### Available APIs
585
586|  API Type   |  API   |
587| ---- | ---- |
588|   [Loop](#event-loops-in-libuv)  |  uv_loop_init    |
589|   [Loop](#event-loops-in-libuv)  |   uv_loop_close   |
590|   [Loop](#event-loops-in-libuv)  |  uv_default_loop    |
591|   [Loop](#event-loops-in-libuv)  |   uv_run   |
592|   [Loop](#event-loops-in-libuv)  |    uv_loop_alive  |
593|   [Loop](#event-loops-in-libuv)  |  uv_stop    |
594|   [Handle](#handles-and-requests-in-libuv)  |  uv_poll\_\* |
595|   [Handle](#handles-and-requests-in-libuv)  |  uv_timer\_\* |
596|   [Handle](#handles-and-requests-in-libuv)  |  uv_async\_\* |
597|   [Handle](#handles-and-requests-in-libuv)  |   uv_signal\_\*   |
598|   [Handle](#handles-and-requests-in-libuv)  |   uv_fs\_\*  |
599|   [Request](#handles-and-requests-in-libuv)  |  uv_random    |
600|   [Request](#handles-and-requests-in-libuv)  |  uv_getaddrinfo    |
601|   [Request](#handles-and-requests-in-libuv)  |  uv_getnameinfo    |
602|   [Request](#handles-and-requests-in-libuv)  |  uv_queue_work    |
603|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_init    |
604|   [Inter-Thread communication](#inter-thread-communication)  |  uv_async_send    |
605|   [Thread pool](#thread-pool)  |  uv_queue_work    |
606
607### Constraints for libuv Single Thread
608
609When using libuv in OpenHarmony, observe to the following:
610
611The 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.
612
613OpenHarmony 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**.
614
615#### Constraints
616
617The constraints vary depending on the source of the loop. Specifically, you can create a loop or obtain a loop from **env**.
618
619##### Creating a Loop
620
621You 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, must be performed on the loop thread.
622
623If 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, and implement the corresponding operation in the callback. When **uv_async_send** is called, execute the registered callback on the main thread.
624
625ArkTS:
626
627```typescript
628import { hilog } from '@kit.PerformanceAnalysisKit';
629import testNapi from 'libentry.so'
630
631@Entry
632@Component
633struct Index {
634  build() {
635    Row() {
636      Column() {
637        Button("TestTimerAsync")
638          .width('40%')
639          .fontSize('14fp')
640          .onClick(() => {
641              testNapi.testTimerAsync();  // Initialize the async handle.
642        }).margin(20)
643
644          Button("TestTimerAsyncSend")
645          .width('40%')
646          .fontSize('14fp')
647          .onClick(() => {
648              testNapi.testTimerAsyncSend(); // Call uv_async_send from a child thread to submit the timer task.
649        }).margin(20)
650      }.width('100%')
651    }.height('100%')
652  }
653}
654```
655
656Native side:
657
658```cpp
659#include <napi/native_api.h>
660#include <uv.h>
661#define LOG_DOMAIN 0x0202
662#define LOG_TAG "MyTag"
663#include "hilog/log.h"
664#include <thread>
665
666uv_async_t* async = new uv_async_t;
667bool cond1 = false;
668bool cond2 = false;
669
670// Tips: When using a loop, pay special attention to the uv_stop function. Before calling uv_stop,
671// instruct all threads associated with the loop to close their handles. For details, see the implementation of the stop_loop function.
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    // Iterate through all handles. If a handle is active, call ensure_close on it.
683    uv_walk(loop, ensure_close, nullptr);
684    // Continue to run uv_run until there is no active handle or request in the loop.
685    while(true) {
686        if (uv_run(loop, UV_RUN_DEFAULT) == 0) {
687            break;
688        }
689    }
690
691    // Check the loop status.
692    if (uv_loop_alive(loop) != 0) {
693        return -1;
694    }
695    return 0;
696}
697
698// Create a timer.
699void async_cb(uv_async_t* handle) {
700    auto loop = handle->loop;
701    uv_timer_t* timer = new uv_timer_t;
702    uv_timer_init(loop, timer);
703
704    // Close the async handle at appropriate time.
705    if (cond2) {
706        uv_close((uv_handle_t*)handle, [](uv_handle_t* handle){
707            delete (uv_async_t*)handle;
708        });
709        return;
710    }
711
712    uv_timer_start(timer,
713        [](uv_timer_t* timer){
714            // Do something.
715            // Stop the timer at the right time.
716            if (cond1) {
717                uv_timer_stop(timer);
718                uv_close((uv_handle_t*)timer, [](uv_handle_t* handle){
719                    delete(uv_timer_t*)handle;
720                });
721            }
722        },
723        100, 100);
724}
725
726// Initialize the async handle and bind the corresponding callback.
727static napi_value TestTimerAsync(napi_env env, napi_callback_info info) {
728    std::thread t([](){  // Thread A, loop thread
729        uv_loop_t* loop = new uv_loop_t;
730        // Create a loop and manage the loop lifecycle.
731        uv_loop_init(loop);
732        // Initialize an async handle and register a callback.
733        uv_async_init(loop, async, async_cb);
734        // Start the loop.
735        uv_run(loop, UV_RUN_DEFAULT);
736        // Close all handles.
737        stop_loop(loop);
738        // Release the loop.
739        uv_loop_close(loop);
740        delete loop;
741    });
742    t.detach();
743    return 0;
744}
745
746// Call uv_async_send on another thread.
747static napi_value TestTimerAsyncSend(napi_env env, napi_callback_info info)
748{
749    std::thread t1([](){ // Thread B.
750        uv_async_send (async); // Call uv_async_send to instruct the loop thread to call timer_cb bound to the async handle.
751        uv_sleep(500);
752        // Modify cond1 and disable the timer handle.
753        cond1 = true;
754    });
755
756    std::thread t2([](){ // Thread B.
757        uv_sleep(1000);
758        // Modify cond2 and disable the async handle.
759        cond2 = true;
760        uv_async_send(async);
761    });
762
763    t1.detach();
764    t2.detach();
765    return 0;
766}
767
768EXTERN_C_START
769static napi_value Init(napi_env env, napi_value exports)
770{
771    napi_property_descriptor desc[] = {
772        {"testTimerAsync", nullptr, TestTimerAsync, nullptr, nullptr, nullptr, napi_default, nullptr},
773        {"testTimerAsyncSend", nullptr, TestTimerAsyncSend, nullptr, nullptr, nullptr, napi_default, nullptr},
774    };
775    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
776    return exports;
777}
778EXTERN_C_END
779
780static napi_module demoModule = {
781    .nm_version = 1,
782    .nm_flags = 0,
783    .nm_filename = nullptr,
784    .nm_register_func = Init,
785    .nm_modname = "entry",
786    .nm_priv = ((void *)0),
787    .reserved = {0},
788};
789
790extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
791{
792    napi_module_register(&demoModule);
793}
794```
795
796Add the following code to **index.d.ts**:
797
798```
799export const testTimerAsync:() => number;
800export const testTimerAsyncSend:() => number;
801```
802
803##### Obtaining a Loop from env
804
805Generally, the loop obtained from **env** by using **napi_get_uv_event_loop** is an event loop of a JS main thread created by the system. Therefore, avoid calling non-thread-safe functions on its child threads.
806
807If 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** to submit the task to the loop thread. 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).
808
809### Thread-safe Functions
810
811A 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.
812
813Thread-safe functions:
814
815- **uv_async_send()**: sends a signal to an asynchronous handle. This API can be called in any thread.
816- **uv_thread_create()**: creates a thread and executes the specified function. This API can be called in any thread.
817- Lock-related APIs, such as **uv\_mutex\_lock()** and **uv\_mutex\_unlock()**.
818
819>  **NOTE**
820>
821> - 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.
822> - 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.
823
824Non-thread-safe functions:
825
826- **uv\_os\_unsetenv()**: deletes an environment variable.
827- **uv\_os\_setenv()**: sets an environment variable.
828- **uv\_os\_getenv()**: obtains an environment variable.
829- **uv\_os\_environ(**): retrieves all environment variables.
830- **uv\_os\_tmpdir()**: obtains the temporary directory.
831- **uv\_os\_homedir()**: obtains the home directory.
832
833### Event Loops in libuv
834
835As 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.
836
837#### Event Loop Running Modes
838
839- **UV_RUN_DEFAULT**: runs the event loop until there are no active handles or requests. This is the default mode.
840- **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.
841
842- **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.
843
844#### Common APIs
845
846```cpp
847int uv_loop_init(uv_loop_t* loop);
848```
849
850Initializes a loop.
851
852```cpp
853int uv_loop_close(uv_loop_t* loop);
854```
855
856Closes a loop. The operation is successful only after all handles and requests in the loop are closed. Otherwise, **UV_EBUSY** is returned.
857
858```cpp
859int uv_loop_delete(uv_loop_t* loop);
860```
861
862Releases 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.
863
864> **NOTE**
865>
866> Exercise caution when using this API. You are advised not to use this API unless necessary.
867```cpp
868uv_loop_t* uv_default_loop(void);
869```
870
871Creates 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.
872
873```cpp
874int uv_run(uv_loop_t* loop, uv_run_mode mode);
875```
876
877  Runs an event loop. For details about the running mode, see [Event Loop Running Modes](#event-loop-running-modes).
878
879```cpp
880int uv_loop_alive(uv_loop_t loop);
881```
882
883  Checks whether a loop is active.
884
885```cpp
886void uv_stop(uv_loop_t* loop);
887```
888
889Stops 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.
890
891
892### Handles and Requests in libuv
893
894A 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.
895
896A request indicates a temporary request. A request triggers only one callback.
897
898The commonly used handles and requests in OpenHarmony include the following:
899
900```cpp
901/* Handle types. */
902typedef struct uv_handle_s uv_handle_t;
903typedef struct uv_timer_s uv_timer_t;
904typedef struct uv_async_s uv_async_t;
905typedef struct uv_signal_s uv_signal_t;
906
907/* Request types. */
908typedef struct uv_req_s uv_req_t;
909typedef struct uv_work_s uv_work_t;
910typedef struct uv_fs_s uv_fs_t;
911```
912
913> **NOTE**
914>
915> In handles, **uv_xxx_t** inherits from **uv_handle_t**. In requests, **uv_work_t** inherits from **uv_req_t**.
916
917It is critical to understand the handles in libuv and manage its lifecycle. Observe the following when using a handle:
918
919- Perform the handle initialization in the event loop thread.
920- 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.
921- For the handle that is no longer used, call **uv_close** to remove it from the loop.
922
923Note that **uv_close** is used to close a handle asynchronously. Its prototype is as follows:
924
925```cpp
926void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
927```
928
929  Where:
930
931- **handle**: pointer to the handle to close.
932- **close_cb**: function used to process the handle. This function is used to perform operations such as memory management.
933
934After **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.
935
936> **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 is active from the moment that function is called. Likewise, **uv_foo_stop()** deactivates the handle again.
937
938>  **NOTE**
939>
940> - Call **uv_close** before all handles are closed, and all memory operations must be performed in **close_cb** of **uv_close**.
941>
942> - All handle operations cannot be called on non-loop threads by obtaining the loop of other threads.
943
944When 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.
945
946```cpp
947uv_work_t* work = new uv_work_t;
948uv_queue_work(loop, work, [](uv_work_t* req) {
949    // Asynchronous operation
950}, [](uv_work_t* req, int status) {
951    // Callback
952    delete req;
953});
954```
955
956#### Using libuv Timers
957
958Observe the following when using the libuv timers:
959
960- 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.
961- To throw a timer to a thread, use **uv_async_send**.
962
963##### Incorrect Example
964
965In 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.
966
967ArkTS:
968
969```typescript
970import { hilog } from '@kit.PerformanceAnalysisKit';
971import testNapi from 'libentry.so'
972
973function waitforRunner(): number {
974    "use concurrent"
975    hilog.info(0xff, "testTag", "executed");
976    return 0;
977}
978
979@Entry
980@Component
981struct Index {
982  build() {
983    Row() {
984      Column() {
985        Button("TimerTest")
986          .width('40%')
987          .fontSize('14fp')
988          .onClick(() => {
989            let i: number = 20;
990            while (i--) {
991              setTimeout(waitforRunner, 200);
992              testNapi.testTimer();
993          }
994        }).margin(20)
995      }.width('100%')
996    }.height('100%')
997  }
998}
999```
1000
1001Native C++:
1002
1003```cpp
1004#include <napi/native_api.h>
1005#include <uv.h>
1006#define LOG_DOMAIN 0x0202
1007#define LOG_TAG "MyTag"
1008#include "hilog/log.h"
1009#include <thread>
1010#include <unistd.h>
1011
1012static napi_value TestTimer(napi_env env, napi_callback_info info)
1013{
1014    uv_loop_t* loop = nullptr;
1015    uv_timer_t* timer = new uv_timer_t;
1016
1017    napi_get_uv_event_loop(env, &loop);
1018    uv_timer_init(loop, timer);
1019    std::thread t1([&loop, &timer](){
1020        uv_timer_start(timer, [](uv_timer_t* timer){
1021            uv_timer_stop(timer);
1022        }, 1000, 0);
1023    });
1024
1025    t1.detach();
1026    return 0;
1027}
1028
1029EXTERN_C_START
1030static napi_value Init(napi_env env, napi_value exports)
1031{
1032    napi_property_descriptor desc[] = {
1033        {"testTimer", nullptr, TestTimer, nullptr, nullptr, nullptr, napi_default, nullptr},
1034    };
1035    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
1036    return exports;
1037}
1038EXTERN_C_END
1039
1040static napi_module demoModule = {
1041    .nm_version = 1,
1042    .nm_flags = 0,
1043    .nm_filename = nullptr,
1044    .nm_register_func = Init,
1045    .nm_modname = "entry",
1046    .nm_priv = ((void *)0),
1047    .reserved = {0},
1048};
1049
1050extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
1051{
1052    napi_module_register(&demoModule);
1053}
1054```
1055
1056Add the following code to **index.d.ts**:
1057
1058```typescript
1059export const testTimer:() => number;
1060```
1061
1062##### Correct Example
1063
1064**Case 1**: Ensure that timer-related operations are performed on the JS main thread. Modify the **TestTimer()** function used in the previous example as follows:
1065
1066```cpp
1067static napi_value TestTimer(napi_env env, napi_callback_info info)
1068{
1069    uv_loop_t* loop = nullptr;
1070    uv_timer_t* timer = new uv_timer_t;
1071
1072    napi_get_uv_event_loop(env, &loop);
1073    uv_timer_init(loop, timer);
1074    uv_timer_start(timer, [](uv_timer_t* timer){
1075        uv_timer_stop(timer);
1076    }, 1000, 0);
1077
1078    return 0;
1079}
1080```
1081
1082**Case 2**: To throw a timer to a child thread, use the thread-safe function **uv_async_send**.
1083
1084ArkTS:
1085```typescript
1086import { hilog } from '@kit.PerformanceAnalysisKit';
1087import testNapi from 'libentry.so'
1088
1089@Entry
1090@Component
1091struct Index {
1092  build() {
1093    Row() {
1094      Column() {
1095        Button("TestTimerAsync")
1096          .width('40%')
1097          .fontSize('14fp')
1098          .onClick(() => {
1099              testNapi.testTimerAsync();  // Initialize the async handle.
1100        }).margin(20)
1101
1102          Button("TestTimerAsyncSend")
1103          .width('40%')
1104          .fontSize('14fp')
1105          .onClick(() => {
1106              testNapi.testTimerAsyncSend(); // Call uv_async_send from a child thread to submit the timer task.
1107        }).margin(20)
1108      }.width('100%')
1109    }.height('100%')
1110  }
1111}
1112```
1113
1114Native side:
1115
1116```c++
1117#include <napi/native_api.h>
1118#include <uv.h>
1119#define LOG_DOMAIN 0x0202
1120#define LOG_TAG "MyTag"
1121#include "hilog/log.h"
1122#include <thread>
1123#include <unistd.h>
1124uv_async_t* async = new uv_async_t;
1125
1126// Create a timer.
1127void async_cb(uv_async_t* handle)
1128{
1129    auto loop = handle->loop;
1130    uv_timer_t* timer = new uv_timer_t;
1131    uv_timer_init(loop, timer);
1132
1133    uv_timer_start(timer, [](uv_timer_t* timer){
1134        uv_timer_stop(timer);
1135    }, 1000, 0);
1136}
1137
1138// Initialize the async handle and bind the corresponding callback.
1139static napi_value TestTimerAsync(napi_env env, napi_callback_info info)
1140{
1141    uv_loop_t* loop = nullptr;
1142	napi_get_uv_event_loop(env, &loop);
1143    uv_async_init(loop, async, async_cb);
1144    return 0;
1145}
1146
1147static napi_value TestTimerAsyncSend(napi_env env, napi_callback_info info)
1148{
1149    std::thread t([](){
1150        uv_async_send (async); // Call uv_async_send in a child thread to instruct the main thread to call timer_cb associated with async.
1151    });
1152    t.detach();
1153    return 0;
1154}
1155
1156EXTERN_C_START
1157static napi_value Init(napi_env env, napi_value exports)
1158{
1159    napi_property_descriptor desc[] = {
1160        {"testTimerAsync", nullptr, TestTimerAsync, nullptr, nullptr, nullptr, napi_default, nullptr},
1161        {"testTimerAsyncSend", nullptr, TestTimerAsyncSend, nullptr, nullptr, nullptr, napi_default, nullptr},
1162    };
1163    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
1164    return exports;
1165}
1166EXTERN_C_END
1167
1168static napi_module demoModule = {
1169    .nm_version = 1,
1170    .nm_flags = 0,
1171    .nm_filename = nullptr,
1172    .nm_register_func = Init,
1173    .nm_modname = "entry",
1174    .nm_priv = ((void *)0),
1175    .reserved = {0},
1176};
1177
1178extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
1179{
1180    napi_module_register(&demoModule);
1181}
1182```
1183
1184Add the following code to **index.d.ts**:
1185
1186```
1187export const testTimerAsync:() => number;
1188export const testTimerAsyncSend:() => number;
1189```
1190
1191### Inter-Thread Communication
1192
1193So far, you have acquainted yourself with the basic concepts of libuv. Now let's dive into the inter-thread communication in libuv.
1194
1195The inter-thread communication of libuv is implemented based on the **uv_async_t** handle. The related APIs are as follows:
1196
1197```cpp
1198int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb)
1199```
1200
1201  Initializes a handle.<br>**loop**: pointer to the event loop.
1202
1203  **handle**: pointer to the handle for inter-thread communication.
1204
1205  **async_cb**: callback to be invoked.
1206
1207  This API returns **0** if the operation is successful; returns an error code if the operation fails.
1208
1209```cpp
1210int uv_async_send(uv_async_t* handle)
1211```
1212
1213  Wakes up the event loop and calls the async handle's callback.<br>**handle**: pointer to the handle for inter-thread communication.
1214
1215  This API returns **0** if the operation is successful; returns an error code if the operation fails.
1216> **NOTE**
1217>
1218> - **uv_async_t** remains active after **uv_async_init** is called till it is closed by **uv_close**.
1219>
1220> - **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.
1221
1222![Inter-thread communication principle](./figures/libuv-image-1.jpg)
1223
1224Example:
1225
1226```cpp
1227#include <iostream>
1228#include <thread>
1229#include "uv.h"
1230
1231uv_loop_t* loop = nullptr;
1232uv_async_t* async = nullptr;
1233int g_counter = 10;
1234
1235void async_handler(uv_async_t* handle)
1236{
1237    std::cout << "ohos async print" << std::endl;
1238    if (--g_counter == 0) {
1239        // Call uv_close to close the async handle and release the memory in the main loop.
1240        uv_close((uv_handle_t*)async, [](uv_handle_t* handle) {
1241            std::cout << "delete async" << std::endl;
1242            delete (uv_async_t*)handle;
1243        });
1244    }
1245}
1246
1247int main()
1248{
1249    loop = uv_default_loop();
1250    async = new uv_async_t;
1251    uv_async_init(loop, async, async_handler);
1252    std::thread subThread([]() {
1253        for (int i = 0; i < 10; i++) {
1254            usleep (100); // Avoid multiple calls to uv_async_send being executed only once.
1255            std::cout << i << "th: subThread triggered" << std::endl;
1256            uv_async_send(async);
1257        }
1258    });
1259    subThread.detach();
1260    return uv_run(loop, UV_RUN_DEFAULT);
1261}
1262```
1263
1264The sample code describes only a simple scenario. The procedure is as follows:
1265
12661. Initialize the async handle in the main thread.
12672. 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.
12683. Run the event loop on the main thread.
1269
1270As indicated by the following information, each time **uv_async_send** is called, the main thread executes the callback.
1271
1272```
12730th:subThread triggered
1274ohos async print
12751th:subThread triggered
1276ohos async print
12772th:subThread triggered
1278ohos async print
12793th:subThread triggered
1280ohos async print
12814th:subThread triggered
1282ohos async print
12835th:subThread triggered
1284ohos async print
12856th:subThread triggered
1286ohos async print
12877th:subThread triggered
1288ohos async print
12898th:subThread triggered
1290ohos async print
12919th:subThread triggered
1292ohos async print
1293delete async
1294```
1295
1296### Thread Pool
1297
1298The 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:
1299
1300```cpp
1301int uv_queue_work(uv_loop_t* loop,
1302                  uv_work_t* req,
1303                  uv_work_cb work_cb,
1304                  uv_after_work_cb after_work_cb)
1305```
1306
1307Initializes a work request which will run the given **work_cb** in a thread from the thread pool.<br>**work_cb**: task submitted to the worker thread.
1308
1309**after_work_cb**: callback to be executed by the loop thread.
1310
1311**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.
1312
1313#### Submitting Asynchronous Tasks
1314
1315The following figure illustrates a simplified workflow of the native libuv thread pool. The default pending flag of the handle is 1. The number of worker threads is an example only.
1316
1317![Working principle of the libuv thread pool](./figures/libuv-image-3.jpg)
1318
1319#### Precautions for Submitting Asynchronous Tasks
1320##### Workflow of uv_queue_work
1321
1322In OpenHarmony, **uv_queue_work()** in a UI thread works as follows: 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; throw **after_work_cb** to the event queue of **eventhandler** with the corresponding priority, wait for **eventhandler** to schedule, and return to the loop thread for execution. <br>**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 native libuv.
1323
1324In special cases, for example, in memory-sensitive cases, the same request can be used repeatedly when:<br>- The sequence of the same type of tasks is ensured.<br>-The request can be successfully released when **uv_queue_work** is called the last time.
1325
1326```C
1327uv_work_t* work = new uv_work_t;
1328uv_queue_work(loop, work, [](uv_work_t* work) {
1329        // Do something.
1330    },
1331    [](uv_work_t* work, int status) {
1332        // Do something.
1333        uv_queue_work(loop, work, [](...) {/* do something*/}, [](...) {
1334            // Do something.
1335            if (last_task) {  // Release the request after the last task is executed.
1336                delete work;
1337            }
1338        });
1339    },
1340    )
1341```
1342
1343##### Constraints of Using uv_queue_work()
1344
1345**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, it does not guarantee that tasks and their callbacks submitted multiple times will be executed in the order they were submitted.
1346
1347**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 **execute()** 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).
1348
1349### Use of libuv in OpenHarmony
1350
1351Currently, 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.
1352
1353As 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.
1354
1355In 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 async 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.
1356
1357![Usage of the libuv asynchronous thread pool in OpenHarmony](./figures/libuv-ffrt.jpg)
1358
1359The following types of requests can be processed as expected in the application main loop:
1360
1361- uv_random_t
1362
1363  Function prototype:
1364
1365```cpp
1366/**
1367* @brief Adds a work request to an event loop queue.
1368*
1369* @param loop Pointer to the event loop.
1370* @param req Pointer to the request.
1371* @param buf Buffer for storing the random number.
1372* @param buflen Length of the buffer.
1373* @param flags Options for generating a random number. The value is an unsigned integer.
1374* @param cb Callback used to return the random number generated.
1375*
1376* @return Returns 0 if the operation is successful; returns an error code otherwise.
1377*/
1378int uv_random(uv_loop_t* loop,
1379             uv_random_t* req,
1380             void* buf,
1381             size_t buflen,
1382             unsigned flags,
1383             uv_random_cb cb);
1384```
1385
1386- uv_work_t
1387
1388    Function prototype:
1389
1390```cpp
1391/**
1392* @brief Adds a work request to an event loop queue. **work_cb** will be called by a new thread in the next iteration of the event loop. When **work_cb** is complete, **after_work_cb** will be called on the event loop thread.
1393*
1394* @param loop Pointer to the event loop.
1395* @param req Pointer to the work request.
1396* @param work_cb Callback to be executed on a new thread.
1397* @param after_work_cb Callback to be invoked on the event loop thread.
1398*
1399* @return Returns 0 if the operation is successful; returns -1 otherwise.
1400*/
1401int uv_queue_work(uv_loop_t* loop,
1402                  uv_work_t* req,
1403                  uv_work_cb work_cb,
1404                  uv_after_work_cb after_work_cb);
1405```
1406
1407- uv_fs_t
1408
1409    All asynchronous APIs provided by the file class can work as expected in the application main thread. Common APIs include the following:
1410
1411```cpp
1412/**
1413* @brief Reads a file asynchronously.
1414*
1415* @param loop Pointer to the event loop.
1416* @param req Pointer to the file operation request.
1417* @param file File descriptor.
1418* @param bufs An array of buffers for storing the data read.
1419* @param nbufs Number of buffers.
1420* @param off Offset in the file from which data is read.
1421* @param cb Callback to be invoked when the read operation is complete.
1422* @return Returns 0 if the operation is successful; returns -1 otherwise.
1423*/
1424int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
1425              uv_file file,
1426              const uv_buf_t bufs[],
1427              unsigned int nbufs,
1428              int64_t off,
1429              uv_fs_cb cb);
1430
1431/**
1432* @brief Opens a file asynchronously.
1433*
1434* @param loop Pointer to the event loop.
1435* @param req Pointer to the file operation request.
1436* @param path Pointer to the path of the file to open.
1437* @param flags Modes for opening the file.
1438* @param mode Permission on the file.
1439* @param cb Callback to be invoked when the file is opened.
1440*
1441* @return Returns 0 if the operation is successful; returns -1 otherwise.
1442*/
1443int uv_fs_open(uv_loop_t* loop,
1444               uv_fs_t* req,
1445               const char* path,
1446               int flags,
1447               int mode,
1448               uv_fs_cb cb);
1449
1450/**
1451* @brief Sends data from a file to another asynchronously.
1452*
1453* @param loop Pointer to the event loop.
1454* @param req Pointer to the file operation request.
1455* @param out_fd File descriptor of the destination file.
1456* @param in_fd File descriptor of the source file.
1457* @param off Offset in the source file from which data is sent.
1458* @param len Length of the data to be sent.
1459* @param cb Callback to be invoked when the data is sent.
1460*
1461* @return Returns 0 if the operation is successful; returns -1 otherwise.
1462*/
1463int uv_fs_sendfile(uv_loop_t* loop,
1464                   uv_fs_t* req,
1465                   uv_file out_fd,
1466                   uv_file in_fd,
1467                   int64_t off,
1468                   size_t len,
1469                   uv_fs_cb cb);
1470
1471/**
1472* @brief Writes data to a file asynchronously.
1473*
1474* @param loop Pointer to the event loop.
1475* @param req Pointer to the file operation request.
1476* @param file File descriptor.
1477* * @param data An array of buffers for storing the data to be written.
1478* @param nbufs Number of buffers.
1479* @param off Offset in the file from which data is written.
1480* @param cb Callback to be invoked when the read operation is complete.
1481*
1482* @return Returns 0 if the operation is successful; returns -1 otherwise.
1483*/
1484int uv_fs_write(uv_loop_t* loop,
1485                uv_fs_t* req,
1486                uv_file file,
1487                const uv_buf_t bufs[],
1488                unsigned int nbufs,
1489                int64_t off,
1490                uv_fs_cb cb);
1491
1492/**
1493* @brief Copies a file asynchronously.
1494*
1495* @param loop Pointer to the event loop.
1496* @param req Pointer to the file operation request.
1497* @param path Pointer to the path of the file to copy.
1498* @param new_path Pointer to the destination path.
1499* @param flags Options for the copy operation.
1500* @param cb Callback to be invoked when the copy operation is complete.
1501*
1502* @return Returns 0 if the operation is successful; returns -1 otherwise.
1503*/
1504int uv_fs_copyfile(uv_loop_t* loop,
1505                   uv_fs_t* req,
1506                   const char* path,
1507                   const char* new_path
1508                   int flags,
1509                   uv_fs_cb cb);
1510```
1511
1512- uv_getaddrinfo_t
1513
1514     Function prototype:
1515
1516```cpp
1517/**
1518* @brief Obtains address information asynchronously.
1519*
1520* @param loop Pointer to the event loop.
1521* @param req Pointer to the request for obtaining address information.
1522* @param cb Callback to be invoked when the address information is obtained.
1523* @param hostname Pointer to the host name to resolve.
1524* @param service Pointer to the service name.
1525* @param hints Pointer to the address information with additional address type constraints.
1526*
1527* @return Returns 0 if the operation is successful; returns -1 otherwise.
1528*/
1529int uv_getaddrinfo(uv_loop_t* loop,
1530                   uv_getaddrinfo_t* req,
1531                   uv_getaddrinfo_cb cb,
1532                   const char* hostname,
1533                   const char* service,
1534                   const struct addrinfo* hints);
1535```
1536
1537- uv_getnameinfo_t
1538
1539     Function prototype:
1540
1541```cpp
1542/**
1543* @brief Obtains name information asynchronously.
1544*
1545* @param loop Pointer to the event loop.
1546* @param req Pointer to the request.
1547* @param cb Callback to be invoked when the name information is obtained.
1548* @param addr Pointer to the address information to resolve.
1549* @param flags Flags for controlling the behavior of the lookup.
1550*
1551* @return Returns 0 if the operation is successful; returns -1 otherwise.
1552*/
1553int uv_getnameinfo(uv_loop_t* loop,
1554                   uv_getnameinfo_t* req,
1555                   uv_getnameinfo_cb getnameinfo_cb,
1556                   const struct sockaddr* addr,
1557                   int flags);
1558```
1559
1560The following APIs do not work as expected in the application main thread:
1561
1562- **Idle** handle
1563- **prepare** handle
1564- **check** handle
1565- signal-related functions
1566- Functions related to TCP and UDP
1567
1568## Case Study
1569
1570[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)
1571
1572[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)
1573
1574[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)
1575