1#include "node_api.h" 2#include "assert.h" 3#include "uv.h" 4#include <stdlib.h> 5#include "../../js-native-api/common.h" 6 7static int cleanup_hook_count = 0; 8static void MustNotCall(napi_async_cleanup_hook_handle hook, void* arg) { 9 assert(0); 10} 11 12struct AsyncData { 13 uv_async_t async; 14 napi_env env; 15 napi_async_cleanup_hook_handle handle; 16}; 17 18static struct AsyncData* CreateAsyncData() { 19 struct AsyncData* data = (struct AsyncData*) malloc(sizeof(struct AsyncData)); 20 data->handle = NULL; 21 return data; 22} 23 24static void AfterCleanupHookTwo(uv_handle_t* handle) { 25 cleanup_hook_count++; 26 struct AsyncData* data = (struct AsyncData*) handle->data; 27 napi_status status = napi_remove_async_cleanup_hook(data->handle); 28 assert(status == napi_ok); 29 free(data); 30} 31 32static void AfterCleanupHookOne(uv_async_t* async) { 33 cleanup_hook_count++; 34 uv_close((uv_handle_t*) async, AfterCleanupHookTwo); 35} 36 37static void AsyncCleanupHook(napi_async_cleanup_hook_handle handle, void* arg) { 38 cleanup_hook_count++; 39 struct AsyncData* data = (struct AsyncData*) arg; 40 uv_loop_t* loop; 41 napi_status status = napi_get_uv_event_loop(data->env, &loop); 42 assert(status == napi_ok); 43 int err = uv_async_init(loop, &data->async, AfterCleanupHookOne); 44 assert(err == 0); 45 46 data->async.data = data; 47 data->handle = handle; 48 uv_async_send(&data->async); 49} 50 51static void ObjectFinalizer(napi_env env, void* data, void* hint) { 52 // AsyncCleanupHook and its subsequent callbacks are called twice. 53 assert(cleanup_hook_count == 6); 54 55 napi_ref* ref = data; 56 NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref)); 57 free(ref); 58} 59 60static void CreateObjectWrap(napi_env env) { 61 napi_value js_obj; 62 napi_ref* ref = malloc(sizeof(*ref)); 63 NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &js_obj)); 64 NODE_API_CALL_RETURN_VOID( 65 env, napi_wrap(env, js_obj, ref, ObjectFinalizer, NULL, ref)); 66 // create a strong reference so that the finalizer is called at shutdown. 67 NODE_API_CALL_RETURN_VOID(env, napi_reference_ref(env, *ref, NULL)); 68} 69 70static napi_value Init(napi_env env, napi_value exports) { 71 // Reinitialize the static variable to be compatible with musl libc. 72 cleanup_hook_count = 0; 73 // Create object wrap before cleanup hooks. 74 CreateObjectWrap(env); 75 76 { 77 struct AsyncData* data = CreateAsyncData(); 78 data->env = env; 79 napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, &data->handle); 80 } 81 82 { 83 struct AsyncData* data = CreateAsyncData(); 84 data->env = env; 85 napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, NULL); 86 } 87 88 { 89 napi_async_cleanup_hook_handle must_not_call_handle; 90 napi_add_async_cleanup_hook( 91 env, MustNotCall, NULL, &must_not_call_handle); 92 napi_remove_async_cleanup_hook(must_not_call_handle); 93 } 94 95 // Create object wrap after cleanup hooks. 96 CreateObjectWrap(env); 97 98 return NULL; 99} 100 101NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) 102