@@ -27,10 +27,10 @@ public class Lifecycle {
27
27
private let shutdownGroup = DispatchGroup ( )
28
28
29
29
private var state = State . idle
30
- private let stateSemaphore = DispatchSemaphore ( value : 1 )
30
+ private let stateLock = Lock ( )
31
31
32
32
private var items = [ LifecycleItem] ( )
33
- private let itemsSemaphore = DispatchSemaphore ( value : 1 )
33
+ private let itemsLock = Lock ( )
34
34
35
35
/// Creates a `Lifecycle` instance.
36
36
public init ( ) {
@@ -43,16 +43,23 @@ public class Lifecycle {
43
43
/// - parameters:
44
44
/// - configuration: Defines lifecycle `Configuration`
45
45
public func startAndWait( configuration: Configuration = . init( ) ) throws {
46
- let waitSemaphore = DispatchSemaphore ( value: 0 )
46
+ let waitLock = Lock ( )
47
+ let group = DispatchGroup ( )
47
48
var startError : Error ?
48
- let items = self . itemsSemaphore. lock { self . items }
49
+ let items = self . itemsLock. withLock { self . items }
50
+ group. enter ( )
49
51
self . _start ( configuration: configuration, items: items) { error in
50
- startError = error
51
- waitSemaphore. signal ( )
52
+ waitLock. withLock {
53
+ startError = error
54
+ }
55
+ group. leave ( )
52
56
}
53
- waitSemaphore. wait ( )
54
- try startError. map { throw $0 }
55
57
self . shutdownGroup. wait ( )
58
+ try waitLock. withLock {
59
+ startError
60
+ } . map { error in
61
+ throw error
62
+ }
56
63
}
57
64
58
65
/// Starts the provided `LifecycleItem` array.
@@ -62,27 +69,27 @@ public class Lifecycle {
62
69
/// - configuration: Defines lifecycle `Configuration`
63
70
/// - callback: The handler which is called after the start operation completes. The parameter will be `nil` on success and contain the `Error` otherwise.
64
71
public func start( configuration: Configuration = . init( ) , callback: @escaping ( Error ? ) -> Void ) {
65
- let items = self . itemsSemaphore . lock { self . items }
72
+ let items = self . itemsLock . withLock { self . items }
66
73
self . _start ( configuration: configuration, items: items, callback: callback)
67
74
}
68
75
69
76
/// Shuts down the `LifecycleItem` array provided in `start` or `startAndWait`.
70
77
/// Shutdown is performed in reverse order of items provided.
71
78
public func shutdown( on queue: DispatchQueue = DispatchQueue . global ( ) ) {
72
- self . stateSemaphore . wait ( )
79
+ self . stateLock . lock ( )
73
80
switch self . state {
74
81
case . idle:
75
- self . stateSemaphore . signal ( )
82
+ self . stateLock . unlock ( )
76
83
self . shutdownGroup. leave ( )
77
84
case . starting:
78
85
self . state = . shuttingDown
79
- self . stateSemaphore . signal ( )
86
+ self . stateLock . unlock ( )
80
87
case . shuttingDown, . shutdown:
81
- self . stateSemaphore . signal ( )
88
+ self . stateLock . unlock ( )
82
89
return
83
90
case . started( let items) :
84
91
self . state = . shuttingDown
85
- self . stateSemaphore . signal ( )
92
+ self . stateLock . unlock ( )
86
93
self . _shutdown ( on: queue, items: items) {
87
94
self . shutdownGroup. leave ( )
88
95
}
@@ -97,7 +104,7 @@ public class Lifecycle {
97
104
// MARK: - private
98
105
99
106
private func _start( configuration: Configuration , items: [ LifecycleItem ] , callback: @escaping ( Error ? ) -> Void ) {
100
- self . stateSemaphore . lock {
107
+ self . stateLock . withLock {
101
108
guard case . idle = self . state else {
102
109
preconditionFailure ( " invalid state, \( self . state) " )
103
110
}
@@ -110,21 +117,21 @@ public class Lifecycle {
110
117
self . state = . starting
111
118
}
112
119
self . _start ( on: configuration. callbackQueue, items: items, index: 0 ) { _, error in
113
- self . stateSemaphore . wait ( )
120
+ self . stateLock . lock ( )
114
121
if error != nil {
115
122
self . state = . shuttingDown
116
123
}
117
124
switch self . state {
118
125
case . shuttingDown:
119
- self . stateSemaphore . signal ( )
126
+ self . stateLock . unlock ( )
120
127
// shutdown was called while starting, or start failed, shutdown what we can
121
128
self . _shutdown ( on: configuration. callbackQueue, items: items) {
122
129
callback ( error)
123
130
self . shutdownGroup. leave ( )
124
131
}
125
132
case . starting:
126
133
self . state = . started( items)
127
- self . stateSemaphore . signal ( )
134
+ self . stateLock . unlock ( )
128
135
configuration. shutdownSignal? . forEach { signal in
129
136
self . logger. info ( " setting up shutdown hook on \( signal) " )
130
137
let signalSource = Lifecycle . trap ( signal: signal, handler: { signal in
@@ -157,23 +164,20 @@ public class Lifecycle {
157
164
return callback ( index, error)
158
165
}
159
166
// shutdown called while starting
160
- self . stateSemaphore. wait ( )
161
- if case . shuttingDown = self . state {
162
- self . stateSemaphore. signal ( )
167
+ if case . shuttingDown = self . stateLock. withLock ( { self . state } ) {
163
168
return callback ( index, nil )
164
169
}
165
- self . stateSemaphore. signal ( )
166
170
self . _start ( on: queue, items: items, index: index + 1 , callback: callback)
167
171
}
168
172
}
169
173
170
174
private func _shutdown( on queue: DispatchQueue , items: [ LifecycleItem ] , callback: @escaping ( ) -> Void ) {
171
- self . stateSemaphore . lock {
175
+ self . stateLock . withLock {
172
176
self . logger. info ( " shutting down lifecycle " )
173
177
self . state = . shuttingDown
174
178
}
175
179
self . _shutdown ( on: queue, items: items. reversed ( ) , index: 0 ) {
176
- self . stateSemaphore . lock {
180
+ self . stateLock . withLock {
177
181
guard case . shuttingDown = self . state else {
178
182
preconditionFailure ( " invalid state, \( self . state) " )
179
183
}
@@ -253,12 +257,12 @@ public extension Lifecycle {
253
257
/// - parameters:
254
258
/// - items: one or more `LifecycleItem`.
255
259
func register( _ items: [ LifecycleItem ] ) {
256
- self . stateSemaphore . lock {
260
+ self . stateLock . withLock {
257
261
guard case . idle = self . state else {
258
262
preconditionFailure ( " invalid state, \( self . state) " )
259
263
}
260
264
}
261
- self . itemsSemaphore . lock {
265
+ self . itemsLock . withLock {
262
266
self . items. append ( contentsOf: items)
263
267
}
264
268
}
@@ -394,11 +398,3 @@ extension Lifecycle {
394
398
internal static let ALRM : Signal = Signal ( rawValue: SIGALRM)
395
399
}
396
400
}
397
-
398
- private extension DispatchSemaphore {
399
- func lock< T> ( _ body: ( ) -> T ) -> T {
400
- self . wait ( )
401
- defer { self . signal ( ) }
402
- return body ( )
403
- }
404
- }
0 commit comments