Exemplo n.º 1
0
void k_printf(char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	char *p, *sval;
	int ival;
	static char s[80];
	for(p = fmt; *p; p++){
	    if(*p != '%'){
	    	k_putchar(*p);
	        continue;   
	    }
	    switch(*++p){
	        case 'd':
	            ival = va_arg(ap, int);
	            itoa(s, ival, 10);
	            k_puts(s);
	            break;
	        case 'x':
	            ival = va_arg(ap, int);
	            itoa(s, ival, 16);
	            k_puts(s);
	            break;
	        case 'c':
	            ival = va_arg(ap, int);          
	            k_putchar(ival);
	            break;
	        case 's':
	            for(sval = va_arg(ap, char*); *sval; sval++){
	                k_putchar(*sval);
	            }
	            break;
	        default:
	            k_putchar(*p);
	        break;
	    }
	}
	va_end(ap);
	return;
}
Exemplo n.º 2
0
void ksched_scheduler(addr_t             stp,
		      dcb_ro_t 	        *cur_dcb,
		      context_t 	*cur_ctxt )
{
    kernel_st   *st = (kernel_st *)stp;
    SDom_t	*cur_sdom;              /* Current sdom		*/
    Time_ns 	 time;			/* Current time? 		*/
    Time_ns	 itime;			/* Time on interval timer	*/
    Time_ns	 newtime;		/* What to set the itimer to	*/
    Time_ns      ranfor;	        /* How long the domain ran      */
    dcb_ro_t	*dcb;			/* tmp. domain control block	*/
    dcb_rw_t	*dcbrw;
    SDom_t	*sdom;			/* tmp. scheduling domain	*/
    bool_t       blocking;	        /* does the domain wish to block? */
    Activation_Reason   reason;
    

    /* Increment the heartbeat counter in the PIP.  This allows 
       benchmark code, etc. to see how many passes through the scheduler 
       happened as a result of certain tests - useful for spotting bugs! */
    INFO_PAGE.sheartbeat++;

    /* Squash timer and read the time */
    time = Timer$Clear(st->t, &itime);

    /* Give the Measure boys a change to do their stuff */
    MEASURE(ac_measure(st, time)); 

    /* If we were spinning in the idle loop, there is no current
     * domain to deschedule. */
    if (cur_dcb == NULL) {
	goto deschedule_done;
    }

    /*****************************
     * 
     * Deschedule the current scheduling domain
     *
     ****************************/
    
    dcbrw = DCB_RO2RW(cur_dcb);

#ifndef __IX86__
    /* We enable activations here for an RFABlock to avoid trashing
       the actctx on the way into the scheduler.  Turn on activations
       and then treat just like a block */
    if (cur_dcb->schst == DCBST_K_RFABLOCK) {
	dcbrw->mode = 0;
	cur_dcb->schst = DCBST_K_BLOCK;
    }
#endif    

#if defined(INTEL) || defined(__ARM__)
    /* Send any delayed events */
    while(cur_dcb->outevs_processed < dcbrw->outevs_pushed) {
	word_t next_event = cur_dcb->outevs_processed + 1;
	dcb_event *ev = &dcbrw->outevs[next_event % NUM_DCB_EVENTS];
#ifdef INTEL
	k_dsc_send(ev->ep, ev->val);
#else
	k_sc_send(ev->ep, ev->val);
#endif
	cur_dcb->outevs_processed++;
    }
#endif

    /* Record the time the domain was preempted and for how long it
       ran.  Work out if the domain is going to be blocked to save
       some pointless queue shuffling */
    cur_sdom = st->cur_sdom;
    cur_sdom->lastdsch = time;
    ranfor = (time - cur_sdom->lastschd);
    blocking = (cur_dcb->schst == DCBST_K_BLOCK) && EP_FIFO_EMPTY (dcbrw);

    if ((cur_sdom->state == sdom_run) ||
	(cur_sdom->state == sdom_unblocked)) {

	/* In this block, we are doing accounting for an sdom which has 
	   been running in contracted time.  Note that this could now happen
	   even if the domain is on the wait queue (i.e. if it blocked) */

	/* Deduct guaranteed time from the domain */
	cur_sdom->remain  -= ranfor;
	cur_sdom->ac_time += ranfor;
	MEASURE(cur_sdom->ac_m_tm += ranfor); 

	/* If guaranteed time has run out... */
	if (!blocking && (cur_sdom->remain <= 0)) {
	    /* Move domain to correct position in WAIT queue */
            /* XXX sdom_unblocked doesn't need this since it is 
	     already in the correct place. */
	    dequeue(st, cur_sdom);
	    cur_sdom->state = sdom_wait;
	    requeue(st, cur_sdom);
	} 

    } else {
      
	/*
	 * In this block, the sdom was running optimistically - so no
	 * accounting is necessary. The sdom is not the head of the 
	 * run queue, but st->next_optm gives its position 
	 * in the wait queue 
	 */
	cur_sdom->ac_x += ranfor;
	MEASURE(cur_sdom->ac_m_tm += ranfor);
    }

    /******************
     * 
     * If the domain wishes to block, then block it.
     *
     * We only block a domain if it has no events in the fifo - this 
     * is to avoid the "wake-up-waiting" race 
     *
     *******************/
    if (blocking) { 
	/* Remove the domain from whichever queue and block it */
	dequeue(st, cur_sdom);
	block(st, cur_sdom);
    }
    
  deschedule_done:
    
    /*****************************
     * 
     * We have now successfully descheduled the current sdom.
     * The next task is the allocate CPU time to any sdom it is due to.
     *
     ****************************/
    cur_dcb =  (dcb_ro_t *)0;
    cur_sdom = (SDom_t *)0;
    
    /*****************************
     * 
     * Allocate CPU to any waiting domains who have passed their
     * period deadline.  If necessary, move them to run queue.
     *
     ****************************/
    while(PQ_SIZE(st->wait) && 
	  (sdom = PQ_HEAD(st->wait))->deadline <= time ) {
	
	/* Remove from HEAD of wait queue */
	PQ_REMOVE(st->wait);

	/* Domain begins a new period and receives a slice of CPU 
	 * If this domain has been blocking then throw away the
	 * rest of it's remain - it can't be trusted */
	if (sdom->remain > 0) 
	    sdom->remain = sdom->slice;
    	else 
	    sdom->remain += sdom->slice;
	sdom->prevddln = sdom->deadline;
	sdom->deadline += sdom->period;
	sdom->state = (sdom->remain > 0) ? sdom_run : sdom_wait;

	/* Place on the appropriate queue */
	requeue(st, sdom);

	/* Update the accounts */
	endofperiod(sdom, time);
    }
    
    /*****************************
     * 
     * Next we must handle all domains to which new events have been
     * delivered.  These domains will have been placed in a fifo by
     * the event send code.
     *
     ****************************/
    
    while (st->domq.tail != st->domq.head)  {
	/* Let the event delivery mechanism know we've seen this one. */
	st->domq.tail = (st->domq.tail + 1) % CFG_UNBLOCK_QUEUE_SIZE;
	dcb   = st->domq.q[st->domq.tail];
	sdom  = dcb->sdomptr;

	/*
	 * Do not reschedule stopped or dying domains.
	 * They are not on ANY queue, but other domains may still
	 * send them events.
	 */
	if (dcb->schst == DCBST_K_STOPPED ||
	    dcb->schst == DCBST_K_DYING) continue;

	/* Unblock the domain if necessary */
	if(sdom->state == sdom_block) {

	    /* Remove from the MIDDLE of the blocked queue */
	    dequeue(st, sdom);

	    /* Unblock and move to the appropriate queue */
	    unblock(st, sdom, time);
	    requeue(st, sdom);
	}
    }
    
    /*****************************
     * 
     * Next we must handle all domains whose block timeouts have expired.
     * Currently we treat a timeout as though an event had arrived.  
     *
     ****************************/
    
    /* Wake up any blocked domains whose timeout has expired */
    while(PQ_SIZE(st->blocked) && 
	  (sdom = PQ_HEAD(st->blocked))->deadline <= time ) {
	
	/* Remove from HEAD of blocked queue */
	PQ_REMOVE(st->blocked);
	
	/* Unblock and move to the appropriate queue */
	unblock(st, sdom, time);
	requeue(st, sdom);
    }
    
    /*****************************
     * 
     * Next we need to pick an sdom to run.
     * If anything is actually 'runnable', we run that. 
     * If nothing is, we pick a waiting sdom to run optimistically.
     * If there aren't even any of those, we have to spin waiting for an
     * event or a suitable time condition to happen.
     *
     ****************************/
    
    newtime = FOREVER;
    reason = 0;

    /* If we have an sdom on the RUN queue, then run it. */
    if (PQ_SIZE(st->run)) {
	
	cur_sdom = PQ_HEAD(st->run);
	cur_dcb = cur_sdom->dcb;
	newtime = time + cur_sdom->remain;
	reason  = (cur_sdom->prevddln > cur_sdom->lastschd) ?
	    Activation_Reason_Allocated : Activation_Reason_Preempted;
	
    } else if (PQ_SIZE(st->wait)) {

	int i;

	/* Try running a domain on the WAIT queue - this part of the
	   scheduler isn't particularly efficient but then again, we
	   don't have any guaranteed domains to worry about. */
	
	/* See if there are any unblocked domains on the WAIT
	   queue who we can give preferential treatment to. */
	for (i = 1; i <= PQ_SIZE(st->wait); i++) {
	    sdom = PQ_NTH(st->wait, i);
	    if (sdom->state == sdom_unblocked) {
		cur_sdom = sdom;
		cur_dcb  = sdom->dcb;
		newtime  = time + sdom->remain;
		reason   = Activation_Reason_Preempted;
		goto found;
	    }
	}

	/* Last chance: pick a domain on the wait queue with the XTRA
	   flag set.  The NEXT_OPTM field is used to cheaply achieve
	   an approximation of round-robin order */
	for (i = 0; i < PQ_SIZE(st->wait); i++) {
	    /* Pick (roughly) the next domain on the wait q. */
	    if (++(st->next_optm) > PQ_SIZE(st->wait)) 
		st->next_optm = 1;
	    
	    sdom = PQ_NTH(st->wait, st->next_optm);
	    if (sdom->xtratime) {	
		cur_sdom = sdom;
		cur_dcb  = sdom->dcb;
		newtime = time + BESTEFFORT_QUANTUM;
		reason  = Activation_Reason_Extra;
		goto found;
	    }
	}

    }
    
    found:

    /**********************
     * 
     * We now have to work out the time when we next need to
     * make a scheduling decision.  We set the alarm timer
     * to cause an interrupt at that time.
     *
     **********************/
     
    /* If we might be able to run a waiting domain before this one has */
    /* exhausted its time, cut short the time allocation */
    if (PQ_SIZE(st->wait))
	newtime = MIN(newtime, PQ_HEAD(st->wait)->deadline);
    
    /* If necessary reenter the scheduler to wake up blocked domains */ 
    if (PQ_SIZE(st->blocked))
	newtime = MIN(newtime, PQ_HEAD(st->blocked)->deadline);

    MEASURE(newtime = MIN(newtime, ac_next));

    /* Set timer for newtime */
    Timer$Set(st->t, newtime);  
    
    MEASURE_TRACE(Trace$Add(st->trace, cur_dcb ? cur_dcb->id : 0, time));

    if (cur_dcb) {

	MTRC(k_putchar('0' + (cur_dcb->id & 7)));

	/* New state */
	st->cur_dcb  = cur_dcb;
	st->cur_sdom = cur_sdom;
	st->cur_sdom->lastschd = time;
	cur_dcb->schst = DCBST_K_RUN;
	
	/* Switch to the new protection domain */
	k_swppdom (cur_dcb);

	/* Activate the chosen domain */
	k_activate (cur_dcb, reason);
	
    } else {

	MTRC(k_putchar('.'));
	MTRC(k_putchar('0' + PQ_SIZE(st->run)));
	MTRC(k_putchar('0' + PQ_SIZE(st->wait)));
	MTRC(k_putchar('0' + PQ_SIZE(st->blocked)));

	st->cur_dcb = NULL; /* tested by ksched.S */

	/* Enable interrupts and spin */
	k_idle();
    }
    
}