Exemplo n.º 1
0
//-------------------------------------------------------
//
// mbox_t MboxCreate();
//
// Allocate an available mailbox structure for use. 
//
// Returns the mailbox handle on success
// Returns MBOX_FAIL on error.
//
//-------------------------------------------------------
mbox_t MboxCreate() {
	mbox_t imbox;
	uint32 intrval;

	// grabbing a Mbox should be an atomic operation
	intrval = DisableIntrs();
	for(imbox = 0; imbox < MBOX_NUM_MBOXES; imbox++) {
		if(mboxes[imbox].inuse == false) {
			mboxes[imbox].inuse = true;
			break;
		}
	}
	RestoreIntrs(intrval);
	if(imbox == MAX_SEMS) return MBOX_FAIL;
	if ((mboxes[imbox].s_mbox_emptyslots = SemCreate(MBOX_MAX_BUFFERS_PER_MBOX - 1)) == SYNC_FAIL) {
		printf("Bad sem_create in MboxOpen");
		exitsim();
	}
	if ((mboxes[imbox].s_mbox_fillslots = SemCreate(0)) == SYNC_FAIL) {
		printf("Bad sem_create in MboxOpen");
		exitsim();
	}
	if((mboxes[imbox].l_mbox = LockCreate()) == SYNC_FAIL) {
		printf("Bad lock_create in MboxModInit");
		exitsim();
	}
	return imbox;
}
Exemplo n.º 2
0
//---------------------------------------------------------------------------
//	CondHandleWait
//
//	This function makes the calling process block on the condition variable
//	till either ConditionHandleSignal or ConditionHandleBroadcast is
//	received. The process calling CondHandleWait must have acquired the
//	lock associated with the condition variable (the lock that was passed
//	to CondCreate. This implies the lock handle needs to be stored
//	somewhere. hint! hint!) for this function to
//	succeed. If the calling process has not acquired the lock, it does not
//	block on the condition variable, but a value of 1 is returned
//	indicating that the call was not successful. Return value of 0 implies
//	that the call was successful.
//
//	This function should be written in such a way that the calling process
//	should release the lock associated with this condition variable before
//	going to sleep, so that the process that intends to signal this
//	process could acquire the lock for that purpose. After waking up, the
//	blocked process should acquire (i.e. wait on) the lock associated with
//	the condition variable. In other words, this process does not
//	"actually" wake up until the process calling CondHandleSignal or
//	CondHandleBroadcast releases the lock explicitly.
//---------------------------------------------------------------------------
int CondWait(Cond *c) {
  Link	*l;
  int   intrval;
    
  if (!c) return SYNC_FAIL;

  // Conds are atomic
  intrval = DisableIntrs ();
  dbprintf ('I', "CondWait: Old interrupt value was 0x%x.\n", intrval);

  // Check to see if the current process owns the lock
  if (c->lock->pid != GetCurrentPid()) {
    dbprintf('s', "CondWait: Proc %d does not own cond %d\n", GetCurrentPid(), (int)(c-conds));
    RestoreIntrs(intrval);
    return SYNC_FAIL;
  }

  dbprintf ('s', "CondWait: Proc %d waiting on cond %d.  Putting to sleep.\n", GetCurrentPid(), (int)(c-conds));
  if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) {
    printf("FATAL ERROR: could not allocate link for cond queue in CondWait!\n");
    exitsim();
  }
  if (AQueueInsertLast (&c->waiting, l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert new link into cond waiting queue in CondWait!\n");
    exitsim();
  }
  // Release the lock before going to sleep
  LockRelease(c->lock);
  RestoreIntrs(intrval); // Don't want interrupts disabled while we sleep
  ProcessSleep();
  // Immediately acquire the lock upon waking
  LockAcquire(c->lock);
  return SYNC_SUCCESS;
}
Exemplo n.º 3
0
//----------------------------------------------------------------------
//
//	SemWait
//
//	Wait on a semaphore.  As described in Section 6.4 of _OSC_,
//	we decrement the counter and suspend the process if the
//	semaphore's value is less than 0.  To ensure atomicity,
//	interrupts are disabled for the entire operation, but must be
//      turned on before going to sleep.
//
//----------------------------------------------------------------------
int SemWait (Sem *sem) {
  Link	*l;
  int		intrval;
    
  if (!sem) return SYNC_FAIL;

  intrval = DisableIntrs ();
  dbprintf ('I', "SemWait: Old interrupt value was 0x%x.\n", intrval);
  dbprintf ('s', "SemWait: Proc %d waiting on sem %d, count=%d.\n", GetCurrentPid(), (int)(sem-sems), sem->count);
  if (sem->count <= 0) {
    dbprintf('s', "SemWait: putting process %d to sleep\n", GetCurrentPid());
    if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) {
      printf("FATAL ERROR: could not allocate link for semaphore queue in SemWait!\n");
      exitsim();
    }
    if (AQueueInsertLast (&sem->waiting, l) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not insert new link into semaphore waiting queue in SemWait!\n");
      exitsim();
    }
    ProcessSleep();
    // Don't decrement couter here because that's handled in SemSignal for us
  } else {
    sem->count--; // Decrement internal counter
    dbprintf('s', "SemWait: Proc %d granted permission to continue by sem %d\n", GetCurrentPid(), (int)(sem-sems));
  }
  RestoreIntrs (intrval);
  return SYNC_SUCCESS;
}
Exemplo n.º 4
0
//----------------------------------------------------------------------
//
//	ProcessFreeResources
//
//	Free the resources associated with a process.  This assumes the
//	process isn't currently on any queue.
//
//----------------------------------------------------------------------
void ProcessFreeResources (PCB *pcb) {
  int i = 0;
  int usrsp = MEM_ADDRESS_TO_PAGE(pcb->currentSavedFrame[PROCESS_STACK_USER_STACKPOINTER]);
  
  // Allocate a new link for this pcb on the freepcbs queue
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessFreeResources!\n");
    exitsim();
  }
  // Set the pcb's status to available
  pcb->flags = PROCESS_STATUS_FREE;
  // Insert the link into the freepcbs queue
  if (AQueueInsertLast(&freepcbs, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert PCB link into freepcbs queue in ProcessFreeResources!\n");
    exitsim();
  }

  //------------------------------------------------------------
  // STUDENT: Free any memory resources on process death here.
  //------------------------------------------------------------
  for(i = 0; i < 5; i++) {
    MemoryFreePte(pcb->pagetable[i]);
  }
  for(i = usrsp; i <= MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS); i++) {
    MemoryFreePte(pcb->pagetable[i]);
  }
  MemoryFreePage (pcb->sysStackArea / MEM_PAGESIZE);
  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
  dbprintf ('p', "ProcessFreeResources: function complete\n");
}
Exemplo n.º 5
0
//----------------------------------------------------------------------
//
//	ProcessSchedule
//
//	Schedule the next process to run.  If there are no processes to
//	run, exit.  This means that there should be an idle loop process
//	if you want to allow the system to "run" when there's no real
//	work to be done.
//
//	NOTE: the scheduler should only be called from a trap or interrupt
//	handler.  This way, interrupts are disabled.  Also, it must be
//	called consistently, and because it might be called from an interrupt
//	handler (the timer interrupt), it must ALWAYS be called from a trap
//	or interrupt handler.
//
//	Note that this procedure doesn't actually START the next process.
//	It only changes the currentPCB and other variables so the next
//	return from interrupt will restore a different context from that
//	which was saved.
//
//----------------------------------------------------------------------
void ProcessSchedule () {
  PCB *pcb=NULL;
  int i=0;
  Link *l=NULL;
  uint32 intrvals = 0;

  intrvals = DisableIntrs();

  // The OS exits if there's no runnable process.  This is a feature, not a
  // bug.  An easy solution to allowing no runnable "user" processes is to
  // have an "idle" process that's simply an infinite loop.
  if (AQueueEmpty(&runQueue)) {
    if (!AQueueEmpty(&waitQueue)) {
      printf("FATAL ERROR: no runnable processes, but there are sleeping processes waiting!\n");
      l = AQueueFirst(&waitQueue);
      while (l != NULL) {
        pcb = AQueueObject(l);
        printf("Sleeping process %d: ", i++); printf("PID = %d\n", (int)(pcb - pcbs));
        l = AQueueNext(l);
      }
      exitsim();
    }
    printf ("No runnable processes - exiting!\n");
    exitsim ();	// NEVER RETURNS
  }

  // Move the front of the queue to the end if currentPCB is not on sleep queue.  
  // The running process was the one in front.
  if (currentPCB->flags & PROCESS_STATUS_RUNNABLE) {
    AQueueMoveAfter(&runQueue, AQueueLast(&runQueue), AQueueFirst(&runQueue));
  }

  // Now, run the one at the head of the queue.
  pcb = (PCB *)AQueueObject(AQueueFirst(&runQueue));
  currentPCB = pcb;
  dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n",
	    (int)pcb, pcb->flags, (int)(pcb->sysStackPtr[PROCESS_STACK_IAR]));

  // Clean up zombie processes here.  This is done at interrupt time
  // because it can't be done while the process might still be running
  while (!AQueueEmpty(&zombieQueue)) {
    pcb = (PCB *)AQueueObject(AQueueFirst(&zombieQueue));
    dbprintf ('p', "Freeing zombie PCB 0x%x.\n", (int)pcb);
    if (AQueueRemove(&(pcb->l)) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not remove zombie process from zombieQueue in ProcessSchedule!\n");
      exitsim();
    }
    ProcessFreeResources(pcb);
  }

  RestoreIntrs(intrvals);
}
Exemplo n.º 6
0
//---------------------------------------------------------------------------
//	CondHandleSignal
//
//	This call wakes up exactly one process waiting on the condition
//	variable, if at least one is waiting. If there are no processes
//	waiting on the condition variable, it does nothing. In either case,
//	the calling process must have acquired the lock associated with
//	condition variable for this call to succeed, in which case it returns
//	0. If the calling process does not own the lock, it returns 1,
//	indicating that the call was not successful. This function should be
//	written in such a way that the calling process should retain the
//	acquired lock even after the call completion (in other words, it
//	should not release the lock it has already acquired before the call).
//
//	Note that the process woken up by this call tries to acquire the lock
//	associated with the condition variable as soon as it wakes up. Thus,
//	for such a process to run, the process invoking CondHandleSignal
//	must explicitly release the lock after the call is complete.
//---------------------------------------------------------------------------
int CondSignal(Cond *c) {
  Link *l;
  int intrs;
  PCB *pcb;

  if (!c) return SYNC_FAIL;

  intrs = DisableIntrs ();
  dbprintf ('s', "CondSignal: Proc %d signalling cond %d.\n", GetCurrentPid(), (int)(c-conds));

  if (c->lock->pid != GetCurrentPid()) {
    dbprintf('s', "CondSignal: Proc %d does not own cond %d.\n", GetCurrentPid(), (int)(c-conds));
    return SYNC_FAIL;
  }
  if (!AQueueEmpty(&c->waiting)) { // there is a process to wake up
    l = AQueueFirst(&c->waiting);
    pcb = (PCB *)AQueueObject(l);
    if (AQueueRemove(&l) != QUEUE_SUCCESS) { 
      printf("FATAL ERROR: could not remove link from cond queue in CondSignal!\n");
      exitsim();
    }
    dbprintf ('s', "CondSignal: Waking up PID %d, it still needs to acquire lock.\n", GetPidFromAddress(pcb));
    ProcessWakeup (pcb);
  } else {
    dbprintf('s', "CondSignal: Proc %d signalled, but no processes were waiting.\n", GetCurrentPid());
  }
  RestoreIntrs (intrs);
  return SYNC_SUCCESS;
}
Exemplo n.º 7
0
//---------------------------------------------------------------------------
//	LockHandleRelease
//
//	This procedure releases the unique lock described by the handle. It
//	first checks whether the lock is a valid lock. If not, it returns SYNC_FAIL.
//	If the lock is a valid lock, it should check whether the calling
//	process actually holds the lock. If not it returns SYNC_FAIL. Otherwise it
//	releases the lock, and returns SYNC_SUCCESS.
//---------------------------------------------------------------------------
int LockRelease(Lock *k) {
  Link *l;
  int	intrs;
  PCB *pcb;

  if (!k) return SYNC_FAIL;

  intrs = DisableIntrs ();
  dbprintf ('s', "LockRelease: Proc %d releasing lock %d.\n", GetCurrentPid(), (int)(k-locks));

  if (k->pid != GetCurrentPid()) {
    dbprintf('s', "LockRelease: Proc %d does not own lock %d.\n", GetCurrentPid(), (int)(k-locks));
    return SYNC_FAIL;
  }
  k->pid = -1;
  if (!AQueueEmpty(&k->waiting)) { // there is a process to wake up
    l = AQueueFirst(&k->waiting);
    pcb = (PCB *)AQueueObject(l);
    if (AQueueRemove(&l) != QUEUE_SUCCESS) { 
      printf("FATAL ERROR: could not remove link from lock queue in LockRelease!\n");
      exitsim();
    }
    dbprintf ('s', "LockRelease: Waking up PID %d, assigning lock.\n", (int)(GetPidFromAddress(pcb)));
    k->pid = GetPidFromAddress(pcb);
    ProcessWakeup (pcb);
  }
  RestoreIntrs (intrs);
  return SYNC_SUCCESS;
}
Exemplo n.º 8
0
//----------------------------------------------------------------------
//
//	SemSignal
//
//	Signal on a semaphore.  Again, details are in Section 6.4 of
//	_OSC_.
//
//----------------------------------------------------------------------
int SemSignal (Sem *sem) {
  Link *l;
  int	intrs;
  PCB *pcb;

  if (!sem) return SYNC_FAIL;

  intrs = DisableIntrs ();
  dbprintf ('s', "SemSignal: Process %d Signalling on sem %d, count=%d.\n", GetCurrentPid(), (int)(sem-sems), sem->count);
  // Increment internal counter before checking value
  sem->count++;
  if (sem->count > 0) { // check if there is a process to wake up
    if (!AQueueEmpty(&sem->waiting)) { // there is a process to wake up
      l = AQueueFirst(&sem->waiting);
      pcb = (PCB *)AQueueObject(l);
      if (AQueueRemove(&l) != QUEUE_SUCCESS) { 
        printf("FATAL ERROR: could not remove link from semaphore queue in SemSignal!\n");
        exitsim();
      }
      dbprintf ('s', "SemSignal: Waking up PID %d.\n", (int)(GetPidFromAddress(pcb)));
      ProcessWakeup (pcb);
      // Decrement counter on behalf of woken up PCB
      sem->count--;
    }
  }
  RestoreIntrs (intrs);
  return SYNC_SUCCESS;
}
Exemplo n.º 9
0
void MboxModuleInit() {
	int i;
	int j;
	for(i = 0; i < MBOX_NUM_MBOXES; i++) {
		for(j = 0; j < PROCESS_MAX_PROCS; j++) {
			mboxes[i].opened_pids[j] = false;
		}

		for(j = 0; j < MBOX_MAX_BUFFERS_PER_MBOX; j++) {
			mboxes[i].cbobi[j] = -1; // invalid
		}

		mboxes[i].opened_pids_count = 0;
		mboxes[i].head_cbobi = 0;
		mboxes[i].tail_cbobi = 0;
		mboxes[i].inuse = false;
		mboxes[i].mbox_id = i;
	}
	for(i = 0; i < MBOX_NUM_BUFFERS; i++) {
		mbox_buffers[i].inuse = false;		
	}
	// if ((s_buff_emptyslots = SemCreate(MBOX_NUM_BUFFERS - 1)) == SYNC_FAIL) {
	// 	printf("Bad sem_create in MboxModInit");
	// 	exitsim();
	// }
	if((l_buff = LockCreate()) == SYNC_FAIL) {
		printf("Bad lock_create in MboxModInit");
		exitsim();
	}
}
Exemplo n.º 10
0
//-------------------------------------------------------
// 
// void MboxOpen(mbox_t);
//
// Open the mailbox for use by the current process.  Note
// that it is assumed that the internal lock/mutex handle 
// of the mailbox and the inuse flag will not be changed 
// during execution.  This allows us to get the a valid 
// lock handle without a need for synchronization.
//
// Returns MBOX_FAIL on failure.
// Returns MBOX_SUCCESS on success.
//
//-------------------------------------------------------
int MboxOpen(mbox_t handle) {

  unsigned int curr_pid = GetCurrentPid();

  // Check if handle is a valid number
  if(handle < 0 || handle >= MBOX_NUM_MBOXES){
    return MBOX_FAIL;
  }

  // Check if the mbox is reserved (activated)
  if(system_mbox[handle].num_of_pid_inuse < 0){
    return MBOX_FAIL;
  }

  // Acquire the lock
  if(LockHandleAcquire(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
    exitsim();
  }

  // Update the number of pid used
  if(system_mbox[handle].mbox_pid_list[curr_pid] == 1){
    printf("The mbox %d has already been opened\n", handle);
  }
  else if(system_mbox[handle].mbox_pid_list[curr_pid] == 0){
    system_mbox[handle].num_of_pid_inuse += 1;
    system_mbox[handle].mbox_pid_list[curr_pid] = 1;
  }
  else{
    printf("FATAL ERROR: Unkown Pid %d for mbox %d!\n", curr_pid, handle);
    // Release the lock
    if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
      exitsim();
    }
    return MBOX_FAIL;
  }
  
  // Release the lock
  if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
    exitsim();
  }


  return MBOX_SUCCESS;
}
Exemplo n.º 11
0
static void TrapProcessCreateHandler(uint32 *trapArgs, int sysmode)
{
  char allargs[SIZE_ARG_BUFF];
  char name[100];
  int i=0, j=0, k=0;
  uint32 args[MAX_ARGS];
  char *destination;
  // The first argument is the name of the executable file

  i=0;
  for(i=0;i<100; i++)
    allargs[i] = 0;
  i=0;
  if(!sysmode)
  {
    //Get the arguments into the sytem space
    MemoryCopyUserToSystem (currentPCB, trapArgs, args, sizeof (args));
    do {
      MemoryCopyUserToSystem (currentPCB,((char*)args[0])+i,name+i,1);
      i++;
    } while ((i < sizeof (name)) && (name[i-1] != '\0'));
  } else {
    bcopy (trapArgs, args, sizeof (args));
    dstrncpy ((char *)args[0], name, sizeof (name));
  }
  name[sizeof(name)-1] = '\0';	// null terminate the name
  i=0;
  if(!sysmode)
  {
    //Copy the rest of the arguments to the system space
    for(j=0; (j<11)&&(args[j]!=0); j++)
    {
      k=0;
      do 
      {
        MemoryCopyUserToSystem (currentPCB,((char*)args[j])+k,allargs+i,1);
        i++; k++;
      } while ((i<sizeof(allargs)) && (allargs[i-1]!='\0'));
    }
  }
  else 
  {
    destination = &allargs[0];
    for(j=0; (j<11)&&(args[j]!=0); j++)
    {
      k = dstrlen((char *)args[j]);  //length of the argument
      if(&destination[k]-allargs>100)
      {
        printf("Fatal: Cumulative length of all arguments > 100\n");
	exitsim();
      }
      dstrcpy(destination, (char *)args[j]);
      destination[k] = '\0';
    }
  }
  allargs[sizeof(allargs)-1] = '\0';	// null terminate the name

  ProcessFork(0, (uint32)allargs, name, 1);
}
Exemplo n.º 12
0
//-------------------------------------------------------
// 
// void MboxOpen(mbox_t);
//
// Open the mailbox for use by the current process.  Note
// that it is assumed that the internal lock/mutex handle 
// of the mailbox and the inuse flag will not be changed 
// during execution.  This allows us to get the a valid 
// lock handle without a need for synchronization.
//
// Returns MBOX_FAIL on failure.
// Returns MBOX_SUCCESS on success.
//
//-------------------------------------------------------
int MboxOpen(mbox_t handle) {
    Link *l;

    if(!&mboxs[handle]) return MBOX_FAIL;

    if ((l = AQueueAllocLink ((void *)GetCurrentPid())) == NULL) {
        printf("FATAL ERROR: could not allocate link for pid queue in Mbox Open!\n");
        exitsim();
    }

    if (AQueueInsertLast (&mboxs[handle].pids, l) != QUEUE_SUCCESS) {
        printf("FATAL ERROR: could not insert new link into pid queue in Mbox Open!\n");
        exitsim();
    }

    return MBOX_SUCCESS;
}
Exemplo n.º 13
0
int CondInit(Cond *c) {
  if (!c) return SYNC_FAIL;
  if (AQueueInit (&c->waiting) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not initialize lock waiting queue in CondInit!\n");
    exitsim();
  }
  return SYNC_SUCCESS;
}
Exemplo n.º 14
0
//----------------------------------------------------------------------
//
//	ProcessDestroy
//
//	Destroy a process by setting its status to zombie and putting it
//	on the zombie queue.  The next time the scheduler is called, this
//	process will be marked as free.  We can't necessarily do it now
//	because we might be the currently running process.
//
//	NOTE: This must only be called from an interrupt or trap.  However,
//	it need not be followed immediately by a ProcessSchedule() because
//	the process can continue running.
//
//----------------------------------------------------------------------
void ProcessDestroy (PCB *pcb) {
  dbprintf('p', "Entering ProcessDestroy for 0x%x.\n", (int)pcb);
  ProcessSetStatus (pcb, PROCESS_STATUS_ZOMBIE);
  if (AQueueRemove(&(pcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from queue in ProcessDestroy!\n");
    exitsim();
  }
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get link for zombie PCB in ProcessDestroy!\n");
    exitsim();
  }
  if (AQueueInsertFirst(&zombieQueue, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    exitsim();
  }
  dbprintf('p', "Leaving ProcessDestroy for 0x%x.\n", (int)pcb);
}
Exemplo n.º 15
0
//----------------------------------------------------------------------
//
//	ProcessFreeResources
//
//	Free the resources associated with a process.  This assumes the
//	process isn't currently on any queue.
//
//----------------------------------------------------------------------
void ProcessFreeResources (PCB *pcb) {
  int i = 0;
  uint32 page;

  // Allocate a new link for this pcb on the freepcbs queue
  if ((pcb->l = AQueueAllocLink(pcb)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessFreeResources!\n");
    exitsim();
  }
  // Set the pcb's status to available
  pcb->flags = PROCESS_STATUS_FREE;
  // Insert the link into the freepcbs queue
  if (AQueueInsertLast(&freepcbs, pcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert PCB link into freepcbs queue in ProcessFreeResources!\n");
    exitsim();
  }

  //------------------------------------------------------------
  // STUDENT: Free any memory resources on process death here.
  //------------------------------------------------------------

  /////////////////////////////////////////////////////////////
  // TODO CHANGE FOR 2 LEVEL Free Resource
  // JSM - free all physical pages corresponding to valid page table entries in process
  // AS WEL AS FREEING SYSTEM STACK PAGE ASSOCIATED WITH PROCESS
  for (i = 0; i < MEM_L1_PAGE_TABLE_SIZE; i++)
  {
  	if(pcb->pagetable[i] & MEM_PTE_VALID) // For every page currently valid in page table
  	{
  		pcb->pagetable[i] &= ~(MEM_PTE_VALID);  // Invalidate page table entry
  		page = (pcb->pagetable[i]) / MEM_PAGE_SIZE;
  		dbprintf ('p', "Preparing to free physical page #%d\n", page);
  		MemoryFreePage(page); // Free page in freemap
  	}
  }
	dbprintf ('p', "Preparing to free physical page #%d (System Stack)\n", (pcb->sysStackArea / MEM_PAGE_SIZE) );
	MemoryFreePage(pcb->sysStackArea / MEM_PAGE_SIZE); // Free page in freemap

  /////////////////////////////////////////////////////////////

  dbprintf ('p', "Free Resources DONE!\n\n");
  //while(1);

  ProcessSetStatus (pcb, PROCESS_STATUS_FREE);
}
Exemplo n.º 16
0
//---------------------------------------------------------------------
//
//	SemInit
//
//	Initialize a semaphore to a particular value.  This just means
//	initting the process queue and setting the counter.
//
//----------------------------------------------------------------------
int SemInit (Sem *sem, int count) {
  if (!sem) return SYNC_FAIL;
  if (AQueueInit (&sem->waiting) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not initialize semaphore waiting queue in SemInit!\n");
    exitsim();
  }
  sem->count = count;
  return SYNC_SUCCESS;
}
Exemplo n.º 17
0
int LockInit(Lock *l) {
  if (!l) return SYNC_FAIL;
  if (AQueueInit (&l->waiting) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not initialize lock waiting queue in LockInit!\n");
    exitsim();
  }
  l->pid = -1;
  return SYNC_SUCCESS;
}
Exemplo n.º 18
0
//----------------------------------------------------------------------
//
//	ProcessWakeup
//
//	Wake up a process from its slumber.  This only involves putting
//	it on the run queue; it's not guaranteed to be the next one to
//	run.
//
//	NOTE: This must only be called from an interrupt or trap.  It
//	need not be followed immediately by ProcessSchedule() because
//	the currently running process is unaffected.
//
//----------------------------------------------------------------------
void ProcessWakeup (PCB *wakeup) {
  dbprintf ('p',"Waking up PID %d.\n", (int)(wakeup - pcbs));
  // Make sure it's not yet a runnable process.
  ASSERT (wakeup->flags & PROCESS_STATUS_WAITING, "Trying to wake up a non-sleeping process!\n");
  ProcessSetStatus (wakeup, PROCESS_STATUS_RUNNABLE);
  if (AQueueRemove(&(wakeup->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove wakeup PCB from waitQueue in ProcessWakeup!\n");
    exitsim();
  }
  if ((wakeup->l = AQueueAllocLink(wakeup)) == NULL) {
    printf("FATAL ERROR: could not get link for wakeup PCB in ProcessWakeup!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, wakeup->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessWakeup!\n");
    exitsim();
  }
}
Exemplo n.º 19
0
//----------------------------------------------------------------------
//
//	ProcessModuleInit
//
//	Initialize the process module.  This involves initializing all
//	of the process control blocks to appropriate values (ie, free
//	and available).  We also need to initialize all of the queues.
//
//----------------------------------------------------------------------
void ProcessModuleInit () {
  int		i,j;

  dbprintf ('p', "Entering ProcessModuleInit\n");
  AQueueInit (&freepcbs);
  AQueueInit (&runQueue);
  AQueueInit (&waitQueue);
  AQueueInit (&zombieQueue);
  // For each PCB slot in the global pcbs array:
  for (i = 0; i < PROCESS_MAX_PROCS; i++) {
    dbprintf ('p', "Initializing PCB %d @ 0x%x.\n", i, (int)&(pcbs[i]));
    // First, set the internal PCB link pointer to a newly allocated link
    if ((pcbs[i].l = AQueueAllocLink(&pcbs[i])) == NULL) {
      printf("FATAL ERROR: could not allocate link in ProcessModuleInit!\n");
      exitsim();
    }
    // Next, set the pcb to be available
    pcbs[i].flags = PROCESS_STATUS_FREE;

    //-------------------------------------------------------
    // STUDENT: Initialize the PCB's page table here.
    //-------------------------------------------------------
    
    ////////////////////////////////////
    // TODO3 CHANGE FOR 2 LEVEL DONE
    // JSM, Set all entries of every page table to 0 (Invalid) since no pages have been allocated for any process
    // and no level 2 page tables have been allocated for any processes
    for (j = 0; j < MEM_L1_PAGE_TABLE_SIZE; j++)
    {
    	pcbs[i].pagetable[j] = 0x00000000;
    }
    
    ///////////////////////////////////

    // Finally, insert the link into the queue
    if (AQueueInsertFirst(&freepcbs, pcbs[i].l) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not insert PCB link into queue in ProcessModuleInit!\n");
      exitsim();
    }
  }
  // There are no processes running at this point, so currentPCB=NULL
  currentPCB = NULL;
  dbprintf ('p', "Leaving ProcessModuleInit\n");
}
Exemplo n.º 20
0
//----------------------------------------------------------------------
//
//	ProcessSuspend
//
//	Place a process in suspended animation until it's
//	awakened by ProcessAwaken.
//
//	NOTE: This must only be called from an interrupt or trap.  It
//	should be immediately followed by ProcessSchedule().
//
//----------------------------------------------------------------------
void ProcessSuspend (PCB *suspend) {
  // Make sure it's already a runnable process.
  dbprintf ('p', "Suspending PCB 0x%x (%s).\n", (int)suspend, suspend->name);
  ASSERT (suspend->flags & PROCESS_STATUS_RUNNABLE, "Trying to suspend a non-running process!\n");
  ProcessSetStatus (suspend, PROCESS_STATUS_WAITING);
  ClkResetProcess();
  if (AQueueRemove(&(suspend->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove process from run Queue in ProcessSuspend!\n");
    exitsim();
  }
  if ((suspend->l = AQueueAllocLink(suspend)) == NULL) {
    printf("FATAL ERROR: could not get Queue Link in ProcessSuspend!\n");
    exitsim();
  }
  if (AQueueInsertLast(&waitQueue, suspend->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert suspend PCB into waitQueue!\n");
    exitsim();
  }
}
Exemplo n.º 21
0
//-------------------------------------------------------
//
// mbox_t MboxCreate();
//
// Allocate an available mailbox structure for use. 
//
// Returns the mailbox handle on success
// Returns MBOX_FAIL on error.
//
//-------------------------------------------------------
mbox_t MboxCreate() {
    mbox_t mbox;
    uint32 intrval;

    //grabbing a mailbox should be an atomic operation
    intrval = DisableIntrs();
    for(mbox=0; mbox<MBOX_NUM_MBOXES; mbox++){
        if(mboxs[mbox].inuse == 0){
            mboxs[mbox].inuse = 1;
            break;
        }
    }
    RestoreIntrs(intrval);

    if((mboxs[mbox].l = LockCreate()) == SYNC_FAIL){
        printf("FATAL ERROR: Could not create lock for mbox\n");
        exitsim();
    }

    if((mboxs[mbox].s_msg_full = SemCreate(0)) == SYNC_FAIL) {
        printf("Bad sem create in mbox create\n ");
        exitsim();
    }

    if((mboxs[mbox].s_msg_empty = SemCreate(MBOX_MAX_BUFFERS_PER_MBOX)) == SYNC_FAIL) {
        printf("Bad sem create in mbox create\n ");
        exitsim();
    }

    if(mbox == MBOX_NUM_MBOXES) return MBOX_FAIL;

    if(AQueueInit(&mboxs[mbox].messages) != QUEUE_SUCCESS){
        printf("FATAL ERROR: Could not initialize mbox messsage queue\n");
        exitsim();
    }

    if(AQueueInit(&mboxs[mbox].pids) != QUEUE_SUCCESS){
        printf("FATAL ERROR: Could not initialize mbox pid queue\n");
        exitsim();
    }

    return mbox;
}
Exemplo n.º 22
0
int AQueueModuleInit() {
  int i;
  if (AQueueInit(&freeLinks) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not initialize freeLinks queue in AQueueModuleInit!\n");
    exitsim();
  }
  dbprintf ('q', "Initializing %d links.\n", QUEUE_MAX_LINKS);
  for (i = 0; i < QUEUE_MAX_LINKS; i++) {
    // Initialize link structure
    linkpool[i].next = NULL;
    linkpool[i].prev = NULL;
    linkpool[i].object = NULL;
    // Add link to freeLinks queue
    if (AQueueInsertLast(&freeLinks, &(linkpool[i])) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not insert link into freeLinks in AQueueModuleInit!\n"); // Adds structure to global queue of free links
      exitsim();
    }
  }
  return QUEUE_SUCCESS;
}
Exemplo n.º 23
0
//---------------------------------------------------------------------------
//	LockHandleAcquire
//
//	This routine acquires a lock given its handle. The handle must be a 
//	valid handle for this routine to succeed. In that case this routine 
//	returns SYNC_FAIL. Otherwise the routine returns SYNC_SUCCESS.
//
//	Your implementation should be such that if a process that already owns
//	the lock calls LockHandleAcquire for that lock, it should not block.
//---------------------------------------------------------------------------
int LockAcquire(Lock *k) {
  Link	*l;
  int		intrval;
    
  if (!k) return SYNC_FAIL;

  // Locks are atomic
  intrval = DisableIntrs ();
  dbprintf ('I', "LockAcquire: Old interrupt value was 0x%x.\n", intrval);

  // Check to see if the current process owns the lock
  if (k->pid == GetCurrentPid()) {
    dbprintf('s', "LockAcquire: Proc %d already owns lock %d\n", GetCurrentPid(), (int)(k-locks));
    RestoreIntrs(intrval);
    return SYNC_SUCCESS;
  }

  dbprintf ('s', "LockAcquire: Proc %d asking for lock %d.\n", GetCurrentPid(), (int)(k-locks));
  if (k->pid >= 0) { // Lock is already in use by another process
    dbprintf('s', "LockAcquire: putting process %d to sleep\n", GetCurrentPid());
    if ((l = AQueueAllocLink ((void *)currentPCB)) == NULL) {
      printf("FATAL ERROR: could not allocate link for lock queue in LockAcquire!\n");
      exitsim();
    }
    if (AQueueInsertLast (&k->waiting, l) != QUEUE_SUCCESS) {
      printf("FATAL ERROR: could not insert new link into lock waiting queue in LockAcquire!\n");
      exitsim();
    }
    ProcessSleep();
  } else {
    dbprintf('s', "LockAcquire: lock is available, assigning to proc %d\n", GetCurrentPid());
    k->pid = GetCurrentPid();
  }
  RestoreIntrs(intrval);
  return SYNC_SUCCESS;
}
//----------------------------------------------------------------------
//
//	ProcessSchedule
//
//	Schedule the next process to run.  If there are no processes to
//	run, exit.  This means that there should be an idle loop process
//	if you want to allow the system to "run" when there's no real
//	work to be done.
//
//	NOTE: the scheduler should only be called from a trap or interrupt
//	handler.  This way, interrupts are disabled.  Also, it must be
//	called consistently, and because it might be called from an interrupt
//	handler (the timer interrupt), it must ALWAYS be called from a trap
//	or interrupt handler.
//
//	Note that this procedure doesn't actually START the next process.
//	It only changes the currentPCB and other variables so the next
//	return from interrupt will restore a different context from that
//	which was saved.
//
//----------------------------------------------------------------------
void
ProcessSchedule ()
{
  PCB		*pcb;
  int		i;

  dbprintf ('p', "Now entering ProcessSchedule (cur=0x%x, %d ready)\n",
	    currentPCB, QueueLength (&runQueue));
  // The OS exits if there's no runnable process.  This is a feature, not a
  // bug.  An easy solution to allowing no runnable "user" processes is to
  // have an "idle" process that's simply an infinite loop.
  if (QueueEmpty (&runQueue)) {
    printf ("No runnable processes - exiting!\n");
    exitsim ();	// NEVER RETURNS
  }

// Move the front of the queue to the end, if it is the running process.

  pcb = (PCB *)((QueueFirst (&runQueue))->object);
  if (pcb == currentPCB)
  {
    QueueRemove (&pcb->l);
    QueueInsertLast (&runQueue, &pcb->l);
  }

  // Now, run the one at the head of the queue.
  pcb = (PCB *)((QueueFirst (&runQueue))->object);
  currentPCB = pcb;
  dbprintf ('p',"About to switch to PCB 0x%x,flags=0x%x @ 0x%x\n",
	    pcb, pcb->flags,
	    pcb->sysStackPtr[PROCESS_STACK_IAR]);

  // Clean up zombie processes here.  This is done at interrupt time
  // because it can't be done while the process might still be running
  while (!QueueEmpty (&zombieQueue)) {
    pcb = (PCB *)(QueueFirst (&zombieQueue)->object);
    dbprintf ('p', "Freeing zombie PCB 0x%x.\n", pcb);
    QueueRemove (&pcb->l);
    ProcessFreeResources (pcb);
  }
  // Set the timer so this process gets at most a fixed quantum of time.
  TimerSet (processQuantum);
  dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", currentPCB);
}
Exemplo n.º 25
0
//-------------------------------------------------------
//
// int MboxRecv(mbox_t handle, int maxlength, void* message);
//
// Receive a message from the specified mailbox.  The call 
// blocks when there is no message in the buffer.  Maxlength
// should indicate the maximum number of bytes that can be
// copied from the buffer into the address of "message".  
// An error occurs if the message is larger than maxlength.
// Note that the calling process must have opened the mailbox 
// via MboxOpen.
//   
// Returns MBOX_FAIL on failure.
// Returns number of bytes written into message on success.
//
//-------------------------------------------------------
int MboxRecv(mbox_t handle, int maxlength, void* message) {
	int ibuff;
	int cpid = GetCurrentPid();
	int i;
	mbox* xbox = &mboxes[handle];
	char* cmessage = (char*) message;

	if(xbox->opened_pids[cpid] == false) {
		return MBOX_FAIL;
	}
	// printf("***%d Waiting on mbox filled slot\n", cpid);
	SemHandleWait(xbox->s_mbox_fillslots);
	// printf("******%d Done waiting on mbox filled slot\n", cpid);
	// printf("=%d is waiting on mbox lock\n", cpid);
	while(LockHandleAcquire(xbox->l_mbox) != SYNC_SUCCESS);
	// printf("==%d has acquired mbox lock\n", cpid);
	ibuff = xbox->cbobi[xbox->head_cbobi];
	if(ibuff < 0) {
		printf("Invalid message buffer index from cbobi.head: %d\n", xbox->head_cbobi);
		exitsim();
	}
	if(mbox_buffers[ibuff].inuse == false) {
		LockHandleRelease(xbox->l_mbox);
		return MBOX_FAIL;
	}
	if(mbox_buffers[ibuff].length > maxlength) {
		LockHandleRelease(xbox->l_mbox);
		return MBOX_FAIL;
	}

	for(i = 0; i < mbox_buffers[ibuff].length; i++) {
		cmessage[i] = mbox_buffers[ibuff].msg[i];
	}
	xbox->cbobi[xbox->head_cbobi] = -1; // invalidate the cbobi
	mbox_buffers[ibuff].inuse = false;
	xbox->head_cbobi = (xbox->head_cbobi + 1) % MBOX_MAX_BUFFERS_PER_MBOX;
	// SemHandleSignal(s_buff_emptyslots);
	SemHandleSignal(xbox->s_mbox_emptyslots);
	LockHandleRelease(xbox->l_mbox);
	// printf("===%d has released mbox lock\n", cpid);

	return mbox_buffers[ibuff].length;
}
Exemplo n.º 26
0
//--------------------------------------------------------------------------------
// 
// int MboxCloseAllByPid(int pid);
//
// Scans through all mailboxes and removes this pid from their "open procs" list.
// If this was the only open process, then it makes the mailbox available.  Call
// this function in ProcessFreeResources in process.c.
//
// Returns MBOX_FAIL on failure.
// Returns MBOX_SUCCESS on success.
//
//--------------------------------------------------------------------------------
int MboxCloseAllByPid(int pid) {

  int ct;
  int clear_ct;
  int mbox_pid_status;

  // Check if the pid is valid
  if(pid < 0 || pid >= PROCESS_MAX_PROCS){
    return MBOX_FAIL;
  }

  // Go througth all the mboxes
  for(ct = 0; ct < MBOX_NUM_MBOXES; ct++){
    // Acquire the lock of the mbox
    if(LockHandleAcquire(system_mbox[ct].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Acquire lock for the mbox %d!\n", ct);
      exitsim();
    }
  
    // Check if the pid is in the mbox's "open procs" list. 
    // If so, remove the pid and make the mailbox available if no other proc opens the mbox
    // Else, do nothing
    mbox_pid_status = system_mbox[ct].mbox_pid_list[pid];

    if(mbox_pid_status == 0){
      // Do nothing
    }
    else if(mbox_pid_status == 1){
      // Update the number of pid used
      system_mbox[ct].num_of_pid_inuse -= 1;
      system_mbox[ct].mbox_pid_list[pid] = 0;
    }
    else{
      printf("FATAL ERROR: Unkown Pid %d for mbox %d\n", pid, ct);
      // Release the lock
      if(LockHandleRelease(system_mbox[ct].mbox_buffer_lock) != SYNC_SUCCESS){
	printf("FATAL ERROR: Release lock for the mbox %d!\n", ct);
	exitsim();
      }
      return MBOX_FAIL;
    }

    // Return the mbox to the pool of available mboxes for the system
    // Reset this mbox, clear rest of messages in this mbox (clear the linkings in the system)
    if(system_mbox[ct].num_of_pid_inuse == 0){
      system_mbox[ct].num_of_pid_inuse = -1;
      for(clear_ct = 0; clear_ct < system_mbox[ct].mbox_buffer_slot_used; clear_ct++){
	// Make the system buffer slot available again
	system_mbox_message.system_buffer_index_array[system_mbox[ct].mbox_buffer_tail] = 0;
	system_mbox_message.system_buffer_slot_used -= 1;
	system_mbox[ct].mbox_buffer_tail = (system_mbox[ct].mbox_buffer_tail + 1) % MBOX_MAX_BUFFERS_PER_MBOX;
    }
    }

    // Release the lock of the mbox
    if(LockHandleRelease(system_mbox[ct].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Release lock for the mbox %d!\n", ct);
      exitsim();
    }

  }

  return MBOX_SUCCESS;
}
Exemplo n.º 27
0
//-------------------------------------------------------
//
// int MboxRecv(mbox_t handle, int maxlength, void* message);
//
// Receive a message from the specified mailbox.  The call 
// blocks when there is no message in the buffer.  Maxlength
// should indicate the maximum number of bytes that can be
// copied from the buffer into the address of "message".  
// An error occurs if the message is larger than maxlength.
// Note that the calling process must have opened the mailbox 
// via MboxOpen.
//   
// Returns MBOX_FAIL on failure.
// Returns number of bytes written into message on success.
//
//-------------------------------------------------------
int MboxRecv(mbox_t handle, int maxlength, void* message) {

  int ct;
  unsigned int curr_pid = GetCurrentPid();
  int system_buffer_index = system_mbox[handle].mbox_buffer_index_array[system_mbox[handle].mbox_buffer_tail];
  
  // Check if the length of the message can fit into the buffer slot
  if(maxlength < 0 || maxlength >  MBOX_MAX_MESSAGE_LENGTH){
    return MBOX_FAIL;
  }
  
  // Check if handle is a valid number
  if(handle < 0 || handle >= MBOX_NUM_MBOXES){
    return MBOX_FAIL;
  }
  
  // Check if the mbox is reserved (activated). If not, return FAIL
  if(system_mbox[handle].num_of_pid_inuse < 0){
    return MBOX_FAIL;
  }

  // Check if the mbox is opened. If the mbox is not opened, return FAIL
  if(system_mbox[handle].mbox_pid_list[curr_pid] == 0){
    printf("Mbox Send Error: The mbox %d hasn't been opened yet\n", handle);
    return MBOX_FAIL;
  }


  // Acquire the lock of the mbox
  if(LockHandleAcquire(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
    exitsim();
  }
  
  
  // Else, check if the mbox is empty. If so, wait
  while(system_mbox[handle].mbox_buffer_slot_used == 0){
    if(CondHandleWait(system_mbox[handle].mbox_buffer_fill) != SYNC_SUCCESS){
      printf("FATAL ERROR: Wait on CV empty for mbox %d!\n", handle);
      exitsim();
    }
  }
  
  // Acquire the lock of the mbox message buffer
  if(LockHandleAcquire(system_mbox_message.system_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
    exitsim();
  }

  // Receive the message from the mbox
  for(ct = 0; ct < maxlength; ct++){
    *((char *) message + ct) = system_mbox_message.system_message_buffer[system_buffer_index][ct];
  }

  // Make the system buffer slot available again
  system_mbox_message.system_buffer_index_array[system_mbox[handle].mbox_buffer_tail] = 0;
  system_mbox_message.system_buffer_slot_used -= 1;

  // Update mbox used and mbox buffer tail info
  system_mbox[handle].mbox_buffer_slot_used -= 1;
  system_mbox[handle].mbox_buffer_tail = (system_mbox[handle].mbox_buffer_tail + 1) % MBOX_MAX_BUFFERS_PER_MBOX;


  // Signal system buffer empty CV
  if(CondHandleSignal(system_mbox_message.system_buffer_empty) != SYNC_SUCCESS){
    printf("FATAL ERROR: Signal on CV empty for system buffer!\n");
    exitsim();
  }


  // Release the lock of the mbox message buffer
  if(LockHandleRelease(system_mbox_message.system_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the system buffer!\n");
    exitsim();
  }

  // Signal mbox empty CV
  if(CondHandleSignal(system_mbox[handle].mbox_buffer_empty) != SYNC_SUCCESS){
    printf("FATAL ERROR: Signal on CV empty for mbox %d!\n", handle);
    exitsim();
  }

  
  // Release the lock of the mbox
  if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
    exitsim();
  }



  return MBOX_SUCCESS;
}
Exemplo n.º 28
0
//-------------------------------------------------------
//
// int MboxSend(mbox_t handle,int length, void* message);
//
// Send a message (pointed to by "message") of length
// "length" bytes to the specified mailbox.  Messages of
// length 0 are allowed.  The call 
// blocks when there is not enough space in the mailbox.
// Messages cannot be longer than MBOX_MAX_MESSAGE_LENGTH.
// Note that the calling process must have opened the 
// mailbox via MboxOpen.
//
// Returns MBOX_FAIL on failure.
// Returns MBOX_SUCCESS on success.
//
//-------------------------------------------------------
int MboxSend(mbox_t handle, int length, void* message) {

  int ct;
  int system_buffer_index;
  unsigned int curr_pid = GetCurrentPid();

  // Check if the length of the message can fit into the buffer slot
  if(length < 0 || length >  MBOX_MAX_MESSAGE_LENGTH){
    return MBOX_FAIL;
  }

  // Check if handle is a valid number
  if(handle < 0 || handle >= MBOX_NUM_MBOXES){
    return MBOX_FAIL;
  }
  
  // Check if the mbox is reserved (activated)
  if(system_mbox[handle].num_of_pid_inuse < 0){
    return MBOX_FAIL;
  }

  // Check if the mbox is opened
  if(system_mbox[handle].mbox_pid_list[curr_pid] == 0){
    printf("Mbox Send Error: The mbox %d hasn't been opened yet\n", handle);
    return MBOX_FAIL;
  }
  
  // Acquire the lock of the mbox
  if(LockHandleAcquire(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
    exitsim();
  }
  
  // Else, check if the mbox is full. If so, wait
  while(system_mbox[handle].mbox_buffer_slot_used == MBOX_MAX_BUFFERS_PER_MBOX){
    if(CondHandleWait(system_mbox[handle].mbox_buffer_empty) != SYNC_SUCCESS){
      printf("FATAL ERROR: Wait on CV empty for mbox %d!\n", handle);
      exitsim();
    }
  }

  // Acquire the lock of the mbox message buffer
  if(LockHandleAcquire(system_mbox_message.system_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the system buffer!\n");
    exitsim();
  }

  // Check if the system buffer is full. If so, wait 
  while(system_mbox_message.system_buffer_slot_used == MBOX_NUM_BUFFERS){
    // First Release the lock of the mbox
    if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
      exitsim();
    }

    // Wait on the system CV
    if(CondHandleWait(system_mbox_message.system_buffer_empty) != SYNC_SUCCESS){
      printf("FATAL ERROR: Wait on CV empty for system buffer!\n");
      exitsim();
    }

    // Re-Acquire the lock of the mbox
    if(LockHandleAcquire(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
      exitsim();
    }
  }

  // Find out an available slot in the system message buffer for the message
  for(system_buffer_index = 0; system_buffer_index < MBOX_NUM_BUFFERS; system_buffer_index++){
    if(system_mbox_message.system_buffer_index_array[system_buffer_index] == 0){
      system_mbox_message.system_buffer_index_array[system_buffer_index] = 1; // Reserved the slot
      break;
    }
  }
  
  // Double check if the index is valid
  if(system_buffer_index == MBOX_NUM_BUFFERS){
    printf("FATAL ERROR: System buffer sync error\n");
    exitsim();
  }


  // Put the message into the system message slot 
  for(ct = 0; ct < length; ct++){
    system_mbox_message.system_message_buffer[system_buffer_index][ct] = *((char *) message + ct);
  }

  // Set the mbox linking
  system_mbox[handle].mbox_buffer_index_array[system_mbox[handle].mbox_buffer_head] = system_buffer_index;
  
  // Update head and used info
  system_mbox_message.system_buffer_slot_used += 1;

  system_mbox[handle].mbox_buffer_slot_used += 1;
  system_mbox[handle].mbox_buffer_head = (system_mbox[handle].mbox_buffer_head + 1) % MBOX_MAX_BUFFERS_PER_MBOX;


  // Release the lock of the mbox message buffer
  if(LockHandleRelease(system_mbox_message.system_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the system buffer %d!\n", handle);
    exitsim();
  }

  
  // Signal mbox fill CV
  if(CondHandleSignal(system_mbox[handle].mbox_buffer_fill) != SYNC_SUCCESS){
    printf("FATAL ERROR: Signal on CV fill for mbox %d!\n", handle);
    exitsim();
  }
  
  // Release the lock of the mbox
  if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
    exitsim();
  }


  return MBOX_SUCCESS;
}
Exemplo n.º 29
0
//-------------------------------------------------------
//
// int MboxClose(mbox_t);
//
// Close the mailbox for use to the current process.
// If the number of processes using the given mailbox
// is zero, then disable the mailbox structure and
// return it to the set of available mboxes.
//
// Returns MBOX_FAIL on failure.
// Returns MBOX_SUCCESS on success.
//
//-------------------------------------------------------
int MboxClose(mbox_t handle) {

  int clear_ct;
  unsigned int curr_pid = GetCurrentPid();
  int mbox_pid_status = system_mbox[handle].mbox_pid_list[curr_pid];

  // Check if handle is a valid number
  if(handle < 0 || handle >= MBOX_NUM_MBOXES){
    return MBOX_FAIL;
  }
  
  // Check if the mbox is reserved (activated)
  if(system_mbox[handle].num_of_pid_inuse < 0){
    return MBOX_FAIL;
  }

  // Acquire the lock
  if(LockHandleAcquire(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Acquire lock for the mbox %d!\n", handle);
    exitsim();
  }


  if(mbox_pid_status == 0){
    printf("The mbox %d has already been closed for process %d\n", handle, curr_pid);
  }
  else if(mbox_pid_status == 1){
    // Update the number of pid used
    system_mbox[handle].num_of_pid_inuse -= 1;
    system_mbox[handle].mbox_pid_list[curr_pid] = 0;
  }
  else{
    printf("FATAL ERROR: Unkown Pid %d for mbox %d\n", curr_pid, handle);
    // Release the lock
    if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
      printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
      exitsim();
    }
    return MBOX_FAIL;
  }
  
  // Return the mbox to the pool of available mboxes for the system
  // Reset this mbox, clear rest of messages in this mbox (clear the linkings in the system)
  if(system_mbox[handle].num_of_pid_inuse == 0){
    system_mbox[handle].num_of_pid_inuse = -1;

    for(clear_ct = 0; clear_ct < system_mbox[handle].mbox_buffer_slot_used; clear_ct++){
      // Make the system buffer slot available again
      system_mbox_message.system_buffer_index_array[system_mbox[handle].mbox_buffer_tail] = 0;
      system_mbox_message.system_buffer_slot_used -= 1;
      system_mbox[handle].mbox_buffer_tail = (system_mbox[handle].mbox_buffer_tail + 1) % MBOX_MAX_BUFFERS_PER_MBOX;
    }

  }


  // Release the lock
  if(LockHandleRelease(system_mbox[handle].mbox_buffer_lock) != SYNC_SUCCESS){
    printf("FATAL ERROR: Release lock for the mbox %d!\n", handle);
    exitsim();
  }

  return MBOX_SUCCESS;
}
Exemplo n.º 30
0
//--------------------------------------------------------------------
//
// int process_create(char *exec_name, ...);
//
// Here we support reading command-line arguments.  Maximum MAX_ARGS 
// command-line arguments are allowed.  Also the total length of the 
// arguments including the terminating '\0' should be less than or 
// equal to SIZE_ARG_BUFF.
//
//--------------------------------------------------------------------
static void TrapProcessCreateHandler(uint32 *trapArgs, int sysmode) {
  char allargs[SIZE_ARG_BUFF];  // Stores full string of arguments (unparsed)
  char name[PROCESS_MAX_NAME_LENGTH]; // Local copy of name of executable (100 chars or less)
  char *username=NULL;          // Pointer to user-space address of exec_name string
  int i=0, j=0;                 // Loop index variables
  char *args[MAX_ARGS];         // All parsed arguments (char *'s)
  int allargs_position = 0;     // Index into current "position" in allargs
  char *userarg = NULL;         // Current pointer to user argument string
  int numargs = 0;              // Number of arguments passed on command line

  dbprintf('p', "TrapProcessCreateHandler: function started\n");
  // Initialize allargs string to all NULL's for safety
  for(i=0;i<SIZE_ARG_BUFF; i++) {
    allargs[i] = '\0';
  }

  // First deal with user-space addresses
  if(!sysmode) {
    dbprintf('p', "TrapProcessCreateHandler: creating user process\n");
    // Get the known arguments into the kernel space.
    // Argument 0: user-space pointer to name of executable
    MemoryCopyUserToSystem (currentPCB, (char *)(trapArgs+0), (char *)&username, sizeof(char *));

    // Copy the user-space string at user-address "username" into kernel space
    for(i=0; i<PROCESS_MAX_NAME_LENGTH; i++) {
      MemoryCopyUserToSystem(currentPCB, (char *)(username+i), (char *)&(name[i]), sizeof(char));
      // Check for end of user-space string
      if (name[i] == '\0') break;
    }
    dbprintf('p', "TrapProcessCreateHandler: just parsed executable name (%s) from trapArgs\n", name);
    if (i == PROCESS_MAX_NAME_LENGTH) {
      printf("TrapProcessCreateHandler: length of executable filename longer than allowed!\n");
      exitsim();
    }

    // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0])
    allargs_position = 0;
    dstrcpy(&(allargs[allargs_position]), name);
    allargs_position += dstrlen(name) + 1; // The "+1" is so we're pointing just beyond the NULL

    // Rest of arguments: a series of char *'s until we hit NULL or MAX_ARGS
    for(i=0; i<MAX_ARGS; i++) {
      // First, must copy the char * itself into kernel space in order to read its value
      MemoryCopyUserToSystem(currentPCB, (char *)(trapArgs+1+i), (char *)&userarg, sizeof(char *));
      // If this is a NULL in the set of char *'s, this is the end of the list
      if (userarg == NULL) break;
      // Store a pointer to the kernel-space location where we're copying the string
      args[i] = &(allargs[allargs_position]);
      // Copy the string into the allargs, starting where we left off last time through this loop
      for (j=0; j<SIZE_ARG_BUFF; j++) {
        MemoryCopyUserToSystem(currentPCB, (char *)(userarg+j), (char *)&(allargs[allargs_position]), sizeof(char));
        // Move current character in allargs to next spot
        allargs_position++;
        // Check that total length of arguments is still ok
        if (allargs_position == SIZE_ARG_BUFF) {
          printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n");
          exitsim();
        }
        // Check for end of user-space string
        if (allargs[allargs_position-1] == '\0') break;
      }
    }
    if (i == MAX_ARGS) {
      printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n");
      exitsim();
    }
    numargs = i+1;
    // Arguments are now setup
  } else {
    // Addresses are already in kernel space, so just copy into our local variables 
    // for simplicity
    // Argument 0: (char *) name of program
    dstrncpy(name, (char *)(trapArgs[0]), PROCESS_MAX_NAME_LENGTH);
    // Copy the program name into "allargs", since it has to be the first argument (i.e. argv[0])
    allargs_position = 0;
    dstrcpy(&(allargs[allargs_position]), name);
    allargs_position += dstrlen(name) + 1;  // The "+1" is so that we are now pointing just beyond the "null" in the name
    allargs_position = 0;
    for (i=0; i<MAX_ARGS; i++) {
      userarg = (char *)(trapArgs[i+1]);
      if (userarg == NULL) break; // found last argument
      // Store the address of where we're copying the string
      args[i] = &(allargs[allargs_position]);
      // Copy string into allargs
      for(j=0; j<SIZE_ARG_BUFF; j++) {
        allargs[allargs_position] = userarg[j];
        allargs_position++;
        if (allargs_position == SIZE_ARG_BUFF) {
          printf("TrapProcessCreateHandler: strlen(all arguments) > maximum length allowed!\n");
          exitsim();
        }
        // Check for end of user-space string
        if (allargs[allargs_position-1] == '\0') break;
      }
    }
    if (i == MAX_ARGS) {
      printf("TrapProcessCreateHandler: too many arguments on command line (did you forget to pass a NULL?)\n");
      exitsim();
    }
    numargs = i+1;
  }

  ProcessFork(0, (uint32)allargs, name, 1);
}