I'm trying to set up a hardware interrupt handler in protected mode, using djgpp-2 for compiling in dosbox-0.74. Here's the smallest code possible (timer interrupt), I guess:
#include <dpmi.h>
#include <go32.h>
#include <stdio.h>
unsigned int counter = 0;
void handler(void) {
++counter;
}
void endHandler(void) {}
int main(void) {
_go32_dpmi_seginfo oldInfo, newInfo;
_go32_dpmi_lock_data(&counter, sizeof(counter));
_go32_dpmi_lock_code(handler, endHandler - handler);
_go32_dpmi_get_protected_mode_interrupt_vector(8, &oldInfo);
newInfo.pm_offset = (int) handler;
newInfo.pm_selector = _go32_my_cs();
_go32_dpmi_allocate_iret_wrapper(&newInfo);
_go32_dpmi_set_protected_mode_interrupt_vector(8, &newInfo);
while (counter < 3) {
printf("%u\n", counter);
}
_go32_dpmi_set_protected_mode_interrupt_vector(8, &oldInfo);
_go32_dpmi_free_iret_wrapper(&newInfo);
return 0;
}
Note that I'm not chaining my handler but replacing it. The counter won't increase beyond 1 (therefore never stopping the main loop) making me guess that the handler doesn't return correctly or is called only once. Chaining on the other hand works fine (remove the wrapper-lines and replace set_protected_mode with chain_protected_mode).
Am I missing a line?
You need to chain the old interrupt handler, like in the example Jonathon Reinhart linked to in the documentation, as the old handler will tell the interrupt controller to stop asserting the interrupt. It will also have the added benefit of keeping the BIOS clock ticking, so it doesn't lose a few seconds each time you run the program. Otherwise when your interrupt handler returns the CPU will immediately call the handler again and your program will get stuck in an infinite loop.
Also there's no guarantee that GCC will place endHandler after handler. I'd recommend just simply locking both the page handler starts on and the next page in case it straddles a page:
_go32_dpmi_lock_code((void *) handler, 4096);
Note the cast is required here, as there's no automatic conversion from pointer to a function types to pointer to void.
Related
Suppose I wanted to implement a mechanism for calling a piece of code exactly once (e.g. for initialization purposes), even when multiple threads hit the call site repeatedly. Basically, I'm trying to implement something like pthread_once, but with GCC atomics and spin-locking. I have a candidate implementation below, but I'd like to know if
a) it could be faster in the common case (i.e. already initialized), and,
b) is the selected memory ordering strong enough / too strong?
Architectures of interest are x86_64 (primarily) and aarch64.
The intended use API is something like this
void gets_called_many_times_from_many_threads(void)
{
static int my_once_flag = 0;
if (once_enter(&my_once_flag)) {
// do one-time initialization here
once_commit(&my_once_flag);
}
// do other things that assume the initialization has taken place
}
And here is the implementation:
int once_enter(int *b)
{
int zero = 0;
int got_lock = __atomic_compare_exchange_n(b, &zero, 1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
if (got_lock) return 1;
while (2 != __atomic_load_n(b, __ATOMIC_ACQUIRE)) {
// on x86, insert a pause instruction here
};
return 0;
}
void once_commit(int *b)
{
(void) __atomic_store_n(b, 2, __ATOMIC_RELEASE);
}
I think that the RELAXED ordering on the compare exchange is okay, because we don't skip the atomic load in the while condition even if the compare-exchange gives us 2 (in the "zero" variable), so the ACQUIRE on that load synchronizes with the RELEASE in once_commit (I think), but maybe on a successful compare-exchange we need to use RELEASE? I'm unclear here.
Also, I just learned that lock cmpxchg is a full memory barrier on x86, and since we are hitting the __atomic_compare_exchange_n in the common case (initialization has already been done), that barrier it is occurring on every function call. Is there an easy way to avoid this?
UPDATE
Based on the comments and accepted answer, I've come up with the following modified implementation. If anybody spots a bug please let me know, but I believe it's correct. Basically, the change amounts to implementing double-check locking. I also switched to using SEQ_CST because:
I mainly care that the common (already initialized) case is fast.
I observed that GCC doesn't emit a memory fence instruction on x86 for the first read (and it does do so on ARM even with ACQUIRE).
#ifdef __x86_64__
#define PAUSE() __asm __volatile("pause")
#else
#define PAUSE()
#endif
int once_enter(int *b)
{
if(2 == __atomic_load_n(b, __ATOMIC_SEQ_CST)) return 0;
int zero = 0;
int got_lock = __atomic_compare_exchange_n(b, &zero, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
if (got_lock) return 1;
while (2 != __atomic_load_n(b, __ATOMIC_SEQ_CST)) {
PAUSE();
};
return 0;
}
void once_commit(int *b)
{
(void) __atomic_store_n(b, 2, __ATOMIC_SEQ_CST);
}
a, What you need is a double-checked lock.
Basically, instead of entering the lock every time, you do an acquiring-load to see if the initialisation has been done yet, and only invoke once_enter if it has not.
void gets_called_many_times_from_many_threads(void)
{
static int my_once_flag = 0;
if (__atomic_load_n(&my_once_flag, __ATOMIC_ACQUIRE) != 2) {
if (once_enter(&my_once_flag)) {
// do one-time initialization here
once_commit(&my_once_flag);
}
}
// do other things that assume the initialization has taken place
}
b, I believe this is enough, your initialisation happens before the releasing store of 2 to my_once_flag, and every other thread has to observe the value of 2 with an acquiring load from the same variable.
I'm using MikroC for PIC v7.2, to program a PIC18f67k40.
Within functii.h, I have the following variable declaration:
extern volatile unsigned char byte_count;
Within main.c, the following code:
#include <functii.h>
// ...
volatile unsigned char byte_count = 0;
// ...
void interrupt () {
if (RC1IF_bit) {
uart_rx = Uart1_read();
uart_string[byte_count] = uart_rx;
byte_count++;
}
// ...
}
Then, within command.c, I have the following code:
#include <functii.h>
void how_many_bytes () {
// ...
uart1_write(byte_count);
// ...
}
In main.c, I process data coming through the UART, using an interrupt. Once the end of transmission character is received, I call how_many_bytes(), which sends back the length of the message that was received (plus the data bytes themselves, the code for which I didn't include here, but those are all OK!!).
The problem is that on the uart1_write() call, byte_count is always 0, instead of having been incremented in the interrupt sequence.
Probably you need some synchronization between the interrupt handler and the main processing.
If you do something like this
if(byte_count != 0) {
uart1_write(byte_count);
byte_count = 0;
}
the interrupt can occur anywhere, for example
between if(byte_count != 0)and uart1_write(byte_count); or
during the processing of uart1_write(byte_count); which uses a copy of the old value while the value gets changed or
between uart1_write(byte_count); and byte_count = 0;.
With the code above case 1 is no problem but 2 and 3 are. You would lose all characters received after reading byte_count for the function call.
Maybe you can disable/enable interrupts at certain points.
A better solution might be to not reset byte_count outside of interrupt() but instead implement a ring buffer with separate read and write index. The read index would be modified by how_many_bytes() (or uart1_write()) only and the write index by interrupt() only.
I have a handler for SysTick exception which counts ticks and calls other functions (f1, f2, f3) whose execution time can be longer than SysTick period. These functions set and clear their active status (global variables) so if a SysTick exception occurs it can detect an overload and return to interrupted function.
I have assigned fixed priority to SysTick exception (let's say 16). I want to somehow make possible for SysTick to generate an exception regardless of it's prior active status, go to SysTickHandler, increase tick counter and return to interrupted function.
One solution which may be useful is to use BASEPRI. It can be set to priority lower than SysTick so it would enable that exception. Unfortunately, using BASEPRI got me nowhere because nothing happened (I set it to max value). BASEPRI value was 0 inside SysTickHandler before I changed it. Should that value be equal to SysTick priority when processor enters handler function? Is exception priority loaded automatically in BASEPRI?
I have also considered for NVIC to have an issue with preempting already active exception but found nothing regarding that in ARM documentation.
Also, return from handler when oveload is detected could set the processor state to thread mode. Let's ignore that for now.
void SysTickHandler(void) {
ticks++;
//set_BASEPRI(max_value);
if (f1_act || f2_act || f3_act) return;
else {
f1();
f2();
f3();
}
}
A simpler example for this problem (without return) would be to increase tick counter when having an infinite loop inside handler.
void SysTickHandler(void) {
ticks++;
set_BASEPRI(max_value);
while(1);
}
If the interrupt becomes pending while its handler is already running, the handler will run to completion and immediately re-enter. Your tick will be aperiodic, and if the functions consistently take longer that one tick period, you may never leave the interrupt context.
It may be possible I suppose to increase the priority of the interrupt in the handler so that it will preempt itself, but even if that were to work, I would hesitate to recommend it.
It sounds that what you actually need is an RTOS.
Sorry to disappoint you, but it seems a overall design problem to me...
Why won't you just set some flag in SysTick and read it somewhere else?
Like:
#include <stdbool.h>
volatile bool flag = false;
//Consider any form of atomicity here
//atomic_bool or LDREX/STREX instructions here. Bitbanding will also work
void sysTickHandler(void) {
ticks++;
if (f1_act || f2_act || f3_act) return;
else {
flag = true; //or increment some counter if you want to keep track of the amount of executions
}
And somewhere else:
int main() {
// some init code
//main loop
for(;;) {
foo();//do sth
bar(x); //do sth else
if (flag) {
f1();
f2();
f3();
flag = false;
}
}
}
Or if we assume that every interrupt wakes the microcontroller and power-down mode is needed, then sth. like this might work:
if (flag) {
f1();
f2();
f3();
flag = false;
}
goToSleep(powerDownModeX); //whatever;
I'm producing a game in C on a microprocessor. The score is controlled by how long you can survive; the score increases by 1 every 3 seconds. The score is an integer which is declared globally, but displayed from a function.
int score = 0;//globally declared
void draw_score(int score_d)
{
char score_draw[99];
sprintf(score_draw,"%d", score_d);
draw_string(score_draw, 9, 0);
}
I was thinking of a function which just increases the score by one with a delay on it, however that has not worked.
void score_increaser(int score)
{
score++;
_delay_ms( 3000 );
}
Does it need to be in a while loop? the function itself would go into a while loop in the main anyway.
C is pass by value.
score_increaser() as shown in your question increases just a copy of what is passed in.
To fix this there are (mainly) two options:
As score is defined globally, do not pass in anything:
void score_increaser(void) {
score++;
_delay_ms( 3000 );
}
This modifes the globale score directly.
Pass in the address of score and de-reference it inside the function
void score_increaser(int * pscore) {
(*pscore)++;
_delay_ms( 3000 );
}
Call it like this
...
score_increaser(&score);
...
A 3rd, a bit more complex, approach (which assumes signals are supported on the target platform) would
setup a signal and a referring handler, then
setup a timer to fire a signal every N seconds.
This signal then is handled by the handler, which in turn
increases the global score and
starts the timer again.
This might look like:
#include <signal.h> /* for signal() and sig_atomic_t */
#include <unistd.h> /* for alarm() */
#define DURATION (3) /* Increase score every 3 seconds. */
sig_atomic_t score = 0;
void set_alarm(unsigned);
void handler_alarm(int sig)
{
++score;
set_alarm(DURATION);
}
void set_alarm(unsigned duration)
{
signal(SIGALRM, handler_alarm);
alarm(duration);
}
int main(void)
{
set_alarm(DURATION);
... /* The game's codes here. */
}
This latter approach has the advantage that your game's code does not need to take care about increasing score. score is just increased every 3 seconds as long as the program runs.
I'd recommend using a timer interrupt. Configure the timer to 3 seconds.
volatile int score = 0; //global
void Intr_Init(peripheral_t per)
{
//Initialize the timer interrupt
}
void draw_score(int score_d)
{
char score_draw[99];
sprintf(score_draw,"%d", score_d);
draw_string(score_draw, 9, 0);
}
int main(void)
{
Intr_Init(TIMER);
while(1)
{
//Code that makes your game run
draw_score(score);
}
}
ISR (TIMER1_COMPA_vect)
{
//clear disable interrupt
score++;
//enable interrupt
}
In embedded, you should rely on Timers for better time critical tasks and accuracy. The way Delay routines are implemented is usually a loop or a up/down counter. Whereas a timer is usually based on counting SysTicks.
Another major advantage of Interrupts is that you let processor do its tasks all the while instead of making it block in a delay loop.
score is global value then do not need to pass it in function if that function has access to that global space
void score_increaser() {
score++;
_delay_ms( 3000 );
}
here is a good method for handling the score.
in the 'start game' function,
clear 'score' to 0
setup a timer:
--to expire once each 3 seconds
--enable the automatic reload feature,
--enable the timer interrupt
--enable the timer counter
in the timer interrupt handler function
--increment 'score'
--clear the timer interrupt pending flag
in the 'end game' function
disable the timer counter
disable the timer interrupt
display the 'score' value
You dont need parameter for the score since it's declared globally..
//global
int score = 0;
void score_increaser()
{
_delay_ms(3000);
score++;
}
calling is like: score_increaser(); should do the work..
i suggest you check for score in any other line/function.. maybe you have redeclared it or accidentally changed the value..
hope this helped..
I have a function to disable interrupts, but the problem is that if I disable them and I call a function which also disables/enables them, they get re-enabled too early. Is the following logic enough to prevent this?
static volatile int IrqCounter = 0;
void EnableIRQ()
{
if(IrqCounter > 0)
{
IrqCounter--;
}
if(IrqCounter == 0)
{
__enable_irq();
}
}
void DisableIRQ()
{
if(IrqCounter == 0)
{
__disable_irq();
}
IrqCounter++;
}
The way every operating system I know of does it is to save IRQ state into a local variable, and then restore that.
Clearly, your code has TOCTOU issues - if two threads run at the same time, checking the IrqCounter > 0, if IrqCounter == 1, then the first thread will see it as 1, the second thread sees it as 1, and both decrement the counter.
I would definitely try to arrange something like this:
int irq_state = irq_save();
irq_disable();
... do stuff with IRQ's turned off ...
irq_restore(irq_state);
Now, you don't have to worry about counters that can get out of sync, etc.
Assuming that you've got a system where you can't change context when interrupts are disabled, then what you've got is fine, assuming you keep careful track of when call the enable().
In the usage you're describing in the comments below, you plan on using these sections from within an interrupt service routine. Your main use is blocking higher-priority interrupts from running for a certain portion of an ISR.
Be aware that you'll have to consider the stack depth of these nested ISRs, as when you enable interrupts before your return from interrupt, you'll have interrupts enabled in the ISR.
Regarding other answers: the lack of thread-safety of the enable() (due to the if(IrqCounter > 0)) doesn't matter, because anytime you're in the enable() context switches are already disabled due to interrupts being off. (Unless for some reason you have unmatched disable/enable pairs, and in that case you've got other issues.)
The only suggestion I'd have would be to add an ASSERT to the enable instead of the run-time check, as you should never be enabling interrupts that you didn't disable.
void EnableIRQ()
{
ASSERT(IrqCounter != 0) //should never be 0, or we'd have an unmatched enable/disable pair
IrqCounter--; //doesn't matter that this isn't thread safe, as the enable is always called with interrupts disabled.
if(IrqCounter == 0)
{
__enable_irq();
}
}
I prefer the technique you've listed over the save(); disable(); restore(); technique as I don't like having to keep track of a piece of the OS' data every time I work with the interrupts. But, you do have to be aware of when you (directly or indirectly) make a call to the enable() from an ISR.
That looks fine, except it's not thread-safe.
Another common option is to query the interrupt-enable/disable state and save it into a local variable, then disable interrupts, then do whatever you want to be done while interrupts are disabled, then restore the state from the local variable.
static volatile int IrqCounter = 0;
void EnableIRQ(void)
{
ASSERT(IrqCounter != 0) //should never be 0, or we'd have an unmatched enable/disable pair
if (IrqCounter > 0)
{
IrqCounter--;
}
if (IrqCounter == 0)
{
__enable_irq();
}
}
void DisableIRQ(void)
{
__disable_irq(); // Fix TOCTOU issues. In CMSIS there is no harm in extra disables, so always disable.
IrqCounter++;
}