//---------------------------------------------------------------------- // // 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; dbprintf ('p', "Now entering ProcessSchedule (cur=0x%x, %d ready)\n", (int)currentPCB, AQueueLength (&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 (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); } GracefulExit(); } printf ("No runnable processes - exiting!\n"); GracefulExit (); // NEVER RETURNS } // Move the front of the queue to the end. The running process was the one in front. 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"); GracefulExit(); } ProcessFreeResources(pcb); } dbprintf ('p', "Leaving ProcessSchedule (cur=0x%x)\n", (int)currentPCB); }
//------------------------------------------------------- // // 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 i; int length; Link *l; if(!&mboxs[handle]) return MBOX_FAIL; if(!AQueueEmpty(&mboxs[handle].pids)){ length = AQueueLength(&mboxs[handle].pids); l = AQueueFirst(&mboxs[handle].pids); for(i=0; i < length; i++){ if((int)AQueueObject(l) == GetCurrentPid()){ AQueueRemove(&l); break; } l = AQueueNext(l); } } if(AQueueEmpty(&mboxs[handle].pids)){ while(!AQueueEmpty(&mboxs[handle].messages)){ l = AQueueFirst(&mboxs[handle].messages); AQueueRemove(&l); } mboxs[handle].inuse = 0; } return MBOX_SUCCESS; }
//////////////////////////////////////////////////////////////////// // Moves link "l" to the position after link "after" in queue "q" //////////////////////////////////////////////////////////////////// int AQueueMoveAfter(Queue *q, Link *after, Link *l) { if (!q) return QUEUE_FAIL; if (!l) return QUEUE_FAIL; if (l->queue != q) return QUEUE_FAIL; // l does not belong to q // If after is NULL, then l is the last item on the queue, // so we don't have to do anything if (!after) { if (AQueueLength(q) != 1) return QUEUE_FAIL; if (AQueueFirst(q) != AQueueLast(q)) return QUEUE_FAIL; return QUEUE_SUCCESS; } if (after->queue != q) return QUEUE_FAIL; if (after == l) { // don't have to do anything return QUEUE_SUCCESS; } // First fix Queue first/last pointers if (q->last == l) return QUEUE_FAIL; // this would be strange if it happened if (q->first == l) q->first = l->next; if (q->last == after) q->last = l; // Now remove l from it's original position in the list if (l->next) l->next->prev = l->prev; if (l->prev) l->prev->next = l->next; // Now update l's prev and next pointers to put l into the list after the link "after" l->prev = after; l->next = after->next; // Now fix the list around l after->next = l; if (l->next) l->next->prev = l; return QUEUE_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 i; int qlen; Link *l; int exists = 0; mbox_message *m; //check if mailbox is real if(!&mboxs[handle]) return MBOX_FAIL; //check if pid opened this mailbox if(!AQueueEmpty(&mboxs[handle].pids ) ){ qlen = AQueueLength(&mboxs[handle].pids); l = AQueueFirst(&mboxs[handle].pids); for(i=0; i < qlen; i++){ if((int)AQueueObject(l) == GetCurrentPid()){ exists = 1; break; } l = AQueueNext(l); } //actualy checks if pid exists if(exists == 0){ return MBOX_FAIL; } //wait until queue has something in it if(SemHandleWait(mboxs[handle].s_msg_full) == SYNC_FAIL){ printf("bad sem handle wait in mbox recv\n"); exitsim(); } //lock if(LockHandleAcquire(mboxs[handle].l) != SYNC_SUCCESS){ printf("FATAL ERROR: could not get lock in Mbox send!\n"); exitsim(); } l = AQueueFirst(&mboxs[handle].messages); m = (mbox_message *) l->object; //check if message longer than max length if(m->length > maxlength) { return MBOX_FAIL; } //copy message to local variable dstrncpy(message,(void*) m->message, m->length); //reset structure for use elsewhere m->inuse =0; //delete link AQueueRemove(&l); //unlock if(LockHandleRelease(mboxs[handle].l) != SYNC_SUCCESS){ printf("FATAL ERROR: could not release lock in Mbox send!\n"); exitsim(); } if(SemHandleSignal(mboxs[handle].s_msg_empty) == SYNC_FAIL){ printf("bad sem handle signal in mbox recv\n"); exitsim(); } }else{ return MBOX_FAIL; } 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 i; int qlen; Link *l; int exists = 0; //check if mailbox is real if(!&mboxs[handle]) return MBOX_FAIL; //check if pid opened this mailbox if(!AQueueEmpty(&mboxs[handle].pids ) ){ qlen = AQueueLength(&mboxs[handle].pids); l = AQueueFirst(&mboxs[handle].pids); for(i=0; i < qlen; i++){ if((int)AQueueObject(l) == GetCurrentPid()){ exists = 1; break; } l = AQueueNext(l); } //actuall checks if pid exists if(exists == 0){ return MBOX_FAIL; } //check if message longer than max length if(length > MBOX_MAX_MESSAGE_LENGTH) { return MBOX_FAIL; } //check for space in mailbox if((SemHandleWait(mboxs[handle].s_msg_empty)) == SYNC_FAIL ){ printf("bad sem handle wait in mbox send\n"); exitsim(); } //lock if(LockHandleAcquire(mboxs[handle].l) != SYNC_SUCCESS){ printf("FATAL ERROR: could not get lock in Mbox send!\n"); exitsim(); } for(i=0; i<MBOX_NUM_BUFFERS; i++){ if(mbox_messages[i].inuse == 0){ mbox_messages[i].inuse = 1; break; } } //creating mbox_message structure dstrncpy(mbox_messages[i].message, (char *) message, length); mbox_messages[i].length = length; if ((l = AQueueAllocLink(&mbox_messages[i])) == NULL) { printf("FATAL ERROR: could not allocate link for pid queue in Mbox Open!\n"); exitsim(); } //add message to end of queue AQueueInsertLast(&mboxs[handle].messages, l); //unlock if(LockHandleRelease(mboxs[handle].l) != SYNC_SUCCESS){ printf("FATAL ERROR: could not release lock in Mbox send!\n"); exitsim(); } if(SemHandleSignal(mboxs[handle].s_msg_full) == SYNC_FAIL){ printf("bad sem handle signal in mbox send\n"); exitsim(); } }else{ return MBOX_FAIL; } return MBOX_SUCCESS; }
// Returns true is the queue is empty, false otherwise int AQueueEmpty (Queue *q) { return (AQueueLength (q) == 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 intrs; int wasFull = 0, buffersSaturated = 0; mbox_message * user_mesg; Link *l; if(MailBox[handle].inuse == false) { printf("Currently passed mailbox handle : %d by calling process : %d is unallocated\n", handle, GetCurrentPid()); return MBOX_FAIL; } if(MailBox[handle].procs_link[GetCurrentPid()] == false) { printf("Mailbox : %d not already opened by calling proces :%d\n", handle, GetCurrentPid()); return MBOX_FAIL; } intrs = DisableIntrs(); LockHandleAcquire(MailBox[handle].lock); while(AQueueLength(&MailBox[handle].buffers) == 0) { //printf("Waiting for mailbox to have more messages\n"); CondHandleWait(MailBox[handle].moreData); } //printf("Received mailbox lock by calling process : %d with mailbox buffer count : %d\n", GetCurrentPid(), AQueueLength(&MailBox[handle].buffers)); if(AQueueLength(&MailBox[handle].buffers) == MBOX_MAX_BUFFERS_PER_MBOX) wasFull = 1; if(AQueueLength(&MailBox[handle].buffers) < MBOX_MAX_BUFFERS_PER_MBOX && used_buffers == MBOX_NUM_BUFFERS) buffersSaturated = 1; //printf("Obtained message in receiver : %d from buffer index : %d\n", user_mesg->size, (user_mesg - Messg_Buffers)); if((user_mesg = (mbox_message *)AQueueObject(MailBox[handle].buffers.first)) == NULL) { printf("Undefined/unallocated Link pointer obtained from mailbox queue with handle :%d in process : %d\n", handle, GetCurrentPid()); //printf("MailBox buffer size : %d\n", AQueueLength(&MailBox[handle].buffers)); return MBOX_FAIL; } if(maxlength < user_mesg->size) { printf("Message : %s requested by user process : %d larger than acceptable message length : %d (Messge length received : %d)\n", user_mesg->message, GetCurrentPid(), maxlength, user_mesg->size); return MBOX_FAIL; } bcopy(user_mesg->message, message, user_mesg->size); l = MailBox[handle].buffers.first; MailBox[handle].buffers.first = AQueueNext(MailBox[handle].buffers.first); if(AQueueRemove(&l) == QUEUE_FAIL) { printf("FATAL Error : Message object Link for buffer : %d received by process : %d could not be removed from queue of mailbox handle : %d",used_buffers, GetCurrentPid(), handle); exitsim(); } used_buffers--; //if(wasFull || buffersSaturated) CondHandleSignal(MailBox[handle].moreSpace); LockHandleRelease(MailBox[handle].lock); RestoreIntrs(intrs); return user_mesg; }
//------------------------------------------------------- // // 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 intrs; int wasEmpty = 0; Link * mbuffer_link; if(MailBox[handle].inuse == 0) { printf("Currently passed mailbox handle : %d by calling process : %d is unallocated\n", handle, GetCurrentPid()); return MBOX_FAIL; } if(MailBox[handle].procs_link[GetCurrentPid()] == false) { printf("Mailbox : %d not already opened by calling proces :%d\n", handle, GetCurrentPid()); return MBOX_FAIL; } intrs = DisableIntrs(); LockHandleAcquire(MailBox[handle].lock); while(AQueueLength(&MailBox[handle].buffers) == MBOX_MAX_BUFFERS_PER_MBOX || used_buffers == MBOX_NUM_BUFFERS) { CondHandleWait(MailBox[handle].moreSpace); } //printf("Buffer size of queue before inserting messager by : %d is : %d\n", GetCurrentPid(), AQueueLength(&MailBox[handle].buffers)); if(AQueueLength(&MailBox[handle].buffers) == 0) wasEmpty = 1; if(AQueueLength(&MailBox[handle].buffers) != MBOX_MAX_BUFFERS_PER_MBOX) { if(length > MBOX_MAX_MESSAGE_LENGTH) { printf("Messge passed by user process : %d larger than accepted message length (Messge length sent - %d)", GetCurrentPid(), length); return MBOX_FAIL; } bcopy(message, Messg_Buffers[used_buffers++].message, 8); Messg_Buffers[used_buffers - 1].size = length; //printf("Original Message : %s Copied : %s in : %d\n", (char *)message, (char *)(Messg_Buffers[used_buffers - 1].message), handle); if((mbuffer_link = AQueueAllocLink(&Messg_Buffers[used_buffers - 1])) == QUEUE_FAIL) { printf("FATAL Error : Link object could not be created for message buffer : %d in process : %d",used_buffers - 1, GetCurrentPid()); exitsim(); } if(AQueueInsertLast(&MailBox[handle].buffers, mbuffer_link) != QUEUE_SUCCESS) { printf("FATAL Error : Link object could not be created for message buffer : %d in process : %d",used_buffers - 1, GetCurrentPid()); exitsim(); } } //printf("Message inserted by process : %d using buffer : %d with current count : %d\n", GetCurrentPid(), buffer_no, AQueueLength(&MailBox[handle].buffers)); //if(wasEmpty) CondHandleSignal(MailBox[handle].moreData); LockHandleRelease(MailBox[handle].lock); RestoreIntrs(intrs); return MBOX_SUCCESS; }