// TO DO: check pipe size and adjust it if necessary or terminate if impossible
// Enable SIGIO for sread pipe of supervisor. O_ASYNC would be used.
// use fcntl for both
//
// Note: read() from pipe with O_NOBLOCK set returns 0 if the sender has closed
// its end of the pipe or -1 and errno = EAGAIN if the pipe is empty.
//
// check_for_msg()/get_msg() accounts for the possibility that read() may return less bytes
// than expected. However, some testing might be needed to ensure that the way
// check_for_msg()/get_msg() deals with this error is adequate.  
// If this is not the case, some functions could be created to read and write
// bytes one by one. Then, struct proc would have two additional items: one buffer
// to hold the bytes of a message that is being received, which is filled with bytes 
// of data as they arrive, and one integer indicating how many bytes are in the 
// buffer. 
//
// The debugInfo of the supervisor should use a lock.

#define ___SUPERVISOR

#include<stdarg.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
#include<fcntl.h>
#include<signal.h>


#define MSG_READ_LIMIT 10 
// max number of messages read from a single process during an iteration 

char ___debug; // value determined by parameters of main function
int ___finish; // the program terminates when its value is nonzero
pid_t ___pid;
pthread_t ___tid; // thread id of the main program
FILE* ___f;
char* ___name;


#include"spcommon.h"//--- ANY change on this line MUST be reflected in BOTH ProcessTemplate.c and filltmpl.lex, in order that filltmpl.lex may be able to replace this line with the adequate include directive

// The following is used for unnamed pipe communication between plant
// and supervisor.

int ___read_ch, ___write_ch; // the read and write ends of the pipe to which
// plant components write. 

struct ___comm {
  int sread, swrite; 
  int pread, pwrite;
  char pclosed; // nonzero if pread and pwrite pipes have been closed
};

// The following is used in the command line when a process is started.
// The size should be updated if the communication approach is changed.
// A size of (4*sizeof(int)+1) is sufficient to represent one signed 
// int-type number in text form. 

char ___com[4*sizeof(int)+1]; 

// The following is used to store transition lists in "struct proc"

struct trlist { 
  int t; // transition number
  int a; // action label of plant transition
  //char type; // 0: if input transition, 1: if output transition
};

// When a plant process is created, an object of type "struct proc" 
// is created. The address of this object is transmitted to the process and
// this address is included in all messages from the process to the supervisor.
// These objects are placed in three lists, as follows:
// - prlist is the list of all processes started by the supervisor. 
// - wtlist[i] is a list of processes of the type i that wait for the supervisor.
// - queue is a queue list of all processes that wait for the supervisor.
 
struct proc {
  int type; // identifies the type of the process
  int request; // id of last request (not notification!) made by the proc to the supervisor
  int solved; // id of last resolved request (so solved == request when all 
              // requests of the process have been answered).
  char atype; // the action type (permission request or firing notification)
              // bit 0: 0 -- permission, 1 -- notification
              // bit 1: 1 -- if part of qelist (QueueEntryList of IsPermissible)
  int fireable; // the plant transition selected by the supervisor algorithms
  int ntlist; // number of elements of the list below
  struct trlist *tlist; // list of firable plant transitions 
  // All entries below must be ZERO when not used
  struct proc *next_in_queue; // next element of lower priority
  struct proc *prev_in_queue; // next element of higher priority
  struct proc *next_in_prlist; // next element in the list of processes
  struct proc *prev_in_prlist; // previous element
  struct proc *next_in_wtlist; // next element in the list of processes of the 
                               // same type that wait for a supervisor action
  struct proc *prev_in_wtlist;
  struct proc *next_in_qelist;

  pthread_t thread_id; // id of thread
  pid_t pid; // id of forked process

  void* comm; // pointer to an unspecified communication structure, such as
              // struct ___comm.
};

struct proc *___prlist; // pointer to the first element of the list
// wtlist is defined automatically as "struct proc *___wtlist[n];" 
// wtlistLast[n] (pointer to last element of wtlist[n]) is defined the same way. 

struct proc *___first, *___last; // Queue pointers

// When a process sends a message requesting action i, the supervisor
// examines the data associated with the action i. This data consists of 
// process types that are involved in firing the transition and of supervisor 
// transitions that are involved. This data is stored in 'struct ___action'
// objects (the structure is defined below). Note that a transition is fired 
// if all process type requirements are met and one of the supervisor 
// transitions in the list is enabled. 

// Conditions are expressed by process type lists and transition lists.
// There are npr process types: type[i] denotes the type of process i and
// weight[i] denotes the weight of the transition of process i that is part
// of the synchronization. 
// There are ntr supevisor transitions having the same label as the plant
// transitions participating in the synchronization. Their indices are 
// in the array t.

// The structure allows expressing constraints in which a synchronization may 
// involve either t (non-source) or t' (source tran), where t and t' belong to 
// the same process. This situation may arise when t and t' have the same label. 
// This is done by means of the 'disj' field. If disj[i] != 0, then one of
// the transitions itr[i] should be chosen OR one of the transitions corresp to 
// oplace[disj[i]-1].

