2015-04-27 08:42:07 +00:00
//: Routines can be put in a 'waiting' state, from which it will be ready to
//: run again when a specific memory location changes its value. This is mu's
//: basic technique for orchestrating the order in which different routines
//: operate.
2015-05-03 18:53:15 +00:00
: ( scenario wait_for_location )
2016-03-08 09:30:14 +00:00
def f1 [
2015-07-28 21:33:22 +00:00
1 : number < - copy 0
2016-01-18 07:15:03 +00:00
start - running f2
2015-05-13 17:03:26 +00:00
wait - for - location 1 : number
2015-04-27 08:42:07 +00:00
# now wait for f2 to run and modify location 1 before using its value
2015-05-13 17:03:26 +00:00
2 : number < - copy 1 : number
2015-04-27 08:42:07 +00:00
]
2016-03-08 09:30:14 +00:00
def f2 [
2015-07-28 21:33:22 +00:00
1 : number < - copy 34
2015-04-27 08:42:07 +00:00
]
# if we got the synchronization wrong we'd be storing 0 in location 2
+ mem : storing 34 in location 2
//: define the new state that all routines can be in
: ( before " End routine States " )
WAITING ,
: ( before " End routine Fields " )
// only if state == WAITING
2016-03-14 03:26:47 +00:00
int waiting_on_location ;
2015-05-13 00:00:56 +00:00
int old_value_of_waiting_location ;
2015-04-27 08:42:07 +00:00
: ( before " End routine Constructor " )
2015-05-08 07:57:05 +00:00
waiting_on_location = old_value_of_waiting_location = 0 ;
2015-04-27 08:42:07 +00:00
//: primitive recipe to put routines in that state
: ( before " End Primitive Recipe Declarations " )
WAIT_FOR_LOCATION ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " wait-for-location " , WAIT_FOR_LOCATION ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case WAIT_FOR_LOCATION : {
break ;
}
2015-04-27 08:42:07 +00:00
: ( before " End Primitive Recipe Implementations " )
case WAIT_FOR_LOCATION : {
2015-10-26 04:42:18 +00:00
reagent loc = current_instruction ( ) . ingredients . at ( 0 ) ;
canonize ( loc ) ;
2015-04-27 08:42:07 +00:00
Current_routine - > state = WAITING ;
Current_routine - > waiting_on_location = loc . value ;
2015-11-06 19:06:58 +00:00
Current_routine - > old_value_of_waiting_location = get_or_insert ( Memory , loc . value ) ;
trace ( 9998 , " run " ) < < " waiting for location " < < loc . value < < " to change from " < < no_scientific ( get_or_insert ( Memory , loc . value ) ) < < end ( ) ;
2015-04-27 08:42:07 +00:00
break ;
}
//: scheduler tweak to get routines out of that state
: ( before " End Scheduler State Transitions " )
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( Routines ) ; + + i ) {
2015-05-07 22:49:40 +00:00
if ( Routines . at ( i ) - > state ! = WAITING ) continue ;
2015-05-08 01:35:33 +00:00
if ( Routines . at ( i ) - > waiting_on_location & &
2015-11-06 19:06:58 +00:00
get_or_insert ( Memory , Routines . at ( i ) - > waiting_on_location ) ! = Routines . at ( i ) - > old_value_of_waiting_location ) {
2015-10-29 18:56:10 +00:00
trace ( 9999 , " schedule " ) < < " waking up routine \n " < < end ( ) ;
2015-05-07 22:49:40 +00:00
Routines . at ( i ) - > state = RUNNING ;
2015-05-08 07:57:05 +00:00
Routines . at ( i ) - > waiting_on_location = Routines . at ( i ) - > old_value_of_waiting_location = 0 ;
2015-04-27 08:42:07 +00:00
}
}
2015-05-06 01:30:53 +00:00
2015-05-08 02:16:19 +00:00
//: also allow waiting on a routine to stop running
2015-05-06 01:30:53 +00:00
: ( scenario wait_for_routine )
2016-03-08 09:30:14 +00:00
def f1 [
2015-07-28 21:33:22 +00:00
1 : number < - copy 0
2016-01-18 07:15:03 +00:00
12 : number / routine < - start - running f2
2015-05-13 17:03:26 +00:00
wait - for - routine 12 : number / routine
2015-05-06 01:30:53 +00:00
# now wait for f2 to run and modify location 1 before using its value
2015-05-13 17:03:26 +00:00
3 : number < - copy 1 : number
2015-05-06 01:30:53 +00:00
]
2016-03-08 09:30:14 +00:00
def f2 [
2015-07-28 21:33:22 +00:00
1 : number < - copy 34
2015-05-06 01:30:53 +00:00
]
2015-05-08 02:27:17 +00:00
+ schedule : f1
+ run : waiting for routine 2
+ schedule : f2
+ schedule : waking up routine 1
+ schedule : f1
2015-05-06 01:30:53 +00:00
# if we got the synchronization wrong we'd be storing 0 in location 3
+ mem : storing 34 in location 3
: ( before " End routine Fields " )
// only if state == WAITING
2016-03-14 03:26:47 +00:00
int waiting_on_routine ;
2015-05-06 01:30:53 +00:00
: ( before " End routine Constructor " )
waiting_on_routine = 0 ;
: ( before " End Primitive Recipe Declarations " )
WAIT_FOR_ROUTINE ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " wait-for-routine " , WAIT_FOR_ROUTINE ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
2015-05-06 01:30:53 +00:00
case WAIT_FOR_ROUTINE : {
2015-10-02 00:30:14 +00:00
if ( SIZE ( inst . ingredients ) ! = 1 ) {
2016-03-21 09:25:52 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'wait-for-routine' requires exactly one ingredient, but got " < < to_original_string ( inst ) < < ' \n ' < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2015-10-07 05:15:45 +00:00
if ( ! is_mu_number ( inst . ingredients . at ( 0 ) ) ) {
2016-02-26 21:04:55 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " first ingredient of 'wait-for-routine' should be a routine id generated by 'start-running', but got " < < inst . ingredients . at ( 0 ) . original_string < < ' \n ' < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2015-10-02 00:30:14 +00:00
break ;
}
: ( before " End Primitive Recipe Implementations " )
case WAIT_FOR_ROUTINE : {
2015-07-25 21:19:28 +00:00
if ( ingredients . at ( 0 ) . at ( 0 ) = = Current_routine - > id ) {
2016-03-21 09:25:52 +00:00
raise < < maybe ( current_recipe_name ( ) ) < < " routine can't wait for itself! " < < to_original_string ( current_instruction ( ) ) < < ' \n ' < < end ( ) ;
2015-07-25 21:19:28 +00:00
break ;
}
2015-05-06 01:30:53 +00:00
Current_routine - > state = WAITING ;
2015-05-08 02:27:17 +00:00
Current_routine - > waiting_on_routine = ingredients . at ( 0 ) . at ( 0 ) ;
2015-10-29 19:09:23 +00:00
trace ( 9998 , " run " ) < < " waiting for routine " < < ingredients . at ( 0 ) . at ( 0 ) < < end ( ) ;
2015-05-06 01:30:53 +00:00
break ;
}
: ( before " End Scheduler State Transitions " )
2015-05-08 01:35:33 +00:00
// Wake up any routines waiting for other routines to go to sleep.
// Important: this must come after the scheduler loop above giving routines
// waiting for locations to change a chance to wake up.
2016-03-14 03:26:47 +00:00
for ( int i = 0 ; i < SIZE ( Routines ) ; + + i ) {
2015-05-07 22:49:40 +00:00
if ( Routines . at ( i ) - > state ! = WAITING ) continue ;
if ( ! Routines . at ( i ) - > waiting_on_routine ) continue ;
2016-03-14 03:26:47 +00:00
int id = Routines . at ( i ) - > waiting_on_routine ;
2015-07-25 21:19:28 +00:00
assert ( id ! = Routines . at ( i ) - > id ) ; // routine can't wait on itself
2016-03-14 03:26:47 +00:00
for ( int j = 0 ; j < SIZE ( Routines ) ; + + j ) {
2015-05-08 02:27:17 +00:00
if ( Routines . at ( j ) - > id = = id & & Routines . at ( j ) - > state ! = RUNNING ) {
2015-10-29 18:56:10 +00:00
trace ( 9999 , " schedule " ) < < " waking up routine " < < Routines . at ( i ) - > id < < end ( ) ;
2015-05-07 22:49:40 +00:00
Routines . at ( i ) - > state = RUNNING ;
Routines . at ( i ) - > waiting_on_routine = 0 ;
2015-05-06 01:30:53 +00:00
}
}
}
2015-05-10 13:02:36 +00:00
: ( before " End Primitive Recipe Declarations " )
SWITCH ,
: ( before " End Primitive Recipe Numbers " )
2015-11-06 19:06:58 +00:00
put ( Recipe_ordinal , " switch " , SWITCH ) ;
2015-10-02 00:30:14 +00:00
: ( before " End Primitive Recipe Checks " )
case SWITCH : {
break ;
}
2015-05-10 13:02:36 +00:00
: ( before " End Primitive Recipe Implementations " )
case SWITCH : {
2016-03-14 03:26:47 +00:00
int id = some_other_running_routine ( ) ;
2015-05-10 13:02:36 +00:00
if ( id ) {
assert ( id ! = Current_routine - > id ) ;
Current_routine - > state = WAITING ;
Current_routine - > waiting_on_routine = id ;
}
break ;
}
: ( code )
2016-03-14 03:26:47 +00:00
int some_other_running_routine ( ) {
for ( int i = 0 ; i < SIZE ( Routines ) ; + + i ) {
2015-05-10 13:02:36 +00:00
if ( i = = Current_routine_index ) continue ;
assert ( Routines . at ( i ) ! = Current_routine ) ;
assert ( Routines . at ( i ) - > id ! = Current_routine - > id ) ;
if ( Routines . at ( i ) - > state = = RUNNING )
return Routines . at ( i ) - > id ;
}
return 0 ;
}