[Pntool-developers] SF.net SVN: pntool:[248]
Brought to you by:
compaqdrew,
miordache
From: <mio...@us...> - 2011-05-13 22:48:26
|
Revision: 248 http://pntool.svn.sourceforge.net/pntool/?rev=248&view=rev Author: miordache Date: 2011-05-13 22:48:19 +0000 (Fri, 13 May 2011) Log Message: ----------- added some examples Added Paths: ----------- doc/ doc/GettingStarted.htm doc/input2.sp examples/ examples/+README+ examples/reader.sp examples/test.sp examples/test2.sp examples/test2a.sp examples/test2b.sp examples/test2c.sp examples/test2d.sp examples/test2e.sp examples/test2f.sp examples/test2g.sp examples/test3a.sp examples/test3b.sp examples/test3c.sp examples/test3d.sp Added: doc/GettingStarted.htm =================================================================== --- doc/GettingStarted.htm (rev 0) +++ doc/GettingStarted.htm 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,41 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <title></title> + </head> + + <body> + <h1></h1> + +<p><b>A Concurrency Tool Suite--Getting Started</b> + +<p>The software is intended for Unix operating systems. If you use a Windows computer, you may download cygwin from <a href="http://www.cygwin.com">http://www.cygwin.com</a>. The cygwin program runs in Windows and emulates Linux. Thus, you may run the software in Windows by means of cygwin. + +<p>To build the software, type the command "make" in the main directory of the source code. This will execute the commands of the file called "Makefile" and build an executable file called "ct.exe". In spite of its extension, this is not a Windows executable file. It can only be executed within cygwin or in Unix. + +<p>If you run ct.exe you can see a description of its options. + +<p>In order to run the program on a specification file: +<ul> +<li> Copy the files SupervisorTemplate.c ProcessTemplate.c and spcommon.h from the newcodegen directory to your working directory. +<li> Run ct.exe on your specification file. For instance, if spec.sp is the specification file, you could type "./ct.exe -d4 spec.sp". The d4 option can be used in order to have ct.exe display messages describing what it is doing. +<li>If the specification file is correct, ct.exe will exit normally and create a number of sources files allowing you to build your program. +<li> You can build your program using "make" and the makefile generated by ct.exe. For instance, to build the program from the source code generated for spec.sp, type "make -f spec.mak". +<li> The previous step will generate an executable file. When you run it, you can force it to terminate with Ctrl-c. This should terminate also all other processes (if any) started by the executable file. +</ul> + +<p>To create your own specification files: +<ul> +<li>See the example directory of the source code. +<li>Check also input2.sp. However, note that the features of input2.sp are not fully implemented in the translator module (which is unfinished at this time) and input2.sp is not a complete description of the low level specification language. Some syntax details (such as semicolon separators and braces) are not described in this version of input2.sp. +</ul> + + + + <hr> +<!-- Created: Fri May 13 17:16:03 CDT 2011 --> +<!-- hhmts start --> +Last modified: Fri May 13 17:43:01 CDT 2011 +<!-- hhmts end --> + </body> +</html> Added: doc/input2.sp =================================================================== --- doc/input2.sp (rev 0) +++ doc/input2.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,342 @@ +// This is a preliminary description of the low level specification language. + +// FOR REFERENCE ONLY. ON ONE HAND, NOT ALL FEATURES HAVE BEEN IMPLEMENTED +// IN THE TRANSLATOR. ON THE OTHER HAND, SOME IMPLEMENTED FEATURES ARE NOT +// DESCRIBED HERE. THIS FILE MAY NOT DESCRIBE THE ENTIRE SYNTAX. SEE THE +// EXAMPLES FOR INFORMATION ON THE SYNTAX. + +// Version 2.1.1 - 04/21/2011 +// The keyword "init" was added for initialization code. +// Version 2.1 - 05/19/2009 +// Compared to version 2, the following keywords were added: +// "nondeterministic", "select", "uncontrollable", and "unobservable". +// The low level (PN level) specification language is illustrated on a +// specification of independent reader and writer processes with shared memory. +// The high level language has not been developed yet. + +// The concurrent programming tool operates as follows. +// +// Given a specification file (say input.sp), the tool generates +// - input.c containing the code of the supervisor; +// - input.mak a makefile; +// - additional c files, one for each process defined below. +// +// After the application is built, the user can start it by +// running the supervisor program (say input.exe). The supervisor program +// will start all other processes and ensure that they operate +// correctly. Terminating the supervisor program will also +// terminate children processes. + + +// The specification file consists of three parts containing +// - process-type declarations +// - definitions +// - process declarations and dependencies +// - instructions on supervisor design + +// 1. PROCESS-TYPE DECLARATIONS + +// Format: +// +// process type // Write here the name of the process type. + // Note that all processes of the same type have the same + // executable file. +// build command: // Write here the line(s) used to build the executable. + // For instance: 'make -f process_name.mak' or + // 'gcc -o process_name process_name.sp.c functions.c ...' + // Note that process_name.sp.c is the c file generated + // by the concurrent programing tool for the process_name + // type. +// include: // Write here what should be included at the beginning of + // process_name.sp.c, such as #include directives. +// extern process type // Declares a process type for which the tool should + // not generate code. Such a process type may describe + // hardware or software functions already implemented. + // If such external processes impose relevant + // constraints, the specification should + // describe them. This may help: + // - simplify some supervisory control methods + // - reveal potential deadlock situations + // A process may not be external unless all transitions + // unique to the process are uncontrollable and + // unobservable. + +process type READER + +build command: make -f reader.mak + +include: { + #include<stdio.h> + #include<string.h> + + int state = 0; /* variables can be declared here as well */ +} + + +init: { + // include here declarations and initialization code +} + +process type WRITER + +build command: make -f writer.mak + +include: #include "writer.h" + + +extern process type ARBITER // Note that no build or include commands follow + // the declaration of an external process type. + + +// 2. DEFINITIONS + +// This version of the specification format describes only a low level PN +// definition of the processes. + +// Format: + +// process_name.PN: +// places: list of place names +// transitions: list of transition names +// place.code: gives the C code associated with a place. The C code +// is not parsed here! Rather the "text" structure associated +// to the PN place is initialized with the position of the C code. +// *place: list of input transitions +// place*: list of the output transition of place +// ([place], transition, [place, ...])[.{c code}] where items between +// square brackets are optional. +// Note that the c code is not parsed but its position is copied to a "text" +// structure associated with the arc. + + + +ARBITER.PN: + +places: p1 p2 // place names do not have to start with a 'p' + +transitions: t1 t2 // transition names do not have to start with a 't' + +// Note the absence of place.code lines for an external process. + +*p1: t1 +p1*: t2 +*p2: t2 +p2*: t1 + + +// The format *place: input transition(s), place*: output transition(s) +// is ideal for representing a PN structure and this is what we need for an +// external process. However, the format it is ambiguous for the processes for +// which code should be generated. For instance, assume a transition t such +// that *t: p1 p2 and t*: p3 p4. Recall that each process of type X is a +// token in the underlying PN. Thus, assuming two processes, one in the stage +// p1 and one in the stage p2, it is not clear what action should be taken +// when t is fired. The following format will be used to describe the outcome +// of firing t. +// 1. The process in p1 goes to p3 and the one in p2 to p4 +// (p1, t, p3) (p2, t, p4) +// 2. The process in p1 goes to p3 and forks one child process in p4. The +// process in p2 terminates. +// (p1, t, p3, p4) (p2, t) +// 3. Both processes in p1 and p2 terminate and two new processes are created +// in p3 and p4. +// (p1, t) (p2, t) (t, p3) (t, p4) +// 4. ... +// ... + +READER.PN: + +places: p1 p1b p2 p3 + +transitions: t1 t2 t3 t4 ti t_end + +p1.code: initialize_r(); + +p1b.code: initialize_r_b(); + +p2.code: { + str = read_data(); +} + +p3.code: process_data(str); + +// The following lines describe the structure of the PN + +(p1b, ti, p1) +(p1, t1, p2).{i != 0} // the transition will be taken only if the condition + // between braces is TRUE. +// The expression between braces should only be copied; it does not have to +// be parsed. + +(p2, t2, p3) +(p3, t3, p1) +(p1, t_end).{exit_v == TRUE} +(p1, t4, p3) + +// Note that a process in p1 has three choices. +// if(i != 0) then fire t1 +// else if(exit_v == TRUE) then fire t_end +// else fire t4 + +// Instead of using the conditions above to determine which transitions to +// fire, a function to select them could be specified. + +select function p1.{select_t} // select_t is the name of the function + +// Thus, when there is a token in p1, the function select_f is invoked to +// to determine which transition should be fired. + +nondeterministic places: p1 + +// By default a place p is deterministic. For a deterministic place, one of the +// enabled output transition is selected and then the process waits until the +// supervisor permits its firing. However, if the place p is nondeterministic, +// a protocol such as the one below is used. +// +// 1. The select function is invoked to produce the list of enabled transitions +// in the order of firing preference (first in list is the transition the +// process is most interested to fire). +// 1.b. Optionally, the supervisor is inquired about the transitions it +// enables. However, note that the set of transitions enabled by the +// supervisor can change before the process asks the supervisor for +// permission to fire. +// 2. The list of transitions is sent to the supervisor. Then, the process +// sleeps until the supervisor replies. +// 4. The supervisor gives permission to fire one of the transitions on the +// list. +// +// The main difference between a deterministic and a nondetermistic place is +// as follows. For a deterministic place a transition is selected and then the +// process sleeps until it can continue by firing that transition. For a +// nondeterministic place the choice of the next transition depends on the +// transitions enabled by the supervisor. + + + +WRITER.PN: + +places: p pwr_1 pwr2 + +transitions: t1 t2 t3 t4 + +p.code: process_wrdata(); + +pwr_1.code: write_dest1(); + +pwr_2.code: write_dest2(); + +(p, t1, pwr_1).{dest == 1} +(p, t2, pwr_2) +(pwr_1, t3, p) +(pwr_2, t4, p) + + + +// 3. PROCESS DECLARATIONS + +READER r_group(p1:2, p3:1) // This declares a group of 2+1= 3 READER + // processes. Two processes begin in the state + // p1 and one in the state p3. + // The name of this group of processes is 'r_group'. + // They will be implemented by the READER.PN with + // initial marking m(p1) = 2 and m(p3) = 1. + +READER reader1(p1b) // This declares a single READER process that begins in + // the state p1b. The name of the process is reader1. + +WRITER writer1(p) + +WRITER w_group(p:2) + +ARBITER arbiter(p1) + + +// DEPENDENCIES (transitions that processes synchronize on their own) + +sync reader1.t1 arbiter.t1 + // mentions that the two transitions are synchronized + // (they take place simultaneously). + +sync writer1.t2 arbiter.t2 + +// Remark: all transitions of the external processes are considered to be +// uncontrollable and unobservable, excepting the transitions synchronized +// with transitions of internal processes. Such transitions have the type +// specified by the internal process. + + +// 4. INSTRUCTIONS ON THE DESIGN OF THE SUPERVISOR + +// These describe what the objectives of the supervisor. +// - 'start' commands describe what processes the supervisor should start +// - 'constraints' commands describe what constraints should be enforced +// Constraints have the form +// weighted sum <= free term +// Since we deal with integers, <, >, and >= are all equivalent to this +// form. For instance, a < b is the same as a <= b - 1. +// Disjunctive constraints are also allowed +// (weighted sum <= free term) || (weighted sum 2 <= free term 2) +// The keyword 'live' is used to introduce a list of transitions that +// should always be eventually firable. +// Similarly, the keywords "uncontrollable" and "unobservable" introduce +// lists of transitions that the supervisor should not attempt to control +// and observe, respectively. + +start r_group w_group reader1 writer1 // Unimplemented as of May 2011. + + +// CONSTRAINTS + +r_group.constraints: // these are constraints on the PN of r_group + +live: t2 t4 // requests that the transitions t2 and t4 of r_group be live + // (i.e. they never deadlock). + +uncontrollable: t1 t_end t4 + +unobservable: t1 t_end t4 + + +w_group.constraints: // these are constraints on the PN of w_group + +// Here are some constraints that two writers may not be at the same time +// in the same critical section. + +pwr_1 <= 1 // requests that the marking of pwr_1 does not exceed 1 +pwr_2 <= 1 // requests that the marking of pwr_2 does not exceed 1 + +live: all // requests all transitions of w_group to be live. + + +// NOTE: Some constraint features are not implemented as of May 2011. + +global.constraints: // these are constraints on all PNs + +(r_group.p2 <= 0) || (w_group.pwr_1 <= 0) + +// The line above requests that at all times either the place p2 of r_group +// has no tokens or the place pwr_1 of w_group has no tokens. That is, any +// number of readers may be at the same time in the critical section, but +// a reader and a writer may not be there at the same time. + +q.reader1.t1 - writer1.p <= 0 //'q.' denotes the firing vector. The constraint + // requires that t1 of reader1 may be fired only + // if there is one token in the place p of + // writer1. + +2*reader1.t1 - 2*reader1.t2 + w_group.pwr_2 <= 2 +// reader1.t1 denotes the number of firings of t1. This constraint is +// another way of requesting 2*reader1.p2 + w_group.pwr_2 <= 2 + + + +// More general constraints, such as requiring a certain language to be +// generated, will be implemented when the need will arise. + + + +// 5. OTHER COMMANDS + +print supervisor to debug.log // 'print supervisor to file_name' requests the + // PN produced by the supervisory control + // algorithms to be written to file_name. Added: examples/+README+ =================================================================== --- examples/+README+ (rev 0) +++ examples/+README+ 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,36 @@ + +Here is the list of test examples: + +test2.sp: When running this example a single process (not thread) is started. The process prints messages indicating its state until it terminates. + +Variants: + +test2a.sp: a single processes (not thread) is started. + +test2b.sp: several identical processes (not threads) are started. + +test2c.sp: only one thread (not forked process) will run this time. + +test2d.sp: multiple threads (not forked processes) will run this time. + +test2e.sp: synchronization by means of transitions between single threads. + +test2f.sp: synchronization by means of transitions between multiple threads. + +test2g.sp: same as test2f.sp except for using forked processes (not threads). + + + +test3: A dining philosopher example. + +test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. + +test3b.sp: A test involving two philosophers. + +test3c.sp: A test involving 5 philosophers. + +test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. + + + +reader.sp: A reader, inserter, deleter problem. Added: examples/reader.sp =================================================================== --- examples/reader.sp (rev 0) +++ examples/reader.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,124 @@ +// This is a reader/writer/inserter example + +process READER; +build: {<thread>}; + +process DELETER; +build: {<thread>}; + +process INSERTER; +build: {<thread>}; + +READER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +// The main function for a thread/process defines a void* type pointer p___ initialized to zero. +// This is useful when several copies of a thread run in parallel, so that each thread copy +// has a known variable to allocate so that it can save its own data. Further, an initialization +// function can be called if p___ = 0. + +pv.code: { +//evaluate_data(&p___); + debugInfo("READER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//read_data(&p___); + debugInfo("READER: Entering the read block"); + sleep(1); + debugInfo("READER: Exiting the read block"); +}; + +pd.code: { +//process_data(&p___); + debugInfo("READER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +DELETER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//d_evaluate_data(&p___); + debugInfo("DELETER: Entering the evaluation block"); + sleep(1); + +}; + +pc.code: { +//delete_data(&p___); + debugInfo("DELETER: Entering the read block"); + sleep(1); + debugInfo("DELETER: Exiting the read block"); + +}; + +pd.code: { +//d_process_data(&p___); + debugInfo("DELETER: Entering the processing block"); + sleep(1); + +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +INSERTER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//i_evaluate_data(&p___); + debugInfo("INSERTER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//insert_data(&p___); + debugInfo("INSERTER: Entering the read block"); + sleep(1); + debugInfo("INSERTER: Exiting the read block"); +}; + +pd.code: { +//i_process_data(&p___); + debugInfo("INSERTER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +READER read(pv:5); // defines five reader processes starting in state pv +INSERTER insert(pv:3); +DELETER delete(pv:3); + + +global.constraints: + +insert.pc <= 1; + +// delete.pc <= 1; // not necessary: see constraint below + +// The following should be read.pc + insert.pc + 6*delete.pc <= 6 +// However, the translator has a bug preventing it from recognizing multipliers + +read.pc + insert.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc<= 6; // 6 is max(reader.pc + inserter.pc) Added: examples/test.sp =================================================================== --- examples/test.sp (rev 0) +++ examples/test.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,19 @@ +// This is a test file created in order to check the functionality of the +// pn translator. + +process TST; + +TST.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2; + +(p0, t0); +(t2, p0); +(p1, t1, p2, p0); +(p1, t1, p2, p0); +(p2, t2, p1).{i == 3}; + +TST testpn(p0:2,p1:1); + Added: examples/test2.sp =================================================================== --- examples/test2.sp (rev 0) +++ examples/test2.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2a.sp =================================================================== --- examples/test2a.sp (rev 0) +++ examples/test2a.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2b.sp =================================================================== --- examples/test2b.sp (rev 0) +++ examples/test2b.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:3,p1:0,p2:0); + +PN3 pr2; + Added: examples/test2c.sp =================================================================== --- examples/test2c.sp (rev 0) +++ examples/test2c.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2d.sp =================================================================== --- examples/test2d.sp (rev 0) +++ examples/test2d.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + Added: examples/test2e.sp =================================================================== --- examples/test2e.sp (rev 0) +++ examples/test2e.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test2f.sp =================================================================== --- examples/test2f.sp (rev 0) +++ examples/test2f.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test2g.sp =================================================================== --- examples/test2g.sp (rev 0) +++ examples/test2g.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN (%d): State 0 u = %d", (int) getpid(), u); + //fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN (%d): State 1", (int) getpid()); + //fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN (%d): State 2", (int) getpid()); + //fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + //fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + //fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test3a.sp =================================================================== --- examples/test3a.sp (rev 0) +++ examples/test3a.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,105 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t2; + +// --->| t2 +// p | +// t0 |--->O +// + + +(p, t2); (t0, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE left(p:1); +RESOURCE right(p:1); + +PHIL ph1(p0:1); + +sync ph1.t1 left.t2; +sync ph1.t2 right.t2; +sync ph1.t3 left.t0; +sync ph1.t3 right.t0; + +ph1.constraints: + +live: t1; Added: examples/test3b.sp =================================================================== --- examples/test3b.sp (rev 0) +++ examples/test3b.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE left(p:1); +RESOURCE right(p:1); + +PHIL ph1(p0:1); +PHIL ph2(p0:1); + +sync ph1.t1 left.t2; +sync ph2.t1 right.t2; +sync ph1.t2 right.t3; +sync ph2.t2 left.t3; +sync ph1.t3 left.t0; +sync ph1.t3 right.t0; +sync ph2.t3 left.t1; +sync ph2.t3 right.t1; + +ph1.constraints: +live: t1; + +ph2.constraints: +live: t1; \ No newline at end of file Added: examples/test3c.sp =================================================================== --- examples/test3c.sp (rev 0) +++ examples/test3c.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); + +PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; + +ph1.constraints: +live: t1; +ph2.constraints: +live: t1; +ph3.constraints: +live: t1; +ph4.constraints: +live: t1; +ph5.constraints: +live: t1; Added: examples/test3d.sp =================================================================== --- examples/test3d.sp (rev 0) +++ examples/test3d.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<supervisor>}; // code is ignored for supervisor components + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); + +PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; + +ph1.constraints: +live: t1; +ph2.constraints: +live: t1; +ph3.constraints: +live: t1; +ph4.constraints: +live: t1; +ph5.constraints: +live: t1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |