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 {
|
||||
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
|
||||
description string
|
||||
actors usync.RWMonitor[*actorSets]
|
||||
main MainRunnable
|
||||
ctx context.Context
|
||||
done context.CancelCauseFunc
|
||||
group sync.WaitGroup
|
||||
|
||||
35
phases.go
35
phases.go
@ -228,6 +228,41 @@ func (this *environment) phase60Initialization() 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)
|
||||
if this.Verb() { log.Println("... (70) starting up") }
|
||||
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
|
||||
// after resetting/initialization before failing, it is considered erratic
|
||||
// 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,
|
||||
// the initial delay interval is 8 seconds, the interval increase per
|
||||
// attempt is 8 seconds, and the maximum interval is one hour.
|
||||
@ -66,6 +68,12 @@ var env environment
|
||||
// configurable, but by default it is once every minute. When an actor
|
||||
// which implements [Resettable] is reset, it is given a configurable
|
||||
// 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
|
||||
// environment, a catastrophic error, [Done] being called, or the program
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user