예제 #1
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;
}
예제 #2
0
// this is used for testing fork
void ProcessForkTestPrints(PCB* pcb) {
  int i;
  uint32 pte;
  int page;
  printf("++ Printing valid PTEs of PID: %d\n", GetPidFromAddress(pcb));
  for(i = 0; i < MEM_PAGE_TBL_SIZE; i++) {
    pte = pcb->pagetable[i];
    page = MEM_ADDRESS_TO_PAGE(pte & MEM_PTE_MASK);
    if(pte & MEM_PTE_VALID) {
      printf("pagetable[%d=0x%x]=>0x%x ppage=%d\n", i, i*MEM_PAGESIZE, pcb->pagetable[i], page);
    }
  }
  printf("== Done printing valid PTEs of PID: %d\n\n", GetPidFromAddress(pcb));
}
예제 #3
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;
}
예제 #4
0
//--------------------------------------------------------------------------
// ProcessKill destroys the current process and then calls ProcessSchedule.
// Therefore, you can only call ProcessKill from inside of a trap.
//--------------------------------------------------------------------------
void ProcessKill(PCB* pcb) {
  dbprintf('m', "ProcessKill: killing processid %d\n", GetPidFromAddress(pcb));
  ProcessDestroy(pcb);
  ProcessSchedule();
}
예제 #5
0
int ProcessRealFork (PCB* ppcb) {
  PCB *cpcb;                // Holds pcb while we build it for this process.
  int intrs;               // Stores previous interrupt settings.
  int newPage;
  int i;
  uint32 *stackframe;


  intrs = DisableIntrs ();
  dbprintf ('I', "Old interrupt value was 0x%x.\n", intrs);
  dbprintf ('p', "Entering ProcessRealFork ppcb=%d\n", GetPidFromAddress(ppcb));
  // Get a free PCB for the new process
  if (AQueueEmpty(&freepcbs)) {
    printf ("FATAL error: no free processes!\n");
    exitsim (); // NEVER RETURNS!
  }
  cpcb = (PCB *)AQueueObject(AQueueFirst (&freepcbs));
  dbprintf ('p', "Got a link @ 0x%x\n", (int)(cpcb->l));
  if (AQueueRemove (&(cpcb->l)) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not remove link from freepcbsQueue in ProcessFork!\n");
    exitsim();
  }
  // This prevents someone else from grabbing this process
  ProcessSetStatus (cpcb, PROCESS_STATUS_RUNNABLE);
  
  // cpcb shares code and global data with ppcb
  for(i = 0; i < 4; i++) {
    ppcb->pagetable[i] |= MEM_PTE_READONLY;
    MemorySharePage(ppcb->pagetable[i]);
  }
  // user stack is also shared at first
  ppcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)] |= MEM_PTE_READONLY; 
  MemorySharePage(ppcb->pagetable[MEM_ADDRESS_TO_PAGE(MEM_MAX_VIRTUAL_ADDRESS)]);

  // copy parent pcb to child pcb
  bcopy((char *)ppcb, (char *)cpcb, sizeof(PCB));
  // At this point, the PCB is allocated and nobody else can get it.
  // However, it's not in the run queue, so it won't be run.  Thus, we
  // can turn on interrupts here.
  RestoreIntrs (intrs);

  // for system stack
  newPage = MemoryAllocPage ();
  if(newPage == MEM_FAIL) {
    printf ("FATAL: couldn't allocate system stack - no free pages!\n");
    ProcessFreeResources (cpcb);
    return PROCESS_FORK_FAIL;
  }
  cpcb->sysStackArea = newPage * MEM_PAGESIZE;
  // copy system stack from ppcb to cpcb
  bcopy((char *)(ppcb->sysStackArea), (char *)(cpcb->sysStackArea), MEM_PAGESIZE);
  dbprintf('p', "ProcessRealFork: SystemStack page=%d sysstackarea=0x%x\n", newPage, cpcb->sysStackArea);
  // printf("ProcessRealFork: parent_sysstackarea=0x%x child_sysstackarea=0x%x\n", ppcb->sysStackArea, cpcb->sysStackArea);

  //----------------------------------------------------------------------
  // Stacks grow down from the top.  The current system stack pointer has
  // to be set to the bottom of the interrupt stack frame, which is at the
  // high end (address-wise) of the system stack.
  stackframe = (uint32 *)(cpcb->sysStackArea + MEM_PAGESIZE - 4);

  // Now that the stack frame points at the bottom of the system stack memory area, we need to
  // move it up (decrement it) by one stack frame size because we're about to fill in the
  // initial stack frame that will be loaded for this PCB when it gets switched in by
  // ProcessSchedule the first time.
  stackframe -= PROCESS_STACK_FRAME_SIZE;

  // The system stack pointer is set to the base of the current interrupt stack frame.
  cpcb->sysStackPtr = stackframe;
  // The current stack frame pointer is set to the same thing.
  cpcb->currentSavedFrame = stackframe;

  dbprintf ('p', "Setting up PCB @ 0x%x (sys stack=0x%x, mem=0x%x, size=0x%x)\n",
    (int)cpcb, cpcb->sysStackArea, cpcb->pagetable[0], cpcb->npages * MEM_PAGESIZE);

  //----------------------------------------------------------------------
  // STUDENT: setup the PTBASE, PTBITS, and PTSIZE here on the current
  // stack frame.
  //----------------------------------------------------------------------
  // Set the base of the level 1 page table.  If there's only one page
  // table level, this is it.  For 2-level page tables, put the address
  // of the level 1 page table here.  For 2-level page tables, we'll also
  // have to build up the necessary tables....
  stackframe[PROCESS_STACK_PTBASE] = (uint32)(&(cpcb->pagetable[0]));

  // Place the PCB onto the run queue.
  intrs = DisableIntrs ();
  if ((cpcb->l = AQueueAllocLink(cpcb)) == NULL) {
    printf("FATAL ERROR: could not get link for forked PCB in ProcessFork!\n");
    exitsim();
  }
  if (AQueueInsertLast(&runQueue, cpcb->l) != QUEUE_SUCCESS) {
    printf("FATAL ERROR: could not insert link into runQueue in ProcessFork!\n");
    exitsim();
  }
  RestoreIntrs (intrs);
  ProcessSetResult(cpcb, 0);
  ProcessSetResult(ppcb, GetPidFromAddress(cpcb));
  
  // TEST PRINTS
  printf("\nIn ProcessRealFork:\n");
  printf("----- Page table of parent process PID:%d -----\n", GetPidFromAddress(ppcb));
  ProcessForkTestPrints(ppcb);
  printf("\n----- Page table of child process PID: %d -----\n", GetPidFromAddress(cpcb));
  ProcessForkTestPrints(cpcb);

  dbprintf ('p', "Leaving ProcessRealFork cpcbid=%d\n", GetPidFromAddress(cpcb));
  return PROCESS_FORK_SUCCESS;
}
예제 #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;
}