safing-portbase/modules/modules.go
2018-08-13 14:05:58 +02:00

147 lines
2.8 KiB
Go

// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package modules
import (
"container/list"
"os"
"time"
"github.com/tevino/abool"
)
var modules *list.List
var addModule chan *Module
var GlobalShutdown chan struct{}
var loggingActive bool
type Module struct {
Name string
Order uint8
Start chan struct{}
Active *abool.AtomicBool
startComplete chan struct{}
Stop chan struct{}
Stopped *abool.AtomicBool
stopComplete chan struct{}
}
func Register(name string, order uint8) *Module {
newModule := &Module{
Name: name,
Order: order,
Start: make(chan struct{}),
Active: abool.NewBool(true),
startComplete: make(chan struct{}),
Stop: make(chan struct{}),
Stopped: abool.NewBool(false),
stopComplete: make(chan struct{}),
}
addModule <- newModule
return newModule
}
func (module *Module) addToList() {
if loggingActive {
logger.Infof("Modules: starting %s", module.Name)
}
for e := modules.Back(); e != nil; e = e.Prev() {
if module.Order > e.Value.(*Module).Order {
modules.InsertAfter(module, e)
return
}
}
modules.PushFront(module)
}
func (module *Module) stop() {
module.Active.UnSet()
defer module.Stopped.Set()
for {
select {
case module.Stop <- struct{}{}:
case <-module.stopComplete:
return
case <-time.After(1 * time.Second):
if loggingActive {
logger.Warningf("Modules: waiting for %s to stop...", module.Name)
}
}
}
}
func (module *Module) StopComplete() {
if loggingActive {
logger.Warningf("Modules: stopped %s", module.Name)
}
module.stopComplete <- struct{}{}
}
func (module *Module) start() {
module.Stopped.UnSet()
defer module.Active.Set()
for {
select {
case module.Start <- struct{}{}:
case <-module.startComplete:
return
}
}
}
func (module *Module) StartComplete() {
if loggingActive {
logger.Infof("Modules: starting %s", module.Name)
}
module.startComplete <- struct{}{}
}
func InitiateFullShutdown() {
close(GlobalShutdown)
}
func fullStop() {
for e := modules.Back(); e != nil; e = e.Prev() {
if e.Value.(*Module).Active.IsSet() {
e.Value.(*Module).stop()
}
}
}
func run() {
select {
case <-loggerRegistered:
logger.Info("Modules: starting")
loggingActive = true
case <-time.After(1 * time.Second):
}
for {
select {
case <-GlobalShutdown:
if loggingActive {
logger.Warning("Modules: stopping")
}
fullStop()
os.Exit(0)
case m := <-addModule:
m.addToList()
// go m.start()
}
}
}
func init() {
modules = list.New()
addModule = make(chan *Module, 10)
GlobalShutdown = make(chan struct{})
loggerRegistered = make(chan struct{}, 1)
loggingActive = false
go run()
}