390 lines
9.6 KiB
Go
390 lines
9.6 KiB
Go
package q5
|
|
|
|
const CONFIG_BASE_SMALL = false
|
|
const TVN_BITS = 6
|
|
const TVR_BITS = 8
|
|
const TVN_SIZE = 1 << TVN_BITS
|
|
const TVR_SIZE = 1 << TVR_BITS
|
|
const TVN_MASK = TVN_SIZE - 1
|
|
const TVR_MASK = TVR_SIZE - 1
|
|
|
|
const (
|
|
TIMEOUT_TIMER = 0
|
|
INTERVAL_TIMER = iota
|
|
)
|
|
|
|
type XTimerDestoryHandleNode struct {
|
|
entry ListHead
|
|
cb func()
|
|
}
|
|
|
|
type XTimer struct {
|
|
freeTimerNum int32
|
|
freeTimerList ListHead
|
|
runningTimer *XTimerList
|
|
timerTick int64
|
|
getTickCount func(interface{}) int64
|
|
context interface{}
|
|
cacheTimerNum int32
|
|
tv1 [TVR_SIZE]ListHead
|
|
tv2 [TVN_SIZE]ListHead
|
|
tv3 [TVN_SIZE]ListHead
|
|
tv4 [TVN_SIZE]ListHead
|
|
tv5 [TVN_SIZE]ListHead
|
|
}
|
|
|
|
func (this *XTimer) Init(
|
|
getTickCount func(interface{}) int64,
|
|
context interface{},
|
|
gcTime int32,
|
|
cacheTimerNum int32) {
|
|
initListHeadFunc := func(head *ListHead) {
|
|
head.Init(nil)
|
|
}
|
|
initListHeadFunc(&this.freeTimerList)
|
|
for i := 0; i < len(this.tv1); i++ {
|
|
initListHeadFunc(&this.tv1[i])
|
|
}
|
|
for i := 0; i < len(this.tv2); i++ {
|
|
initListHeadFunc(&this.tv2[i])
|
|
}
|
|
for i := 0; i < len(this.tv3); i++ {
|
|
initListHeadFunc(&this.tv3[i])
|
|
}
|
|
for i := 0; i < len(this.tv4); i++ {
|
|
initListHeadFunc(&this.tv4[i])
|
|
}
|
|
for i := 0; i < len(this.tv5); i++ {
|
|
initListHeadFunc(&this.tv5[i])
|
|
}
|
|
|
|
this.timerTick = getTickCount(context)
|
|
this.context = context
|
|
this.getTickCount = getTickCount
|
|
this.cacheTimerNum = cacheTimerNum
|
|
this.SetInterval(gcTime, this.gcTimerFunc)
|
|
}
|
|
|
|
func (this *XTimer) UnInit() {
|
|
this.clear()
|
|
}
|
|
|
|
func (this *XTimer) clear() {
|
|
freeTimerFunc := func(head *ListHead) {
|
|
for !head.Empty() {
|
|
timerList := head.FirstEntry().(*XTimerList)
|
|
this.detachTimer(timerList)
|
|
if !timerList.attachEntry.Empty() {
|
|
timerList.attachEntry.DelInit()
|
|
}
|
|
}
|
|
}
|
|
freeTimerFunc(&this.freeTimerList)
|
|
for i := 0; i < len(this.tv1); i++ {
|
|
freeTimerFunc(&this.tv1[i])
|
|
}
|
|
for i := 0; i < len(this.tv2); i++ {
|
|
freeTimerFunc(&this.tv2[i])
|
|
}
|
|
for i := 0; i < len(this.tv3); i++ {
|
|
freeTimerFunc(&this.tv3[i])
|
|
}
|
|
for i := 0; i < len(this.tv4); i++ {
|
|
freeTimerFunc(&this.tv4[i])
|
|
}
|
|
for i := 0; i < len(this.tv5); i++ {
|
|
freeTimerFunc(&this.tv5[i])
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) Update() {
|
|
for this.getTickCount(this.context) >= this.timerTick {
|
|
index := uint32(this.timerTick & TVR_MASK)
|
|
|
|
if index == 0 &&
|
|
this.cascade(&this.tv2, this.getTimerIndex(0)) == 0 &&
|
|
this.cascade(&this.tv3, this.getTimerIndex(1)) == 0 &&
|
|
this.cascade(&this.tv4, this.getTimerIndex(2)) == 0 {
|
|
this.cascade(&this.tv5, this.getTimerIndex(3))
|
|
}
|
|
this.timerTick++
|
|
|
|
var workList ListHead
|
|
this.tv1[index].ReplaceInit(&workList)
|
|
for !workList.Empty() {
|
|
timer := workList.FirstEntry().(*XTimerList)
|
|
this.runningTimer = timer
|
|
timer.cb(TIMER_EXEC_EVENT, nil)
|
|
if this.runningTimer != nil {
|
|
switch this.runningTimer.timerType {
|
|
case TIMEOUT_TIMER:
|
|
this.internalDelete(timer, false, true)
|
|
case INTERVAL_TIMER:
|
|
this.internalModifyTime(timer, timer.expireTime)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.runningTimer = nil
|
|
}
|
|
|
|
func (this *XTimer) NewTimerAttacher() *XTimerAttacher {
|
|
attacher := new(XTimerAttacher)
|
|
attacher.timer = this
|
|
attacher.timers.Init(nil)
|
|
return attacher
|
|
}
|
|
|
|
func (this *XTimer) SetTimeout(expireTime int32, cb TimerCb) {
|
|
this.internalSetTimeout(expireTime, cb, nil, nil)
|
|
}
|
|
|
|
func (this *XTimer) SetTimeoutEx(expireTime int32, cb TimerCb, attacher *XTimerAttacher) {
|
|
this.internalSetTimeout(expireTime, cb, attacher, nil)
|
|
}
|
|
|
|
func (this *XTimer) SetTimeoutWp(expireTime int32, cb TimerCb) *XTimerWp {
|
|
var wp *XTimerWp
|
|
this.internalSetTimeout(expireTime, cb, nil, &wp)
|
|
return wp
|
|
}
|
|
|
|
func (this *XTimer) SetTimeoutExWp(expireTime int32, cb TimerCb, attacher *XTimerAttacher) *XTimerWp {
|
|
var wp *XTimerWp
|
|
this.internalSetTimeout(expireTime, cb, attacher, &wp)
|
|
return wp
|
|
}
|
|
|
|
func (this *XTimer) SetInterval(expireTime int32, cb TimerCb) {
|
|
this.internalSetInterval(expireTime, cb, nil, nil)
|
|
}
|
|
|
|
func (this *XTimer) SetIntervalEx(expireTime int32, cb TimerCb, attacher *XTimerAttacher) {
|
|
this.internalSetInterval(expireTime, cb, attacher, nil)
|
|
}
|
|
|
|
func (this *XTimer) SetIntervalWp(expireTime int32, cb TimerCb) *XTimerWp {
|
|
var wp *XTimerWp
|
|
this.internalSetInterval(expireTime, cb, nil, &wp)
|
|
return wp
|
|
}
|
|
|
|
func (this *XTimer) SetIntervalExWp(expireTime int32, cb TimerCb, attacher *XTimerAttacher) *XTimerWp {
|
|
var wp *XTimerWp
|
|
this.internalSetInterval(expireTime, cb, attacher, &wp)
|
|
return wp
|
|
}
|
|
|
|
func (this *XTimer) internalSetTimeout(expireTime int32, cb TimerCb, attacher *XTimerAttacher, wpPp **XTimerWp) {
|
|
timer := this.newTimerList()
|
|
timer.initTimerList(this, TIMEOUT_TIMER, expireTime, cb)
|
|
if attacher != nil {
|
|
attacher.timers.AddTail(&timer.attachEntry)
|
|
}
|
|
this.internalModifyTime(timer, expireTime)
|
|
if wpPp != nil {
|
|
timer.wp = &XTimerWp{
|
|
timer: timer,
|
|
}
|
|
*wpPp = timer.wp
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) internalSetInterval(expireTime int32, cb TimerCb, attacher *XTimerAttacher, wpPp **XTimerWp) {
|
|
timer := this.newTimerList()
|
|
timer.initTimerList(this, INTERVAL_TIMER, expireTime, cb)
|
|
if attacher != nil {
|
|
attacher.timers.AddTail(&timer.attachEntry)
|
|
}
|
|
this.internalModifyTime(timer, expireTime)
|
|
if wpPp != nil {
|
|
timer.wp = &XTimerWp{
|
|
timer: timer,
|
|
}
|
|
*wpPp = timer.wp
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) ModifyTimer(timerWp *XTimerWp, expireTime int32) {
|
|
if timerWp.Expired() {
|
|
panic("Xtimer ModifyTimer expired timer")
|
|
}
|
|
this.internalModifyTime(timerWp.timer, expireTime)
|
|
}
|
|
|
|
func (this *XTimer) Delete(timerWp *XTimerWp) {
|
|
if timerWp.Expired() {
|
|
panic("Xtimer Delete expired timer")
|
|
}
|
|
this.internalDelete(timerWp.timer, false, true)
|
|
}
|
|
|
|
func (this *XTimer) GetRemainTime(timerWp *XTimerWp) int64 {
|
|
if timerWp.Expired() {
|
|
panic("Xtimer GetRemainTime expired timer")
|
|
}
|
|
return this.internalGetRemainTime(timerWp.timer)
|
|
}
|
|
|
|
func (this *XTimer) internalGetRemainTime(timer *XTimerList) int64 {
|
|
remainTime := timer.expires - this.getTickCount(this.context)
|
|
if remainTime < 0 {
|
|
return 0
|
|
} else {
|
|
return remainTime
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) GetIdleTime() int64 {
|
|
var idleTime int64 = 1
|
|
for i := (this.timerTick & TVR_MASK); i < TVR_SIZE; i++ {
|
|
if !this.tv1[i].Empty() {
|
|
break
|
|
}
|
|
idleTime++
|
|
}
|
|
return idleTime
|
|
}
|
|
|
|
func (this *XTimer) detachTimer(timerList *XTimerList) {
|
|
if !timerList.entry.Empty() {
|
|
timerList.entry.DelInit()
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) addToFreeList(timerList *XTimerList) {
|
|
timerList.reset()
|
|
this.freeTimerList.AddTail(&timerList.entry)
|
|
this.freeTimerNum++
|
|
}
|
|
|
|
func (this *XTimer) cascade(tv *[TVN_SIZE]ListHead, index uint32) uint32 {
|
|
var cascadeList ListHead
|
|
tv[index].ReplaceInit(&cascadeList)
|
|
|
|
if !cascadeList.Empty() {
|
|
pos := cascadeList.next
|
|
next := pos.next
|
|
for pos != &cascadeList {
|
|
this.internalAddTimer(pos.data.(*XTimerList))
|
|
pos = next
|
|
next = pos.next
|
|
}
|
|
}
|
|
return index
|
|
}
|
|
|
|
func (this *XTimer) internalAddTimer(timerList *XTimerList) {
|
|
timerList.entry.data = timerList
|
|
expires := timerList.expires
|
|
idx := expires - this.timerTick
|
|
var vec *ListHead
|
|
var index uint32
|
|
|
|
if idx < 0 {
|
|
index = (uint32)(this.timerTick & TVR_MASK)
|
|
vec = &this.tv1[index]
|
|
} else if idx < TVR_SIZE {
|
|
index = (uint32)(expires & TVR_MASK)
|
|
vec = &this.tv1[index]
|
|
} else if idx < (1 << (TVR_BITS + TVN_BITS)) {
|
|
index = (uint32)((expires >> TVR_BITS) & TVN_MASK)
|
|
vec = &this.tv2[index]
|
|
} else if idx < (1 << (TVR_BITS + 2*TVN_BITS)) {
|
|
index = (uint32)((expires >> (TVR_BITS + 1*TVN_BITS)) & TVN_MASK)
|
|
vec = &this.tv3[index]
|
|
} else if idx < (1 << (TVR_BITS + 3*TVN_BITS)) {
|
|
index = (uint32)((expires >> (TVR_BITS + 2*TVN_BITS)) & TVN_MASK)
|
|
vec = &this.tv4[index]
|
|
} else {
|
|
index = (uint32)((expires >> (TVR_BITS + 3*TVN_BITS)) & TVN_MASK)
|
|
vec = &this.tv5[index]
|
|
}
|
|
vec.AddTail(&timerList.entry)
|
|
}
|
|
|
|
func (this *XTimer) getTimerIndex(index uint32) uint32 {
|
|
return (uint32)((this.timerTick >> (TVR_BITS + index*TVN_BITS)) & TVN_MASK)
|
|
}
|
|
|
|
func (this *XTimer) newTimerList() *XTimerList {
|
|
if !this.freeTimerList.Empty() {
|
|
timerList := this.freeTimerList.FirstEntry().(*XTimerList)
|
|
this.freeTimerNum--
|
|
return timerList
|
|
} else {
|
|
timerList := new(XTimerList)
|
|
timerList.init()
|
|
return timerList
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) gcTimerFunc(ev int32, args *Args) {
|
|
if ev == TIMER_EXEC_EVENT {
|
|
count := 0
|
|
for !this.freeTimerList.Empty() && this.freeTimerNum > this.cacheTimerNum {
|
|
timerList := this.freeTimerList.FirstEntry().(*XTimerList)
|
|
timerList.entry.DelInit()
|
|
this.freeTimerNum--
|
|
count++
|
|
if count > 1000 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) internalDelete(timer *XTimerList, isDestory bool, toFreeList bool) {
|
|
if timer == nil {
|
|
panic("Xtimer.internalDelete error")
|
|
}
|
|
if this.runningTimer == timer {
|
|
this.runningTimer = nil
|
|
}
|
|
this.detachTimer(timer)
|
|
if !timer.attachEntry.Empty() {
|
|
timer.attachEntry.DelInit()
|
|
}
|
|
for !timer.destoryHandleList.Empty() {
|
|
handle := timer.destoryHandleList.FirstEntry().(XTimerDestoryHandleNode)
|
|
handle.entry.DelInit()
|
|
handle.cb()
|
|
}
|
|
if isDestory {
|
|
timer.cb(TIMER_DESTORY_EVENT, nil)
|
|
} else {
|
|
timer.cb(TIMER_DELETE_EVENT, nil)
|
|
}
|
|
timer.cb = nil
|
|
if timer.wp != nil {
|
|
timer.wp.timer = nil
|
|
timer.wp = nil
|
|
}
|
|
if toFreeList {
|
|
this.addToFreeList(timer)
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) internalModifyTime(timer *XTimerList, expireTime int32) {
|
|
this.detachTimer(timer)
|
|
timer.expireTime = expireTime
|
|
timer.expires = this.getTickCount(this.context) + int64(expireTime)
|
|
this.internalAddTimer(timer)
|
|
}
|
|
|
|
func (this *XTimer) clearAttacher(attacher *XTimerAttacher) {
|
|
var workList ListHead
|
|
attacher.timers.ReplaceInit(&workList)
|
|
for !workList.Empty() {
|
|
timer := workList.FirstEntry().(*XTimerList)
|
|
this.internalDelete(timer, false, true)
|
|
}
|
|
}
|
|
|
|
func (this *XTimer) DeleteRunningTimer() {
|
|
if this.runningTimer != nil {
|
|
this.internalDelete(this.runningTimer, false, true)
|
|
this.runningTimer = nil
|
|
}
|
|
}
|