package f5 import ( "q5" ) type taskLock struct { key string entry q5.ListHead } type AsyncTask struct { status int32 debugInfo string cb func(*AsyncTask) succCb func(*AsyncTask) failCb func(*AsyncTask) exitCb func(*AsyncTask) preExecTimes int64 execTimes int64 lockKeys map[string]*taskLock } type LockAsyncTask = AsyncTask func (this *AsyncTask) init(cb func(*AsyncTask)) *AsyncTask { this.cb = cb return this } func (this *AsyncTask) GetExecTimes() int64 { return this.execTimes } func (this *AsyncTask) IsRunning() bool { return this.status == 0 } func (this *AsyncTask) IsSucc() bool { return this.status > 0 } func (this *AsyncTask) IsFail() bool { return this.status < 0 } func (this *AsyncTask) SetSucc() { if !this.IsRunning() { panic("task is not runing") } this.status = 1 this.ClearLocks() if this.succCb != nil { this.succCb(this) } if this.exitCb != nil { this.exitCb(this) } } func (this *AsyncTask) SetFail() { if !this.IsRunning() { panic("task is not runing") } this.status = -1 this.ClearLocks() if this.failCb != nil { this.failCb(this) } if this.exitCb != nil { this.exitCb(this) } } func (this *AsyncTask) Continue() *AsyncTask { if !this.IsRunning() { panic("task is not runing") } if len(this.lockKeys) > 0 { panic("lockTask not support continue") } GetApp().RegisterMainThreadCb( func () { this.cb(this) this.execTimes += 1 }) return this } func (this *AsyncTask) checkDo() *AsyncTask { if !this.IsRunning() { panic("task is not runing") } if this.allIsReady() { if this.preExecTimes <= 0 { this.preExecTimes++ if this.preExecTimes > 1 { panic("locktask preExectimes > 0") } GetApp().RegisterMainThreadCb( func () { this.cb(this) if this.execTimes > 0 { panic("locktask only run once") } this.execTimes += 1 }) } } return this } func (this *AsyncTask) OnSucc(cb func(*AsyncTask)) *AsyncTask { this.succCb = cb return this } func (this *AsyncTask) OnFail(cb func(*AsyncTask)) *AsyncTask { this.failCb = cb return this } func (this *AsyncTask) OnExit(cb func(*AsyncTask)) *AsyncTask { this.exitCb = cb return this } func (this *AsyncTask) allIsReady() bool { var allReady = true for _, lock := range(this.lockKeys) { if !_app.isFirstAsyncTask(lock.key, &lock.entry) { allReady = false break } } return allReady } func (this *AsyncTask) ClearLocks() { for _, lock := range(this.lockKeys) { lock.entry.DelInit() } for _, lock := range(this.lockKeys) { _app.clearEmptyPendingAsyncTask(lock.key) } for _, lock := range(this.lockKeys) { _app.notifyNextTask(lock.key) } } func NewAsyncTask(cb func(*AsyncTask)) *AsyncTask { p := new(AsyncTask) p.lockKeys = make(map[string]*taskLock) return p.init(cb).Continue() } func NewLockAsyncTask(keys [][]string, cb func(*LockAsyncTask)) *LockAsyncTask { p := new(AsyncTask) p.lockKeys = make(map[string]*taskLock) for _, val := range(keys) { if len(val) != 2 { panic("NewLockAsyncTask len error:" + q5.EncodeJson(val)) } lock := new(taskLock) lock.key = val[0] + val[1] lock.entry.Init(p) if _, ok := p.lockKeys[lock.key]; ok { panic("NewLockAsyncTask duplicate key:" + lock.key) } p.lockKeys[lock.key] = lock _app.forcePendingAsyncTask(lock.key).AddTail(&lock.entry) } if q5.IsDebug() { p.debugInfo = q5.GetCallStack() _timer.SetTimeout( 1000 * 2, func (e int32, args* q5.Args) { if e == q5.TIMER_EXEC_EVENT { if p.IsRunning() { _sysLog.Warning("LockAsyncaskTimeOut %s", p.debugInfo) panic("LockAsyncaskTimeOut") } } }) } return p.init(cb).checkDo() }