11cb0ef41Sopenharmony_ci#include "node_api.h"
21cb0ef41Sopenharmony_ci#include "assert.h"
31cb0ef41Sopenharmony_ci#include "uv.h"
41cb0ef41Sopenharmony_ci#include <stdlib.h>
51cb0ef41Sopenharmony_ci#include "../../js-native-api/common.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_cistatic int cleanup_hook_count = 0;
81cb0ef41Sopenharmony_cistatic void MustNotCall(napi_async_cleanup_hook_handle hook, void* arg) {
91cb0ef41Sopenharmony_ci  assert(0);
101cb0ef41Sopenharmony_ci}
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cistruct AsyncData {
131cb0ef41Sopenharmony_ci  uv_async_t async;
141cb0ef41Sopenharmony_ci  napi_env env;
151cb0ef41Sopenharmony_ci  napi_async_cleanup_hook_handle handle;
161cb0ef41Sopenharmony_ci};
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cistatic struct AsyncData* CreateAsyncData() {
191cb0ef41Sopenharmony_ci  struct AsyncData* data = (struct AsyncData*) malloc(sizeof(struct AsyncData));
201cb0ef41Sopenharmony_ci  data->handle = NULL;
211cb0ef41Sopenharmony_ci  return data;
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cistatic void AfterCleanupHookTwo(uv_handle_t* handle) {
251cb0ef41Sopenharmony_ci  cleanup_hook_count++;
261cb0ef41Sopenharmony_ci  struct AsyncData* data = (struct AsyncData*) handle->data;
271cb0ef41Sopenharmony_ci  napi_status status = napi_remove_async_cleanup_hook(data->handle);
281cb0ef41Sopenharmony_ci  assert(status == napi_ok);
291cb0ef41Sopenharmony_ci  free(data);
301cb0ef41Sopenharmony_ci}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cistatic void AfterCleanupHookOne(uv_async_t* async) {
331cb0ef41Sopenharmony_ci  cleanup_hook_count++;
341cb0ef41Sopenharmony_ci  uv_close((uv_handle_t*) async, AfterCleanupHookTwo);
351cb0ef41Sopenharmony_ci}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_cistatic void AsyncCleanupHook(napi_async_cleanup_hook_handle handle, void* arg) {
381cb0ef41Sopenharmony_ci  cleanup_hook_count++;
391cb0ef41Sopenharmony_ci  struct AsyncData* data = (struct AsyncData*) arg;
401cb0ef41Sopenharmony_ci  uv_loop_t* loop;
411cb0ef41Sopenharmony_ci  napi_status status = napi_get_uv_event_loop(data->env, &loop);
421cb0ef41Sopenharmony_ci  assert(status == napi_ok);
431cb0ef41Sopenharmony_ci  int err = uv_async_init(loop, &data->async, AfterCleanupHookOne);
441cb0ef41Sopenharmony_ci  assert(err == 0);
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  data->async.data = data;
471cb0ef41Sopenharmony_ci  data->handle = handle;
481cb0ef41Sopenharmony_ci  uv_async_send(&data->async);
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_cistatic void ObjectFinalizer(napi_env env, void* data, void* hint) {
521cb0ef41Sopenharmony_ci  // AsyncCleanupHook and its subsequent callbacks are called twice.
531cb0ef41Sopenharmony_ci  assert(cleanup_hook_count == 6);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  napi_ref* ref = data;
561cb0ef41Sopenharmony_ci  NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref));
571cb0ef41Sopenharmony_ci  free(ref);
581cb0ef41Sopenharmony_ci}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cistatic void CreateObjectWrap(napi_env env) {
611cb0ef41Sopenharmony_ci  napi_value js_obj;
621cb0ef41Sopenharmony_ci  napi_ref* ref = malloc(sizeof(*ref));
631cb0ef41Sopenharmony_ci  NODE_API_CALL_RETURN_VOID(env, napi_create_object(env, &js_obj));
641cb0ef41Sopenharmony_ci  NODE_API_CALL_RETURN_VOID(
651cb0ef41Sopenharmony_ci      env, napi_wrap(env, js_obj, ref, ObjectFinalizer, NULL, ref));
661cb0ef41Sopenharmony_ci  // create a strong reference so that the finalizer is called at shutdown.
671cb0ef41Sopenharmony_ci  NODE_API_CALL_RETURN_VOID(env, napi_reference_ref(env, *ref, NULL));
681cb0ef41Sopenharmony_ci}
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cistatic napi_value Init(napi_env env, napi_value exports) {
711cb0ef41Sopenharmony_ci  // Reinitialize the static variable to be compatible with musl libc.
721cb0ef41Sopenharmony_ci  cleanup_hook_count = 0;
731cb0ef41Sopenharmony_ci  // Create object wrap before cleanup hooks.
741cb0ef41Sopenharmony_ci  CreateObjectWrap(env);
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  {
771cb0ef41Sopenharmony_ci    struct AsyncData* data = CreateAsyncData();
781cb0ef41Sopenharmony_ci    data->env = env;
791cb0ef41Sopenharmony_ci    napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, &data->handle);
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  {
831cb0ef41Sopenharmony_ci    struct AsyncData* data = CreateAsyncData();
841cb0ef41Sopenharmony_ci    data->env = env;
851cb0ef41Sopenharmony_ci    napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, NULL);
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  {
891cb0ef41Sopenharmony_ci    napi_async_cleanup_hook_handle must_not_call_handle;
901cb0ef41Sopenharmony_ci    napi_add_async_cleanup_hook(
911cb0ef41Sopenharmony_ci        env, MustNotCall, NULL, &must_not_call_handle);
921cb0ef41Sopenharmony_ci    napi_remove_async_cleanup_hook(must_not_call_handle);
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  // Create object wrap after cleanup hooks.
961cb0ef41Sopenharmony_ci  CreateObjectWrap(env);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  return NULL;
991cb0ef41Sopenharmony_ci}
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ciNAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
102