Skip to content

Nanostack hal timer shortcut #6627

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

Merged
merged 2 commits into from
Apr 17, 2018

Conversation

TeroJaasko
Copy link
Contributor

Description

nanostack-hal: timer: conditionalize the use of high pri event thread

nanostack-hal.critical-section-usable-from-interrupt -tunable was
previously added to optionally make critical section code interrupt safe.
The IRQ safe critical section is a prequisite for interrupt safe timer
callbacks.

The same flag can be used to enable calling of the timer callbacks
directly from the timer interrupt context, without bouncing them via
event thread. This removes the code and RAM consumed by EventQueue
and the thread serving the high priority events.

If the system does not have any dependencies on mbed_shared_queues,
by setting this flag the static RAM usage is now further reduced
by ~1600 bytes and code size by 4KB.

Note: the default behavior is not changed, one needs to override the
"nanostack-hal.critical-section-usable-from-interrupt" to have "true".

Pull request type

[x ] Fix
[ ] Refactor
[ ] New target
[ ] Feature
[ ] Breaking change

@TeroJaasko
Copy link
Contributor Author

This PR is something between a fix and feature, as it improves a existing feature. Discussed already about this with @kjbracey-arm

@@ -12,15 +12,25 @@

static Timer timer;
static Timeout timeout;

// High priority event queue is needed if the timer callback is not interrupt safe or the
// critical section implementation is not disabling interrupts.
Copy link
Contributor

Choose a reason for hiding this comment

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

Phrasing is a bit wonky above - this isn't an "or". If the critical section is not disabling interrupts, then it must be claiming a mutex, which means the timer callback is not interrupt safe, and any other code doing critical sections won't be protected against a called-from-interrupt timer.

Maybe something like

// If critical sections are implemented using mutexes, timers must be called in thread context, and
// we use the high-priority event queue for this.
// If critical sections disable interrupts, we can call timers directly from interrupt. Avoiding the
// event queue can save ~1600B of RAM if the rest of the system is not using the event queue either.
// Caveats of this tunable are listed on arm_hal_interrupt.c.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Your version is much better, changed to it and force pushed.

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 13, 2018

@kjbracey-arm if its between, should it rather be feature and 5.9 ? Although looking at the changes, it does not change anything by default, just provides new configuration.

@kjbracey
Copy link
Contributor

kjbracey commented Apr 13, 2018

It's not adding a new option, it's further optimising what happens when that option is on.

Option was new in 5.8, and Tero's bunch are probably the only current users. Saves memory, but with a bunch of caveats.

It's not a fix, it is an effective change to behaviour - this timer is now called from interrupt context, not thread context. That matches the intent of the option and the stated caveats, and /should/ be fine for correctly-written Nanostack code that only does eventOS_event_send or similar, but conceivably might not be.

I'd call it a refactor - won't actually fix any visible bugs, but will save memory, with the usual slim chance of app breakage. App breakage that could only occur with the option on, mind.

nanostack-hal.critical-section-usable-from-interrupt -tunable was
previously added to optionally make critical section code interrupt safe.
The IRQ safe critical section is a prequisite for interrupt safe timer
callbacks.

The same flag can be used to enable calling of the timer callbacks
directly from the timer interrupt context, without bouncing them via
event thread. This removes the code and RAM consumed by EventQueue
and the thread serving the high priority events.

If the system does not have any dependencies on mbed_shared_queues,
by setting this flag the static RAM usage is now further reduced
by ~1600 bytes and code size by 4KB.

Note: the default behavior is not changed, one needs to override the
"nanostack-hal.critical-section-usable-from-interrupt" to have "true".
Compiler reminded that a variable declaration was left behind when
the code using it was put behind #ifdef. Add the missing #ifdef.

Warning being fixed:
---8<---8<----
[Warning] ns_event_loop.c@44,0:  ARMmbed#177-D: variable "event_thread_id"
was declared but never referenced
@TeroJaasko TeroJaasko force-pushed the nanostack_hal_timer_shortcut branch from 4b157e0 to a23b7cf Compare April 13, 2018 10:51
@kjbracey
Copy link
Contributor

Still worth trying the "ticker" mode option, as discussed, which cuts this code out entirely. Not sure if that would actually save significant (or any) extra memory or not

@kjbracey
Copy link
Contributor

Looking at this, I'm nervous there's no error check on the equeue->call. Would an MBED_ASSERT on it do something legible from interrupt context? I guess it should.

