quickjs利用libuv实现setTimeout函数

零、前言

  默认quickjs 是有setTimeout函数的实现的。但是由于js的进程与ui进程会有冲突,因此,需要通过重写quickjs的setTimeout,改用系统进程实现才行。

  这里以大部分基于quickjs开源的框架中使用最多的libuv作为底层库。

一、编译libuv库

  通过github源码编译libuv还是有点麻烦,官方没有怎么提供libuv编译脚本,这里我使用微软的vcpkg工具来编译。

1 git clone https://github.com/microsoft/vcpkg #下载vcpkg
2 bootstrap-vcpkg.bat #下周vcpkg.exe
3 vcpkg.exe search libuv
4 vcpkg.exe install libuv #下载libuv源码,编译、并安装到~/installed目录下

  后面经过测试,发现从vcpkg编译的lib,有个 GetSystemTimePreciseAsFileTime 函数在win7上未找到。因此需要修改libuv的源代码,改成兼容win7版本,具体修改 src/win/util.c:uv_clock_gettime:449 把 GetSystemTimePreciseAsFileTime(&ft); 改成 GetSystemTimeAsFileTime(&ft); 换成低版本。反正windows上只是仿真,精度误差无所谓。改完之后,也可以用cmake进行编译。然后用Visul Studio进行编译。

cmake -G "Visual Studio 16 2019" -B build

  简单代码,测试libuv库是否链接成功

 1 int count = 0;
 2 void wait_for_a_while(uv_idle_t *handle)
 3 {
 4   count ++;
 5   printf("wait for a while %d\n", count);
 6   if(count > 10){
 7     uv_idle_stop(handle);
 8   }
 9 }
10 void test_uv()
11 {
12   uv_idle_t idler;
13   uv_idle_init(uv_default_loop(), &idler);
14   uv_idle_start(&idler, wait_for_a_while);
15   uv_run(uv_default_loop(), UV_RUN_DEFAULT);
16   uv_loop_close(uv_default_loop());
17 }

二、修改原来lvgl-simulator

  原先的lvgl主循环

 1 lv_ui guider_ui;
 2 
 3 int main(int argc, char **argv)
 4 {
 5   (void)argc; /*Unused*/
 6   (void)argv; /*Unused*/
 7 
 8   /*Initialize LVGL*/
 9   lv_init();
10 
11   /*Initialize the HAL (display, input devices, tick) for LVGL*/
12   hal_init();
13 
14   setup_ui(&guider_ui);
15   events_init(&guider_ui);
16   custom_init(&guider_ui);
17 
18   while(1) {
19       /* Periodically call the lv_task handler.
20        * It could be done in a timer interrupt or an OS task too.*/
21       lv_timer_handler();
22       usleep(5 * 1000);
23   }
24 
25   return 0;
26 }

  之前测试,直接在custom_init里运行js脚本时,会因为阻塞问题,导致主界面会卡死。因此需要对这个main主循环进行改造。在主循环里,创建两个线程,一个gui线程,一个event事件线程。

  修改后主循环代码如下

 1 uv_loop_t *event_loop;
 2 uv_loop_t *gui_loop;
 3 
 4 uv_timer_t job_req;
 5 uv_timer_t job_event;
 6 
 7 void gui_loop_cb(uv_timer_t *handle){
 8   lv_timer_handler();
 9 }
10 void event_loop_cb(uv_timer_t *handle){
11   printf("event_loop_cb\n");
12 }
13 
14 int main(int argc, char **argv)
15 {
16   (void)argc; /*Unused*/
17   (void)argv; /*Unused*/
18 
19   /*Initialize LVGL*/
20   lv_init();
21 
22   /*Initialize the HAL (display, input devices, tick) for LVGL*/
23   hal_init();
24   
25   gui_loop = uv_default_loop();
26   event_loop = uv_default_loop();
27   uv_timer_init(gui_loop, &job_req);
28   uv_timer_start(&job_req, gui_loop_cb, 100, 5);
29   
30   uv_timer_init(event_loop, &job_event);
31   uv_timer_start(&job_event, event_loop_cb, 100, 500);
32 
33   setup_ui(&guider_ui);
34   events_init(&guider_ui);
35   custom_init(&guider_ui);
36 
37   while(uv_run(event_loop, UV_RUN_NOWAIT) || uv_run(gui_loop, UV_RUN_NOWAIT) )
38   {
39   }
40   return 0;
41 }

