Skip to content

Commit b000792

Browse files
authored
Add reference for noasync in @available [SE-0340] (#352)
Fixes: rdar://142580634
2 parents 6a078bf + 8b62dbf commit b000792

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

TSPL.docc/ReferenceManual/Attributes.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,80 @@ including important milestones.
210210
obsoleted: <#version number#>
211211
```
212212
The *version number* consists of one to three positive integers, separated by periods.
213+
214+
- The `noasync` argument indicates that
215+
the declared symbol can't be used directly
216+
in an asynchronous context.
217+
218+
Because Swift concurrency can resume on a different thread
219+
after a potential suspension point,
220+
using elements like thread-local storage, locks, mutexes, or semaphores
221+
across suspension points can lead to incorrect results.
222+
223+
To avoid this problem,
224+
add an `@available(*, noasync)` attribute to the symbol's declaration:
225+
226+
```swift
227+
extension pthread_mutex_t {
228+
229+
@available(*, noasync)
230+
mutating func lock() {
231+
pthread_mutex_lock(&self)
232+
}
233+
234+
@available(*, noasync)
235+
mutating func unlock() {
236+
pthread_mutex_unlock(&self)
237+
}
238+
}
239+
```
240+
241+
This attribute raises a compile-time error
242+
when someone uses the symbol in an asynchronous context.
243+
You can also use the `message` argument to provide additional information
244+
about the symbol.
245+
246+
```swift
247+
@available(*, noasync, message: "Migrate locks to Swift concurrency.")
248+
mutating func lock() {
249+
pthread_mutex_lock(&self)
250+
}
251+
```
252+
253+
If you can guarantee that your code
254+
uses a potentially unsafe symbol in a safe manner,
255+
you can wrap it in a synchronous function and call that function
256+
from an asynchronous context.
257+
258+
```swift
259+
260+
// Provide a synchronous wrapper around methods with a noasync declaration.
261+
extension pthread_mutex_t {
262+
mutating func withLock(_ operation: () -> ()) {
263+
self.lock()
264+
operation()
265+
self.unlock()
266+
}
267+
}
268+
269+
func downloadAndStore(key: Int,
270+
dataStore: MyKeyedStorage,
271+
dataLock: inout pthread_mutex_t) async {
272+
// Safely call the wrapper in an asynchronous context.
273+
dataLock.withLock {
274+
dataStore[key] = downloadContent()
275+
}
276+
}
277+
```
278+
279+
You can use the `noasync` argument on most declarations;
280+
however, you can't use it when declaring deinitializers.
281+
Swift must be able to call a class's deinitializers from any context,
282+
both synchronous and asynchronous.
283+
213284
- The `message` argument provides a textual message that the compiler displays
214-
when emitting a warning or error about the use of a deprecated or obsoleted declaration.
285+
when emitting a warning or error about the use
286+
of a declaration marked `deprecated`, `obsoleted`, or `noasync`.
215287
It has the following form:
216288

217289
```swift

0 commit comments

Comments
 (0)