Add MainRunnable interface for locking to the main thread
This commit is contained in:
parent
f0611e53ce
commit
32c8e7f7c3
12
actor.go
12
actor.go
@ -134,3 +134,15 @@ type RunShutdownable interface {
|
|||||||
type Cleanupable interface {
|
type Cleanupable interface {
|
||||||
Cleanup(ctx context.Context) error
|
Cleanup(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MainRunnable is any object with a function that must be bound to the main
|
||||||
|
// thread. Only one actor may implement this at a time, and it must have been
|
||||||
|
// added at the start of the environment as an argument to the run function.
|
||||||
|
type MainRunnable interface {
|
||||||
|
// RunMain is run in the main thread and must stop once ShutdownMain
|
||||||
|
// is called.
|
||||||
|
RunMain() error
|
||||||
|
// ShutdownMain is like [RunShutdownable.Shutdown], but unblocks RunMain
|
||||||
|
// instead of Run.
|
||||||
|
ShutdownMain(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ type environment struct {
|
|||||||
name string
|
name string
|
||||||
description string
|
description string
|
||||||
actors usync.RWMonitor[*actorSets]
|
actors usync.RWMonitor[*actorSets]
|
||||||
|
main MainRunnable
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
done context.CancelCauseFunc
|
done context.CancelCauseFunc
|
||||||
group sync.WaitGroup
|
group sync.WaitGroup
|
||||||
|
|||||||
35
phases.go
35
phases.go
@ -228,6 +228,41 @@ func (this *environment) phase60Initialization() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *environment) phase70Running() bool {
|
func (this *environment) phase70Running() bool {
|
||||||
|
for actor := range this.All() {
|
||||||
|
if actor, ok := actor.(MainRunnable); ok {
|
||||||
|
this.main = actor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
result <- this.phase70RunningBody()
|
||||||
|
if this.main != nil {
|
||||||
|
shutdownCtx, done := context.WithTimeout(
|
||||||
|
context.Background(),
|
||||||
|
defaul(this.timing.shutdownTimeout.Load(),
|
||||||
|
defaultShutdownTimeout))
|
||||||
|
defer done()
|
||||||
|
this.main.ShutdownMain(shutdownCtx)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if this.main != nil {
|
||||||
|
mainActor := this.main.(Actor)
|
||||||
|
if this.Verb() { log.Printf("(i) (70) binding %s to main thread", mainActor.Type()) }
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
err := this.main.RunMain()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("XXX [%s] main thread failed: %v", mainActor.Type(), err)
|
||||||
|
}
|
||||||
|
if this.Verb() { log.Printf("(i) (70) main thread exited") }
|
||||||
|
}
|
||||||
|
|
||||||
|
return <- result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *environment) phase70RunningBody() bool {
|
||||||
defer this.Done(nil)
|
defer this.Done(nil)
|
||||||
if this.Verb() { log.Println("... (70) starting up") }
|
if this.Verb() { log.Println("... (70) starting up") }
|
||||||
this.running.Store(true)
|
this.running.Store(true)
|
||||||
|
|||||||
10
run.go
10
run.go
@ -57,7 +57,9 @@ var env environment
|
|||||||
// goroutine. If an actor does not run for a meaningful amount of time
|
// goroutine. If an actor does not run for a meaningful amount of time
|
||||||
// after resetting/initialization before failing, it is considered erratic
|
// after resetting/initialization before failing, it is considered erratic
|
||||||
// and further attempts to restart it will be spaced by a limited,
|
// and further attempts to restart it will be spaced by a limited,
|
||||||
// constantly increasing time interval. The timing is configurable, but by
|
// constantly increasing time interval.
|
||||||
|
//
|
||||||
|
// The timing is configurable, but by
|
||||||
// default the threshold for a meaningful amount of runtime is 16 seconds,
|
// default the threshold for a meaningful amount of runtime is 16 seconds,
|
||||||
// the initial delay interval is 8 seconds, the interval increase per
|
// the initial delay interval is 8 seconds, the interval increase per
|
||||||
// attempt is 8 seconds, and the maximum interval is one hour.
|
// attempt is 8 seconds, and the maximum interval is one hour.
|
||||||
@ -67,6 +69,12 @@ var env environment
|
|||||||
// which implements [Resettable] is reset, it is given a configurable
|
// which implements [Resettable] is reset, it is given a configurable
|
||||||
// timeout, which is 8 minutes by default.
|
// timeout, which is 8 minutes by default.
|
||||||
//
|
//
|
||||||
|
// If one of the actors directly passed to Run implements MainRunnable,
|
||||||
|
// it will be bound to the main thread and the CAMFISH environment will
|
||||||
|
// be run in a different thread. If more than one actor implementing
|
||||||
|
// MainRunnable is passed to the Run function, only the first one is
|
||||||
|
// considered.
|
||||||
|
//
|
||||||
// 80. Shutdown: This can be triggered by all actors being removed from the
|
// 80. Shutdown: This can be triggered by all actors being removed from the
|
||||||
// environment, a catastrophic error, [Done] being called, or the program
|
// environment, a catastrophic error, [Done] being called, or the program
|
||||||
// recieving SIGINT. If necessary, the environment shuts down all running
|
// recieving SIGINT. If necessary, the environment shuts down all running
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user