@ -10,7 +10,7 @@ import (
)
)
// Assumed that thread is already locked for signal
// Assumed that thread is already locked for signal
func ( thread * SimpleThread ) Signal ( context * Read Context, signal GraphSignal ) error {
func ( thread * SimpleThread ) Signal ( context * State Context, signal GraphSignal ) error {
err := thread . SimpleLockable . Signal ( context , signal )
err := thread . SimpleLockable . Signal ( context , signal )
if err != nil {
if err != nil {
return err
return err
@ -18,9 +18,9 @@ func (thread *SimpleThread) Signal(context *ReadContext, signal GraphSignal) err
switch signal . Direction ( ) {
switch signal . Direction ( ) {
case Up :
case Up :
err = Use More States( context , thread , NewLockInfo ( thread , [ ] string { "parent" } ) , func ( context * Read Context) error {
err = Use States( context , thread , NewLockInfo ( thread , [ ] string { "parent" } ) , func ( context * State Context) error {
if thread . parent != nil {
if thread . parent != nil {
return Use More States( context , thread , NewLockInfo ( thread . parent , [ ] string { "signal" } ) , func ( context * Read Context) error {
return Use States( context , thread , NewLockInfo ( thread . parent , [ ] string { "signal" } ) , func ( context * State Context) error {
return thread . parent . Signal ( context , signal )
return thread . parent . Signal ( context , signal )
} )
} )
} else {
} else {
@ -28,10 +28,10 @@ func (thread *SimpleThread) Signal(context *ReadContext, signal GraphSignal) err
}
}
} )
} )
case Down :
case Down :
err = Use More States( context , thread , NewLockMap (
err = Use States( context , thread , NewLockMap (
NewLockInfo ( thread , [ ] string { "children" } ) ,
NewLockInfo ( thread , [ ] string { "children" } ) ,
LockList ( thread . children , [ ] string { "signal" } ) ,
LockList ( thread . children , [ ] string { "signal" } ) ,
) , func ( context * Read Context) error {
) , func ( context * State Context) error {
for _ , child := range ( thread . children ) {
for _ , child := range ( thread . children ) {
err := child . Signal ( context , signal )
err := child . Signal ( context , signal )
if err != nil {
if err != nil {
@ -169,15 +169,15 @@ func (thread * SimpleThread) AddChild(child Thread, info ThreadInfo) error {
return nil
return nil
}
}
func checkIfChild ( context * Wri teContext, target Thread , cur Thread ) bool {
func checkIfChild ( context * Sta teContext, target Thread , cur Thread ) bool {
for _ , child := range ( cur . Children ( ) ) {
for _ , child := range ( cur . Children ( ) ) {
if child . ID ( ) == target . ID ( ) {
if child . ID ( ) == target . ID ( ) {
return true
return true
}
}
is_child := false
is_child := false
Update More States( context , cur , NewLockMap (
Update States( context , cur , NewLockMap (
NewLockInfo ( child , [ ] string { "children" } ) ,
NewLockInfo ( child , [ ] string { "children" } ) ,
) , func ( context * Wri teContext) error {
) , func ( context * Sta teContext) error {
is_child = checkIfChild ( context , target , child )
is_child = checkIfChild ( context , target , child )
return nil
return nil
} )
} )
@ -189,7 +189,9 @@ func checkIfChild(context *WriteContext, target Thread, cur Thread) bool {
return false
return false
}
}
func LinkThreads ( context * WriteContext , princ Node , thread Thread , child Thread , info ThreadInfo ) error {
// Links child to parent with info as the associated info
// Continues the write context with princ, getting children for thread and parent for child
func LinkThreads ( context * StateContext , princ Node , thread Thread , child Thread , info ThreadInfo ) error {
if context == nil || thread == nil || child == nil {
if context == nil || thread == nil || child == nil {
return fmt . Errorf ( "invalid input" )
return fmt . Errorf ( "invalid input" )
}
}
@ -198,7 +200,10 @@ func LinkThreads(context *WriteContext, princ Node, thread Thread, child Thread,
return fmt . Errorf ( "Will not link %s as a child of itself" , thread . ID ( ) )
return fmt . Errorf ( "Will not link %s as a child of itself" , thread . ID ( ) )
}
}
return UpdateMoreStates ( context , princ , LockList ( [ ] Node { child , thread } , [ ] string { "parent" , "children" } ) , func ( context * WriteContext ) error {
return UpdateStates ( context , princ , LockMap {
child . ID ( ) : LockInfo { Node : child , Resources : [ ] string { "parent" } } ,
thread . ID ( ) : LockInfo { Node : thread , Resources : [ ] string { "children" } } ,
} , func ( context * StateContext ) error {
if child . Parent ( ) != nil {
if child . Parent ( ) != nil {
return fmt . Errorf ( "EVENT_LINK_ERR: %s already has a parent, cannot link as child" , child . ID ( ) )
return fmt . Errorf ( "EVENT_LINK_ERR: %s already has a parent, cannot link as child" , child . ID ( ) )
}
}
@ -449,7 +454,7 @@ func NewSimpleThread(id NodeID, name string, state_name string, info_type reflec
}
}
// Requires the read permission of threads children
// Requires the read permission of threads children
func FindChild ( context * Read Context, princ Node , thread Thread , id NodeID ) Thread {
func FindChild ( context * State Context, princ Node , thread Thread , id NodeID ) Thread {
if thread == nil {
if thread == nil {
panic ( "cannot recurse through nil" )
panic ( "cannot recurse through nil" )
}
}
@ -459,7 +464,7 @@ func FindChild(context *ReadContext, princ Node, thread Thread, id NodeID) Threa
for _ , child := range thread . Children ( ) {
for _ , child := range thread . Children ( ) {
var result Thread = nil
var result Thread = nil
Use More States( context , princ , NewLockInfo ( child , [ ] string { "children" } ) , func ( context * Read Context) error {
Use States( context , princ , NewLockInfo ( child , [ ] string { "children" } ) , func ( context * State Context) error {
result = FindChild ( context , princ , child , id )
result = FindChild ( context , princ , child , id )
return nil
return nil
} )
} )
@ -485,7 +490,7 @@ func ChildGo(ctx * Context, thread Thread, child Thread, first_action string) {
} ( child )
} ( child )
}
}
// Main Loop for Threads
// Main Loop for Threads , starts a write context, so cannot be called from a write or read context
func ThreadLoop ( ctx * Context , thread Thread , first_action string ) error {
func ThreadLoop ( ctx * Context , thread Thread , first_action string ) error {
// Start the thread, error if double-started
// Start the thread, error if double-started
ctx . Log . Logf ( "thread" , "THREAD_LOOP_START: %s - %s" , thread . ID ( ) , first_action )
ctx . Log . Logf ( "thread" , "THREAD_LOOP_START: %s - %s" , thread . ID ( ) , first_action )
@ -515,18 +520,8 @@ func ThreadLoop(ctx * Context, thread Thread, first_action string) error {
return err
return err
}
}
err = UpdateStates ( ctx , thread , NewLockInfo ( thread , [ ] string { "state" } ) , func ( context * WriteContext ) error {
err := thread . SetState ( "finished" )
if err != nil {
return err
}
return UnlockLockables ( context , [ ] Lockable { thread } , thread )
} )
if err != nil {
ctx . Log . Logf ( "thread" , "THREAD_LOOP_UNLOCK_ERR: %e" , err )
return err
}
ctx . Log . Logf ( "thread" , "THREAD_LOOP_DONE: %s" , thread . ID ( ) )
ctx . Log . Logf ( "thread" , "THREAD_LOOP_DONE: %s" , thread . ID ( ) )
@ -578,13 +573,16 @@ func (thread * SimpleThread) AllowedToTakeLock(new_owner Lockable, lockable Lock
return false
return false
}
}
// Helper function to start a child from a thread during a signal handler
// Starts a write context, so cannot be called from either a write or read context
func ThreadStartChild ( ctx * Context , thread Thread , signal StartChildSignal ) error {
func ThreadStartChild ( ctx * Context , thread Thread , signal StartChildSignal ) error {
return UpdateStates ( ctx , thread , NewLockInfo ( thread , [ ] string { "children" } ) , func ( context * WriteContext ) error {
context := NewWriteContext ( ctx )
return UpdateStates ( context , thread , NewLockInfo ( thread , [ ] string { "children" } ) , func ( context * StateContext ) error {
child := thread . Child ( signal . ID )
child := thread . Child ( signal . ID )
if child == nil {
if child == nil {
return fmt . Errorf ( "%s is not a child of %s" , signal . ID , thread . ID ( ) )
return fmt . Errorf ( "%s is not a child of %s" , signal . ID , thread . ID ( ) )
}
}
return Update More States( context , thread , NewLockInfo ( child , [ ] string { "start" } ) , func ( context * Wri teContext) error {
return Update States( context , thread , NewLockInfo ( child , [ ] string { "start" } ) , func ( context * Sta teContext) error {
info := thread . ChildInfo ( signal . ID ) . ( * ParentThreadInfo )
info := thread . ChildInfo ( signal . ID ) . ( * ParentThreadInfo )
info . Start = true
info . Start = true
@ -595,11 +593,14 @@ func ThreadStartChild(ctx *Context, thread Thread, signal StartChildSignal) erro
} )
} )
}
}
// Helper function to restore threads that should be running from a parents restore action
// Starts a write context, so cannot be called from either a write or read context
func ThreadRestore ( ctx * Context , thread Thread ) {
func ThreadRestore ( ctx * Context , thread Thread ) {
UpdateStates ( ctx , thread , NewLockMap (
context := NewWriteContext ( ctx )
UpdateStates ( context , thread , NewLockMap (
NewLockInfo ( thread , [ ] string { "children" } ) ,
NewLockInfo ( thread , [ ] string { "children" } ) ,
LockList ( thread . Children ( ) , [ ] string { "start" } ) ,
LockList ( thread . Children ( ) , [ ] string { "start" } ) ,
) , func ( context * Wri teContext) ( error ) {
) , func ( context * Sta teContext) ( error ) {
for _ , child := range ( thread . Children ( ) ) {
for _ , child := range ( thread . Children ( ) ) {
should_run := ( thread . ChildInfo ( child . ID ( ) ) ) . ( ParentInfo ) . Parent ( )
should_run := ( thread . ChildInfo ( child . ID ( ) ) ) . ( ParentInfo ) . Parent ( )
ctx . Log . Logf ( "thread" , "THREAD_RESTORE: %s -> %s: %+v" , thread . ID ( ) , child . ID ( ) , should_run )
ctx . Log . Logf ( "thread" , "THREAD_RESTORE: %s -> %s: %+v" , thread . ID ( ) , child . ID ( ) , should_run )
@ -612,18 +613,15 @@ func ThreadRestore(ctx * Context, thread Thread) {
} )
} )
}
}
// Helper function to be called during a threads start action, sets the thread state to started
// Starts a write context, so cannot be called from either a write or read context
func ThreadStart ( ctx * Context , thread Thread ) error {
func ThreadStart ( ctx * Context , thread Thread ) error {
return UpdateStates ( ctx , thread , NewLockInfo ( thread , [ ] string { "start" , "lock" } ) , func ( context * WriteContext ) error {
context := NewWriteContext ( ctx )
owner_id := NodeID { }
return UpdateStates ( context , thread , NewLockInfo ( thread , [ ] string { "state" } ) , func ( context * StateContext ) error {
if thread . Owner ( ) != nil {
owner_id = thread . Owner ( ) . ID ( )
}
if owner_id != thread . ID ( ) {
err := LockLockables ( context , [ ] Lockable { thread } , thread )
err := LockLockables ( context , [ ] Lockable { thread } , thread )
if err != nil {
if err != nil {
return err
return err
}
}
}
return thread . SetState ( "started" )
return thread . SetState ( "started" )
} )
} )
}
}
@ -657,7 +655,8 @@ func ThreadWait(ctx * Context, thread Thread) (string, error) {
}
}
case <- thread . Timeout ( ) :
case <- thread . Timeout ( ) :
timeout_action := ""
timeout_action := ""
err := UpdateStates ( ctx , thread , NewLockMap ( NewLockInfo ( thread , [ ] string { "timeout" } ) ) , func ( context * WriteContext ) error {
context := NewWriteContext ( ctx )
err := UpdateStates ( context , thread , NewLockMap ( NewLockInfo ( thread , [ ] string { "timeout" } ) ) , func ( context * StateContext ) error {
timeout_action = thread . TimeoutAction ( )
timeout_action = thread . TimeoutAction ( )
thread . ClearTimeout ( )
thread . ClearTimeout ( )
return nil
return nil
@ -671,27 +670,46 @@ func ThreadWait(ctx * Context, thread Thread) (string, error) {
}
}
}
}
func ThreadDefaultFinish ( ctx * Context , thread Thread ) ( string , error ) {
ctx . Log . Logf ( "thread" , "THREAD_DEFAULT_FINISH: %s" , thread . ID ( ) . String ( ) )
return "" , ThreadFinish ( ctx , thread )
}
func ThreadFinish ( ctx * Context , thread Thread ) error {
context := NewWriteContext ( ctx )
return UpdateStates ( context , thread , NewLockInfo ( thread , [ ] string { "state" } ) , func ( context * StateContext ) error {
err := thread . SetState ( "finished" )
if err != nil {
return err
}
return UnlockLockables ( context , [ ] Lockable { thread } , thread )
} )
}
var ThreadAbortedError = errors . New ( "Thread aborted by signal" )
var ThreadAbortedError = errors . New ( "Thread aborted by signal" )
// Default thread abort is to return a ThreadAbortedError
// Default thread a ction function for "abort", sends a signal and returns a ThreadAbortedError
func ThreadAbort ( ctx * Context , thread Thread , signal GraphSignal ) ( string , error ) {
func ThreadAbort ( ctx * Context , thread Thread , signal GraphSignal ) ( string , error ) {
err := UseStates ( ctx , thread , NewLockInfo ( thread , [ ] string { "signal" } ) , func ( context * ReadContext ) error {
context := NewReadContext ( ctx )
err := UseStates ( context , thread , NewLockInfo ( thread , [ ] string { "signal" } ) , func ( context * StateContext ) error {
return thread . Signal ( context , NewStatusSignal ( "aborted" , thread . ID ( ) ) )
return thread . Signal ( context , NewStatusSignal ( "aborted" , thread . ID ( ) ) )
} )
} )
if err != nil {
if err != nil {
return "" , err
return "" , err
}
}
return "" , ThreadAbortedError
return " finish ", ThreadAbortedError
}
}
// Default thread cancel is to finish the thread
// Default thread action for "cancel", sends a signal and returns no error
func ThreadCancel ( ctx * Context , thread Thread , signal GraphSignal ) ( string , error ) {
func ThreadCancel ( ctx * Context , thread Thread , signal GraphSignal ) ( string , error ) {
err := UseStates ( ctx , thread , NewLockInfo ( thread , [ ] string { "signal" } ) , func ( context * ReadContext ) error {
context := NewReadContext ( ctx )
err := UseStates ( context , thread , NewLockInfo ( thread , [ ] string { "signal" } ) , func ( context * StateContext ) error {
return thread . Signal ( context , NewSignal ( "cancelled" ) )
return thread . Signal ( context , NewSignal ( "cancelled" ) )
} )
} )
return " ", err
return " finish ", err
}
}
// Copy the default thread actions to a new ThreadActions map
func NewThreadActions ( ) ThreadActions {
func NewThreadActions ( ) ThreadActions {
actions := ThreadActions { }
actions := ThreadActions { }
for k , v := range ( BaseThreadActions ) {
for k , v := range ( BaseThreadActions ) {
@ -701,6 +719,7 @@ func NewThreadActions() ThreadActions{
return actions
return actions
}
}
// Copy the defult thread handlers to a new ThreadAction map
func NewThreadHandlers ( ) ThreadHandlers {
func NewThreadHandlers ( ) ThreadHandlers {
handlers := ThreadHandlers { }
handlers := ThreadHandlers { }
for k , v := range ( BaseThreadHandlers ) {
for k , v := range ( BaseThreadHandlers ) {
@ -710,12 +729,15 @@ func NewThreadHandlers() ThreadHandlers{
return handlers
return handlers
}
}
// Default thread actions
var BaseThreadActions = ThreadActions {
var BaseThreadActions = ThreadActions {
"wait" : ThreadWait ,
"wait" : ThreadWait ,
"start" : ThreadDefaultStart ,
"start" : ThreadDefaultStart ,
"finish" : ThreadDefaultFinish ,
"restore" : ThreadDefaultRestore ,
"restore" : ThreadDefaultRestore ,
}
}
// Default thread signal handlers
var BaseThreadHandlers = ThreadHandlers {
var BaseThreadHandlers = ThreadHandlers {
"abort" : ThreadAbort ,
"abort" : ThreadAbort ,
"cancel" : ThreadCancel ,
"cancel" : ThreadCancel ,