// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sql

import (
	
	
)

// A closingMutex is an RWMutex for synchronizing close.
// Unlike a sync.RWMutex, RLock takes priority over Lock.
// Reads can starve out close, but reads are safely reentrant.
type closingMutex struct {
	// state is 2*readers+writerWaiting.
	//   0 is unlocked
	//   1 is unlocked and a writer needs to wake
	//   >0 is read-locked
	//   <0 is write-locked
	state atomic.Int64
	mu    sync.Mutex
	read  *sync.Cond
	write *sync.Cond
}

func ( *closingMutex) () {
	if .TryRLock() {
		return
	}

	// Wait for writer.
	.mu.Lock()
	defer .mu.Unlock()
	for {
		if .TryRLock() {
			return
		}
		.init()
		.read.Wait()
	}
}

func ( *closingMutex) () {
	for {
		 := .state.Load()
		if  < 2 {
			panic("runlock of un-rlocked mutex")
		}
		if .state.CompareAndSwap(, -2) {
			if -2 == 1 {
				// We were the last reader, and a writer is waiting.
				// The lock makes sure the writer sees the broadcast.
				.mu.Lock()
				defer .mu.Unlock()
				.write.Broadcast()
			}
			return
		}
	}
}

func ( *closingMutex) () {
	.mu.Lock()
	defer .mu.Unlock()
	for {
		 := .state.Load()
		if  == 0 ||  == 1 {
			if .state.CompareAndSwap(, -1) {
				return
			}
			continue
		}
		// Set writer waiting bit and sleep.
		if &1 == 0 && !.state.CompareAndSwap(, |1) {
			continue
		}
		.init()
		.write.Wait()
	}
}

func ( *closingMutex) () {
	.mu.Lock()
	defer .mu.Unlock()
	if !.state.CompareAndSwap(-1, 0) {
		panic("unlock of unlocked mutex")
	}
	if .read != nil {
		.read.Broadcast()
		.write.Broadcast()
	}
}

func ( *closingMutex) () bool {
	for {
		 := .state.Load()
		// Fail if the mutex is write locked (x < 0)
		// or unlocked with a writer waiting (x == 1).
		//
		// If the mutex is read-locked (x > 1), try to add a reader
		// even if this starves out a waiting writer.
		if  < 0 ||  == 1 {
			return false
		}
		if .state.CompareAndSwap(, +2) {
			return true
		}
	}
}

func ( *closingMutex) () {
	// Lazily create the read/write Conds.
	// In the common, uncontended case, we'll never need them.
	if .read == nil {
		.read = sync.NewCond(&.mu)
		.write = sync.NewCond(&.mu)
	}
}