Skip to content
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

Platform support for Embedded targets #106

Merged
merged 124 commits into from
Dec 21, 2022
Merged

Platform support for Embedded targets #106

merged 124 commits into from
Dec 21, 2022

Conversation

lhstrh
Copy link
Member

@lhstrh lhstrh commented Sep 3, 2022

This PR creates runtime support for (bare-iron) single-threaded targets with interrupts.

  • Polish existing NRF52 support

    • Move logic from wait_until to lf_sleep_until
    • Factor lf_sleep_until into smaller functions
  • Settle on API changes

    • Move LF_MIN_SLEEP_DURATION to platform support
    • Remove ARDUINO directive and add NO_TTY or something along those lines
    • ...
  • Merge changes into lock-time

  • Merge main into lock-time

  • General cleanup, comments, and removal of spurious .c-file includes

Fixes #109
Companion of lf-lang/lingua-franca#1348.

@lhstrh lhstrh added the feature New feature label Sep 3, 2022
Copy link
Contributor

@edwardalee edwardalee left a comment

Choose a reason for hiding this comment

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

The strategy you have followed here relies on the compiler to detect physical actions and set NUMBER_WORKERS, choosing the threaded runtime. This is why the functions in lf_os_single_threaded_support.c can be empty. However, this has a downside: It means the mutex mechanism of the unthreaded runtime is essentially untested. In fact, I have my doubts it is correct. The mutex is held only for very short times compared to the threaded runtime. Seems like there is real risk of lurking race conditions(?).

Only the Arduino is using this, and that doesn't look correct to me because _lf_timer_interrupted seems to never get reset. Do we have any way to test the Arduino implementation?

What I had in mind was to actually allow physical actions with the unthreaded runtime. This means the mutex acquisition and release should closely mimic (or exactly match) what reactor_threaded.c does. This also means we could have regression tests that have physical actions with the unthreaded runtime running on all the platforms.

core/platform/lf_linux_support.c Outdated Show resolved Hide resolved
core/platform/lf_os_single_threaded_support.c Show resolved Hide resolved
core/platform/lf_arduino_support.c Outdated Show resolved Hide resolved
core/reactor.c Show resolved Hide resolved
core/reactor.c Outdated Show resolved Hide resolved
@edwardalee
Copy link
Contributor

It's been a while since I looked at this code, but I think the new API for entering a critical section will take care of a big part of the problem, which is that tracing calls write to a common data structure. Alternatively, this could be refactored to have a separate data structure per worker. I think the reason for needing to create a thread is to write to a file when the data structure fills up. I guess this could be handled differently in the unthreaded runtime with conditional code.

@erlingrj
Copy link
Collaborator

erlingrj commented Dec 11, 2022

It's been a while since I looked at this code, but I think the new API for entering a critical section will take care of a big part of the problem, which is that tracing calls write to a common data structure. Alternatively, this could be refactored to have a separate data structure per worker. I think the reason for needing to create a thread is to write to a file when the data structure fills up. I guess this could be handled differently in the unthreaded runtime with conditional code.

OK, so you are saying that if we are using the unthreaded runtime with tracing enabled, critical_section_enter() should result in acquiring a global mutex, which is also acquired by the tracing thread? This is not implemented as of now. Actually, in the unthreaded runtime, critical_section_enter() does nothing. I guess it should at least disable interrupts.

I don't see the place in trace.c where we are accessing a data structure shared with the runtime. I.e. where is trace.c calling critical_section_enter()

@erlingrj
Copy link
Collaborator

@lhstrh. After a converation with @edwardalee about tracing today I have concluded that the current implementation is sufficient. The tracing only needs to synchronize access "internally". This is done with a mutex local to tracing.c. It seemed to be an edge case when we had unthreaded+tracing. But I don't think it matters. How it looks is like this:

From all the source files including plaform.h EXCEPT tracing.c will see the unthreaded API and its implementation of critical section etc. For the single source file tracing.c it will see the threaded API (and its implementation, the function definitions are in the header files as well). So when we do some tracing the program will call into tracing.c and during that period it will get access to the threaded API and can synchronize with the flushing thread.

I will do a pass through the PR and address Edwards comments and fix what I see, then I guess we could do a final review and merge?