@TeroJaasko
Copy link
Contributor Author

MBED_ASSERT() seems to able to print the correct message even from interrupt. The assert(false) in timer_callback() seems to dump just a "Error - writing to a file in an ISR or critical section". See the trace below. I never realized they actually had functional difference. One learns something new every day. :)

I'm also in favour of some kind of assert() as it would help in tuning the queue size to match the worst case load. But it might also be a bit harsh for users who are perfectly fine with lost timer interrupts. On the other hand, debugging a system with unexpectedly and silently lost timer callbacks is just horrible.

Adding assertion there sounds to me same kind compatibility break as the recent "Mutex xxxx error -6. Not allowed in ISR context" trap which did point out valid bugs in existing code, but which also forced application to change.

0  mbed_die () at ./mbed-os/platform/mbed_board.c:29
#1  0x00027baa in _exit (return_code=1) at ./mbed-os/platform/mbed_retarget.cpp:1117
#2  0x00027bba in __wrap_exit (return_code=<optimized out>) at ./mbed-os/platform/mbed_retarget.cpp:1168
#3  0x000279c0 in error (format=0x49198 "Error - writing to a file in an ISR or critical section\r\n") at ./mbed-os/platform/mbed_error.c:42
#4  0x00027e00 in _write (fh=2, buffer=0x4ad58 "assertion \"%s\" failed: file \"%s\", line %d%s%s\n", length=11, mode=<optimized out>) at ./mbed-os/platform/mbed_retarget.cpp:517
#5  0x000357fa in _write_r ()
#6  0x0002dff2 in __sfvwrite_r ()
#7  0x00033280 in __sprint_r.part.0 ()
#8  0x00033c04 in _vfiprintf_r ()
#9  0x0002dd08 in fiprintf ()
#10 0x0002d90a in __assert_func ()
#11 0x0001ef16 in timer_callback () at ./mbed-os/features/FEATURE_COMMON_PAL/nanostack-hal-mbed-cmsis-rtos/arm_hal_timer.cpp:57
#12 0x0001a97c in mbed::Callback<void ()>::function_call<void (*)()>(void const*) (p=<optimized out>) at ./mbed-os/platform/Callback.h:603
#13 0x0001ae42 in mbed::Callback<void ()>::call() const (this=0x2002ff88) at ./mbed-os/platform/Callback.h:529
#14 mbed::Timeout::handler (this=0x46464) at ./mbed-os/drivers/Timeout.cpp:23
#15 0x0001afc2 in mbed::TimerEvent::irq (id=<optimized out>) at ./mbed-os/drivers/TimerEvent.cpp:35
#16 0x00027116 in ticker_irq_handler (ticker=0x48f34 <us_data>) at ./mbed-os/hal/mbed_ticker_api.c:289
#17 0x000271f8 in us_ticker_irq_handler () at ./mbed-os/hal/mbed_us_ticker_api.c:54
#18 0x0002cac6 in pit_isr () at ./mbed-os/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/us_ticker.c:31

@kjbracey
Copy link
Contributor

Yeah, assert tries to print the thing to stderr and call abort, as specified by the C standard. You can't use stderr from interrupt/exception, so won't fly and MBED_ASSERT fills that gap. It still needs to be upgraded to be console-independent (and we need exception-safe UARTSerial to support that).

You're right, this could well break applications silently getting away with it, so maybe don't do it now. I was thinking the primary user was the tick generation, which if it failed would kill the event loop forever, so would have already been noticed, but there are other high-res timer users. (Not in your system, but with Nanostack).

@0xc0170
Copy link
Contributor

0xc0170 commented Apr 16, 2018

/morph build

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

Build : SUCCESS

Build number : 1754
Build artifacts/logs : http://mbed-os.s3-website-eu-west-1.amazonaws.com/?prefix=builds/6627/

Triggering tests

/morph test
/morph uvisor-test
/morph export-build
/morph mbed2-build

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

@mbed-ci
Copy link

mbed-ci commented Apr 16, 2018

@cmonr
Copy link
Contributor

cmonr commented Apr 16, 2018

Echo test completed too fast, apparently.

Relaunching.
/morph test

@mbed-ci
Copy link

mbed-ci commented Apr 17, 2018

@cmonr cmonr merged commit 853384a into ARMmbed:master Apr 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants