| 231 | | * `s1 == s2`. Holds iff `s1` and `s2` refer to the same dynamic scope. |
| 232 | | * `s1 != s2`. Holds iff `s1` and `s2` refer to different dynamic scopes. |
| 233 | | * `s1 <= s2`. Holds iff `s1` is equal to or a descendant of `s2`, i.e., `s1` is equal to or contained in `s2`. |
| 234 | | * `s1 < s2`. Holds iff `s1` is a strict descendant of `s2`, i.e., `s1` is contained in `s2` and is not equal to `s2`. |
| 235 | | * `s1 > s2`. Equivalent to `s2 < s1`. |
| 236 | | * `s1 >= s2`. Equivalent to `s2 <= s1`. |
| | 231 | * `s1 == s2` holds iff `s1` and `s2` refer to the same dynamic scope. |
| | 232 | * `s1 != s2` holds iff `s1` and `s2` refer to different dynamic scopes. |
| | 233 | * `s1 <= s2` holds iff `s1` is equal to or a descendant of `s2`, i.e., `s1` is equal to or contained in `s2`. |
| | 234 | * `s1 < s2` holds iff `s1` is a strict descendant of `s2`, i.e., `s1` is contained in `s2` and is not equal to `s2`. |
| | 235 | * `s1 > s2` is equivalent to `s2 < s1`. |
| | 236 | * `s1 >= s2` is equivalent to `s2 <= s1`. |
| | 248 | An ''atomic block'' is a statement of the form |
| | 249 | {{{ |
| | 250 | $atomic { |
| | 251 | stmt1; |
| | 252 | stmt2; |
| | 253 | ... |
| | 254 | } |
| | 255 | }}} |
| | 256 | and indicates that the statements comprising the block should be executed without the intervention of other processes. |
| | 257 | |
| | 258 | More precisely, there is a global atomic lock which is initially free. |
| | 259 | A process attempting to execute an atomic block will wait until the atomic lock becomes free, i.e., no other process is inside an atomic block. |
| | 260 | The process must also wait until the guard of the atomic block holds; this means that the first statement in the block is enabled. |
| | 261 | Once the atomic lock is free and the guard holds, the atomic block becomes enabled and the process may enter the atomic block. |
| | 262 | The process may not necessarily enter the atomic block as soon as these conditions hold, because some other enabled process may be scheduled first. |
| | 263 | In fact, some other process may obtain the atomic lock. |
| | 264 | But if the enabling conditions hold and this process is scheduled, it will obtain the atomic lock and begin executing the statements of the atomic block without other processes executing. |
| | 265 | Upon reaching the end of the atomic block, the process releases the atomic lock and exits the block. |
| | 266 | |
| | 267 | There is an exception to atomicity: if the process inside the atomic block executes a `$yield` statement, it releases the atomic lock. |
| | 268 | This allows other processes to execute, and even obtain the lock. |
| | 269 | At any point at which the atomic lock is free and the first statement following the `$yield` is enabled, the original process may re-obtain the atomic lock and continue executing its block atomically. |
| | 270 | |
| | 271 | If a statement inside an atomic block blocks, so that the process executing the atomic block has no enabled statement, execution deadlocks. |
| | 272 | The exception to this rule is that the first statement in the atomic block, and the first statement after a `$yield`, as described above, may block, without necessarily causing deadlock. |
| | 273 | |
| | 274 | Atomic blocks may be nested. |
| | 275 | Hence the atomic lock is held with a certain multiplicity. |
| | 276 | Each time the process enters an atomic block, the multiplicity is incremented. |
| | 277 | Each time it leaves an atomic block, the multiplicity is decremented. |
| | 278 | When the multiplicity hits 0, the atomic lock is released. |
| | 279 | Execution of a `$yield` does not change the multiplicity; the process releases the lock but maintains the multiplicity, so that when the lock is re-obtained, the original multiplicity is still in place. |
| | 280 | |