@@ -207,31 +207,34 @@ func (c *SyncClosers) AcquireReference() bool {
207
207
}
208
208
newRef := ref + 1
209
209
if atomic .CompareAndSwapInt32 (& c .ref , ref , newRef ) {
210
- log .Debugf ("AcquireReference %p: %d" , c , newRef )
210
+ // log.Debugf("AcquireReference %p: %d", c, newRef)
211
211
return true
212
212
}
213
213
}
214
214
}
215
215
216
+ const closersClosed = math .MinInt16
217
+
216
218
func (c * SyncClosers ) Close () error {
217
- for {
218
- ref := atomic . LoadInt32 ( & c . ref )
219
- if ref < 0 {
220
- return nil
221
- }
222
- newRef := ref - 1
223
- if newRef <= 0 {
224
- newRef = math . MinInt16
225
- }
226
- if atomic . CompareAndSwapInt32 ( & c . ref , ref , newRef ) {
227
- log . Debugf ( "Close %p: %d" , c , ref )
228
- if newRef > 0 {
229
- return nil
230
- }
231
- break
232
- }
219
+ ref := atomic . AddInt32 ( & c . ref , - 1 )
220
+ if ref > 0 {
221
+ // log.Debugf("ReleaseReference %p: %d", c, ref)
222
+ return nil
223
+ }
224
+
225
+ if ref < - 1 {
226
+ atomic . StoreInt32 ( & c . ref , closersClosed )
227
+ return nil
228
+ }
229
+
230
+ // Attempt to acquire FinalClose permission.
231
+ // At this point, ref must be 0 or -1. We try to atomically change it to the closersClosed state.
232
+ // Only the first successful goroutine gets the cleanup permission.
233
+ if ! atomic . CompareAndSwapInt32 ( & c . ref , ref , closersClosed ) {
234
+ return nil
233
235
}
234
236
237
+ // log.Debugf("FinalClose %p", c)
235
238
var errs []error
236
239
for _ , closer := range c .closers {
237
240
if closer != nil {
0 commit comments