@@ -63,7 +63,7 @@ extension FileDescriptor.FileLock {
6363 set { rawValue. l_len = CInterop . Offset ( newValue) }
6464 }
6565
66- /// The process ID of the lock holder, filled in by`FileDescriptor.getLock()` .
66+ /// The process ID of the lock holder (if applicable) .
6767 ///
6868 /// The corresponding C field is `l_pid`
6969 @_alwaysEmitIntoClient
@@ -90,8 +90,8 @@ extension FileDescriptor.FileLock {
9090}
9191
9292extension FileDescriptor . FileLock {
93- /// The kind of a lock: read ("shared"), write ("exclusive"), or none
94- /// ("unlock").
93+ /// The kind or type of a lock: read (aka "shared"), write (aka "exclusive"), or none
94+ /// (aka "unlock").
9595 @frozen
9696 public struct Kind : RawRepresentable , Hashable {
9797 @_alwaysEmitIntoClient
@@ -128,13 +128,10 @@ extension FileDescriptor.FileLock {
128128
129129extension FileDescriptor {
130130 /// All bytes in a file
131- ///
132- /// NOTE: We can't make byteRange optional _and_ generic in our API below because that requires type inference even when passed `nil`.
133- ///
134131 @_alwaysEmitIntoClient
135132 internal var _allFileBytes : Range < Int64 > { Int64 . min ..< Int64 . max }
136133
137- /// Get any conflicting locks held by other open file descriptions.
134+ /// Get any conflicting locks held by other open file descriptions.
138135 ///
139136 /// Open file description locks are associated with an open file
140137 /// description (see `FileDescriptor.open`). Duplicated
@@ -151,24 +148,17 @@ extension FileDescriptor {
151148 ///
152149 /// - Parameters:
153150 /// - byteRange: The range of bytes over which to check for a lock. Pass
154- /// `nil` to consider the entire file (TODO: default value with Swift
155- /// 5.7)
156- /// - retryOnInterrupt: Whether to retry the open operation if it throws
151+ /// `nil` to consider the entire file.
152+ /// - retryOnInterrupt: Whether to retry the operation if it throws
157153 /// ``Errno/interrupted``. The default is `true`. Pass `false` to try
158154 /// only once and throw an error upon interruption.
159- /// - Returns; `.none` if there are no other locks, otherwise returns the
155+ /// - Returns; `.none` if there are no locks, otherwise returns the
160156 /// strongest conflicting lock
161157 ///
162158 /// The corresponding C function is `fcntl` with `F_OFD_GETLK`.
163- ///
164- /// FIXME: Does this only return OFD locks or process locks too?
165- /// TODO: document byte-range
166- /// FIXME: Can we just state the OFD docs once and link to it?
167- /// TODO: would a better API be e.g. `canGetLock(.read)`? or `getConflictingLock()`?
168- ///
169159 @_alwaysEmitIntoClient
170160 public func getConflictingLock(
171- byteRange: some RangeExpression < Int64 > ,
161+ byteRange: ( some RangeExpression < Int64 > ) ? = Range ? . none ,
172162 retryOnInterrupt: Bool = true
173163 ) throws -> FileDescriptor . FileLock . Kind {
174164 let ( start, len) = _mapByteRangeToByteOffsets ( byteRange)
@@ -177,15 +167,6 @@ extension FileDescriptor {
177167 ) . get ( )
178168 }
179169
180-
181- @_alwaysEmitIntoClient
182- public func getConflictingLock(
183- retryOnInterrupt: Bool = true
184- ) throws -> FileDescriptor . FileLock . Kind {
185- try getConflictingLock (
186- byteRange: _allFileBytes, retryOnInterrupt: retryOnInterrupt)
187- }
188-
189170 @usableFromInline
190171 internal func _getConflictingLock(
191172 start: Int64 , length: Int64 , retryOnInterrupt: Bool
@@ -202,14 +183,12 @@ extension FileDescriptor {
202183 // 2) Try with a write lock, which will tell us if there's either a
203184 // conflicting read or write lock in place.
204185 var lock = FileDescriptor . FileLock ( ofdType: . read, start: start, length: length)
205- // print(lock.type)
206186 if case let . failure( err) = self . _fcntl (
207187 . getOFDLock, & lock, retryOnInterrupt: retryOnInterrupt
208188 ) {
209189 return . failure( err)
210190 }
211191 if lock. type == . write {
212- // print(lock.type)
213192 return . success( . write)
214193 }
215194 guard lock. type == . none else {
@@ -219,7 +198,6 @@ extension FileDescriptor {
219198 lock = FileDescriptor . FileLock ( ofdType: . write, start: start, length: length)
220199
221200 let secondTry = self . _fcntl ( . getOFDLock, & lock, retryOnInterrupt: retryOnInterrupt)
222- // print(lock.type)
223201 return secondTry. map { lock. type }
224202 }
225203
@@ -229,7 +207,7 @@ extension FileDescriptor {
229207 /// replaced.
230208 ///
231209 /// If the lock cannot be set because it is blocked by an existing lock on a
232- /// file and (TODO: blocking paremeter is false) ,
210+ /// file and `wait` is ` false` ,
233211 /// `Errno.resourceTemporarilyUnavailable` is thrown.
234212 ///
235213 /// Open file description locks are associated with an open file
@@ -248,41 +226,34 @@ extension FileDescriptor {
248226 /// Passing a lock kind of `.none` will remove a lock (equivalent to calling
249227 /// `FileDescriptor.unlock()`).
250228 ///
251- /// TODO: describe non-blocking
229+ /// - Parameters:
230+ /// - kind: The kind of lock to set
231+ /// - byteRange: The range of bytes over which to lock. Pass
232+ /// `nil` to consider the entire file.
233+ /// - wait: Whether to wait (block) until the request can be completed
234+ /// - retryOnInterrupt: Whether to retry the operation if it throws
235+ /// ``Errno/interrupted``. The default is `true`. Pass `false` to try
236+ /// only once and throw an error upon interruption.
252237 ///
253238 /// The corresponding C function is `fcntl` with `F_OFD_SETLK` or
254239 /// `F_OFD_SETLKW`.
255240 @_alwaysEmitIntoClient
256241 public func lock(
257242 _ kind: FileDescriptor . FileLock . Kind = . read,
258- byteRange: ( some RangeExpression < Int64 > ) ? = nil ,
259- nonBlocking : Bool = false , // FIXME: named "wait" or "blocking"? Which default is best?
243+ byteRange: ( some RangeExpression < Int64 > ) ? = Range ? . none ,
244+ wait : Bool = false ,
260245 retryOnInterrupt: Bool = true
261246 ) throws {
262247 let ( start, len) = _mapByteRangeToByteOffsets ( byteRange)
263248 try _lock (
264249 kind,
265250 start: start,
266251 length: len,
267- nonBlocking : nonBlocking ,
252+ wait : wait ,
268253 retryOnInterrupt: retryOnInterrupt
269254 ) . get ( )
270255 }
271256
272- @_alwaysEmitIntoClient
273- public func lock(
274- _ kind: FileDescriptor . FileLock . Kind = . read,
275- nonBlocking: Bool = false , // FIXME: named "wait" or "blocking"? Which default is best?
276- retryOnInterrupt: Bool = true
277- ) throws {
278- try lock (
279- kind,
280- byteRange: _allFileBytes,
281- nonBlocking: nonBlocking,
282- retryOnInterrupt: retryOnInterrupt)
283- }
284-
285-
286257 /// Remove an open file description lock.
287258 ///
288259 /// Open file description locks are associated with an open file
@@ -301,49 +272,43 @@ extension FileDescriptor {
301272 /// Calling `unlock()` is equivalent to passing `.none` as the lock kind to
302273 /// `FileDescriptor.lock()`.
303274 ///
304- /// TODO: Do we need a non-blocking argument? Does that even make sense?
275+ /// - Parameters:
276+ /// - byteRange: The range of bytes over which to lock. Pass
277+ /// `nil` to consider the entire file.
278+ /// - wait: Whether to wait (block) until the request can be completed
279+ /// - retryOnInterrupt: Whether to retry the operation if it throws
280+ /// ``Errno/interrupted``. The default is `true`. Pass `false` to try
281+ /// only once and throw an error upon interruption.
305282 ///
306- /// The corresponding C function is `fcntl` with `F_OFD_SETLK` (TODO: or
307- /// `F_OFD_SETLKW`?) and a lock type of `F_UNLCK`.
283+ /// The corresponding C function is `fcntl` with `F_OFD_SETLK` or
284+ /// `F_OFD_SETLKW` and a lock type of `F_UNLCK`.
308285 @_alwaysEmitIntoClient
309286 public func unlock(
310- byteRange: ( some RangeExpression < Int64 > ) ? = nil ,
311- nonBlocking : Bool = false , // FIXME: needed?
287+ byteRange: ( some RangeExpression < Int64 > ) ? = Range ? . none ,
288+ wait : Bool = false , // FIXME: needed?
312289 retryOnInterrupt: Bool = true
313290 ) throws {
314291 let ( start, len) = _mapByteRangeToByteOffsets ( byteRange)
315292 try _lock (
316293 . none,
317294 start: start,
318295 length: len,
319- nonBlocking : nonBlocking ,
296+ wait : wait ,
320297 retryOnInterrupt: retryOnInterrupt
321298 ) . get ( )
322299 }
323300
324- @_alwaysEmitIntoClient
325- public func unlock(
326- nonBlocking: Bool = false , // FIXME: needed?
327- retryOnInterrupt: Bool = true
328- ) throws {
329- try unlock (
330- byteRange: _allFileBytes,
331- nonBlocking: nonBlocking,
332- retryOnInterrupt: retryOnInterrupt)
333- }
334-
335-
336301 @usableFromInline
337302 internal func _lock(
338303 _ kind: FileDescriptor . FileLock . Kind ,
339304 start: Int64 ,
340305 length: Int64 ,
341- nonBlocking : Bool ,
306+ wait : Bool ,
342307 retryOnInterrupt: Bool
343308 ) -> Result < ( ) , Errno > {
344309 var lock = FileDescriptor . FileLock ( ofdType: kind, start: start, length: length)
345310 let command : FileDescriptor . Control . Command =
346- nonBlocking ? . setOFDLock : . setOFDLockWait
311+ wait ? . setOFDLockWait : . setOFDLock
347312 return _fcntl ( command, & lock, retryOnInterrupt: retryOnInterrupt)
348313 }
349314}
0 commit comments