// package kwg -- именованный ожидатель потоков ядра. // // Не позволяет завершиться ядру, если есть хоть один работающий поток package kwg import ( "context" "sync" "time" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/core_spec" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/defs" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/etypes/ebool" mKh "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers" mL1 "gitp78su.ipnodns.ru/svi/kern/v4/lev1" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/comp_spec" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_buf" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/safe_bool" "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kern_ent/stream_name" "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kspec" ) // kernelWg -- именованный ожидатель потоков ядра. type kernelWg struct { sync.RWMutex ctx context.Context dictStream map[*stream_name.AStreamName]bool // Словарь имён потоков с признаком работы isWork core_spec.ISafeBool log comp_spec.ILogBuf } var ( kernWg *kernelWg // Глобальный объект block sync.Mutex ) // GetKernelWg -- возвращает новый именованный ожидатель потоков ядра. func GetKernelWg(ctx context.Context) kspec.IKernelWg { block.Lock() defer block.Unlock() if kernWg != nil { kernWg.log.Debug(defs.TxtFix("GetKernelWg()")) return kernWg } mKh.If(ctx == nil).Hassert("GetKernelWg(): ctx==nil") paramLogBuf := &log_buf.LogBufParam{ IsTerm_: safe_bool.NewSafeBool(true), Prefix_: defs.TxtFix("kernelWg"), } sf := &kernelWg{ ctx: ctx, dictStream: map[*stream_name.AStreamName]bool{}, isWork: mL1.NewSafeBool(false), log: mL1.NewLogBuf(paramLogBuf), } sf.log.Debug(defs.TxtFix("GetKernelWg(): run")) go sf.close() sf.isWork.Set() kernWg = sf return kernWg } // Log -- возвращает лог ожидателя потоков. func (sf *kernelWg) Log() comp_spec.ILogBuf { return sf.log } // Len -- возвращает размер списка ожидания потоков. func (sf *kernelWg) Len() defs.Int { sf.RLock() defer sf.RUnlock() return defs.Int(len(sf.dictStream)) } // IsWork -- возвращает признак работы ядра. func (sf *kernelWg) IsWork() core_spec.EBool { res := sf.isWork.Get() return ebool.NewEBool(res) } // List -- возвращает список имён потоков на ожидании. func (sf *kernelWg) List() []*stream_name.AStreamName { sf.RLock() defer sf.RUnlock() lst := make([]*stream_name.AStreamName, 0, len(sf.dictStream)) for name := range sf.dictStream { lst = append(lst, name) } return lst } // Done -- удаляет поток из ожидания. func (sf *kernelWg) Done(name *stream_name.AStreamName) { sf.Lock() defer sf.Unlock() delete(sf.dictStream, name) msg := defs.TxtFix("Done(): stream(%v) done", name) sf.log.Debug(msg) } // Wait -- блокирующий вызов; возвращает управление, только когда все потоки завершили работу. func (sf *kernelWg) Wait() { for { time.Sleep(time.Millisecond * 1) if !sf.isWork.Get() { break } } sf.log.Debug(defs.TxtFix("Wait(): done")) } // Add -- добавляет поток в ожидание. func (sf *kernelWg) Add(name *stream_name.AStreamName) { sf.Lock() defer sf.Unlock() msg := defs.TxtFix("Add(): stream('%v') done", name) sf.log.Debug(msg) mKh.If(!sf.isWork.Get()).Hassert("Add(): stream=%v, work end", []any{name}) mKh.If(name.Get() == "").Hassert("Add(): name stream is empty") _, isOk := sf.dictStream[name] mKh.If(defs.Bool(isOk)).Hassert("Add(): stream '%v' already exists", name) sf.dictStream[name] = true } // Ожидает окончания работы ожидателя групп. func (sf *kernelWg) close() { <-sf.ctx.Done() fnDone := func() bool { sf.Lock() defer sf.Unlock() return len(sf.dictStream) == 0 } for { time.Sleep(time.Millisecond * 1) if fnDone() { break } } sf.Lock() defer sf.Unlock() if !sf.isWork.Get() { return } sf.isWork.Reset() sf.log.Debug(defs.TxtFix("close(): end")) }