三、导出setTimeout函数

  为了验证功能,部分对象没有进行释放,setTimeout没有做多实例处理。同时还实现绑定click事件。

 1 extern uv_loop_t *event_loop;
 2 uv_timer_t lvgl_job_req;
 3 typedef struct js_timer_data_s {
 4   JSContext *ctx;
 5   JSValue func;
 6 } js_timer_data_t;
 7 
 8 static void uv__timeout_cb(uv_timer_t *handle) {
 9   // printf("timeout! uv\n");
10   js_timer_data_t *data = (js_timer_data_t *)handle->data;
11   JSContext *ctx = data->ctx;
12   JSValue func = JS_DupValue(ctx, data->func);
13   JSValue ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
14   JS_FreeValue(ctx, func);
15   if(JS_IsException(ret)){
16     js_std_dump_error(ctx);
17   }
18   JS_FreeValue(ctx, ret);
19   return ;
20 }
21 
22 
23 static JSValue lvgl_setTimeout(JSContext *ctx, JSValueConst this_val,
24                                     int argc, JSValueConst *argv)
25 {
26   int delay;
27   JSValueConst func;
28   func = argv[0];
29   if(!JS_IsFunction(ctx, func)){
30     printf("Not a function\n");
31     return JS_EXCEPTION;
32   }
33   JS_ToInt32(ctx, &delay, argv[1]);
34 
35   uv_timer_init(event_loop, &lvgl_job_req);
36 
37   js_timer_data_t *data = calloc(1, sizeof(js_timer_data_t));
38   data->ctx = ctx;
39   data->func = JS_DupValue(ctx, func);
40   lvgl_job_req.data = data;
41   uv_timer_start(&lvgl_job_req, uv__timeout_cb, delay, 0);
42   // uv_run(loop, UV_RUN_ONCE);
43   return JS_NULL;
44 }
45 
46 void click_event_cb(lv_event_t * e){
47   js_timer_data_t *data = (js_timer_data_t *)e->user_data;
48   JSContext *ctx = data->ctx;
49   JSValue func = JS_DupValue(ctx, data->func);
50   JSValue ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
51   JS_FreeValue(ctx, func);
52   if(JS_IsException(ret)){
53     js_std_dump_error(ctx);
54   }
55   JS_FreeValue(ctx, ret);
56 }
57 static JSValue lvgl_bind_click(JSContext *ctx, JSValueConst this_val,
58                                     int argc, JSValueConst *argv)
59 {
60   lv_obj_ptr_t p;
61   JS_ToPointer(ctx, &p, argv[0]);
62   lv_obj_t * obj = (lv_obj_t *)p;
63 
64   JSValueConst func = argv[1];
65   if(!JS_IsFunction(ctx, func)){
66     printf("Not a function\n");
67     return JS_EXCEPTION;
68   }
69   js_timer_data_t *data = calloc(1, sizeof(js_timer_data_t));
70   data->ctx = ctx;
71   data->func = JS_DupValue(ctx, func);
72 
73   lv_obj_add_event_cb(obj, click_event_cb, LV_EVENT_CLICKED, data);
74 }
75 
76 static JSValue lvgl_clearTimeout(JSContext *ctx, JSValueConst this_val,
77                                     int argc, JSValueConst *argv)
78 {
79   uv_timer_stop(&lvgl_job_req);
80   return JS_NULL;
81 }

四、js脚本测试

 1 lvgl.lvgl_set_clickable(lbl); //设置可点击
 2 //绑定点击事件
 3 lvgl.lvgl_bind_click(lbl, function(){
 4   console.log("onclick");
 5   console.log(this);
 6   lvgl.lvgl_obj_set_style_bg_color(lbl, 0xff0000);
 7   clearTimeout();
 8 });
 9 
10 lvgl.lvgl_scr_load(screen);
11 
12 function changeState(){
13   var x = Math.random()*400;
14   var y = Math.random()*300;
15   console.log(x + "  " + y);
16   lvgl.lvgl_obj_set_pos(lbl, x, y);
17   setTimeout(changeState, 1000); //定时执行
18 }
19 changeState();

 

参考资料:

  https://zhuanlan.zhihu.com/c_1094553212761309184

  https://stackoverflow.com/questions/17100883/how-does-the-uv-run-nowait-mode-work-in-libuv

本文地址:https://www.cnblogs.com/wunaozai/p/17853717.html

系列目录:https://www.cnblogs.com/wunaozai/p/17853962.html

 

posted @ 2023-12-01 10:11  无脑仔的小明  阅读(199)  评论(0编辑  收藏  举报