struct ___action { 
  const int ni;
  const int *itype; // input proc. type, array of size ni
  const int *nit; // array of size ni
  const int *disj; // array of size ni; see the disj field of struct sync_element
  const int **itr; // array of size ni x nit[i] for transitions
  const int **iweight; // array of size ni x nit[i]

  const int no;
  const int *otype; // output proc. type, array of size no
  const int *not; // array of size no
  const int **oweight; // array of size no x not[i]
  const int **oplace; // array of size no x not[i] 
                     // (place in which proc is started)
  const int ntr; 
  const int *t; // array of size ntr
};


// The PN structure of the supervisor is represented using the following
// structure. Each transition 0, 1, ..., n has an object of this type.

struct ___PN {
  const int nipl; // number of input places 
  const int *iplace;  // vector of nipl elements
  const int *iweight; // vector of nipl elements

  const int nopl; // number of output places
  const int *oplace;  // vector of nopl elements
  const int *oweight; // vector of nopl elements
};

static char ___no_msg; // indicates absence of plant messages in main function
static sigset_t ___set; // set of signals that may be blocked by main thread

static unsigned char ___start_flag; // used in the main function

int ___run_supervisor(); // this is the main function of the sup. program


// +++++++ OTHER DECLARATIONS (GENERATED CODE HERE) 


struct proc *___prtype[n___prtypes]; // n___prtypes defined in generated code

int ___marking[___pnum]; // supervisor marking; ___pnum defined in gen. code


inline void ___th_send_signal() {
#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  if(pthread_self() != ___tid)
    pthread_kill(___tid, SIGUSR1); 
// it may be that all threads receive the signal, though handler executed only by ___tid
#endif
#endif
}


inline int ___is_enabled(int ___t) { // checks whether ___t is enabled
  int ___i, ___nipl;
  const int *___iplace, *___iweight; 
  const struct ___PN *___p;

  ___p = ___trans + ___t;
  ___nipl = ___p->nipl;
  ___iplace = ___p->iplace;
  ___iweight = ___p->iweight;

  for(___i = 0; ___i < ___nipl; ___i++)
    if(___marking[___iplace[___i]] < ___iweight[___i])
      break;
  return (___i == ___nipl);
}


inline void ___fire(int ___t) { 
  // Fires __t without checking if it is enabled

  int ___i;
  struct ___PN ___d = ___trans[___t];

  for(___i = 0; ___i < ___d.nipl; ___i++)
    ___marking[___d.iplace[___i]] -= ___d.iweight[___i];
  for(___i = 0; ___i < ___d.nopl; ___i++)
    ___marking[___d.oplace[___i]] += ___d.oweight[___i];
}


inline void ___fire_zltrans() {
  // check 0 label transitions and fire them if enabled

  #ifdef ZERO_LABEL_TRANS

  int ___i, ___flag, ___tr;

  for(___flag = 1; ___flag; ) {
    ___flag = 0;
    for(___i = 0; ___i < ZERO_LABEL_TRANS; ___i++) {
      ___tr = ___zltrans[___i];
      if(___is_enabled(___tr)) {
	___fire(___tr);
	___flag = 1;
      }
    }
  }
  #endif
}


inline void ___fire_all(int ___t) { 
  // Fires __t without checking if it is enabled; fires also all zero label
  // transitions that are enabled until none remains enabled.

  int ___i, ___flag, ___tr;

  ___fire(___t);
  ___fire_zltrans();
}


void ___UpdateSupervisorMarking(int ___a) { // ___a is the action number

  #ifdef ___ACTIONS

  const int *___ip = ___act[___a].t, ___n = ___act[___a].ntr;
  int ___i;
 
  for(___i = 0; ___i < ___n; ___i++) 
    if(___is_enabled(___ip[___i])) {
      ___fire_all(___ip[___i]);
      break;
    }
  #endif
}


/*

int find_weight(int ___prtype, int ___a, int ___t) {
  // Returns zero if ___t has no input place. Otherwise, it
  // returns the weight of the input arc of ___t.

  int ___i, ___j, ___w = 0;
  struct ___action ___at = ___act[___a];

  if(___at.ni) {
    for(___i = 0; ___i < ___at.ni; ___i++)
      if(___at.itype[___i] == ___prtype)
	break;
    if(___i < ___at.ni) { // that is, if ___prtype was found
      for(___j = 0; ___j < ___at.nit[___i]; ___j++)
	if(___t == ___at.itr[___i][___j]) {
	  ___w = ___at.iweight[___i][___j];
	  break;
	}
    }
  }
  return ___w;
}

*/


void inline clear_qel_entries(struct proc* ___qel_last) {
  // Clears from QueueEntryList all elements that follow ___qel_last
  struct proc* ___pr, *___pr2;
  for(___pr = ___qel_last->next_in_qelist; ___pr; ___pr = ___pr2) {
    ___pr->atype -= (___pr->atype & 2);  // clear bit 1
    ___pr2 = ___pr->next_in_qelist;
    ___pr->next_in_qelist = 0; 
  }
  ___qel_last->next_in_qelist = 0;
}

