@@ -207,31 +207,34 @@ func (c *SyncClosers) AcquireReference() bool {
207207 }
208208 newRef := ref + 1
209209 if atomic .CompareAndSwapInt32 (& c .ref , ref , newRef ) {
210- log .Debugf ("AcquireReference %p: %d" , c , newRef )
210+ // log.Debugf("AcquireReference %p: %d", c, newRef)
211211 return true
212212 }
213213 }
214214}
215215
216+ const closersClosed = math .MinInt16
217+
216218func (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
233235 }
234236
237+ // log.Debugf("FinalClose %p", c)
235238 var errs []error
236239 for _ , closer := range c .closers {
237240 if closer != nil {
0 commit comments