/** This file is part of the MicroPython project, http://micropython.org/** The MIT License (MIT)** Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd* Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.** Permission is hereby granted, free of charge, to any person obtaining a copy* of this software and associated documentation files (the "Software"), to deal* in the Software without restriction, including without limitation the rights* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell* copies of the Software, and to permit persons to whom the Software is* furnished to do so, subject to the following conditions:** The above copyright notice and this permission notice shall be included in* all copies or substantial portions of the Software.** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN* THE SOFTWARE.*/#include <stdio.h>#include <string.h>#include "py/runtime.h"#include "py/stackctrl.h"#if MICROPY_PY_THREAD#include "py/mpthread.h"#if MICROPY_DEBUG_VERBOSE // print debugging info#define DEBUG_PRINT (1)#define DEBUG_printf DEBUG_printf#else // don't print debugging info#define DEBUG_PRINT (0)#define DEBUG_printf(...) (void)0#endif/****************************************************************/// Lock objectSTATIC const mp_obj_type_t mp_type_thread_lock;typedef struct _mp_obj_thread_lock_t {mp_obj_base_t base;mp_thread_mutex_t mutex;volatile bool locked;} mp_obj_thread_lock_t;STATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) {mp_obj_thread_lock_t *self = m_new_obj_with_finaliser(mp_obj_thread_lock_t);self->base.type = &mp_type_thread_lock;mp_thread_mutex_init(&self->mutex);self->locked = false;return self;}STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) {mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]);bool wait = true;if (n_args > 1) {wait = mp_obj_get_int(args[1]);// TODO support timeout arg}MP_THREAD_GIL_EXIT();int ret = mp_thread_mutex_lock(&self->mutex, wait);MP_THREAD_GIL_ENTER();if (ret == -1) {return mp_const_false;} else if (ret == 0) {self->locked = true;return mp_const_true;} else {mp_raise_OSError(-ret);}}STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire);STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) {mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);if (!self->locked) {mp_raise_msg(&mp_type_RuntimeError, NULL);}self->locked = false;MP_THREAD_GIL_EXIT();mp_thread_mutex_unlock(&self->mutex);MP_THREAD_GIL_ENTER();return mp_const_none;}STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release);STATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) {mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);return mp_obj_new_bool(self->locked);}STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked);STATIC mp_obj_t thread_lock___exit__(size_t n_args, const mp_obj_t *args) {(void)n_args; // unusedreturn thread_lock_release(args[0]);}STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock___exit___obj, 4, 4, thread_lock___exit__);//Added by Freddy@20210818 Allows an application to delete a lock, or the lock is deleted when GC reclaims resourcesSTATIC mp_obj_t mod_thread_delete_lock(mp_obj_t args_in) {const mp_obj_type_t *type = mp_obj_get_type(args_in);if(type->name != MP_QSTR_lock){mp_raise_msg(&mp_type_TypeError, MP_ERROR_TEXT("The argument isn't a lock."));}mp_obj_thread_lock_t *lock = MP_OBJ_TO_PTR(args_in);if((mp_thread_mutex_t)NULL != lock->mutex) {mp_thread_mutex_del(&lock->mutex);lock->locked = false;lock->mutex = (mp_thread_mutex_t)NULL;}return mp_const_none;}STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_thread_delete_lock_obj, mod_thread_delete_lock);STATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = {{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_thread_delete_lock_obj) },{ MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) },{ MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) },{ MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) },{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&thread_lock_acquire_obj) },{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&thread_lock___exit___obj) },};STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table);STATIC const mp_obj_type_t mp_type_thread_lock = {{ &mp_type_type },.name = MP_QSTR_lock,.locals_dict = (mp_obj_dict_t *)&thread_lock_locals_dict,};/****************************************************************/// _thread moduleSTATIC mp_obj_t mod_thread_get_ident(void) {return mp_obj_new_int_from_uint((uintptr_t)mp_thread_get_state());}STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_ident_obj, mod_thread_get_ident);STATIC size_t thread_stack_size = MP_THREAD_DEFAULT_STACK_SIZE;STATIC mp_obj_t mod_thread_stack_size(size_t n_args, const mp_obj_t *args) {if (n_args != 0){int stack_size = mp_obj_get_int(args[0]);if (stack_size < 0){return mp_obj_new_int(-1);}if((stack_size * sizeof(uint32_t)) < MP_THREAD_MIN_STACK_SIZE){return mp_obj_new_int(-1);}thread_stack_size = stack_size * sizeof(uint32_t);return mp_obj_new_int(0);}return mp_obj_new_int_from_uint(thread_stack_size / sizeof(uint32_t));}STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_stack_size_obj, 0, 1, mod_thread_stack_size);typedef struct _thread_entry_args_t {mp_obj_dict_t *dict_locals;mp_obj_dict_t *dict_globals;size_t stack_size;mp_obj_t fun;size_t n_args;size_t n_kw;mp_obj_t args[];} thread_entry_args_t;STATIC void *thread_entry(void *args_in) {// Execution begins here for a new thread. We do not have the GIL.thread_entry_args_t *args = (thread_entry_args_t *)args_in;mp_state_thread_t ts;mp_thread_set_state(&ts);mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scanmp_stack_set_limit(args->stack_size);#if MICROPY_ENABLE_PYSTACK// TODO threading and pystack is not fully supported, for now just make a small stackmp_obj_t mini_pystack[128];mp_pystack_init(mini_pystack, &mini_pystack[128]);#endif// set locals and globals from the calling contextmp_locals_set(args->dict_locals);mp_globals_set(args->dict_globals);MP_THREAD_GIL_ENTER();// signal that we are set up and runningmp_thread_start();// TODO set more thread-specific state here:// mp_pending_exception? (root pointer)// cur_exception (root pointer)DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top));nlr_buf_t nlr;if (nlr_push(&nlr) == 0) {mp_call_function_n_kw(args->fun, args->n_args, args->n_kw, args->args);nlr_pop();} else {// uncaught exception// check for SystemExitmp_obj_base_t *exc = (mp_obj_base_t *)nlr.ret_val;if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {// swallow exception silently} else {// print exception outmp_printf(MICROPY_ERROR_PRINTER, "Unhandled exception in thread started by ");mp_obj_print_helper(MICROPY_ERROR_PRINTER, args->fun, PRINT_REPR);mp_printf(MICROPY_ERROR_PRINTER, "\n");mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(exc));}}DEBUG_printf("[thread] finish ts=%p\n", &ts);// signal that we are finishedmp_thread_finish();MP_THREAD_GIL_EXIT();return NULL;}STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) {// This structure holds the Python function and arguments for thread entry.// We copy all arguments into this structure to keep ownership of them.// We must be very careful about root pointers because this pointer may// disappear from our address space before the thread is created.thread_entry_args_t *th_args;// get positional argumentssize_t pos_args_len;mp_obj_t *pos_args_items;mp_obj_get_array(args[1], &pos_args_len, &pos_args_items);// check for keyword argumentsif (n_args == 2) {// just position argumentsth_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len);th_args->n_kw = 0;} else {// positional and keyword argumentsif (mp_obj_get_type(args[2]) != &mp_type_dict) {mp_raise_TypeError(MP_ERROR_TEXT("expecting a dict for keyword args"));}mp_map_t *map = &((mp_obj_dict_t *)MP_OBJ_TO_PTR(args[2]))->map;th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used);th_args->n_kw = map->used;// copy across the keyword argumentsfor (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) {if (mp_map_slot_is_filled(map, i)) {th_args->args[n++] = map->table[i].key;th_args->args[n++] = map->table[i].value;}}}// copy across the positional argumentsth_args->n_args = pos_args_len;memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t));// pass our locals and globals into the new threadth_args->dict_locals = mp_locals_get();th_args->dict_globals = mp_globals_get();// set the stack size to useth_args->stack_size = thread_stack_size;// set the function for thread entryth_args->fun = args[0];// spawn the thread!int thread_id = mp_thread_create(thread_entry, th_args, &th_args->stack_size);return mp_obj_new_int_from_uint((unsigned int)thread_id);}STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread);STATIC mp_obj_t mod_thread_exit(void) {mp_raise_type(&mp_type_SystemExit);}STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit);STATIC mp_obj_t mod_thread_allocate_lock(void) {return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock());}STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock);STATIC mp_obj_t mod_thread_get_heap_size(void){unsigned int res = 0;res = mp_get_available_memory_size();return mp_obj_new_int(res);}STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_get_heap_size_obj, mod_thread_get_heap_size);//删除线程STATIC mp_obj_t mod_thread_stop_thread(mp_obj_t thread_id){Helios_Thread_t curr_id = Helios_Thread_GetID();int th_id = (int)mp_obj_get_int_truncated(thread_id);extern Helios_Thread_t ql_micropython_task_ref;//自己删除自己,先退出线程锁if((curr_id == (Helios_Thread_t)th_id) || (0 == th_id)){th_id = (int)curr_id;//不允许删除主线程if(th_id == ql_micropython_task_ref){mp_raise_ValueError("Deleting the main thread is not allowed!");return mp_obj_new_int(-1);//must not be here}MP_THREAD_GIL_EXIT();}if(mp_thread_finish_by_threadid(th_id)){_vPortCleanUpTCB((void *)th_id);if(curr_id == (Helios_Thread_t)th_id){Helios_Thread_Exit();for(;;){;}}else{Helios_Thread_Delete((Helios_Thread_t)th_id);}return mp_obj_new_int(0);}mp_raise_msg_varg(&mp_type_ValueError, "No thread with thread id %d was found!", th_id);return mp_obj_new_int(-1);//must not be here}STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_thread_stop_thread_obj, mod_thread_stop_thread);STATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = {{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) },{ MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) },{ MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) },{ MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) },{ MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) },{ MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) },{ MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) },{ MP_ROM_QSTR(MP_QSTR_delete_lock), MP_ROM_PTR(&mod_thread_delete_lock_obj) },{ MP_ROM_QSTR(MP_QSTR_get_heap_size), MP_ROM_PTR(&mod_thread_get_heap_size_obj) },{ MP_ROM_QSTR(MP_QSTR_stop_thread), MP_ROM_PTR(&mod_thread_stop_thread_obj) },};STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table);const mp_obj_module_t mp_module_thread = {.base = { &mp_type_module },.globals = (mp_obj_dict_t *)&mp_module_thread_globals,};#endif // MICROPY_PY_THREAD
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。