Wednesday, January 14, 2009

Concurrency Screw-ups

The above code will work perfectly, except when more than one task try to access the same port register. Since the port setting statement is not atomic, the 3 assembly steps could be pre-empted at anytime. Consider tasks A and B, both accessing PortA bits 0 and 1 respectively.

Task A code
1A. mov R0,PortA ; get PortA contents into R0
2A. OR R0,0x0001 ; Or the contents of R0 with bitmap
3A. mov PortA,R0 ; restore the modified PortA from R0

Task B code
1B. mov R0,PortA ; get PortA contents into R0
2B. OR R0,0x0002 ; Or the contents of R0 with bitmap
3B. mov PortA,R0 ; restore the modified PortA from R0

Lets say, Task A intends to set bit 0 of PortA, when after step 2A, gets pre-empted by Task B. Since Task B has no way to know that there exists another task accessing a shared resource as itself, it takes the snapshot of PortA register available to it and goes ahead with steps 1B to 2B. Once Task A cones around to complete its job of setting with steps 2A and 3A, it posseses an old snapshot of PortA. Task B will be in for a surprise as bit 1 is over-written to 0 by Task B. The result is Port A bit 1, if got set will only be so for few moments. The result can be as graver as your imagination can carry.

The solution
Any solution presented would need to involve a method that controls access to shared resources like ports. Task A could either flag the port register as used so as to tell Task B to be careful, or just force the 3 steps to be atomic. Below are the few easy get-aways:
- Disable interrupts globally and restore them once the steps have been completed.
- If restoring interrupts turnouts to be an overhead for a trivial task as port setting, some micros provide instructions which enforce CPU level atomicity for a given number of instructions.

Certain micros provide an architecture which overcomes this issue at the hardware level. There never is a single Port register that performs the setting as well as resetting functionality. Rather, 2 seperate I/O registers are dedicated for setting and resetting. Concurrency problem is again avoided here by allowing bits to change state only when 1 is written.

No comments: