views:

74

answers:

1

I started implementing something similar to task switching in my app on atmega8. The main idea is that there's a pointer to a "current screen" structure. The "current screen" contains handlers for refreshing the screen, handling buttons and interrupts.

Unfortunately I discovered that changing a function pointer is done in done in 2 operations. That means some interrupt may try to do current_screen->handle_signal(...); while current_screen is partly changed. Due to handling precise timing, I cannot just disable and reenable interrupts during that change. Setting a flag about the handler being changed could do the trick, since I don't care that much about missing some interrupts in the middle of the task change (but then handling those I cannot miss becomes a bit harder).

I thought about copying current_screen to current_screen_old during the change and setting a flag, like this:

current_screen_old = current_screen; // safe to call current_screen->handler
during_update = 1; // safe to call current_screen_old->handler
current_screen = new_value;
during_update = 0; // safe to call current_screen->handler again

But I'm not 100% sure this doesn't contain some other tricks if the handler wants to change current_screen too.

Is there some better way to approach it? Some good idioms?

+2  A: 

You can use double buffering.

That is, use an array of two function pointers and an index to the current one. Set the non-current pointer to the new value, then toggle the index. Since the index is small (0 or 1) setting it is atomic.

You need to make sure that no task accessing the pointer during a change can be suspended long enough to be disturbed by the next change.

starblue
That's a good idea. I'll try to do that.
viraptor