Skip to content

Timed lock aquisition #5599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed

Conversation

mcdeoliveira
Copy link

This PR handles the timeout parameter in thread_lock_acquire.

It provides a set of compilation flags, tests, and an implementation for the unix and the esp32 ports. Other ports based on freertos should be easy to implement based on the esp32 port, because freertos lock_acquire already handles the timeout parameter. Unfortunately I do not have access to other hardware, so I think it is better to leave to others the task of replicating the functionality on other ports.

Let me just add a word about the relevance of handling the timeout parameter in lock_acquire. The only feature used by the current CPython implementation of threading.py that is nor yet supported by _thread is precisely a call to lock_acquire with a timeout parameter. In fact, a _thread_lock_acquire with timeout is issued in RLock and all subsequent classes in threading.py are based on RLock! Implementing the timeout parameter essentially enables a micropython version of Threading.

@dpgeorge
Copy link
Member

dpgeorge commented Feb 1, 2020

Thanks for the contribution. In general I'd be supportive of adding this feature. But please see previous discussion about this at #3332, and also try to fix the Travis CI failures.

Copy link
Contributor

@dlech dlech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see this getting implemented. 😄

I also like the suggestion of just modifying mp_thread_mutex_lock instead of adding a new mp_thread_mutex_lock_timed function. This would simplify things a bit.

@@ -123,6 +123,7 @@
#define MICROPY_PY_THREAD (1)
#define MICROPY_PY_THREAD_GIL (1)
#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32)
#define MICROPY_PY_THREAD_TIMEDLOCK (1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to name this after the python feature rather than the posix thread feature, e.g. MICROPY_PY_THREAD_LOCK_TIMEOUT

@@ -123,6 +123,9 @@ ifeq ($(MICROPY_PY_THREAD),1)
CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
LDFLAGS_MOD += $(LIBPTHREAD)
endif
ifeq ($(MICROPY_PY_THREAD_TIMEDLOCK),1)
Copy link
Contributor

@dlech dlech Feb 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new configuration option doesn't really need to be in the Makefile. It could go in mpconfigport.h instead.

The only reason MICROPY_PY_THREAD is in the Makefile is because it affects the compiler flags.

#ifdef MICROPY_PY_THREAD_TIMEDLOCK
ret = mp_thread_mutex_lock_timed(&self->mutex, timeout);
#else
mp_raise_ValueError("timeout not supported");

This comment was marked as resolved.

struct timeval _timeval;
struct timezone _timezone;
gettimeofday(&_timeval, &_timezone);
uint32_t _timeout_nano = ((uint32_t) (1e9*timeout)) + 1000 * _timeval.tv_usec;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe do the float conversion like ports/unix/modtime.c?

    struct timeval tv;
    mp_float_t val = mp_obj_get_float(arg);
    double ipart;
    tv.tv_usec = round(modf(val, &ipart) * 1000000);
    tv.tv_sec = ipart;

Otherwise, _timeout_nano probably needs to be uint64_t

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the updated version I am handling the float to int conversion in modthread.c and passing an int number of milliseconds to mp_thread_mutex_lock_timeout. See my comment regarding whether one should support int and float as timeout argument.

Regarding the overflow issue, the updated version is safe with uint32_t because _timeout_nano will always be smaller than 2 seconds.

@@ -0,0 +1,34 @@
# test timed _thread lock object using a single thread
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this say "multiple threads" instead of "single thread"?

@mcdeoliveira
Copy link
Author

Glad to see this getting implemented.

I also like the suggestion of just modifying mp_thread_mutex_lock instead of adding a new mp_thread_mutex_lock_timed function. This would simplify things a bit.

The one problem I see with this is that mp_thread_mutex_lock is used a lot throughout the code and I am afraid a change here could leave some undetected side effects. The semantics of the call would be different and a wait of 1 would have to be changed to a negative timeout_ms. How about something like this:

#ifdef MICROPY_PY_THREAD_LOCK_TIMEOUT
int mp_thread_mutex_lock_timed(mp_thread_mutex_t *mutex, int timeout_ms);
#define mp_thread_mutex_lock(mutex, wait) mp_thread_mutex_lock_timed(mutex, wait ? -1 : 0 )
#else
int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait);
#endif

This way the existing calls to mp_thread_mutex_lock would continue to be valid and ports supporting the timed option would only have to implement one function.

@mcdeoliveira
Copy link
Author

Glad to see this getting implemented.

I also like the suggestion of just modifying mp_thread_mutex_lock instead of adding a new mp_thread_mutex_lock_timed function. This would simplify things a bit.

Thanks for all the great suggestions!

- label as mp_thread_mutex_lock_timeout
- change signature to avoid handling floats on the ports
- fixing possible overflow in unix port implementation
- removing changes in Makefile for unix port
- implementation for cc3200
- no longer raising exception when GIL lock is released
@mcdeoliveira
Copy link
Author

Thanks for the contribution. In general I'd be supportive of adding this feature. But please see previous discussion about this at #3332, and also try to fix the Travis CI failures.

The only failure at Travis CI after the update is the growth in core size in the "bare-arm and minimal ports" build.

@dpgeorge I also have a question regarding thread safety in micropython. The first four concurrency tests, the mutate_* files, in the thread testing directory all fail. I was under the impression that the GIL would automatically prevent concurrent data access but this does not seem to be the case. Should that be fixed with a local mutex. Any thoughts?

Finally, the other test that fails is thread_exc2.py. This one seems to be hard to perform because the output produced by the uncaught exception will vary depending on the python version you're using.

Copy link
Author

@mcdeoliveira mcdeoliveira left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going from ms to us. ms timeout can be too inaccurate if used in clocks or timers that have ms periods. Tradeoff is the maximum timeout encoded with ints. For 32 bits ints should give a maximum of 2147 seconds. 16 bits could be problematic. Perhaps the signature should explicitly have int32_t.

@dpgeorge
Copy link
Member

@mcdeoliveira thanks for the effort on this and sorry it got left behind. I'll close this PR for now, but feel free to reopen if you're still interested to work on it and take into account the comment #3332 (comment)

@dpgeorge dpgeorge closed this Nov 17, 2021
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Nov 19, 2021
…n-main

Translations update from Hosted Weblate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants