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

FunctionalInterrupt/ScheduledFunctions should be in a library, not in core_esp8266_wiring_digital #6038

Closed
wants to merge 24 commits into from

Conversation

dok-net
Copy link
Contributor

@dok-net dok-net commented May 2, 2019

After mulling over the situation with the pending PR #6003 , I have rewritten the support for std::functional and scheduled interrupts to be less intrusive.
First, the support is revoked. Second, the refactored code is brought back as an example in libraries/esp8266/examples/GPIO/FunctionalInterrupt.
I have unified the code with the ESP32 version: espressif/arduino-esp32#2734

dok-net added 3 commits May 2, 2019 09:21
…ndling:

- VIP treatment in general attach/detach/handling looks untidy:
  extern symbols without matching header include but copy&paste
  special under-the-hood c++ delete support, where everyone else has to do their own
  resource tracking as usual.
- FunctionalInterrupt is not used by anything inside core ESP8266 Arduino for 2 years now,
  it can be a library, which reduces precious core size for everyone else.

Expose attachInterruptArg via Arduino.h.
It should be decided whether to reinstate these in the core, or make them an optional library.
@dok-net
Copy link
Contributor Author

dok-net commented May 2, 2019

@hreintke I should not have missed anything, so it's working as before, and bringing back the functional interrupts in one way or the other is basically a matter of changing the locations of the files, and altering #include's "" back to <>. What do you think? What about your review of my exposing attachInterruptArg(), that PR is still pending, causing me some daily grievance in my library work :-)

@devyte devyte self-requested a review May 2, 2019 11:59
@hreintke
Copy link
Contributor

hreintke commented May 2, 2019

@dok-net @devyte
I will review but, unless I missed something in my first quick review, this is not backward compatible with the current implementation.

Is is correct that in your implementation all support for functional and scheduled scheduled interrupt is removed from core and a "user" needs to create it's own ? (Eventually using the example code)

@dok-net
Copy link
Contributor Author

dok-net commented May 2, 2019

Let me first put into perspective what I believe is the state in the present master branch:

  • attachInterruptArg() is not exposed in the API, for good measure, because:
  • __attachInterruptArg must not be used directly, as that would expose the bug where cleanupFunctional(void* arg), linked as external against the next best definition in the depths of the build tree, without checks, casts void* interrupt_handler_t::arg to ArgStructure* and deletes that ostensible object and the members thereof.
    Or putting more easily, FunctionalInterrupt.h is the only safe access to attachInterruptArg.

I have some reservations regarding the MT safety of the implementation of FunctionalInterrupt.h/ScheduledFunctions.h, especially on ESP32 where there is a possibility to run without core affinity. But even for single core all-userspace interrupts without atomic access, I am not so sure.

As regards your question concerning backward compatibility of this PR, only in the context of PR #6003 which fixes the interoperability between FunctionalInterrupt and direct use of attachInterruptArg(), without further work there is a need for the user to use, either one or the other, the attachInterrupt/attachInterrruptArg/detatchInterrupt functions from Arduino.h directly, or stick completely to the FunctionalInterrupt.h wrappers. This is because the interrupt handling in core now has no way of telling what type of objects are behind the arg pointer, thus in general, leaking them on detach.

Depending on the outcome of this discussion, it is my understanding, that there is nothing keeping us from creating a new library that provides FunctionalInterrupt and friends. Or if so decided, the files can be moved back into cores/esp8266 after addressing the mentioned shortcomings if any, and pointing the Arduino.h entry points in attachInterrupt et al at implementations in FunctionalInterrupt and "hiding" those in core_exp8266_wiring_digital.*. The same can be applied accordingly to ESP32.

My take on the matter is that right now I am perfectly happy with explicitly managing the argument objects's lifetimes in user code. Probably we could also use std::function objects in interrupt_handler_t for a cleaner solution than what I perceive is in core right now.

Let me ask a final question, I don't quite seem to understand how ScheduledFunctions works right now without the user code always having to call ScheduledFunctions::runScheduledFunctions() explicitly in loop()?

@d-a-v
Copy link
Collaborator

d-a-v commented May 2, 2019

Let me ask a final question, I don't quite seem to understand how ScheduledFunctions works right now without the user code always having to call ScheduledFunctions::runScheduledFunctions() explicitly in loop()?

It is run there (meaning: at very arduino main loop())
(#6039 would like to change that: at every yield())

@d-a-v
Copy link
Collaborator

d-a-v commented May 2, 2019

[...] there is a possibility to run without core affinity

Scheduled Functions are meant to be run outside from any callback / interrupt state.
This is to ensure "Atomic access" or any locking facility is not needed.

@hreintke
Copy link
Contributor

hreintke commented May 2, 2019

@dok-net @d-a-v :
The files ScheduledFunctions.h and .cpp can/should be removed.
It is/was an attemp to generalize the current schedule_function(...) and by accident included in the ScheduledInterrupt patch.

dok-net added a commit to dok-net/arduino-esp32 that referenced this pull request May 2, 2019
dok-net added 3 commits May 2, 2019 22:34
…n attachInterruptArg().

This is sufficient for resource management - the function has static duration anyway.
@dok-net dok-net force-pushed the functional-shouldbe-lib branch from aac1cdd to f89b22c Compare May 3, 2019 12:32
@dok-net
Copy link
Contributor Author

dok-net commented May 3, 2019

Any use of std::bind or std::functional objects is not ICACHE_RAM interrupt service routine policy compliant. The whole debate over FunctionalInterrupts, except the scheduled ones, is moot for this reason. Even if the check implemented in attachInterrupt doesn't catch the error, does not mean it's not inherent.
So, until lambdas, std::bind, std::function can handle the ICACHE_RAM attribute, the only "legal" use of the FunctionalInterrupt.h/cpp is for scheduled handler, which are only dropped into the scheduler, but get called outside of the ISR context. This is fine.
I vote for merging this PR instead of #6003, but certainly not doing anything about the situation seems completely wrong to me.

// Arduino C API:
attachInterruptArg(PIN, [](void* self) {
static_cast<Button*>(self)->isr();
}, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any use of std::bind, std::function or lambdas in the code-path of ISRs in fact is a case of ISR not in IRAM, just like this, only wrapped in some other functions.

//attachInterruptArg(PIN, reinterpret_cast<void(*)(void*)>(&isr_static), this, FALLING); // works on ESP32; works on ESP8266
// FunctionalInterrupts API:
//attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266
//attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { Serial.print("Pin "); Serial.println(ii.pin); isr(); }, FALLING); // works on ESP32; works on ESP8266
Copy link
Contributor Author

@dok-net dok-net May 3, 2019

Choose a reason for hiding this comment

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

This attachScheduledInterrupt() is a valid use of std::bind, std::function or lambdas, since the actual call is made in the context of the task that runs the scheduler, not in a interrupt service routine.

dok-net added a commit to dok-net/arduino-esp8266 that referenced this pull request Oct 22, 2020
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