struct proc* SearchQueue(int ___prtype, int ___t, int ___w, int ___cnt,\
			 struct proc* ___qel_last) {
  // The search is done for transitions 't' with *t!=0 corresponding to  
  // an action 'a' and to processes of type 'prtype'. 'w' is the weight
  // of 't'. 'qel_last' denotes the last element of QueueEntryList. The 
  // function returns zero if nothing is found. Otherwise, it adds the 
  // appropriate processes to the QueueEntryList and returns the new 
  // last element of QueueEntryList.

  struct proc *___pr, *___qlast;
  struct trlist* ___ptl;
  int ___i, ___c = ___cnt;

  ___qlast = ___qel_last;
  for(___pr = ___wtlist[___prtype]; ___pr; ___pr = ___pr->next_in_wtlist) {
    if(___pr->atype & 2) // if entry in QueueEntryList
      continue;
    // Check if t is in the transition list
    for(___ptl = ___pr->tlist, ___i = 0; ___i < ___pr->ntlist; ___i++) 
      if(___t == ___ptl[___i].t)
	break;
    if(___i < ___pr->ntlist) { // That is, if the transition was found
      ___pr->fireable = ___t;
      ___pr->atype |= 2; // set the bit 1
      ___qlast->next_in_qelist = ___pr;
      ___qlast = ___pr;
      ___c++;
      if(___c >= ___w)
	return ___qlast;
    } 
  }
  clear_qel_entries(___qel_last); // clear qel entries added by SearchQueue
  return 0;
}


#ifdef ___MASK
inline void ___reset_mask(int ___n) {
  int ___i;
  for(___i = 0; ___i < ___n; ___i++)
    ___mask[___i] = 0;
}
#endif


#ifdef ___ACTIONS // The following function called in the context of actions

int IsPermissible(struct proc* ___q) {
  // Checks whether the entry ___q of the queue has some transition that 
  // may be fired. It returns a nonzero number (action number + 1) if this 
  // is the case.

  int ___i, ___j, ___k, ___a, ___t, ___w;
  int ___count, ___permissible, ___ptype, ___type;
  char ___first;
  struct ___action *___pa;
  struct proc *___qel_last, *___q2;
 
  ___q->atype |= 2; // the instruction places {q} in QueueEntryList
  ___ptype = ___q->type;
  for(___i = 0; ___i < ___q->ntlist; ___i++) {
    ___a = ___q->tlist[___i].a;
    ___pa = ___act + ___a; // pa: pointer to the action element

    // Check whether any of the supervisor transitions associated with the
    // action ___a is enabled. To execute ___a, at least one should be enabled.

    if(___pa->ntr) { // if there are sup. trans. associated with ___a
      for(___j = 0; ___j < ___pa->ntr; ___j++)
	if(___is_enabled(___pa->t[___j]))
	  break; // found one enabled supervisor transition
      if(___j >= ___pa->ntr)
	continue; // line reached if there are supervisor transitions 
      // associated with the action and none is enabled.
    }

    // Note: For any correct supervisor, if the supervisor enables t
    // it enables also all transitions with the same label as t. Thus, 
    // it is not necessary to check whether any other transition synchronized 
    // with t is supervisor enabled, since they have the same label.

    ___t = ___q->tlist[___i].t;
    ___q->fireable = ___t;
    ___qel_last = ___q;
    ___permissible = 1;
    #ifdef ___MASK
    ___reset_mask(___pa->no);
    #endif
    for(___j = 0, ___first = 1; ___j < ___pa->ni; ___j++) {
      // Note: pa->ni cannot be zero, because ___t cannot be a source 
      // transition (a plant will not request permission to fire one of its
      // source transitions). Thus, ___t must be part of the input transition
      // list of *___pa, so ni >= 1. 

      ___type = ___pa->itype[___j];
 
      // (a) Check first whether entry j of pa corresponds to t
      // If yes, it is necessary to check the weight of t and whether enough
      // many processes enable t.

      if(___first && ___ptype == ___type) { 
	for(___k = 0; ___k < ___pa->nit[___j]; ___k++)
	  if(___t == ___pa->itr[___j][___k])
	    break;
	if(___k < ___pa->nit[___j]) { // if the transition t was found
	  ___first = 0;
	  // If a non-source transition is chosen and source transitions are an
	  // alternative, an alternative source transition should not be fired
	  #ifdef ___MASK
	  ___w = ___pa->disj[___j];
	  if(___w)  // if source tran alternatives are present
	    ___mask[___w-1] = 1; // then mask (inhibit) them
          #endif 
	  ___w = ___pa->iweight[___j][___k];
	  if(___w == 1) 
	    continue; // continues with the next ___j 
	  ___q2 = SearchQueue(___type, ___t, ___w, 1, ___qel_last);
	  if(___q2) {
	    ___qel_last = ___q2;
	    continue; // continues with the next ___j
	  }
	  ___permissible = 0; // line reached if t is unfirable
	  clear_qel_entries(___q); // clear QueueEntryList
	  break; // Go to next i, since t is unfirable
	}  // endif ___k < ...
      } // endif ___first && ...

      // (b) Check whether some transition of entry j of pa is firable

      for(___k = 0; ___k < ___pa->nit[___j]; ___k++) {
	___w = ___pa->iweight[___j][___k];
	___q2 = SearchQueue(___type, ___pa->itr[___j][___k], ___w, 0, ___qel_last);
	if(___q2) { // if a firable entry was found
	  ___qel_last = ___q2;
	  // If a non-source transition is chosen and source transitions are an
	  // alternative, an alternative source transition should not be fired
	  #ifdef ___MASK
	  ___w = ___pa->disj[___j];
	  if(___w)  // if source tran alternatives are present
	    ___mask[___w-1] = 1; // then mask (inhibit) them
          #endif 
	  break; // Go to the next ___j
	}
      } // end for(___k ...
      if(___k >= ___pa->nit[___j]) { // if no firable transition was found
	if(___pa->disj[___j]) // if there are alternative source transitions
	  continue; // continue with the next ___j
	clear_qel_entries(___q); //clear QueueEntryList; line reached if no sol found
	___permissible = 0; 
	break; // Go to next i, since t is unfirable
      }

    } // end for(___j ...
    if(___permissible)
      return ___a + 1; // the transition may be fired!
  } // end for(___i ...
  ___q->atype -= ___q->atype & 2; // reset bit 1 of atype
  return 0; // no transition of ___q may be fired!
} // ends IsPermissible

