resource node op all_the_caps(node_cap[1:*] : cap node) op request_msg(number, id : int) op reply_msg(id : int) body node(id, num_nodes, max_outside_time, max_inside_time : int) write("node", id, "starting with max_outside_time of", max_outside_time, "and max_inside_time of", max_inside_time) var node_cap[1:num_nodes] : cap node var number : int := 0 var high_number : int := 0 var requesting : bool := false var reply_count : int := 0 sem s := 1 sem wake_up := 0 var deferred[1:num_nodes] : bool := ([num_nodes] false) procedure choose_number() P(s) requesting := true number := high_number + 1 V(s) end choose_number procedure send_request() reply_count := 0 fa j := 1 to num_nodes st j ~= id -> send node_cap[j].request_msg(number, id) af end send_request procedure wait_for_reply() P(wake_up) end wait_for_reply procedure reply_to_deferred_nodes() P(s) requesting := false V(s) fa j := 1 to num_nodes -> if deferred[j] -> deferred[j] := false send node_cap[j].reply_msg(id) fi af end reply_to_deferred_nodes procedure outside_cs(id : int) var napping : int napping := int(random(1000*max_outside_time)) writes("age=", age(), ", node ", id, " outside critical section for ", napping, "ms\n") nap(napping) end outside_cs procedure inside_cs(id : int) var napping : int napping := int(random(1000*max_inside_time)) writes("age=", age(), ", node ", id, " inside critical section for ", napping, "ms\n") nap(napping) end inside_cs process main receive all_the_caps(node_cap) write("node", id, "has all the node caps now") do true -> outside_cs(id) writes("age=", age(), ", node ", id, " wants to enter its critical section\n") choose_number() # PRE-PROTOCOL send_request() # " wait_for_reply() # " inside_cs(id) writes("age=", age(), ", node ", id, " has now left its critical section\n") reply_to_deferred_nodes() # POST-PROTOCOL od end main process handle_requests var received_number : int var received_id : int var decide_to_defer : bool do true -> receive request_msg(received_number, received_id) high_number := max(high_number, received_number) P(s) decide_to_defer := requesting and (number < received_number or (number = received_number and id < received_id)) if decide_to_defer -> deferred[received_id] := true [] else -> send node_cap[received_id].reply_msg(id) fi V(s) od end handle_requests process handle_replies var received_id : int do true -> receive reply_msg(received_id) reply_count++ if reply_count = num_nodes - 1 -> V(wake_up) fi od end handle_replies end node resource driver() import node var run_time : int := 30 var max_outside_time : int := 8 var max_inside_time : int := 2 var stat : int var num_nodes : int var machine_name : string[64] var first_machine_name_position : int write("driver starting up") # First argument on command line is run time. first_machine_name_position := 1 stat := getarg(first_machine_name_position, run_time) if stat = EOF -> # first argument is nonexistent write("Some machine names needed!"); stop [] stat = 0 -> # first argument is not a number but machine name write("Using default value of", run_time, "for run time.") [] else -> first_machine_name_position++ fi if run_time <= 1 -> write("run time =", run_time, "is too small."); stop fi # Second argument on command line is max_outside_time. stat := getarg(first_machine_name_position, max_outside_time) if stat = EOF -> # second argument is nonexistent write("Some machine names needed!"); stop [] stat = 0 -> # second argument is not a number but machine name write("Using default value of", max_outside_time, "for max_outside_time.") [] else -> first_machine_name_position++ fi if max_outside_time <= 1 -> write("max_outside_time =", max_outside_time, "is too small."); stop fi # Third argument on command line is max_inside_time. stat := getarg(first_machine_name_position, max_inside_time) if stat = EOF -> # second argument is nonexistent write("Some machine names needed!"); stop [] stat = 0 -> # second argument is not a number but machine name write("Using default value of", max_inside_time, "for max_inside_time.") [] else -> first_machine_name_position++ fi if max_inside_time <= 1 -> write("max_inside_time =", max_inside_time, "is too small."); stop fi num_nodes := numargs() - first_machine_name_position + 1 if num_nodes <= 0 -> write("Some machine names needed!"); stop fi # Subsequent arguments on command line are machine names. var machine_cap[1:num_nodes] : cap vm var node_cap[1:num_nodes] : cap node fa i := 1 to num_nodes -> getarg(first_machine_name_position + i - 1, machine_name) machine_cap[i] := create vm() on machine_name if machine_cap[i] = null -> write("Cannot create vm on", machine_name, "so aborting."); stop fi writes("Virtual machine starting up on machine ", machine_name, ".\n") af write(num_nodes, "nodes to run for", run_time, "seconds") fa j := 1 to num_nodes -> node_cap[j] := create node(j, num_nodes, max_outside_time, max_inside_time) on machine_cap[j] af fa j := 1 to num_nodes -> call node_cap[j].all_the_caps(node_cap) af write("all nodes started") nap(1000*run_time); write("must stop now"); stop end driver /* ............... Example compile and run(s) % sr -o distr_mutual_excl distr_mutual_excl.sr % ./distr_mutual_excl 10 4 2 king queen lily rose violet driver starting up Virtual machine starting up on machine king. Virtual machine starting up on machine queen. Virtual machine starting up on machine lily. Virtual machine starting up on machine rose. Virtual machine starting up on machine violet. 5 nodes to run for 10 seconds node 1 starting with max_outside_time of 4 and max_inside_time of 2 node 2 starting with max_outside_time of 4 and max_inside_time of 2 node 3 starting with max_outside_time of 4 and max_inside_time of 2 node 4 starting with max_outside_time of 4 and max_inside_time of 2 node 5 starting with max_outside_time of 4 and max_inside_time of 2 node 1 has all the node caps now node 2 has all the node caps now age=8576, node 1 outside critical section for 752ms age=6959, node 2 outside critical section for 785ms node 3 has all the node caps now node 4 has all the node caps now node 5 has all the node caps now all nodes started age=810, node 5 outside critical section for 1431ms age=2540, node 4 outside critical section for 1233ms age=4550, node 3 outside critical section for 356ms age=4920, node 3 wants to enter its critical section age=5080, node 3 inside critical section for 1836ms age=9341, node 1 wants to enter its critical section age=7762, node 2 wants to enter its critical section age=3780, node 4 wants to enter its critical section age=2250, node 5 wants to enter its critical section age=6920, node 3 has now left its critical section age=6930, node 3 outside critical section for 1756ms age=11024, node 1 inside critical section for 545ms age=11588, node 1 has now left its critical section age=9966, node 2 inside critical section for 209ms age=11613, node 1 outside critical section for 1061ms age=10182, node 2 has now left its critical section age=5730, node 4 inside critical section for 1966ms age=10184, node 2 outside critical section for 962ms age=12697, node 1 wants to enter its critical section age=8690, node 3 wants to enter its critical section age=11152, node 2 wants to enter its critical section age=5940, node 5 inside critical section for 756ms age=7710, node 4 has now left its critical section age=7710, node 4 outside critical section for 267ms age=7990, node 4 wants to enter its critical section age=6700, node 5 has now left its critical section age=14583, node 1 inside critical section for 1822ms age=6700, node 5 outside critical section for 3716ms age=16419, node 1 has now left its critical section age=12400, node 3 inside critical section for 1699ms age=16462, node 1 outside critical section for 728ms age=17203, node 1 wants to enter its critical section age=14110, node 3 has now left its critical section age=14110, node 3 outside critical section for 2778ms age=16553, node 2 inside critical section for 989ms age=10430, node 5 wants to enter its critical section must stop now */