Skip to content

Commit 801d1b3

Browse files
committed
py/modthread: Implement lock object, for creating a mutex.
1 parent 2dacd60 commit 801d1b3

3 files changed

Lines changed: 104 additions & 0 deletions

File tree

py/modthread.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,73 @@
4242
#define DEBUG_printf(...) (void)0
4343
#endif
4444

45+
/****************************************************************/
46+
// Lock object
47+
48+
STATIC const mp_obj_type_t mp_type_thread_lock;
49+
50+
typedef struct _mp_obj_thread_lock_t {
51+
mp_obj_base_t base;
52+
mp_thread_mutex_t mutex;
53+
bool locked;
54+
} mp_obj_thread_lock_t;
55+
56+
STATIC mp_obj_thread_lock_t *mp_obj_new_thread_lock(void) {
57+
mp_obj_thread_lock_t *self = m_new_obj(mp_obj_thread_lock_t);
58+
self->base.type = &mp_type_thread_lock;
59+
mp_thread_mutex_init(&self->mutex);
60+
self->locked = false;
61+
return self;
62+
}
63+
64+
STATIC mp_obj_t thread_lock_acquire(size_t n_args, const mp_obj_t *args) {
65+
mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(args[0]);
66+
bool wait = true;
67+
if (n_args > 1) {
68+
wait = mp_obj_get_int(args[1]);
69+
// TODO support timeout arg
70+
}
71+
int ret = mp_thread_mutex_lock(&self->mutex, wait);
72+
if (ret == 0) {
73+
return mp_const_false;
74+
} else if (ret == 1) {
75+
self->locked = true;
76+
return mp_const_true;
77+
} else {
78+
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-ret)));
79+
}
80+
}
81+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(thread_lock_acquire_obj, 1, 3, thread_lock_acquire);
82+
83+
STATIC mp_obj_t thread_lock_release(mp_obj_t self_in) {
84+
mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);
85+
// TODO check if already unlocked
86+
self->locked = false;
87+
mp_thread_mutex_unlock(&self->mutex);
88+
return mp_const_none;
89+
}
90+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_release_obj, thread_lock_release);
91+
92+
STATIC mp_obj_t thread_lock_locked(mp_obj_t self_in) {
93+
mp_obj_thread_lock_t *self = MP_OBJ_TO_PTR(self_in);
94+
return mp_obj_new_bool(self->locked);
95+
}
96+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(thread_lock_locked_obj, thread_lock_locked);
97+
98+
STATIC const mp_rom_map_elem_t thread_lock_locals_dict_table[] = {
99+
{ MP_ROM_QSTR(MP_QSTR_acquire), MP_ROM_PTR(&thread_lock_acquire_obj) },
100+
{ MP_ROM_QSTR(MP_QSTR_release), MP_ROM_PTR(&thread_lock_release_obj) },
101+
{ MP_ROM_QSTR(MP_QSTR_locked), MP_ROM_PTR(&thread_lock_locked_obj) },
102+
};
103+
104+
STATIC MP_DEFINE_CONST_DICT(thread_lock_locals_dict, thread_lock_locals_dict_table);
105+
106+
STATIC const mp_obj_type_t mp_type_thread_lock = {
107+
{ &mp_type_type },
108+
.name = MP_QSTR_lock,
109+
.locals_dict = (mp_obj_dict_t*)&thread_lock_locals_dict,
110+
};
111+
45112
/****************************************************************/
46113
// _thread module
47114

@@ -149,12 +216,19 @@ STATIC mp_obj_t mod_thread_exit(void) {
149216
}
150217
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_exit_obj, mod_thread_exit);
151218

219+
STATIC mp_obj_t mod_thread_allocate_lock(void) {
220+
return MP_OBJ_FROM_PTR(mp_obj_new_thread_lock());
221+
}
222+
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_thread_allocate_lock_obj, mod_thread_allocate_lock);
223+
152224
STATIC const mp_rom_map_elem_t mp_module_thread_globals_table[] = {
153225
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__thread) },
226+
{ MP_ROM_QSTR(MP_QSTR_LockType), MP_ROM_PTR(&mp_type_thread_lock) },
154227
{ MP_ROM_QSTR(MP_QSTR_get_ident), MP_ROM_PTR(&mod_thread_get_ident_obj) },
155228
{ MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&mod_thread_stack_size_obj) },
156229
{ MP_ROM_QSTR(MP_QSTR_start_new_thread), MP_ROM_PTR(&mod_thread_start_new_thread_obj) },
157230
{ MP_ROM_QSTR(MP_QSTR_exit), MP_ROM_PTR(&mod_thread_exit_obj) },
231+
{ MP_ROM_QSTR(MP_QSTR_allocate_lock), MP_ROM_PTR(&mod_thread_allocate_lock_obj) },
158232
};
159233

160234
STATIC MP_DEFINE_CONST_DICT(mp_module_thread_globals, mp_module_thread_globals_table);

py/mpthread.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
mp_state_thread_t *mp_thread_get_state(void);
4040
void mp_thread_set_state(void *state);
4141
void mp_thread_create(void *(*entry)(void*), void *arg, size_t stack_size);
42+
void mp_thread_mutex_init(mp_thread_mutex_t *mutex);
43+
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait);
44+
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex);
4245

4346
#endif // MICROPY_PY_THREAD
4447

unix/mpthreadport.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,31 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t stack_size) {
7676
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ret)));
7777
}
7878

79+
void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
80+
pthread_mutex_init(mutex, NULL);
81+
}
82+
83+
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
84+
int ret;
85+
if (wait) {
86+
ret = pthread_mutex_lock(mutex);
87+
if (ret == 0) {
88+
return 1;
89+
}
90+
} else {
91+
ret = pthread_mutex_trylock(mutex);
92+
if (ret == 0) {
93+
return 1;
94+
} else if (ret == EBUSY) {
95+
return 0;
96+
}
97+
}
98+
return -ret;
99+
}
100+
101+
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
102+
pthread_mutex_unlock(mutex);
103+
// TODO check return value
104+
}
105+
79106
#endif // MICROPY_PY_THREAD

0 commit comments

Comments
 (0)