There are two general locking schemes, advisory locking and mandatory locking. Advisory locks have no effect on clients that do not explicitly check for a lock. Mandatory locks do not require clients to explicitly check for locks, but represent a security risk because it is possible to interfere with the normal operation of a system by placing mandatory locks on essential files. For this reason mandatory locks are excluded from the POSIX.1 standard. A platform file system usually supports either advisory or mandatory locking but not both.
The locking constants in the CfsConstants pool dictionary appear
in the following table:
Table 12. File locking constants
Pool variable | Description |
---|---|
FRDLOCK | Specifies a shared (read) advisory lock. A shared advisory lock prevents any other client from setting an exclusive advisory lock on any portion of the protected area. Noncooperating clients can read or write in protected areas. |
FWRLOCK | Specifies an exclusive (write) advisory lock. An exclusive advisory lock prevents any other client from setting a shared or exclusive advisory lock on any portion of the protected area. Noncooperating clients can read or write in protected areas. |
FMDLOCK | Specifies an exclusive mandatory lock. An exclusive mandatory lock prevents any other client from reading, writing, or locking any portion of the protected area. |
In general, a platform operating system supports either advisory locking or mandatory locking, but not both. To determine whether a lock type is supported, send the supportsLockType: message to the CfsFileDescriptor class, with the desired locking constant as an argument. If the specified type of lock is supported, true is answered. Otherwise, false is answered. An example follows:
"Need exclusive lock, preferably mandatory. Answer what is available" (CfsFileDescriptor supportsLockType: FMDLOCK) ifTrue: [^FMDLOCK] ifFalse: [ (CfsFileDescriptor supportsLockType: FWRLOCK) ifTrue: [^FWRLOCK] ifFalse: [^self error: 'No exclusive lock types are supported']].
Sending the lock:start:len: message to a CfsFileDescriptor instance sets a segment lock on the file associated with the CfsFileDescriptor instance. The first argument is one of the file locking constants described in the table in the preceding section. The second argument is an integer specifying the zero-based offset of the first byte to be locked. The third argument is an integer specifying the number of bytes to be locked. If the specified locking constant is not supported, a CfsError instance is answered. To release a lock, use the unlock:start:len: message. The arguments are identical. Examples are as follows:
| fd theSize | (fd := CfsFileDescriptor open: 'lockable.fil' oflag: ORDWR | OCREAT | OTRUNC) isCfsError ifTrue: [^self error: fd message]. fd write: 'This is a TEST LOCK area' startingAt: 1 nbyte: 24.
"Lock the word test with a mandatory lock - should really determine appropriate lock type first as shown in previous section on determining lock type" fd lock: FMDLOCK start: 10 len: 4.
"Release the lock, must use same lock constant" fd unlock: FMDLOCK start: 10 len: 4
"Lock the entire file and then unlock it" "The size is saved so that the region is locked as was unlocked, even if the file size increased between the operations." fd lock: FMDLOCK start: 0 len: (theSize :=fd size). fd unlock: FMDLOCK start: 0 len: theSize. fd close.
When releasing a lock, the value of the lock type, start, and length arguments must be exactly the same as those used to set the lock. Otherwise the unlock operation can fail or have unpredictable behavior. Using the size message when releasing a lock as shown in the previous example is dangerous, because the size might have changed since the lock was set. Instead, save the parameters used when locking and reuse these values when releasing the lock. An example follows:
| fd len | (fd := CfsFileDescriptor open: 'lockable.fil' oflag: ORDWR | OCREAT | OTRUNC) isCfsError ifTrue: [^self error: fd message]. fd write: 'This is a TEST LOCK area' startingAt: 1 nbyte: 24.
fd lock: FMDLOCK start: 0 len: (len := fd size). fd unlock: FMDLOCK start: 0 len: len. fd close.
The effect of locking overlapping regions or releasing locks that have not been set is platform-specific. It is recommended that all locks be explicitly released before closing the file.