/**
* @brief Sleep until an absolute time.
* FIXME: For improved power consumption this should be implemented with a HW timer and interrupts.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, sleep until is for internal use only and should only be called from a critical section, while advancing time. Maybe the API should be: _lf_sleep_until_locked?

return 0;
}

int lf_critical_section_enter() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for suggestion will add this!

* set appropriately (see `man 2 clock_gettime`).
*/
int lf_clock_gettime(instant_t* t) {
if (t == NULL) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good idea

core/reactor.c Show resolved Hide resolved
include/core/platform.h Outdated Show resolved Hide resolved
Copy link
Member Author

@lhstrh lhstrh left a comment

Choose a reason for hiding this comment

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

Left some comments...

core/platform/lf_arduino_support.c Outdated Show resolved Hide resolved
core/platform/lf_arduino_support.c Outdated Show resolved Hide resolved
include/core/platform.h Outdated Show resolved Hide resolved
core/platform/lf_arduino_support.c Show resolved Hide resolved
core/platform/lf_nrf52_support.c Outdated Show resolved Hide resolved
core/threaded/reactor_threaded.c Outdated Show resolved Hide resolved
core/trace.c Outdated
@@ -29,14 +29,19 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Include this file instead of trace.h to get tracing.
* See trace.h file for instructions.
*/

// FIXME: Should be renamed if we use the hack below maybe: LF_INCLUDE_TRACE_FILES
Copy link
Member Author

Choose a reason for hiding this comment

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

Also this FIXME should not be left unaddressed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes. My suggestion is to call it LF_TRACE, and the macro below can be called _LF_TRACE. The second macro should never be messed with by the user and is only for getting the threaded API from platform.h even if the unthreaded runtime is used

@@ -42,8 +42,20 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef PLATFORM_H
#define PLATFORM_H

#if defined(ARDUINO)
// FIXME: We could also use a single flag since this is truly binary
Copy link
Member Author

Choose a reason for hiding this comment

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

?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I will remove the fixme. I think it is okay to have 2 flags (THREADED and UNTHREADED)

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, that sounds confusing though. What if both are true?

core/trace.c Outdated Show resolved Hide resolved
include/core/platform/lf_nrf52_support.h Outdated Show resolved Hide resolved
erlingrj and others added 2 commits December 19, 2022 09:25
Co-authored-by: Marten Lohstroh <marten@berkeley.edu>
@edwardalee
Copy link
Contributor

What is the status of this lock-time PR?

@lhstrh
Copy link
Member Author

lhstrh commented Dec 21, 2022

It's almost ready, but there are still a few small things that need @erlingrj's attention (comments ☝️). Once addressed, we can merge.

@@ -42,8 +42,20 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef PLATFORM_H
#define PLATFORM_H

#if defined(ARDUINO)
// FIXME: We could also use a single flag since this is truly binary
Copy link
Collaborator

Choose a reason for hiding this comment

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

I will remove the fixme. I think it is okay to have 2 flags (THREADED and UNTHREADED)

include/core/platform.h Outdated Show resolved Hide resolved
core/trace.c Outdated Show resolved Hide resolved
core/trace.c Show resolved Hide resolved
#else
#include "lf_C11_threads_support.h"
#endif
#include "lf_os_single_threaded_support.c"
Copy link
Collaborator

Choose a reason for hiding this comment

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

The Windows implementation is moved to its header-file (like it is for macOS and Linux). This makes it possible to have both the threaded and the unthreaded API present in the same binary.

core/threaded/reactor_threaded.c Outdated Show resolved Hide resolved
core/trace.c Outdated
@@ -29,14 +29,19 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Include this file instead of trace.h to get tracing.
* See trace.h file for instructions.
*/

// FIXME: Should be renamed if we use the hack below maybe: LF_INCLUDE_TRACE_FILES
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes. My suggestion is to call it LF_TRACE, and the macro below can be called _LF_TRACE. The second macro should never be messed with by the user and is only for getting the threaded API from platform.h even if the unthreaded runtime is used

core/trace.c Outdated Show resolved Hide resolved
core/platform/lf_arduino_support.c Outdated Show resolved Hide resolved
#endif

int lf_critical_section_enter() {
// FIXME: Is this what we want? Dont we want to grab a mutex here?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the unthreaded runtime + Linux is intended to be a very special case where you should not use other threads to schedule physical actions. I think the macro above would catch such a scenario. I think we can close this for now. I will remove the fixme

@lhstrh lhstrh merged commit d97620b into main Dec 21, 2022
@lhstrh lhstrh deleted the lock-time branch December 21, 2022 22:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make threshold for sleeping platform dependent
5 participants