pcp_generic {; NumberOfTasks : NATURAL, 
               NumberOfSemaphores : NATURAL,
               tasks : pcp_task{[1..NumberOfSemaphores]; NumberOfTasks}!TaskDescriptors,
               budgets : ARRAY [1..NumberOfTasks] OF NATURAL
            } : CONTEXT =
BEGIN

  Semaphore : TYPE = [1..NumberOfSemaphores];

  semSetCtx : CONTEXT = simple_set{Semaphore;};

  SemSet : TYPE = semSetCtx!Set;

  taskCtx : CONTEXT = pcp_task{Semaphore; NumberOfTasks};

  JobIdx : TYPE = taskCtx!JobIdx;
  
  rsrcCtx : CONTEXT = pcp_rsrc{Semaphore; NumberOfTasks, tasks};

  RSRC : TYPE = rsrcCtx!RSRC;

  schCtx : CONTEXT = pcp_scheduler{Semaphore; NumberOfTasks, tasks};
  
  Turn : TYPE = schCtx!Turn;

  alloc_step(r : RSRC, j : JobIdx, s : Semaphore) : RSRC =
    rsrcCtx!alloc_step(r,j,s);

  release_step(r : RSRC, j : JobIdx, s : Semaphore) : RSRC =
    rsrcCtx!release_step(r,j,s);

  turn?(t : Turn, j : JobIdx) : BOOLEAN = schCtx!turn?(t, j);

  JobStatus : TYPE = schCtx!JobStatus;

  precedes?(j : JobIdx, k : JobIdx) : BOOLEAN =
    schCtx!precedes?(j,k);

  priority(j : JobIdx) : NATURAL =
    schCtx!priority(j);

  lock(r : RSRC, j : JobIdx, s : Semaphore) : RSRC =
		schCtx!lock(r,j,s);

  unlock(r : RSRC, j : JobIdx, s : Semaphore) : RSRC = 
    schCtx!unlock(r,j,s);

  unlock_all(r : RSRC, j : JobIdx) : RSRC = 
    schCtx!unlock_all(r,j);

  step(r : RSRC, j : JobIdx) : RSRC =
    schCtx!step(r,j);

  uses?(j : JobIdx, s : Semaphore) : BOOLEAN =
    semSetCtx!contains?(s, tasks[j].semaphores);

  job [id : JobIdx] : MODULE =
  BEGIN
    INPUT turn : Turn
    OUTPUT status : JobStatus
    GLOBAL rsrc : RSRC
    OUTPUT pc : [1..budgets[id]]
  INITIALIZATION
    status = schCtx!finished;
    pc = 1
	TRANSITION
    [
      ([] (s : Semaphore) : pc < budgets[id] AND turn?(turn', id) AND 
                            uses?(id, s) --> 
            status' = IF pc = 1 THEN schCtx!started ELSE status ENDIF;
            rsrc' IN {lock(rsrc, id, s),
                      step(rsrc, id),
                      unlock(rsrc, id, s)};
            pc' = pc + 1)
      []      
      pc = budgets[id] AND turn?(turn', id) --> rsrc' = unlock_all(rsrc, id);
                                                status' = schCtx!finished;
                                                pc' = 1
    ]
  END;

  system : MODULE = 
	  schCtx!scheduler ||
	  ((WITH OUTPUT job_status : ARRAY JobIdx OF JobStatus;
	         OUTPUT job_pc : ARRAY JobIdx OF NATURAL
		([] (j : JobIdx) : RENAME status TO job_status[j],
                              pc TO job_pc[j]
                       IN job[j]))
    []
    schCtx!idle_process);  

  JobState : TYPE = schCtx!JobState;
  deadlock? (job_state : ARRAY JobIdx OF JobState, t : Turn) : BOOLEAN = schCtx!deadlock?(job_state, t);

  deadline_missed? (dispatch : ARRAY JobIdx OF schCtx!ClockRange,
                    job_state : ARRAY JobIdx OF BOOLEAN,
                    clock : schCtx!ClockRange) : BOOLEAN = schCtx!deadline_missed?(dispatch, job_state, clock);

END
