Need more than eight locks?
Phil Pilgrim (PhiPi)
Posts: 23,514
The Propeller provides eight locks for access control to shared resources. But what if you have more than eight shared resources, each needing its own lock? One way to solve this is with a master lock/sub lock scheme. In this method one hardware lock (the master lock) is checked out from the Propeller. The master lock lock controls access to up to 32 sub locks, each one controlling access to a shared resource.
To lock a resource, you first lock the master lock, then look to see if the resource's sub lock is locked. If it is, the resource is busy, so you have to unlock the master lock and try again. If the sub lock is unlocked, you can lock it, then unlock the master lock so others have a chance to use their resources.
Once you're finished using the shared resource, you then relock the master lock, unlock the resource's sub lock, then unlock the master lock again.
The scheme relies on the fact that the master lock is locked only when checking or locking/unlocking a sub lock. So the master lock won't be monopolized while the resource that uses the sub lock is being accessed.
Here's a program that implements and demonstrates the scheme. When run, it will launch six cogs, each flashing its own LED on the demo board. If locking is turned on, and if all six cogs use the same sub lock, none of the LEDs will be on simultaneously, yet each should get a chance to flash. As the number of sub locks increases, the LEDs split into groups. No two LEDs within a group will be on at the same time, yet different groups will have LEDs on simultaneously.
-Phil
To lock a resource, you first lock the master lock, then look to see if the resource's sub lock is locked. If it is, the resource is busy, so you have to unlock the master lock and try again. If the sub lock is unlocked, you can lock it, then unlock the master lock so others have a chance to use their resources.
Once you're finished using the shared resource, you then relock the master lock, unlock the resource's sub lock, then unlock the master lock again.
The scheme relies on the fact that the master lock is locked only when checking or locking/unlocking a sub lock. So the master lock won't be monopolized while the resource that uses the sub lock is being accessed.
Here's a program that implements and demonstrates the scheme. When run, it will launch six cogs, each flashing its own LED on the demo board. If locking is turned on, and if all six cogs use the same sub lock, none of the LEDs will be on simultaneously, yet each should get a chance to flash. As the number of sub locks increases, the LEDs split into groups. No two LEDs within a group will be on at the same time, yet different groups will have LEDs on simultaneously.
-Phil
[b]CON[/b] locking = [b]true[/b] [b]'Change to false to view effects of not locking.[/b] nlocks = 1 [b]'Number of sub locks used (1,2,3, or 6).[/b] [b]VAR[/b] [b]long[/b] stack[noparse][[/noparse]192] [b]'Six 32-LONG stacks.[/b] [b]PUB[/b] demo | j [b]'' Demo code for master lock/sub lock scheme.[/b] [b]'' If successful, six LEDs will flash, no more than nlocks at a time (or all at once if locking is false).[/b] start [b]'Create the master lock.[/b] [b]repeat[/b] j [b]from[/b] 0 to 5 [b]'Create six cogs that need access to sub lock 0:[/b] [b]cognew[/b](test_lock(j), @stack[noparse][[/noparse]j * 32]) [b]' Start the cog, using a poriton of the main stack.[/b] [b]PUB[/b] test_lock(which) | lockno [b]'' Cog which locks its sub lock, flashes its LED, then unlocks the sub lock.[/b] [b]dira[/b][noparse][[/noparse]which + 16] := 1 [b]'Set the output bit for this cog, using "which".[/b] lockno := which * nlocks / 6 [b]'Compute lock number from number of locks and "which".[/b] [b]repeat[/b] [b]'Repeat forever:[/b] [b]if[/b] locking [b]' Using locks?[/b] lock(lockno) [b]' Yes: Lock the sub lock.[/b] [b]outa[/b] := -1 [b]' Turn on the LED.[/b] [b]waitcnt[/b]([b]cnt[/b] + clkfreq / 10) [b]' Wait 1/10 sec.[/b] [b]outa[/b] := 0 [b]' Turn off the LED.[/b] [b]if[/b] locking [b]' Using locks?[/b] unlock(lockno) [b]' Yes: Unlock the sub lock.[/b] [b]waitcnt[/b]([b]cnt[/b] + clkfreq / 2) [b]' Wait 1/2 sec. [/b] [b]PUB[/b] start [b]'' Startup code. Obtain the master lock. [/b] [b]if[/b] (master_lock := [b]locknew[/b]) => 0 [b]'Can get a new master lock?[/b] [b]lockclr[/b](master_lock) [b]' Yes: Make sure it's unlocked.[/b] [b]return[/b] [b]true[/b] [b]' Return success.[/b] [b]else[/b] [b]return[/b] [b]false[/b] [b]' No: Return failure. [/b] [b]PUB[/b] lock(sub_lock) | lock_mask [b]'' Lock the indicated lock (0 .. 31).[/b] [b]if[/b] master_lock => 0 [b]'Do we have a master lock?[/b] lock_mask := 1 << sub_lock [b]' Yes: Create a mask from the sub lock.[/b] [b]repeat[/b] [b]' Wait for sub lock to be unlocked:[/b] [b]repeat[/b] [b]while[/b] [b]lockset[/b](master_lock) [b]' First, lock the master lock.[/b] [b]if[/b] [b]not[/b] sub_locks & lock_mask [b]' Is the sub lock locked?[/b] [b]quit[/b] [b]' No: Okay to exit loop and proceed.[/b] [b]lockclr[/b](master_lock) [b]' Yes: Unlock the master lock and try again.[/b] sub_locks |= lock_mask [b]' Sub lock was unlocked, so lock it.[/b] [b]lockclr[/b](master_lock) [b]' Now unlock the master lock.[/b] [b]return[/b] [b]true[/b] [b]' Return success.[/b] [b]else[/b] [b]return[/b] [b]false[/b] [b]' No: Return failure.[/b] [b]PUB[/b] unlock(sub_lock) [b]'' Unlock the indicated lock (0 .. 31).[/b] [b]if[/b] master_lock => 0 [b]'Do we have a master lock?[/b] [b]repeat[/b] [b]while[/b] [b]lockset[/b](master_lock) [b]' Lock the master lock.[/b] sub_locks &= !(1 << sub_lock) [b]' Unlock the sub lock.[/b] [b]lockclr[/b](master_lock) [b]' Unlock the master lock. [/b] [b]return[/b] [b]true[/b] [b]' Return success.[/b] [b]else[/b] [b]return[/b] [b]false[/b] [b]' No: Return failure.[/b] [b]DAT[/b] master_lock [b]long[/b] -1 [b]'Master lock number.[/b] sub_locks [b]long[/b] 0 [b]'32 sub locks. Bit = 0 (unlocked) or 1 (locked)[/b]