#endif // ends ifdef ACTIONS


struct ___comm* ___new_comm_struct() {
  int ___ip[2];
  struct ___comm* ___p;

  ___p = malloc(sizeof(*___p));
  if(! ___p) {
    debugInfo("Could not allocate memory for 'struct ___comm' object");
    return 0;
  }

  if (pipe(___ip) == -1) {
    debugInfo("Could not open unnamed pipes");
    free(___p);
    return 0;
  }


#ifdef SINGLE_READ_CHANNEL

  ___p->sread = ___read_ch;
  ___p->pwrite = ___write_ch;

#else

  ___p->sread = ___ip[0];
  ___p->pwrite = ___ip[1];

  if (pipe(___ip) == -1) {
    debugInfo("Could not open unnamed pipes");
    close(___p->sread);
    close(___p->pwrite);
    free(___p);
    return 0;
  }

  fcntl( ___p->sread, F_SETFL, O_NONBLOCK); // supervisor has nonblocking read
  fcntl( ___p->pwrite, F_SETFL, O_NONBLOCK); // plant has nonblocking write 

#endif

  ___p->swrite = ___ip[1];
  ___p->pread = ___ip[0];

  fcntl( ___p->swrite, F_SETFL, O_NONBLOCK); // sup. has nonblocking write 

  return ___p;
}


struct proc* ___NewProcess(int ___type) {
  // Creates new process structure. Places it at the beginning in prlist.

  struct proc *___p;

  ___p = calloc(1, sizeof(*___p)); // initializes everything to zero
  if(!___p) {
    debugInfo("Could not allocate memory for 'struct proc' object");
    return 0;
  }

  ___p->comm = ___new_comm_struct(); 
  if(!___p->comm) {
    free(___p);
    return 0;
  }

  ___p->tlist = calloc(___maxOutpTranNum[___type], sizeof(*(___p->tlist)));
  if( ! ___p->tlist) {
    debugInfo("Could not allocate memory for 'tlist' field of 'struct proc'");
    free(___p->comm);
    free(___p);
    return 0;
  }

  ___p->ntlist = ___maxOutpTranNum[___type];
  ___p->type = ___type;

  // insert element in ___prlist

  if( ! ___prlist)
    ___prlist = ___p;
  else {
    ___prlist->prev_in_prlist = ___p;
    ___p->next_in_prlist = ___prlist;
    ___prlist = ___p;
  }

  return ___p;
}


void ___free_comm(struct ___comm *___pc) {
  if(___pc) {

#ifdef SINGLE_READ_CHANNEL
    close(___pc->swrite);
    if( ! ___pc->pclosed ) // plant end of pipes already closed for processes 
      close(___pc->pread); // line reached in the case of threads
#else
    close(___pc->sread); close(___pc->swrite);
    if( ! ___pc->pclosed ) {// plant end of pipes already closed for processes
      close(___pc->pread); close(___pc->pwrite);
    }
#endif

    free(___pc);
  }  
}


void inline ___remove_from_prlist(struct proc *___p) {
  if(___prlist == ___p)   // is ___p first element of ___prlist?
    ___prlist = ___p->next_in_prlist;
  if(___p->prev_in_prlist)
    ___p->prev_in_prlist->next_in_prlist = ___p->next_in_prlist;
  if(___p->next_in_prlist)
    ___p->next_in_prlist->prev_in_prlist = ___p->prev_in_prlist;
  ___p->next_in_prlist = 0; // these two lines unnecessary if ___p is freed next
  ___p->prev_in_prlist = 0;
}

void inline ___remove_from_queue(struct proc *___p) {
  if(___first == ___p)
    ___first = ___p->next_in_queue;
  if(___last == ___p)
    ___last = ___p->prev_in_queue;
  if(___p->prev_in_queue)
    ___p->prev_in_queue->next_in_queue = ___p->next_in_queue;
  if(___p->next_in_queue)
    ___p->next_in_queue->prev_in_queue = ___p->prev_in_queue;
  ___p->prev_in_queue = 0;
  ___p->next_in_queue = 0;
}

