#include "../h/syscall.h"
extern pcb_t* currentProcess; // pointer to the current executing process
extern int softBlockCount; // number of soft blocked processes
extern int device_semaphores[49];
extern pcb_t* readyQueue; // tail pointer to the queue of ready pcbs
extern int processCount; // number of started but not terminated processes
extern cpu_t startTime; // start time
state_t* savedException;
void SyscallExceptionHandler(state_t* exception_state)
{
savedException = exception_state;
savedException->pc_epc += 4; // increment by 4B to avoid repeat
unsigned int sysCallCode = 0;
sysCallCode = (unsigned int) savedException->reg_a0;
switch (sysCallCode)
{
case CREATEPROCESS:
Create_Process_SYS1();
break;
case TERMPROCESS:
Terminate_Process_SYS2();
break;
case PASSEREN:
// Requests the Nucleus to perform a P operation on a semaphore
Passeren_SYS3((int*) exception_state->reg_a1);
break;
case VERHOGEN:
Verhogen_SYS4((int*) exception_state->reg_a1);
break;
case IOWAIT:
Wait_For_IO_Device_SYS5();
break;
case GETTIME:
Get_CPU_Time_SYS6();
break;
case CLOCKWAIT:
Wait_For_Clock_SYS7();
break;
case GETSUPPORTPTR:
Get_Support_Data_SYS8(exception_state);
break;
default:
PassUpOrDie(GENERALEXCEPT, exception_state);
break;
}
}
void Create_Process_SYS1()
{
// Create local copies of reg_a1 and reg_a2
state_t a1Copy = *((state_t*) savedException->reg_a1);
support_t* a2Copy = (support_t*) savedException->reg_a2;
pcb_t* allocatedPcb = allocPcb();
if(allocatedPcb != NULL){
// the pcb for the process is successfully created
// PCB tree and queue fields are set to null in allocPcb process
insertProcQ(&readyQueue, allocatedPcb);
insertChild(currentProcess, allocatedPcb);
currentProcess->p_s.reg_v0 = OK;
processCount++;
allocatedPcb->p_semAdd = NULL;
allocatedPcb->p_time = 0;
allocatedPcb->p_s = a1Copy;
allocatedPcb->p_supportStruct = a2Copy;
} else {
// process creation was unsuccessful
currentProcess->p_s.reg_v0 = NOPROC;
}
LDST(savedException);
}
/*
* This services causes the executing process to cease to exist. In addition,
* recursively, all progeny of this process are terminated as well.
*/
void Terminate_Process_SYS2()
{
if (currentProcess != NULL) {
// If the current process exists
outChild(currentProcess);
TerminateTree(currentProcess);
currentProcess = NULL;
Scheduler();
}
}
/*
* This method will terminate all children of the current process (referred to as to_terminate) and
* should finally terminate the to_terminate itself.
*/
void TerminateTree(pcb_t* to_terminate)
{
if (to_terminate == NULL) {
return;
}
while (!emptyChild(to_terminate)) {
// terminated process has a child process
pcb_t* removedChild = removeChild(to_terminate);
TerminateTree(removedChild); // recursively remove all children
}
TerminateSingleProcess(to_terminate); // terminate the current process
}
void TerminateSingleProcess(pcb_t* to_terminate) // declared static so it can only be called in this file's scope.
{
outProcQ(&readyQueue, to_terminate);
processCount--;
if (to_terminate->p_semAdd != NULL) {
if (to_terminate->p_semAdd >= &(device_semaphores[0]) && to_terminate->p_semAdd <= &(device_semaphores[48])) {
softBlockCount--;
} else {
*(to_terminate->p_semAdd) = *(to_terminate->p_semAdd) + 1;
}
outBlocked(to_terminate);
}
freePcb(to_terminate);
}
void Passeren_SYS3(int* semAddr)
{
(*semAddr) = (*semAddr) - 1; // Decrement the semaphore value
if (*semAddr < 0) {
currentProcess->p_s = *savedException;
int result = insertBlocked(semAddr, currentProcess);
switch (result) {
case 0: // false case
Scheduler();
break;
case 1: // true case
PANIC();
}
} else {
LDST(savedException);
}
}
void Verhogen_SYS4(int* semAddr)
{
(*semAddr) = (*semAddr) + 1; // Increment the semaphore value
pcb_t* removedPcb = removeBlocked(semAddr);
if(removedPcb != NULL){
// The process was in a blocked state
removedPcb->p_semAdd = NULL;
insertProcQ(&readyQueue, removedPcb);
}
LDST(savedException);
}
void Wait_For_IO_Device_SYS5()
{
int deviceNumber;
// Access the saved exception state
if (savedException->reg_a1 == 7) {
// Terminal device
deviceNumber = 2 * savedException->reg_a2 + savedException->reg_a3;
} else {
// Non-terminal device
deviceNumber = savedException->reg_a2;
}
// Calculate semaphore index
int semIndex = (savedException->reg_a1 - 3) * 8 + deviceNumber;
// Increment soft block count
softBlockCount++;
// Perform the P operation on the device semaphore
Passeren_SYS3(&device_semaphores[semIndex]);
}
/* This service requests that the accumulated processor
* (in microseconds) used by the requesting process be placed/returned in the caller’s v0.
*/
void Get_CPU_Time_SYS6()
{
currentProcess->p_time += (CURRENT_TOD - startTime);
savedException->reg_v0 = currentProcess->p_time;
STCK(startTime);
LDST(savedException);
}
/*
* This service performs a P operation on the Nucleus maintained pseudo-clock semaphore
*/
void Wait_For_Clock_SYS7()
{
softBlockCount++;
Passeren_SYS3(&device_semaphores[48]); // call SYS3
}
/*
* This service requests a pointer to the current process's support structure.
* If no value for p_supportStruct was provided for the current process when it was created,
* return NULL.
*/
void Get_Support_Data_SYS8()
{
savedException->reg_v0 = (unsigned int) currentProcess->p_supportStruct;
LDST(savedException);
}