Browse Source

fix thread and socket on freertos

use pikaMalloc/Free inner platform_thread()

socket multithread test passed on linux

update

improve fast_test.sh
lyon 3 năm trước cách đây
mục cha
commit
165cc7d041

+ 61 - 0
examples/socket/socket_thread.py

@@ -0,0 +1,61 @@
+import socket
+import _thread
+import random
+import time
+
+test_finished = False
+server_started = False
+
+def socket_server_task(host, port):
+    """
+    socket 服务器任务
+    :return:
+    """
+    print("socket server start:", host, port)
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.bind((host, port))
+    s.listen(5)
+    print("socket server waiting accept")
+    global server_started
+    server_started = True
+    accept, addr = s.accept()
+    print("socket server accepted at", addr)
+    while True:
+        try:
+            data = accept.recv(1024)
+            print('socket server recv:', data.decode())
+            accept.send(data)
+        except Exception:
+            print('socket server closing accept')
+            accept.close()
+            break
+    print("socket server closing")
+    s.close()
+    global test_finished
+    test_finished = True
+
+
+def socket_server_init(host='0.0.0.0', port=36500):
+    _thread.start_new_thread(socket_server_task, (host, port))
+
+
+def socket_client_task(host, port):
+    print("socket client start:", host, port)
+    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    client.connect((host, port))
+    client.send("hello".encode())
+    recv = client.recv(1024).decode()
+    print("client recv:", recv)
+    client.close()
+
+def socket_server_test(host='0.0.0.0', port=36500):
+    _thread.start_new_thread(socket_client_task, (host, port))
+
+
+test_port = random.randint(10000, 65535)
+socket_server_init(port=test_port)
+while not server_started:
+    time.sleep(0.1)
+socket_server_test(port=test_port)
+while not test_finished:
+    time.sleep(0.1)

+ 8 - 2
package/_thread/_thread.c

