Motivation:
The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.
Modifications:
- Drop and reacquire the lock in TokenBucket.
- Switch to NIOLockedValueBox
Result:
Lower chance of deadlock
Motivation:
The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.
Modifications:
- Drop and reacquire the lock in the NIOThrowingAsyncSequenceProducer.
- Merge 'next()' and 'next(for:)' methods in the state machine into a
single func; this reduces the amount of duplicated logic across the two
functions.
Result:
Lower chance of deadlock
Motivation:
The various 'withMumbleContinuation' APIs are supposed to be invoked
synchronously with the caller. This assumption allows a lock to be
acquired before the call and released from the body of the
'withMumbleContinuation' after e.g. storing the continuation. However
this isn't the case and the job may be re-enqueued on the executor
meaning that this is pattern is vulnerable to deadlocks.
Modifications:
- Drop and reacquire the lock in the NIOAsyncWriter
Result:
Lower chance of deadlock
Motivation:
The compiler is better at optimising closures wrapped in nominal types
than raw closures when used as generic parameters. CallbackList is used
a lot and stores an optional closure as well as on optional array of
closures. Wrapping these internally should save some allocations.
Modifications:
- Wrap the element stored in the `CallbackList`.
Result:
Fewer allocs
---------
Co-authored-by: Cory Benfield <lukasa@apple.com>
Motivation:
Due to https://bugs.swift.org/browse/SR-14516 , we sometimes get
allocating (!?) `subscript.read` accessors in the CircularBuffer.first
depending on the `Element` type...
Modifications:
Implement `CircularBuffer.first` instead of inheriting it from
Collection.
Result:
Fewer allocs in some cases.
Motivation:
Calling `function(otherFunction)` allocates, but
`function({ otherFunction($0) }` does not.
See: SR-12115 and SR-12116.
Modifications:
Avoid passing functions directly; pass them in new closures instead.
Result:
Fewer allocations.