jerryscript-project / iotjs

Platform for Internet of Things with JavaScript http://www.iotjs.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ICE: Assertion 'JERRY_CONTEXT (jmem_heap_allocated_size) == 0

durgaprasad21 opened this issue · comments

We are trying to port nodejs to iotjs in our project and we have developed a native addon which will interacting with the third party libraries.

Currently we are using N-API of iotjs to develop the native addon. But there is a major issue in N-API for triggering the callback from native to JS when there is any event triggered from third party library.

we have checked N-API async functionality using the napi_create_async_work with execute and complete.
But when there are multiple events are triggered from the third party library for same request napi_create_async_work design cant be used.

So we have taken alternate approach to handle this issue by using the uv_async_send.
With uv_async_send we are able to achieve the events triggering from native to JS .But there is any during the program exits and iotjs cleanup is called.
During the iotjs cleanup encountered the "ICE: Assertion 'JERRY_CONTEXT (jmem_heap_allocated_size) == 0"

Code snippet:-

#include <node_api.h>
#include <string.h>
#include <pthread.h> 
#include<uv.h>

typedef struct{
 napi_ref _callback;
 napi_async_work _request;
 napi_value jsthis_;
 napi_env env;
 uv_async_t async; 
 napi_value object;
 int i;

 }carrier;

static napi_ref ConstructRef;
#define DECLARE_NAPI_METHOD(name, func)                          \
  { name, 0, func, 0, 0, 0, napi_default, 0 }

static napi_value hello_world(napi_env env, napi_callback_info info) {
  napi_value world;
  const char* str = "Hello world!";
  size_t str_len = strlen(str);

  if (napi_create_string_utf8(env, str, str_len, &world) != napi_ok)
    return NULL;

  return world;
}
void *myThreadFun(void *data) 
{ 
	carrier*c=(carrier*)data;
	printf("my thread func\n");
	c->i=0;
	while(c->i<5)
		{
			printf("while loop thread\n");
			c->async.data = data;
			uv_async_send(&c->async);
			c->i++;
			sleep(1);
		}
	printf("exiting thread func");
//	pthread_exit(NULL);
	return NULL; 
} 
static void cleanup(void* data) {
  printf("cleanup\n");
  napi_env env = (napi_env)data;
  napi_delete_reference(env, ConstructRef);
}

void EmitCallback(uv_async_t*h){

	printf("Triggered EmitCallback\n ");
	
    carrier*c=(carrier*)h->data;
	napi_env env = c->env;

	napi_value callbac;
	napi_status k;
	napi_value argv[2];
	k=napi_get_reference_value(env,c->_callback, &callbac);
	if(k==napi_ok)printf("get_ref is ok\n");

	napi_value emitFxnPtr;
	napi_get_named_property(env, callbac, "emit", &emitFxnPtr);

	napi_valuetype func_type;
	napi_typeof(env, emitFxnPtr, &func_type);

	if (func_type == napi_function)   printf("Complete : napi_function pass\n");
	else  printf("Complete : napi_function fail. Not a function\n");

	const char * str1 = "response";
	size_t str_len1 = strlen(str1);
	napi_create_string_utf8(env, str1, str_len1, &argv[0]);

	const char * str = "start_up_listener";
	size_t str_len = strlen(str);
	napi_create_string_utf8(env, str, str_len, &argv[1]);

	k=napi_call_function(env, callbac, emitFxnPtr, 2, argv, NULL);
	if(k==napi_ok){printf("call_func is ok\n");}else{printf("call_func is not ok\n");}

	if(c->i>=5) {
		printf("deleting reference\n");
		k=napi_delete_reference(env,c->_callback);
		if(k==napi_ok){printf("del_ref is ok\n");}else{printf("del_ref is not ok\n");}

		uv_close((uv_handle_t*)&c->async, NULL);	
	
	if(c)
		free(c);
	}
}

static napi_value UVListener(napi_env env, napi_callback_info info) {
	printf("UVListener wrapper Listener start\n");
	 carrier*c=(carrier*)malloc(sizeof(carrier));
	 if(c==NULL)return NULL;

	napi_value construct;
	napi_status status;
	size_t argc=2;
	napi_value argv[2], resource_name, _this;
	
	void*data;
	napi_get_reference_value(env, ConstructRef, &construct);


	c->env = env;
	napi_value result;
	napi_new_instance(env, construct, argc, argv, &result);
	c->object = result;

	status=napi_create_reference(env, result, 1, &c->_callback);
	if(status==napi_ok){
		printf("napi_create_reference is ok\n");
	}else{
		printf("napi_create_reference is NOT ok\n");
	}	
	uv_loop_t *loop=NULL;
	status=napi_get_uv_event_loop(env,&loop);
	if(status==napi_ok){
		printf("loop is ok\n");
	}else{
		printf("loop is NOT ok\n");
		return NULL;
	}	
	int ab=uv_async_init(loop, &c->async, EmitCallback);
	
	printf("uv_async_init: %d\n", ab);
    pthread_t thread_id; 
    pthread_create(&thread_id, NULL, myThreadFun, c); 
	return result;
}