void inline ___remove_from_wtlist(struct proc *___p) {
  struct proc **___ap = ___wtlist + ___p->type, **___apL = ___wtlistLast + ___p->type;

  if(*___ap == ___p)
    *___ap = ___p->next_in_wtlist;
  if(*___apL == ___p)
    *___apL = ___p->prev_in_wtlist;
  if(___p->prev_in_wtlist)
    ___p->prev_in_wtlist->next_in_wtlist = ___p->next_in_wtlist;
  if(___p->next_in_wtlist)
    ___p->next_in_wtlist->prev_in_wtlist = ___p->prev_in_wtlist;
  ___p->prev_in_wtlist = 0;
  ___p->next_in_wtlist = 0;
}



void ___free_proc(struct proc* ___p) {
  if(___p) {

    if(___p->tlist)  free(___p->tlist);

    ___free_comm(___p->comm); // Close communication channels and free memory

    // Remove ___p from process lists

    ___remove_from_prlist(___p);
    ___remove_from_queue(___p);
    ___remove_from_wtlist(___p);

    free(___p);
  }
}


struct ___thread_data* get_thread_data(struct proc* ___p, int ___where) {
  struct ___thread_data *___pthr;
  struct ___thread_comm *___pc;

  ___pthr = calloc(1, sizeof(*___pthr));
  if(!___pthr) {
    debugInfo("Could not allocate 'struct ___thread_data' object");
    return 0;
  }
  ___pc = calloc(1, sizeof(*___pc));
  if(!___pc) {
    free(___pthr);
    debugInfo("Could not allocate 'struct ___thread_comm' object");
    return 0;
  }

  ___pc->pread = ((struct ___comm*) ___p->comm)->pread;
  ___pc->pwrite = ((struct ___comm*) ___p->comm)->pwrite;
  ___pthr->comm = ___pc;
  ___pthr->debug = ___debug;
  ___pthr->state = ___where;
  ___pthr->id = (void*) ___p;

  return ___pthr;
}


void get_process_comm_data(struct proc* ___p) {
  sprintf(___com, "%d", ((struct ___comm*)___p->comm)->pread);
}


int ___upd_comm_param(int ___sup, struct proc* ___p, int ___where) {
  // This function is used for processes created via "fork" instructions. 
  // Since "fork" creates duplicate file descriptors in the child process, 
  // unnecessary descriptors are closed in this function.  

  struct proc *___pa;
  void *___v = ___p;

  if(!___sup) { // if this is the child process, close 'sread' and 'swrite' 
    close(((struct ___comm*)___p->comm)->sread);
    close(((struct ___comm*)___p->comm)->swrite);
    for(___pa = ___prlist; ___pa; ___pa = ___pa->next_in_prlist) {
      if(___pa == ___p)
	continue;

#ifndef SINGLE_READ_CHANNEL
      close(((struct ___comm*)___pa->comm)->sread);
#endif
      close(((struct ___comm*)___pa->comm)->swrite);
    }
    return 1;
  }
  else { // if this is the supervisor process
    close(((struct ___comm*)___p->comm)->pread);
#ifndef SINGLE_READ_CHANNEL
    close(((struct ___comm*)___p->comm)->pwrite);
#endif
    ((struct ___comm*)___p->comm)->pclosed = 1;

    // send parameters to child process

    if(write(((struct ___comm*)___p->comm)->swrite,		\
	     &((struct ___comm*)___p->comm)->pwrite, \
	     sizeof(((struct ___comm*)___p->comm)->pwrite)) == -1)
      return 0;
    if(write(((struct ___comm*)___p->comm)->swrite, & ___v, \
	     sizeof(void*)) == -1)
      return 0;
    if(write(((struct ___comm*)___p->comm)->swrite, & ___debug, \
	     sizeof(___debug)) == -1)
      return 0;
    if(write(((struct ___comm*)___p->comm)->swrite, & ___where, \
	     sizeof(___where)) == -1)
      return 0;
  }
  return 1;
}


inline int ___send_to_supervisor(const void* ___pdata, int ___n, \
				 struct proc* ___p) {
  // Sends ___n bytes of data located at address ___pdata. Here, ___p is the
  // address of the 'struct proc' object of the sender process.
  // This function is called only from error conditions. It returns 0 if the
  // message could not be sent.  

  return ___send_msg(___pdata, ___n, ((struct ___comm*)___p->comm)->pwrite, debugInfo);
}


void ___terminate_process(struct proc* ___p) {
  if(___p->pid)  // then this is a forked process
    kill(___p->pid, SIGINT); 
  else  // then this is a thread
    pthread_kill(___p->thread_id, SIGINT);
  ___free_proc(___p);
}