@@ -36,9 +36,15 @@ static void _thread_func(void* arg) {
     arg_deinit(info->function);
     arg_deinit(info->args);
     pika_debug("thread exiting");
-    pika_GIL_EXIT();
-    pika_platform_thread_destroy(info->thread);
+    pika_platform_thread_t* thread = info->thread;
     pikaFree(info, sizeof(pika_thread_info));
+    pika_GIL_EXIT();
+#if PIKA_FREERTOS_ENABLE
+    pikaFree(thread, sizeof(pika_platform_thread_t));
+    pika_platform_thread_exit(NULL);
+#else
+    pika_platform_thread_exit(thread);
+#endif
 }
 
 void _thread_start_new_thread(PikaObj* self, Arg* function, Arg* args_) {

+ 2 - 0
package/socket/PikaPlatform_socket.c

@@ -69,6 +69,7 @@ PIKA_WEAK int pika_platform_recv(int __fd,
     return recv(__fd, __buf, __n, __flags);
 #else
     WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
+    return -1;
 #endif
 }
 
@@ -78,6 +79,7 @@ PIKA_WEAK int pika_platform_gethostname(char* __name, size_t __len) {
     return gethostname(__name, __len);
 #else
     WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
+    return -1;
 #endif
 }
 

+ 10 - 5
package/socket/_socket.c

@@ -75,10 +75,11 @@ Arg* _socket_socket__recv(PikaObj* self, int num) {
     pika_GIL_EXIT();
     ret = __platform_recv(sockfd, data_recv, num, 0);
     pika_GIL_ENTER();
-    if (ret < 0) {
+    if (ret <= 0) {
         if (obj_getInt(self, "blocking")) {
             obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-            __platform_printf("recv error\n");
+            // __platform_printf("recv error\n");
+            arg_deinit(res);
             return NULL;
         } else {
             Arg* res_r = arg_newBytes(NULL, 0);
@@ -110,14 +111,18 @@ void _socket_socket__connect(PikaObj* self, char* host, int port) {
     server_addr.sin_port = htons(port);
     server_addr.sin_addr.s_addr = inet_addr(host);
     pika_GIL_EXIT();
-    __platform_connect(sockfd, (struct sockaddr*)&server_addr,
-                       sizeof(server_addr));
+    int err = pika_platform_connect(sockfd, (struct sockaddr*)&server_addr,
+                                    sizeof(server_addr));
     pika_GIL_ENTER();
+    if (0 != err) {
+        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
+        return;
+    }
     if (obj_getInt(self, "blocking") == 0) {
         int flags = fcntl(sockfd, F_GETFL);
         if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
             obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-            __platform_printf("Unable to set socket non blocking\n");
+            pika_platform_printf("Unable to set socket non blocking\n");
             return;
         }
     }

+ 2 - 0
package/time/_time.c

@@ -12,7 +12,9 @@ void (*global_do_sleep_ms)(uint32_t);
 static void _do_sleep_ms_tick(uint32_t ms) {
     uint32_t tick = pika_platform_get_tick();
     while (pika_platform_get_tick() - tick < ms) {
+#if PIKA_EVENT_ENABLE
         _VMEvent_pickupEvent();
+#endif
         pika_platform_thread_delay();
     }
 }

+ 1 - 1
port/linux/.vscode/launch.json

@@ -11,7 +11,7 @@
             "program": "${workspaceFolder}/build/test/pikascript_test",
             // "program": "${workspaceFolder}/build/boot/demo06-pikamain/pikascript_demo06-pikamain",
             "args": [
-                "--gtest_filter=pikaMain.SHELL_filter*"
+                // "--gtest_filter=socket.thread"
             ],
             "stopAtEntry": false,
             "cwd": "${workspaceFolder}",

+ 9 - 1
port/linux/fast_test.sh

@@ -1,5 +1,13 @@
+
 ROOT=$PWD
 rm $(find build -name *.gcda) -f
 cd build && rm ./test/pikascript_test -f &&  ninja -j0 
 cd $ROOT
-build/test/pikascript_test
+if [ $# == 0 ] ; then
+    build/test/pikascript_test
+fi
+
+if [ $# == 1 ] ; then
+	filter=$1
+    build/test/pikascript_test --gtest_filter=$filter
+fi

+ 8 - 2
port/linux/package/pikascript/pikascript-lib/_thread/_thread.c

@@ -36,9 +36,15 @@ static void _thread_func(void* arg) {
     arg_deinit(info->function);
     arg_deinit(info->args);
     pika_debug("thread exiting");
-    pika_GIL_EXIT();
-    pika_platform_thread_destroy(info->thread);
+    pika_platform_thread_t* thread = info->thread;
     pikaFree(info, sizeof(pika_thread_info));
+    pika_GIL_EXIT();
+#if PIKA_FREERTOS_ENABLE
+    pikaFree(thread, sizeof(pika_platform_thread_t));
+    pika_platform_thread_exit(NULL);
+#else
+    pika_platform_thread_exit(thread);
+#endif
 }
 
 void _thread_start_new_thread(PikaObj* self, Arg* function, Arg* args_) {

+ 2 - 0
port/linux/package/pikascript/pikascript-lib/socket/PikaPlatform_socket.c

@@ -69,6 +69,7 @@ PIKA_WEAK int pika_platform_recv(int __fd,
     return recv(__fd, __buf, __n, __flags);
 #else
     WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
+    return -1;
 #endif
 }
 
@@ -78,6 +79,7 @@ PIKA_WEAK int pika_platform_gethostname(char* __name, size_t __len) {
     return gethostname(__name, __len);
 #else
     WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
+    return -1;
 #endif
 }
 

+ 10 - 5
port/linux/package/pikascript/pikascript-lib/socket/_socket.c

@@ -75,10 +75,11 @@ Arg* _socket_socket__recv(PikaObj* self, int num) {
     pika_GIL_EXIT();
     ret = __platform_recv(sockfd, data_recv, num, 0);
     pika_GIL_ENTER();
-    if (ret < 0) {
+    if (ret <= 0) {
         if (obj_getInt(self, "blocking")) {
             obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-            __platform_printf("recv error\n");
+            // __platform_printf("recv error\n");
+            arg_deinit(res);
             return NULL;
         } else {
             Arg* res_r = arg_newBytes(NULL, 0);
@@ -110,14 +111,18 @@ void _socket_socket__connect(PikaObj* self, char* host, int port) {
     server_addr.sin_port = htons(port);
     server_addr.sin_addr.s_addr = inet_addr(host);
     pika_GIL_EXIT();
-    __platform_connect(sockfd, (struct sockaddr*)&server_addr,
-                       sizeof(server_addr));
+    int err = pika_platform_connect(sockfd, (struct sockaddr*)&server_addr,
+                                    sizeof(server_addr));
     pika_GIL_ENTER();
+    if (0 != err) {
+        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
+        return;
+    }
     if (obj_getInt(self, "blocking") == 0) {
         int flags = fcntl(sockfd, F_GETFL);
         if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
             obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
-            __platform_printf("Unable to set socket non blocking\n");
+            pika_platform_printf("Unable to set socket non blocking\n");
             return;
         }
     }

+ 21 - 6
src/PikaCompiler.c

@@ -827,8 +827,9 @@ int32_t __foreach_handler_linkCompiledModules(Arg* argEach, Args* context) {
     return 0;
 }
 
-PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
-                                               char* lib_path) {
+PIKA_RES _do_pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
+                                                   char* lib_path,
+                                                   PIKA_BOOL gen_c_array) {
     PIKA_RES compile_err = (PIKA_RES)obj_getInt(self, "err");
     if (PIKA_RES_OK != compile_err) {
         pika_platform_printf("  Error: compile failed, link aborted.\r\n");
@@ -847,19 +848,33 @@ PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
     char* folder_path = strsPathJoin(&buffs, pwd, lib_path_folder);
     char* lib_file_path = strsPathJoin(&buffs, pwd, lib_path);
     LibObj_saveLibraryFile(lib, lib_file_path);
-    Lib_loadLibraryFileToArray(lib_file_path, folder_path);
+    if (gen_c_array) {
+        Lib_loadLibraryFileToArray(lib_file_path, folder_path);
+    }
     strsDeinit(&buffs);
     return PIKA_RES_OK;
 }
 
-PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name) {
+PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self,
+                                               char* lib_path) {
+    return _do_pikaMaker_linkCompiledModulesFullPath(self, lib_path, PIKA_TRUE);
+}
+
+PIKA_RES _do_pikaMaker_linkCompiledModules(PikaMaker* self,
+                                           char* lib_name,
+                                           PIKA_BOOL gen_c_array) {
     Args buffs = {0};
     char* lib_file_path = strsPathJoin(&buffs, "pikascript-api/", lib_name);
-    PIKA_RES res = pikaMaker_linkCompiledModulesFullPath(self, lib_file_path);
+    PIKA_RES res = _do_pikaMaker_linkCompiledModulesFullPath(
+        self, lib_file_path, gen_c_array);
     strsDeinit(&buffs);
     return res;
 }
 
+PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name) {
+    return _do_pikaMaker_linkCompiledModules(self, lib_name, PIKA_TRUE);
+}
+
 PIKA_RES pikaMaker_linkRaw(PikaMaker* self, char* file_path) {
     LibObj* lib = obj_getPtr(self, "lib");
     LibObj_staticLinkFile(lib, file_path);
@@ -898,6 +913,6 @@ int pikafs_fwrite(void* buf, size_t size, size_t count, pikafs_FILE* file) {
 }
 
 int pikafs_fclose(pikafs_FILE* file) {
-    pikaFree(file,sizeof(pikafs_FILE));
+    pikaFree(file, sizeof(pikafs_FILE));
     return 0;
 }

+ 3 - 1
src/PikaCompiler.h

@@ -29,6 +29,9 @@ char* pikaMaker_getFirstNocompiled(PikaMaker* self);
 PIKA_RES pikaMaker_compileModuleWithDepends(PikaMaker* self, char* module_name);
 PIKA_RES pikaMaker_linkCompiledModulesFullPath(PikaMaker* self, char* lib_path);
 PIKA_RES pikaMaker_linkCompiledModules(PikaMaker* self, char* lib_name);
+PIKA_RES _do_pikaMaker_linkCompiledModules(PikaMaker* self,
+                                           char* lib_name,
+                                           PIKA_BOOL gen_c_array);
 int LibObj_loadLibrary(LibObj* self, uint8_t* library_bytes);
 void LibObj_printModules(LibObj* self);
 void pikaMaker_deinit(PikaMaker* self);
@@ -56,5 +59,4 @@ int pikafs_fread(void* buf, size_t size, size_t count, pikafs_FILE* file);
 int pikafs_fwrite(void* buf, size_t size, size_t count, pikafs_FILE* file);
 int pikafs_fclose(pikafs_FILE* file);
 
-
 #endif

+ 24 - 8
src/PikaPlatform.c

@@ -32,6 +32,9 @@
 #include <Windows.h>
 #endif
 
+void pikaFree(void* mem, uint32_t size);
+void* pikaMalloc(uint32_t size);
+
 PIKA_WEAK void pika_platform_disable_irq_handle(void) {
     /* disable irq to support thread */
 }
@@ -331,11 +334,11 @@ PIKA_WEAK pika_platform_thread_t* pika_platform_thread_init(
     void* (*thread_entry)(void*);
 
     thread_entry = (void* (*)(void*))entry;
-    thread = pika_platform_malloc(sizeof(pika_platform_thread_t));
+    thread = pikaMalloc(sizeof(pika_platform_thread_t));
 
     res = pthread_create(&thread->thread, NULL, thread_entry, param);
     if (res != 0) {
-        pika_platform_free(thread);
+        pikaFree(thread, sizeof(pika_platform_thread_t));
     }
 
     thread->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
@@ -346,14 +349,14 @@ PIKA_WEAK pika_platform_thread_t* pika_platform_thread_init(
     BaseType_t err;
     pika_platform_thread_t* thread;
 
-    thread = pika_platform_malloc(sizeof(pika_platform_thread_t));
+    thread = pikaMalloc(sizeof(pika_platform_thread_t));
 
     (void)tick;
 
     err = xTaskCreate(entry, name, stack_size, param, priority, thread->thread);
 
     if (pdPASS != err) {
-        pika_platform_free(thread);
+        pikaFree(thread, sizeof(pika_platform_thread_t));
         return NULL;
     }
 
@@ -407,20 +410,33 @@ PIKA_WEAK void pika_platform_thread_destroy(pika_platform_thread_t* thread) {
 #ifdef __linux
     if (NULL != thread) {
         pthread_detach(thread->thread);
-        pika_platform_free(thread);
+        pikaFree(thread, sizeof(pika_platform_thread_t));
         thread = NULL;
+        return;
     }
 #elif PIKA_FREERTOS_ENABLE
     if (NULL != thread) {
-        vTaskDelete(NULL);  // test on esp32c3
-        // vTaskDelete(thread->thread);
-        pika_platform_free(thread);
+        vTaskDelete(thread->thread);
+        pikaFree(thread, sizeof(pika_platform_thread_t));
+        return;
     }
 #else
     WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
 #endif
 }
 
+PIKA_WEAK void pika_platform_thread_exit(pika_platform_thread_t* thread) {
+#ifdef __linux
+    return pika_platform_thread_destroy(thread);
+#elif PIKA_FREERTOS_ENABLE
+    vTaskDelete(NULL);  // test on esp32c3
+    // vTaskDelete(thread->thread);
+    return;
+#else
+    WEAK_FUNCTION_NEED_OVERRIDE_ERROR();
+#endif
+}
+
 PIKA_WEAK int pika_platform_thread_mutex_init(pika_platform_thread_mutex_t* m) {
 #ifdef __linux
     return pthread_mutex_init(&(m->mutex), NULL);

+ 1 - 0
src/PikaPlatform.h

@@ -228,6 +228,7 @@ void pika_platform_thread_startup(pika_platform_thread_t* thread);
 void pika_platform_thread_stop(pika_platform_thread_t* thread);
 void pika_platform_thread_start(pika_platform_thread_t* thread);
 void pika_platform_thread_destroy(pika_platform_thread_t* thread);
+void pika_platform_thread_exit(pika_platform_thread_t* thread);
 
 #ifdef __linux
 #include <pthread.h>

+ 2 - 1
src/PikaVM.c

@@ -3673,7 +3673,8 @@ PikaObj* pikaVM_runFile(PikaObj* self, char* file_name) {
     PikaMaker* maker = New_PikaMaker();
     pikaMaker_setPWD(maker, pwd);
     pikaMaker_compileModuleWithDepends(maker, module_name);
-    pikaMaker_linkCompiledModules(maker, "pikaModules_cache.py.a");
+    _do_pikaMaker_linkCompiledModules(maker, "pikaModules_cache.py.a",
+                                      PIKA_FALSE);
     pikaMaker_deinit(maker);
     pika_platform_printf("(pikascript) all succeed.\r\n\r\n");
 

+ 21 - 0
test/module-test.cpp

@@ -239,6 +239,27 @@ TEST(socket, server_client) {
     obj_deinit(pikaMain);
     EXPECT_EQ(pikaMemNow(), 0);
 }
+
+TEST(socket, thread) {
+    /* init */
+    pikaMemInfo.heapUsedMax = 0;
+    PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
+    extern unsigned char pikaModules_py_a[];
+    obj_linkLibrary(pikaMain, pikaModules_py_a);
+    /* run */
+    __platform_printf("BEGIN\r\n");
+    pikaVM_runSingleFile(pikaMain, "test/python/socket/socket_thread.py");
+    /* collect */
+    /* assert */
+    EXPECT_STREQ(log_buff[4], "socket server accepted at 127.0.0.1\r\n");
+    EXPECT_STREQ(log_buff[3], "socket server recv: hello\r\n");
+    EXPECT_STREQ(log_buff[2], "client recv: hello\r\n");
+    EXPECT_STREQ(log_buff[1], "socket server closing accept\r\n");
+    EXPECT_STREQ(log_buff[0], "socket server closing\r\n");
+    /* deinit */
+    obj_deinit(pikaMain);
+    EXPECT_EQ(pikaMemNow(), 0);
+}
 #endif
 
 #if !PIKA_NANO_ENABLE

+ 63 - 0
test/python/socket/socket_thread.py

@@ -0,0 +1,63 @@
+import socket
+import _thread
+import random
+import time
+
+test_finished = False
+server_started = False
+
+
+def socket_server_task(host, port):
+    """
+    socket 服务器任务
+    :return:
+    """
+    print("socket server start:", host, port)
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.bind((host, port))
+    s.listen(5)
+    print("socket server waiting accept")
+    global server_started
+    server_started = True
+    accept, addr = s.accept()
+    print("socket server accepted at", addr)
+    while True:
+        try:
+            data = accept.recv(1024)
+            print('socket server recv:', data.decode())
+            accept.send(data)
+        except Exception:
+            print('socket server closing accept')
+            accept.close()
+            break
+    print("socket server closing")
+    s.close()
+    global test_finished
+    test_finished = True
+
+
+def socket_server_init(host='0.0.0.0', port=36500):
+    _thread.start_new_thread(socket_server_task, (host, port))
+
+
+def socket_client_task(host, port):
+    print("socket client start:", host, port)
+    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    client.connect((host, port))
+    client.send("hello".encode())
+    recv = client.recv(1024).decode()
+    print("client recv:", recv)
+    client.close()
+
+
+def socket_server_test(host='0.0.0.0', port=36500):
+    _thread.start_new_thread(socket_client_task, (host, port))
+
+
+test_port = random.randint(10000, 65535)
+socket_server_init(port=test_port)
+while not server_started:
+    time.sleep(0.1)
+socket_server_test(port=test_port)
+while not test_finished:
+    time.sleep(0.1)