//------------------------------------------------------- // // 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; }
//--------------------------------------------------------------------------- // 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; }
//---------------------------------------------------------------------- // // 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; }
//---------------------------------------------------------------------- // // 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"); }
//---------------------------------------------------------------------- // // 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); }
//--------------------------------------------------------------------------- // 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; }
//--------------------------------------------------------------------------- // 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; }
//---------------------------------------------------------------------- // // 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; }
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(); } }
//------------------------------------------------------- // // 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; }
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); }
//------------------------------------------------------- // // 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; }
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; }
//---------------------------------------------------------------------- // // 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); }
//---------------------------------------------------------------------- // // 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); }
//--------------------------------------------------------------------- // // 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; }
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; }
//---------------------------------------------------------------------- // // 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(); } }
//---------------------------------------------------------------------- // // 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"); }
//---------------------------------------------------------------------- // // 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(); } }
//------------------------------------------------------- // // 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; }
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; }
//--------------------------------------------------------------------------- // 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); }
//------------------------------------------------------- // // 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; }
//-------------------------------------------------------------------------------- // // 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; }
//------------------------------------------------------- // // 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; }
//------------------------------------------------------- // // 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; }
//------------------------------------------------------- // // 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; }
//-------------------------------------------------------------------- // // 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); }