inline struct proc*  ___StartProcess_sub(int ___type, int ___where) {
  struct proc *___pr;
  int ___i;
  struct ___thread_data *___pthr;
  pid_t ___cpid;
  struct ___msg ___ms;

  ___pr = ___NewProcess(___type);
  if( ! ___pr) {
    debugInfo("Unable to create new process!\n");
    return 0;
  }

  #ifdef ___THREADS

  if(___start_fn[___type]) {
    ___pthr = get_thread_data(___pr, ___where);
    if(!___pthr) {
      debugInfo("Cannot start thread with empty ___thread_data object");
      return 0;
    }
    ___i = pthread_create(&___pr->thread_id, 0, ___start_fn[___type],\
			  (void*) ___pthr);
    if(___i) {
      debugInfo("pthread_create has returned the error code %d", ___i);
      free(___pthr);
      ___free_proc(___pr);
      return 0;
    }
    return ___pr;
  }

  #endif

  #ifdef ___PROCESSES

  if(___pname[___type]) {
    get_process_comm_data(___pr); // updates the ___com variable
    ___cpid = fork();
    if(___cpid == -1) {
      debugInfo("fork() was not able to create a new process");
      ___free_proc(___pr);
      return 0;
    }
    if( ! ___cpid) { // code execuded by child process
      ___upd_comm_param(0, ___pr, ___where);
      execl(___pname[___type], ___pname[___type], ___com, (char*)0);
      debugInfo("excl was unable to start \"%s %s\"", ___pname[___type], ___com);
      ___ms.type = ___EXIT_NOTIFICATION;
      ___ms.id = ___pr;
      ___send_to_supervisor(&___ms, sizeof(___ms), ___pr);
      exit(EXIT_FAILURE); // this line should not be reached
    }
    else { // code executed by supervisor
      // upd_comm_param below updates the communication settings of the 
      // supervisor and sends input parameters to the child process
      ___pr->pid = ___cpid;
      if( ! ___upd_comm_param(1, ___pr, ___where)) {
	debugInfo("Unable to initiate communication with child process");
	___terminate_process(___pr); // also calls  ___free_proc(___pr)
	return 0;
      }
      return ___pr;
    }
  }

  #endif

  debugInfo("___StartProcess indicates a problem with the supervisor template or\
 the supervisor compiler"); // this line should not be reached

  return 0; 
}



struct proc*  ___StartProcess(int ___type, int ___where) {
  struct proc* ___p;

#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_BLOCK, &___set, 0);
#endif
#endif

  ___p = ___StartProcess_sub(___type, ___where);

#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_UNBLOCK, &___set, 0); 
#endif
#endif

  return ___p;
}


void ___finish_sig_handler(int ___sig) {
  struct proc* ___p;
  void* ___v;

  if(getpid() != ___pid)
    exit(EXIT_FAILURE); 
  else if(pthread_self() != ___tid)
    pthread_exit(0);
  else {
    debugInfo("A signal has been received and the program will be terminated");
    for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) {
      //___terminate_process(___p); // also calls ___free_proc(___p);
      if(___p->pid)  // then this is a forked process
	kill(___p->pid, SIGTERM); 
      /*else  { // then this is a thread
	pthread_kill(___p->thread_id, SIGINT);
	pthread_join(___p->thread_id, &___v); // wait for it to terminate
	}*/
      ___free_proc(___p);
    }
    debugInfo("The program is terminating ... ");
    //sleep(1);
    raise(SIGTERM);
    //exit(EXIT_SUCCESS);
  }
}


#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS

void ___newmsg_sig_handler(int ___sig) {

  debugInfo("SIGUSR1 received");
  if(getpid() == ___pid)
    if(pthread_self() == ___tid)
      ___no_msg = 0;
  return;
}

#endif
#endif


inline int ___check_for_msg(struct proc *___p, struct ___msg *p___ms) {
  // The function returns 0 if there are no messages
  int ___i;

  // Block signals while receiving data

#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_BLOCK, &___set, 0);
#endif
#endif
  ___i =  ___get_msg(((struct ___comm*)___p->comm)->sread, p___ms, \
		     sizeof(*p___ms), debugInfo);
#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_UNBLOCK, &___set, 0); 
#endif
#endif
  return ___i;
}


void inline  ___PerformAction(int ___a, char* ___msk) {

#ifdef ___ACTIONS

  int ___i, ___j, ___n, ___w;
  struct ___action* ___ac = ___act + ___a;

  // Start new processes (if applicable)

  ___n = ___ac->no;
  for(___i = 0; ___i < ___n; ___i++) {
    if(___msk)
      if(___msk[___i]) // ignore masked entries
	continue;
    ___j = 0;
    if(___ac->not[___i] > 1)
      ___j = rand() % ___ac->not[___i]; // select one of the source transitions
    ___w = ___ac->oweight[___i][___j];
    for( ; ___w; ___w--)
     ___StartProcess(___ac->otype[___i], ___ac->oplace[___i][___j]); 
  }

#endif

}


void ___execute_action(int ___a) { 
  int ___i = 1;

#ifdef ___ACTIONS

  ___i = (___a < 0) || (___a >= ___ACTIONS);

#endif

  if(___i) {
    debugInfo("Action %d is undefined", ___a);
    return;
  }

  ___UpdateSupervisorMarking(___a);
  ___PerformAction(___a, 0); // start new processes, if applicable
}


