- live browsing of Self object memory -

lobby traitslock

CopyDowns: vector

CreatorPath: traits lock

Module: lock

parent* = traits clonable

copying and (re)initializing

copy = ( resend.copy init)
reinitialize = ( init)Reinitialize lock to force it into consistent and free state (see category 'testing'). Careful: this operation should only be performed when it is known that no processes are accessing the lock.
init =
( 
    sema: semaphore copyBinary.
    holderProcess: nil.
    lockCount: 0)

debugging

debug = falseWhether to test assertions (for debugging).
assert: =
( 
    debug ifTrue: [blk assert].
    self)
assertLockHeld =
( 
    assert: [0 < lockCount].
    assert: [isHeldByThisProcess])

locking

lock =
( 
    isHeldByThisProcess ifFalse: [
        sema wait.
        holderProcess: process this.
    ].
    lockCount: 1 + lockCount)
Acquire the lock (fast operation if current process already holds lock).
lock: =
( 
    0 < n ifTrue: [
        lock.
        lockCount: (n - 1) + lockCount.
    ].
    self)
Perform 'n' lock opeations (no-op if 'n = 0').
lockMe: = ( lock)

structured operations

forceUnlock

forceUnlockForWaitOn: = ( forceUnlockForWaitOn: waitSema TimeOut: waitSema noTimeOut)Like 'forUnlockForWaitOn:TimeOut:' but without timeout.
forceUnlockForWaitOn:TimeOut: =
( | lc <- 0. res |
    assertLockHeld.
    lc: lockCount.
    res: (basicUnlockUsing: [sema signalAndThenWaitOn: waitSema TimeOut: ms]).
    lock: lc.    "Relock before returning."
    res)
Atomically unlock (in the sense of 'forceUnlock') and then wait on the semaphore 'waitSema' with timeout 'ms'. Once this wait operation completes, reacquire the lock. Return result of wait operation.

protect

protect: =
( 
    "For efficiency, it is worth avoiding the 'onReturn:'
     when possible (i.e., all but the first time the lock
     is claimed)."
    isHeldByThisProcess ifTrue: blk
                         False: [lock. blk onReturn: [unlock]])
While holding the lock, evaluate 'blk'. Return result of 'blk'.
protect:Me: = ( protect: blk)

protectNoNLR

protectNoNLR: =
( 
    isHeldByThisProcess ifTrue: blk
                         False: [|res|
        lock.
        res: blk value.
        unlock.
        res.
    ])
Like 'protect:' but blk is not allowed to do a non-local return through this activation (nor is any block invoked by 'blk' allowed to do so)!
protectNoNLR:Me: = ( protectNoNLR: blk)

protectSafeNLR

protectSafeNLR: =
( 
    isHeldByThisProcess ifTrue: [blk value: []]
                         False: [|res|
        lock.
        res: (blk value: [unlock]).
        unlock.
        res.
    ])
Like 'protectNoNLR:' but NLR is allowed if 'blk' first invokes its argument block (which will unlock).
protectSafeNLR:Me: = ( protectSafeNLR: blk)

testing

isAvailable = ( holderProcess isNil || [isHeldByThisProcess])Return true iff lock is not held or is held by this process.
isConsistent = ( isFree = sema isAvailable)Do internal consistency check on lock. Return true iff all is well (aborting processes that hold the lock may put in inconsistent state). The lock can be made consisten again by reinitializing it.
isFree = ( holderProcess isNil)Return true iff lock is currerntly not held by any process.
isHeldByThisProcess = ( process this = holderProcess)Return true iff the executing process holds this lock.

transporting

storeStringIfFail: = ( 'lock copy')
storeStringNeeds = ( lock)

unlocking

forceUnlock =
( | lc <- 0 |
    lc: lockCount.
    basicUnlock.
    assert: [holderProcess isNil && [sema isAvailable]].
    lc)
Perform just enough unlock operations to release this lock. Return how many unlocks where performed.
unlock =
( 
    assertLockHeld.
    1 = lockCount ifTrue: [basicUnlock]
                   False: [lockCount: -1 + lockCount].
    self)
Release the lock. Only call after lock was acquired.
unlock: =
( 
    assertLockHeld.
    assert: [0 > n. "negative unlock count not  allowed"].
    lockCount compare: n IfLess: [error: 'too many unlocks']
                          Equal: [basicUnlock]
                        Greater: [lockCount: lockCount - n].
    self)
Perform 'n' unlocks.
unlockMe: = ( unlock)
basicUnlock =
( 
    basicUnlockUsing: [sema signal].
    self)
basicUnlockUsing: =
( 
    assertLockHeld.
    lockCount: 0.
    holderProcess: nil.
    blk value)