Exemple #1
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;

  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);
}
Exemple #2
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 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;
}
Exemple #4
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 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;


}
Exemple #5
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 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;
}