@@ -102,18 +102,14 @@ public interface Job : CoroutineContext.Element {
102
102
* Registers handler that is **synchronously** invoked on completion of this job.
103
103
* When job is already complete, then the handler is immediately invoked
104
104
* with a cancellation cause or `null`. Otherwise, handler will be invoked once when this
105
- * job is complete. Note, that [cancellation][cancel] is also a form of completion) .
105
+ * job is complete. Note, that [cancellation][cancel] is also a form of completion.
106
106
*
107
- * The resulting [Registration] can be used to [Registration.unregister] if this
108
- * registration is no longer needed. There is no need to unregister after completion.
107
+ * The resulting [DisposableHandle] can be used to [dispose][DisposableHandle.dispose] the
108
+ * registration of this handler and release its memory if its invocation is no longer needed.
109
+ * There is no need to dispose the handler after completion of this job. The reference to
110
+ * all the handlers are released when this job completes.
109
111
*/
110
- public fun invokeOnCompletion (handler : CompletionHandler ): Registration
111
-
112
- /* *
113
- * @suppress **Deprecated**: Renamed to `invokeOnCompletion`
114
- */
115
- @Deprecated(message = " Renamed to `invokeOnCompletion`" , replaceWith = ReplaceWith (" invokeOnCompletion(handler)" ))
116
- public fun onCompletion (handler : CompletionHandler ): Registration
112
+ public fun invokeOnCompletion (handler : CompletionHandler ): DisposableHandle
117
113
118
114
/* *
119
115
* Suspends coroutine until this job is complete. This invocation resumes normally (without exception)
@@ -161,15 +157,40 @@ public interface Job : CoroutineContext.Element {
161
157
/* *
162
158
* Registration object for [invokeOnCompletion]. It can be used to [unregister] if needed.
163
159
* There is no need to unregister after completion.
160
+ * @suppress **Deprecated**: Replace with `DisposableHandle`
164
161
*/
162
+ @Deprecated(message = " Replace with `DisposableHandle`" ,
163
+ replaceWith = ReplaceWith (" DisposableHandle" ))
165
164
public interface Registration {
166
165
/* *
167
166
* Unregisters completion handler.
167
+ * @suppress **Deprecated**: Replace with `dispose`
168
168
*/
169
+ @Deprecated(message = " Replace with `dispose`" ,
170
+ replaceWith = ReplaceWith (" dispose()" ))
169
171
public fun unregister ()
170
172
}
171
173
}
172
174
175
+ /* *
176
+ * A handle to an allocated object that can be disposed to make it eligible for garbage collection.
177
+ */
178
+ public interface DisposableHandle : Job .Registration {
179
+ /* *
180
+ * Disposes the corresponding object, making it eligible for garbage collection.
181
+ * Repeated invocation of this function has no effect.
182
+ */
183
+ public fun dispose ()
184
+
185
+ /* *
186
+ * Unregisters completion handler.
187
+ * @suppress **Deprecated**: Replace with `dispose`
188
+ */
189
+ @Deprecated(message = " Replace with `dispose`" ,
190
+ replaceWith = ReplaceWith (" dispose()" ))
191
+ public override fun unregister () = dispose()
192
+ }
193
+
173
194
/* *
174
195
* Handler for [Job.invokeOnCompletion].
175
196
*/
@@ -187,9 +208,23 @@ public typealias CancellationException = java.util.concurrent.CancellationExcept
187
208
* ```
188
209
* invokeOnCompletion { registration.unregister() }
189
210
* ```
211
+ * @suppress: **Deprecated**: Renamed to `disposeOnCompletion`.
190
212
*/
191
- public fun Job.unregisterOnCompletion (registration : Job .Registration ): Job .Registration =
192
- invokeOnCompletion(UnregisterOnCompletion (this , registration))
213
+ @Deprecated(message = " Renamed to `disposeOnCompletion`" ,
214
+ replaceWith = ReplaceWith (" disposeOnCompletion(registration)" ))
215
+ public fun Job.unregisterOnCompletion (registration : DisposableHandle ): DisposableHandle =
216
+ invokeOnCompletion(DisposeOnCompletion (this , registration))
217
+
218
+ /* *
219
+ * Disposes a specified [handle] when this job is complete.
220
+ *
221
+ * This is a shortcut for the following code with slightly more efficient implementation (one fewer object created).
222
+ * ```
223
+ * invokeOnCompletion { handle.dispose() }
224
+ * ```
225
+ */
226
+ public fun Job.disposeOnCompletion (handle : DisposableHandle ): DisposableHandle =
227
+ invokeOnCompletion(DisposeOnCompletion (this , handle))
193
228
194
229
/* *
195
230
* Cancels a specified [future] when this job is complete.
@@ -199,7 +234,7 @@ public fun Job.unregisterOnCompletion(registration: Job.Registration): Job.Regis
199
234
* invokeOnCompletion { future.cancel(false) }
200
235
* ```
201
236
*/
202
- public fun Job.cancelFutureOnCompletion (future : Future <* >): Job . Registration =
237
+ public fun Job.cancelFutureOnCompletion (future : Future <* >): DisposableHandle =
203
238
invokeOnCompletion(CancelFutureOnCompletion (this , future))
204
239
205
240
/* *
@@ -212,12 +247,19 @@ public suspend fun Job.join() = this.join()
212
247
/* *
213
248
* No-op implementation of [Job.Registration].
214
249
*/
215
- public object EmptyRegistration : Job.Registration {
250
+ @Deprecated(message = " Replace with `NonDisposableHandle`" ,
251
+ replaceWith = ReplaceWith (" NonDisposableHandle" ))
252
+ typealias EmptyRegistration = NonDisposableHandle
253
+
254
+ /* *
255
+ * No-op implementation of [DisposableHandle].
256
+ */
257
+ public object NonDisposableHandle : DisposableHandle {
216
258
/* * Does not do anything. */
217
- override fun unregister () {}
259
+ override fun dispose () {}
218
260
219
- /* * Returns "EmptyRegistration " string. */
220
- override fun toString (): String = " EmptyRegistration "
261
+ /* * Returns "NonDisposableHandle " string. */
262
+ override fun toString (): String = " NonDisposableHandle "
221
263
}
222
264
223
265
// --------------- utility classes to simplify job implementation
@@ -280,7 +322,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
280
322
private var _state : Any? = if (active) EmptyActive else EmptyNew // shared objects while we have no listeners
281
323
282
324
@Volatile
283
- private var registration : Job . Registration ? = null
325
+ private var parentHandle : DisposableHandle ? = null
284
326
285
327
protected companion object {
286
328
@JvmStatic
@@ -298,16 +340,16 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
298
340
* It shall be invoked at most once after construction after all other initialization.
299
341
*/
300
342
public fun initParentJob (parent : Job ? ) {
301
- check(registration == null )
343
+ check(parentHandle == null )
302
344
if (parent == null ) {
303
- registration = EmptyRegistration
345
+ parentHandle = NonDisposableHandle
304
346
return
305
347
}
306
348
// directly pass HandlerNode to parent scope to optimize one closure object (see makeNode)
307
349
val newRegistration = parent.invokeOnCompletion(ParentOnCompletion (parent, this ))
308
- registration = newRegistration
350
+ parentHandle = newRegistration
309
351
// now check our state _after_ registering (see updateState order of actions)
310
- if (isCompleted) newRegistration.unregister ()
352
+ if (isCompleted) newRegistration.dispose ()
311
353
}
312
354
313
355
internal open fun onParentCompletion (cause : Throwable ? ) {
@@ -338,7 +380,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
338
380
require(expect is Incomplete && update !is Incomplete ) // only incomplete -> completed transition is allowed
339
381
if (! STATE .compareAndSet(this , expect, update)) return false
340
382
// Unregister from parent job
341
- registration?.unregister () // volatile read registration _after_ state was updated
383
+ parentHandle?.dispose () // volatile read parentHandle _after_ state was updated
342
384
return true // continues in completeUpdateState
343
385
}
344
386
@@ -515,9 +557,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
515
557
}
516
558
}
517
559
518
- override fun onCompletion (handler : CompletionHandler ): Job .Registration = invokeOnCompletion(handler)
519
-
520
- final override fun invokeOnCompletion (handler : CompletionHandler ): Job .Registration {
560
+ final override fun invokeOnCompletion (handler : CompletionHandler ): DisposableHandle {
521
561
var nodeCache: JobNode <* >? = null
522
562
while (true ) { // lock-free loop on state
523
563
val state = this .state
@@ -545,7 +585,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
545
585
}
546
586
else -> { // is inactive
547
587
handler((state as ? CompletedExceptionally )?.exception)
548
- return EmptyRegistration
588
+ return NonDisposableHandle
549
589
}
550
590
}
551
591
}
@@ -560,7 +600,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
560
600
}
561
601
562
602
private suspend fun joinSuspend () = suspendCancellableCoroutine<Unit > { cont ->
563
- cont.unregisterOnCompletion (invokeOnCompletion(ResumeOnCompletion (this , cont)))
603
+ cont.disposeOnCompletion (invokeOnCompletion(ResumeOnCompletion (this , cont)))
564
604
}
565
605
566
606
override fun <R > registerSelectJoin (select : SelectInstance <R >, block : suspend () -> R ) {
@@ -576,7 +616,7 @@ public open class JobSupport(active: Boolean) : AbstractCoroutineContextElement(
576
616
}
577
617
if (startInternal(state) == 0 ) {
578
618
// slow-path -- register waiter for completion
579
- select.unregisterOnCompletion (invokeOnCompletion(SelectJoinOnCompletion (this , select, block)))
619
+ select.disposeOnSelect (invokeOnCompletion(SelectJoinOnCompletion (this , select, block)))
580
620
return
581
621
}
582
622
}
@@ -731,12 +771,12 @@ private class Empty(override val isActive: Boolean) : JobSupport.Incomplete {
731
771
732
772
internal abstract class JobNode <out J : Job >(
733
773
@JvmField val job : J
734
- ) : LockFreeLinkedListNode(), Job.Registration , CompletionHandler, JobSupport.Incomplete {
774
+ ) : LockFreeLinkedListNode(), DisposableHandle , CompletionHandler, JobSupport.Incomplete {
735
775
final override val isActive: Boolean get() = true
736
776
final override val idempotentStart: Any? get() = null
737
777
// if unregister is called on this instance, then Job was an instance of JobSupport that added this node it itself
738
778
// directly without wrapping
739
- final override fun unregister () = (job as JobSupport ).removeNode(this )
779
+ final override fun dispose () = (job as JobSupport ).removeNode(this )
740
780
override abstract fun invoke (reason : Throwable ? )
741
781
}
742
782
@@ -756,12 +796,12 @@ private class ResumeOnCompletion(
756
796
override fun toString () = " ResumeOnCompletion[$continuation ]"
757
797
}
758
798
759
- internal class UnregisterOnCompletion (
799
+ internal class DisposeOnCompletion (
760
800
job : Job ,
761
- @JvmField val registration : Job . Registration
801
+ @JvmField val handle : DisposableHandle
762
802
) : JobNode<Job>(job) {
763
- override fun invoke (reason : Throwable ? ) = registration.unregister ()
764
- override fun toString (): String = " UnregisterOnCompletion[ $registration ]"
803
+ override fun invoke (reason : Throwable ? ) = handle.dispose ()
804
+ override fun toString (): String = " DisposeOnCompletion[ $handle ]"
765
805
}
766
806
767
807
private class ParentOnCompletion (
0 commit comments