gitee.com/h79/goutils@v1.22.10/common/system/run.go (about) 1 package system 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "gitee.com/h79/goutils/common/option" 8 "os" 9 "os/signal" 10 "sync" 11 "sync/atomic" 12 "syscall" 13 "time" 14 ) 15 16 var closeCh chan bool 17 var quited bool 18 var quitErr error 19 var quitCode int32 20 var ErrNormalQuit = errors.New("normal quit") 21 22 func init() { 23 var _ = closeCh 24 var _ = quited 25 closeCh = make(chan bool) 26 quited = false 27 } 28 29 type ExitSig struct { 30 S chan os.Signal 31 } 32 33 func (c *ExitSig) Done() <-chan os.Signal { 34 return c.S 35 } 36 37 func Exit() *ExitSig { 38 e := &ExitSig{S: make(chan os.Signal)} 39 signal.Notify(e.S, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGQUIT) 40 return e 41 } 42 43 func IsNormalQuit() bool { 44 return quited && (quitErr == nil || errors.Is(ErrNormalQuit, quitErr)) 45 } 46 47 func IsQuit() bool { 48 return quited 49 } 50 51 func GetQuitCode() int32 { 52 return quitCode 53 } 54 55 func SetQuitCode(code int32) { 56 quitCode = code 57 } 58 59 func GetQuitErr() error { 60 return quitErr 61 } 62 63 func SetQuitErr(err error) { 64 quitErr = err 65 } 66 67 func QuitApp(code int32) { 68 if quited { 69 return 70 } 71 quited = true 72 quitCode = code 73 close(closeCh) 74 fmt.Println("quit program.") 75 } 76 77 func Close() { 78 QuitApp(-1) 79 } 80 81 func Closed() <-chan bool { 82 return closeCh 83 } 84 85 func AfterQuit(t time.Duration) { 86 Wait(t) 87 } 88 89 func Wait(t time.Duration) { 90 ti := time.NewTimer(t) 91 defer ti.Stop() 92 select { 93 case <-ti.C: 94 return 95 } 96 } 97 98 func Stop(d time.Duration, stop chan bool) { 99 go func() { 100 Wait(d) 101 ti := time.NewTimer(d * 2) 102 defer ti.Stop() 103 select { 104 case <-stop: 105 stop <- true 106 return 107 case <-ti.C: 108 return 109 } 110 }() 111 stop <- true 112 <-stop 113 } 114 115 type Running struct { 116 ev *Event 117 c int32 118 wg sync.WaitGroup 119 } 120 121 var ( 122 mainIf int32 = 0 123 running *Running 124 once sync.Once 125 ) 126 127 func Go() *Running { 128 once.Do(func() { 129 running = NewRunning() 130 }) 131 return running 132 } 133 134 // NewRunning 135 // f 是否fire 136 func NewRunning() *Running { 137 return &Running{ev: NewEvent()} 138 } 139 140 func ChildRunning(fn func(), exits ...func()) { 141 Go().Run(false, fn, exits...) 142 } 143 144 func MainRunning(fn func(), exits ...func()) { 145 if atomic.AddInt32(&mainIf, 1) > 1 { 146 panic("can not repeat call,only call one") 147 } 148 Go().runM(fn, exits...) 149 } 150 151 // Run if fire=true, select Running.Done() 152 func (m *Running) Run(fire bool, fn func(), exits ...func()) { 153 if quited { 154 return 155 } 156 var c = atomic.AddInt32(&m.c, 1) 157 fmt.Println("enter child go coroutine,count: ", c) 158 m.wg.Add(1) 159 go func() { 160 defer m.done(true, fire) 161 defer Recover(exits...) 162 fn() 163 }() 164 } 165 166 func (m *Running) runM(fn func(), exits ...func()) { 167 if quited { 168 return 169 } 170 var c = atomic.AddInt32(&m.c, 1) 171 fmt.Println("enter main go coroutine,count: ", c) 172 m.wg.Add(1) 173 go func() { 174 defer m.done(false, true) 175 defer Recover(exits...) 176 defer Close() 177 defer atomic.StoreInt32(&mainIf, 0) 178 fn() 179 }() 180 } 181 182 func (m *Running) done(child, fire bool) { 183 var c = atomic.AddInt32(&m.c, -1) 184 fmt.Println("exit go coroutine, count: ", c, ",it is main coroutine: ", !child) 185 if fire { 186 m.ev.Fire() 187 } 188 m.wg.Done() 189 } 190 191 func (m *Running) Done() <-chan struct{} { 192 return m.ev.Done() 193 } 194 195 func (m *Running) Wait() { 196 m.wg.Wait() 197 } 198 199 func (m *Running) Count() int32 { 200 return atomic.LoadInt32(&m.c) 201 } 202 203 type RunningCheck struct { 204 rm sync.RWMutex 205 fRun bool 206 } 207 208 func (rc *RunningCheck) IsRunning() bool { 209 rc.rm.RLock() 210 defer rc.rm.RUnlock() 211 return rc.fRun 212 } 213 214 // Deprecated: this function simply calls [GoRunning]. 215 func (rc *RunningCheck) TryGoRunning(fn func(), exits ...func()) { 216 rc.GoRunning(fn, exits...) 217 } 218 219 func (rc *RunningCheck) GoRunning(fn func(), exits ...func()) { 220 rc.GoRunningV2(func() {}, fn, exits...) 221 } 222 223 func (rc *RunningCheck) GoRunningV2(running func(), fn func(), exits ...func()) { 224 if rc.IsRunning() { 225 return 226 } 227 rc.runningSet(true) 228 running() 229 ChildRunning(func() { 230 defer rc.runningSet(false) 231 fn() 232 }, exits...) 233 } 234 235 func (rc *RunningCheck) runningSet(flag bool) { 236 rc.rm.Lock() 237 rc.fRun = flag 238 rc.rm.Unlock() 239 } 240 241 type Task func(opts ...option.Option) (any, error) 242 243 func RunAfter(timeout time.Duration, task Task, opts ...option.Option) (any, error) { 244 if timeout <= 0 { 245 return task(opts...) 246 } 247 resultCh := make(chan *resultWithError, 1) 248 249 ChildRunning(func() { 250 result, err := task(opts...) 251 resultCh <- &resultWithError{result, err} 252 }) 253 ti := time.NewTimer(timeout) 254 defer ti.Stop() 255 select { 256 case <-ti.C: 257 return nil, TimeoutError 258 case rwe := <-resultCh: 259 return rwe.result, rwe.err 260 case <-Closed(): 261 return nil, ClosedError 262 } 263 } 264 265 func RunWithContext(ctx context.Context, task Task) (any, error) { 266 resultCh := make(chan *resultWithError, 1) 267 ChildRunning(func() { 268 result, err := task() 269 resultCh <- &resultWithError{result, err} 270 }) 271 select { 272 case <-ctx.Done(): 273 return nil, ctx.Err() 274 case rwe := <-resultCh: 275 return rwe.result, rwe.err 276 case <-Closed(): 277 return nil, ClosedError 278 } 279 } 280 281 // Ticker 282 // 定时调用 283 func Ticker(tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) { 284 Delay(0, tick, fun, param, funcDefer, paramDefer) 285 } 286 287 func DelayOnly(delay time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) { 288 Delay(delay, 0, fun, param, funcDefer, paramDefer) 289 } 290 291 func Delay(delay, tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) { 292 if fun == nil { 293 panic("fun is nil") 294 } 295 ChildRunning(func() { 296 pd := ParamDefer{P: paramDefer} 297 defer func() { 298 if funcDefer != nil { 299 funcDefer(pd) 300 } 301 }() 302 if delay > 0 { 303 Wait(delay) 304 } 305 if tick <= 0 { 306 fun(param) 307 pd.Reason = 2 308 return 309 } 310 if delay > 0 { 311 if fun(param) { 312 pd.Reason = 2 313 return 314 } 315 } 316 ticker := time.NewTicker(tick) 317 defer ticker.Stop() 318 for { 319 select { 320 case <-ticker.C: 321 if fun(param) { 322 pd.Reason = 2 323 return 324 } 325 case <-Closed(): 326 pd.Reason = 1 327 return 328 } 329 } 330 }) 331 } 332 333 type resultWithError struct { 334 result any 335 err error 336 } 337 338 type ParamDefer struct { 339 P any 340 Reason int 341 }