package syncUtil

import (
	"fmt"
	"runtime/debug"
	"sync"
	"time"
)

// 写锁对象
type Locker struct {
	locking   bool
	prevStack []byte
	mutex     sync.Mutex
}

// 内部锁
// 返回值：
// 加锁是否成功
func (this *Locker) lock() bool {
	this.mutex.Lock()
	defer this.mutex.Unlock()

	// 如果已经被锁定，则返回失败
	if this.locking {
		return false
	}

	// 否则进行锁定，并返回成功
	this.locking = true

	// 记录Stack信息
	if if_record_stack_info {
		this.prevStack = debug.Stack()
	}

	return true
}

// 尝试加锁，如果在指定的时间内失败，则会返回失败；否则返回成功
// timeout:指定的毫秒数,timeout<=0则将会死等
// 返回值：
// 成功或失败
// 如果失败，返回上一次成功加锁时的堆栈信息
// 如果失败，返回当前的堆栈信息
func (this *Locker) Lock(timeout int) (successful bool, prevStack string, currStack string) {
	timeout = getTimeout(timeout)

	// 遍历指定的次数（即指定的超时时间）
	for i := 0; i < timeout; i++ {
		// 如果锁定成功，则返回成功
		if this.lock() {
			successful = true
			break
		}

		// 如果锁定失败，则休眠1ms，然后再重试
		time.Sleep(time.Millisecond)
	}

	// 如果时间结束仍然是失败，则返回上次成功的堆栈信息，以及当前的堆栈信息
	if successful == false {
		if this.prevStack != nil && len(this.prevStack) > 0 {
			prevStack = string(this.prevStack)
		}
		currStack = string(debug.Stack())
	}

	return
}

// 锁定（死等方式）
func (this *Locker) WaitLock() {
	successful, prevStack, currStack := this.Lock(0)
	if successful == false {
		fmt.Printf("Locker.WaitLock():{PrevStack:%s, currStack:%s}\n", prevStack, currStack)
	}
}

// 解锁
func (this *Locker) Unlock() {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	this.locking = false
}

// 创建新的锁对象
func NewLocker() *Locker {
	return &Locker{}
}