int ___process_msg(struct ___msg *p___ms) {
  // Returns zero if the process of p___ms has terminated
  struct proc **___ap, **___apL, *___p, *___pa = p___ms->id;
  int ___i;

  switch(p___ms->type) {

  case ___EXIT_NOTIFICATION:  // then deallocate process

    for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) {
      if(___pa == ___p) {
	___free_proc(___p);
	break;
      }
    }
    return 0;

  case ___FIRING_REQUEST:


    // Is this message about the last answered request?
    if(___pa->solved == p___ms->req_id) // req_id may not be zero
      return 1; // nothing to do, the request is already answered

    // Is this firing request already in the queue? 

    if(___pa->request == p___ms->req_id) {
      ___i = ___pa->ntlist;
      if(___i >= ___maxOutpTranNum[___pa->type])
	debugInfo("Transition list of (%d:%d) exceeds maximum size", (int) ___pa->pid, (int) ___pa->thread_id);
      else {
	___pa->tlist[___i].t = p___ms->t;
	___pa->tlist[___i].a = p___ms->a;
	___pa->ntlist++;
      }
      debugInfo("Proc. type %d (%d:%d): t%d (a%d) alternative tran. to fir. req. %d", (int)___pa->type, (int) ___pa->pid, (int) ___pa->thread_id, (int)p___ms->t, (int)p___ms->a,  (int)___pa->request); 
      return 1;
    }

    // If not in queue, add to queue and wtlist

    ___pa->request = p___ms->req_id;

    ___pa->tlist[0].t = p___ms->t;
    ___pa->tlist[0].a = p___ms->a;
    ___pa->ntlist = 1;

    if(!___last) {  // update queue
      ___last = ___pa;
      ___first = ___pa;
    }
    else {
      ___last->next_in_queue = ___pa;
      ___pa->prev_in_queue = ___last;
      ___last = ___pa;
    }

    ___ap = ___wtlist + ___pa->type;  // update wtlist
    ___apL = ___wtlistLast + ___pa->type;
    if(!*___apL)  { 
      *___apL = ___pa;
      *___ap = ___pa;
    }
    else {
      (*___apL)->next_in_wtlist = ___pa;
      ___pa->prev_in_wtlist = *___apL;
      *___apL = ___pa;
    }

    debugInfo("Firing req. [id:%d] (%d:%d): proc. type %d requests t%d (a%d)", (int)___pa->request, (int) ___pa->pid, (int) ___pa->thread_id, (int) ___pa->type, (int)p___ms->t, (int)p___ms->a); 
    
    return 1;

  case ___FIRING_NOTIFICATION:

    ___execute_action(p___ms->a);
    return 1;

  default:
    debugInfo("Type %d of (%d:%d) is an undefined message type", (int)p___ms->type, (int) ___pa->pid, (int) ___pa->thread_id);
  }

  return 1;
}



inline void ___send_permission_msg(struct proc *___p) {

#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_BLOCK, &___set, 0);
#endif
#endif

  ___send_msg(&___p->fireable, sizeof(int), ((struct ___comm*)___p->comm)->swrite, debugInfo);

#ifndef SINGLE_READ_CHANNEL
#ifdef ___SIGNALS
  pthread_sigmask(SIG_UNBLOCK, &___set, 0); 
#endif
#endif

}



// Define the main function of the supervisor program

