diff --git a/py/modthread.c b/py/modthread.c index 2420cfc214..01316f9624 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -42,6 +42,73 @@ #define DEBUG_printf(...) (void)0 #endif +/****************************************************************/ +// Lock object + +STATIC 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; + 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(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 + } + int ret = mp_thread_mutex_lock(&self->mutex, wait); + if (ret == 0) { + return mp_const_false; + } else if (ret == 1) { + self->locked = true; + return mp_const_true; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-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); + // TODO check if already unlocked + self->locked = false; + mp_thread_mutex_unlock(&self->mutex); + 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 const mp_rom_map_elem_t thread_lock_locals_dict_table[] = { + { 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) }, +}; + +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 module @@ -149,12 +216,19 @@ STATIC mp_obj_t mod_thread_exit(void) { } 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 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) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table); diff --git a/py/mpthread.h b/py/mpthread.h index bbf27da50d..498380a5e1 100644 --- a/py/mpthread.h +++ b/py/mpthread.h @@ -39,6 +39,9 @@ mp_state_thread_t *mp_thread_get_state(void); void mp_thread_set_state(void *state); void mp_thread_create(void *(*entry)(void*), void *arg, size_t stack_size); +void mp_thread_mutex_init(mp_thread_mutex_t *mutex); +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait); +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex); #endif // MICROPY_PY_THREAD diff --git a/unix/mpthreadport.c b/unix/mpthreadport.c index 73e08dcb86..3a7e3ad4f5 100644 --- a/unix/mpthreadport.c +++ b/unix/mpthreadport.c @@ -76,4 +76,31 @@ er: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ret))); } +void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { + pthread_mutex_init(mutex, NULL); +} + +int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { + int ret; + if (wait) { + ret = pthread_mutex_lock(mutex); + if (ret == 0) { + return 1; + } + } else { + ret = pthread_mutex_trylock(mutex); + if (ret == 0) { + return 1; + } else if (ret == EBUSY) { + return 0; + } + } + return -ret; +} + +void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { + pthread_mutex_unlock(mutex); + // TODO check return value +} + #endif // MICROPY_PY_THREAD