static napi_value New(napi_env env, napi_callback_info info) {
  size_t argc = 1;
  napi_value argv[1];
  
  napi_value jsthis;
  printf("Created new object\n");
  napi_value target;
  napi_status status;
  status = napi_get_new_target(env, info, &target);

  bool is_constructor = target != NULL;

	printf("is_constructor = %d\n",is_constructor );
  napi_get_cb_info(env, info, &argc, argv, &jsthis, NULL);

return jsthis;						   
				  
}

napi_value init_query(napi_env env, napi_value exports) {
  napi_property_descriptor desc[] = {
  	{"hello", 0, hello_world,  0, 0, 0, napi_default, 0 },
	DECLARE_NAPI_METHOD("uvlistener", UVListener)  ,
	};

  napi_value cons;
  napi_status status;
  status =
      napi_define_class(env, "Handle",NAPI_AUTO_LENGTH, New, NULL, sizeof(desc)/sizeof(*desc), desc, &cons);
  if (status != napi_ok) return NULL;

  status = napi_create_reference(env, cons, 1, &ConstructRef);
  if (status != napi_ok) return NULL;
  napi_add_env_cleanup_hook(env, cleanup, env);

  status = napi_set_named_property(env, exports, "Handle", cons);
  if (status != napi_ok) return NULL;

  return exports;
}

NAPI_MODULE(query, init_query)

NAPI_MODULE(query, init_query)

Backtrace:-
Thread 1 "iotjs" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffffe6608b1 in __GI_abort () at abort.c:79
#2 0x000000000057e9c3 in jerry_port_fatal (code=ERR_FAILED_INTERNAL_ASSERTION) at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-port/default/default-fatal.c:30
#3 0x000000000052800a in jerry_fatal (code=ERR_FAILED_INTERNAL_ASSERTION) at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/jrt/jrt-fatals.c:63
#4 0x000000000052805c in jerry_assert_fail (assertion=0x5b7b90 "JERRY_CONTEXT (jmem_heap_allocated_size) == 0",
file=0x5b7b40 "/home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/jmem/jmem-heap.c", function=0x5cc410 <func.23698> "jmem_heap_finalize", line=107)
at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/jrt/jrt-fatals.c:87
#5 0x0000000000527089 in jmem_heap_finalize () at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/jmem/jmem-heap.c:107
#6 0x0000000000526df5 in jmem_finalize () at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/jmem/jmem-allocator.c:170
#7 0x00000000004365eb in jerry_cleanup () at /home/durgaprasad/work/iotjs/iotjs/deps/jerry/jerry-core/api/jerry.c:254
#8 0x000000000042095c in iotjs_terminate (env=0x7ef780 <current_env>) at /home/durgaprasad/work/iotjs/iotjs/src/iotjs.c:282
#9 0x0000000000420acb in iotjs_entry (argc=2, argv=0x7ffffffee448) at /home/durgaprasad/work/iotjs/iotjs/src/iotjs.c:318
#10 0x000000000041fe17 in main (argc=2, argv=0x7ffffffee448) at /home/durgaprasad/work/iotjs/iotjs/src/platform/linux/iotjs_linux.c:19
(gdb)

This error means you didn't free up some memory. Usually the best way is capturing these with valgrind. I recommend to compile the project with 32 bit and system allocator:
--target-arch=i686 --jerry-cmake-param=-DJERRY_SYSTEM_ALLOCATOR=ON --jerry-cmake-param=-DJERRY_CPOINTER_32_BIT=ON

Run valgrind with: --leak-check=full --show-leak-kinds=all

How can we trigger the callback from native addon to JS using n-api?
In my project I have a thread running in glib context and my JS code is running in UV context
Based on the request from JS i.e. from UV context native addon will trigger a request to thread in glib context.
Glib thread will respond asynchronously.
When I receive the data from the glibc thread context I need to make a callback to JS from native addon using the JS reference created during the request from UV context.

How can I achieve callback from native addon to JS using n-api asynchronously?
How can we integrate libtuv and Glib?
How can we support uv_prepare_start and uv_check_start functionality in libtuv