int ___run_supervisor()  {
  int ___i, ___j, ___a, ___ip[2];
  long ___def_flags;
  struct proc *___p, *___pa, *___pn;
  struct sigaction ___act;
  struct ___msg ___ms;
  time_t ___ctime;


  ___pid = getpid();
  ___tid = pthread_self();

  //___debug = 0;
  ___finish = 0;
  ___f = stderr;
  ___name = 0;
  ___prlist = 0;
  ___first = 0; ___last = 0;

  // install signal handlers

  sigaction(SIGINT, 0, &___act); // initialize act
  ___act.sa_flags = 0;  
  //sigemptyset(&act.sa_mask);  // no signals blocked 
  ___act.sa_handler = ___finish_sig_handler;
  sigaction(SIGINT, &___act, 0); // initialize act

#ifdef SINGLE_READ_CHANNEL

  if (pipe(___ip) == -1) {
    debugInfo("Could not open unnamed pipes");
    return 1;
  }
  ___read_ch = ___ip[0]; // read end of supervisor
  ___write_ch = ___ip[1]; // write end of plant components
  ___def_flags = fcntl(___read_ch, F_GETFL); 
#else
#ifdef ___SIGNALS
  sigaction(SIGUSR1, 0, &___act); // initialize act
  ___act.sa_flags = SA_RESTART;  
  ___act.sa_handler = ___newmsg_sig_handler;
  sigaction(SIGUSR1, &___act, 0); // initialize act
  sigemptyset(&___set);
  sigaddset(&___set, SIGUSR1);
#endif
#endif

  time(&___ctime);
  srand(___ctime%64000);



  // initialize supervisor ___marking
  memset(___marking, 0, sizeof(*___marking)*___pnum); 
  for(___i = 0; ___i < n___m0; ___i++) 
    ___marking[___m0[___i][0]] = ___m0[___i][1];
  ___fire_zltrans(); // fire zero label transitions of supervisor if enabled

  // start processes
  for(___i = 0; ___i < n___pm0; ___i++) 
    for(___j = 0; ___j < ___pm0[___i][2]; ___j++) // ___pm0[___i][2]: # of tokens
      ___StartProcess(___pm0[___i][0], ___pm0[___i][1]); // arguments: type, place


  while( ! ___finish) {

    if(!___prlist)
      break; // all processes have terminated, so the supervisor terminates

    // Check all processes for new messages

#ifdef SINGLE_READ_CHANNEL
    fcntl(___read_ch, F_SETFL, ___def_flags); // next read will be blocking
    for(___i = 0; ___i < MSG_READ_LIMIT; ___i++) {
      ___j = ___get_msg(___read_ch, &___ms, sizeof(___ms), debugInfo);
      if(!___j)
	break; // exit loop since there are no more messages
      ___process_msg(&___ms);
      if(!___i)
	fcntl(___read_ch, F_SETFL, O_NONBLOCK); // next reads nonblocking
    }
#else
    for(___p = ___prlist, ___no_msg = 1; ___p; ___p = ___pn) {
      ___pn = ___p->next_in_prlist; // process_msg below may deallocate ___p
      for(___i = 0; ___i < MSG_READ_LIMIT; ___i++) {
	___j = ___check_for_msg(___p, &___ms);
	if( ! ___j )
	  break; // exit loop, since there are no messages
	___no_msg = 0;
	if( ! ___process_msg(&___ms) ) // processes the message
	  break; // exit loop since the process of ___p has terminated
      }
    }

    if(___no_msg) { // if SIGUSR1 occurs between if and sleep --> ignored!
      #ifdef ___SLEEP
      sleep(___SLEEP); // any signal will awake the process
      #endif
      continue;
    }
#endif

    // Check for queued requests that can be resolved

#ifdef ___ACTIONS // There may be queued requests only if actions are defined,
               // as can be seen in the definition of ___process_msg().

    for(___p = ___first; ___p; ___p = ___pn) { // search queued requests
      ___pn = ___p->next_in_queue; // the loop will not deallocate ___p but
      // it may remove ___p from the queue
      ___a = IsPermissible(___p); // creates EntryList (qelist)
      if(___a > 0) { // then the request of ___p can be resolved

	// Make sure that ___pn is not in EntryList, since everything in
	// EntryList will be removed from the queue

	for(; ___pn; ___pn = ___pn->next_in_queue)
	  if(!(___pn->atype & 2)) // if not in EntryList
	    break;

	// Grant permission to fire to the processes in EntryList
	// Remove also from queue and wait list processes in EntryList

	for(___pa = ___p; ___pa; ___pa = ___pa->next_in_qelist) {
	  // This loop does not affect 'qelist' (EntryList).
	  // However, it does affect 'queue' and 'wtlist'.
	  //if(___pn == ___pa) // if ___pn will be removed from queued requests
	  //  ___pn = ___pn->next_in_queue; // select next queued request
	  ___send_permission_msg(___pa);
	  ___remove_from_queue(___pa); // remove ___pa from queued requests
	  ___remove_from_wtlist(___pa);
	}

	clear_qel_entries(___p); // delete EntryList except for first element
        ___p->atype -= (___p->atype & 2);  // remove first el of EntryList
	___a--; // since IsPermissible adds 1 to the return value
	___UpdateSupervisorMarking(___a); // update supervisor marking
#ifdef ___MASK
	___PerformAction(___a, ___mask); // start new processes, if applicable
#else
	___PerformAction(___a, 0); // start new processes, if applicable
#endif

      }
    }
#endif // end of ifdef ___ACTIONS

  } // end of while( ! ___finish)   (the main loop)

#ifdef SINGLE_READ_CHANNEL
    close(___read_ch);
    close(___write_ch);
#endif

  debugInfo("The end of the supervisor function was reached.\n");
  
  return 0;
}




// ++++++++++++++++++++++++++ USER CODE--DECLARATIONS (GENERATED CODE HERE) 



int ___smain_fn() {


  // +++++++++++++++++++ USER CODE--MAIN FUNCTION (GENERATED CODE HERE) 


  return ___run_supervisor();
}


#ifdef ___MAIN_FUNCTION

int main(int argc, char* argv[]) {
  int ___i, ___j;
  char *___str, ___help_msg[] = "\nCommand line options: \n\
 -d: display error and status messages\n\
 -s: start the program right away without displaying this introductory message\n\n\
 Ctrl-C (SIGINT) can be used to stop the program. This will terminate all\n\
 its processes.\n";

  ___debug = 0;
  ___start_flag = (argc <= 1);
  for(___i = 1; ___i < argc; ___i++) {
    if(!strcmp(argv[___i], "-d")) 
      ___debug = 1;
    else if(!strcmp(argv[___i], "-h") || !strcmp(argv[___i], "--help")) {
      fputs(___help_msg, stdout);
      return 0;
    }
    else if(!strcmp(argv[___i], "-s")) {
      ___start_flag = 0; 
    }
  }

  if(___start_flag) {
    fprintf(stdout, "%s\nThe program will start in five seconds.\n", ___help_msg);
    sleep(5);
  }

  if(___debug) {
    if(argc <= 1)
      debugInfo("The main function was entered. The main functions has no parameters.");
    else {
      for(___i = 0, ___j = 0; ___i < argc; ___i++)
	___j += strlen(argv[___i]);
      ___j += argc + 1;
      ___str = malloc(___j*sizeof(char));
      for(___i = 0, ___j = 0; ___i < argc - 1; ___i++) { 
	sprintf(___str + ___j, "%s ", argv[___i]);
	___j += strlen(argv[___i]) + 1;
      }
      sprintf(___str + ___j, "%s", argv[___i]);
      debugInfo("The program was started with the following command line\n\t%s", ___str);
      free(___str);
    }
  }

  return ___smain_fn();
}

#endif
