コード例 #1
0
ファイル: threads.c プロジェクト: Sudoka/Measure
int thread_init (void) {
    char  our_thread[4]="Tao";
    printk(KERN_INFO "in init\n");

    unsigned long t1;
    unsigned long t2;
    int i;
    int max;
    max = 20000;

    for (i = 0; i < max; i++)
    {
	t1 = get_tsc();
	thread1 = kthread_create(thread_fn,NULL,our_thread);
	t2 = get_tsc();
	//printk(KERN_INFO, "TAO:kthread_create_time=%ld\n", t2 - t1);
	printk("TAO:%d:kthread_create_time=%ld\n", i,(t2 - t1));
    }
    if((thread1))
    {
	printk(KERN_INFO "helloworld\n");
	wake_up_process(thread1);
    }

    return 0;
}
コード例 #2
0
ファイル: process.c プロジェクト: Sudoka/Measure
int main()
{
    int i;
    unsigned long t1, t2;

    i = 0;
    pid_t pid;

    pid = fork();
    if (pid)
    {
	t1 = get_tsc();
	//sched_yield();
	//give up in parent. Child has its time pieces
	waitpid(pid);
	printf("%ld",t1);
	sleep(0.01);
	return 0;
    }
    else
    {
	t2 = get_tsc();
	printf("%ld\n",t2);
	return 0;
    }
}
コード例 #3
0
ファイル: mem_read.c プロジェクト: Sudoka/Measure
int main(int arvc, char* argv[])
{
	int num1,num2;
	sscanf (argv[1],"%d",&num1);
	sscanf (argv[2],"%d",&num2);
	unsigned long t1;
	unsigned long t2;
	unsigned long long sum;
	sum = 1;
	double diff;

//str is in byte, while size is in kb

	//int stride = num1/4;//stride = 4mb
	int stride = num1;
	int n;
	for (n = 0;n<TIMES;n++)
	{
	        //int size = (pow(2,num2)/4)*pow(2,10);//8kb
		int size = (pow(2,num2))*pow(2,10);//8kb
	        int i;
	        //int a[array_size];
	        long* a = malloc(size); 
		long* b = a;
		//printf("%d\n",sizeof(long*));
		//printf("%d\n",sizeof(long));
	    
	        for(i = 0;i< (size / 8);i++)
	        {
		    
		    //a[i] = (i+stride)%size * 4 + &a[i];
		    //a[i] = (int)(&(a[i]) + (stride % size));
		    //a[i] = (long)(a);
		    //a[i] = (long)(&a[i] + stride % size);
		    a[i] = (long)(&a[(i + stride / 8) % (size / 8)]);
                	//	a[i] = 2;
	        } 
	        int index =0;
		int j = 0;
		t1 = get_tsc();
		for(j = 0;j<REPETITION;j++)
		{
		    b = *b;
		}
		t2 = get_tsc();
		if (sum == 1)
		{
		    sum = 0;
		}else{
		    sum += diff_tsc(t1, t2);
		    //printf("%f\n", 1.0 *  diff_tsc(t1, t2) / REPETITION);
		}
		free(a);
	}
	diff = 1.0 * sum / TIMES / REPETITION;
	printf("%f\n",diff);
}
コード例 #4
0
/* vizualizes the traversal cost of a pixel */
Vec3fa renderPixelCycles(float x, float y, const Vec3fa& vx, const Vec3fa& vy, const Vec3fa& vz, const Vec3fa& p)
{
  /* initialize ray */
  RTCRay ray;
  ray.org = p;
  ray.dir = normalize(x*vx + y*vy + vz);
  ray.tnear = 0.0f;
  ray.tfar = inf;
  ray.geomID = RTC_INVALID_GEOMETRY_ID;
  ray.primID = RTC_INVALID_GEOMETRY_ID;
  ray.mask = -1;
  ray.time = g_debug;

  /* intersect ray with scene */
  int64_t c0 = get_tsc();
  rtcIntersect(g_scene,ray);
  int64_t c1 = get_tsc();
  /* shade pixel */
  return Vec3fa((float)(c1-c0)*scale,0.0f,0.0f);
}
コード例 #5
0
int main(int argc, char** argv) {
	int i;						/* iterator for the loop */
	int rv;						/* return value */
	struct sched_param sp = { PRIORITY };		/* sched priority */

	uint64_t main_start;				/* when did the program start to run */

	uint64_t loop_start;
	uint64_t loop_end;
	uint64_t loop_elapsed;

	uint64_t foo;

	printf ("sched_setscheduler(): %d\n", sched_setscheduler (0, SCHED_FIFO, &sp));

	rv = mlockall (MCL_CURRENT | MCL_FUTURE);
	fprintf (stderr, "mlockall(): %d\n", rv);

	main_start = get_tsc();
	printf ("get_tsc(): %ld\n", main_start);

	while (1) {

		loop_start = get_tsc();
		foo = loop_start;

		for (i=0; i<1000; i++) {
			foo += (loop_start + i) ^ argc;
		}

		loop_end = get_tsc();
		loop_elapsed = loop_end - loop_start;

		/* this takes about 7700 cycles on a 2.66Ghz Xeon X5550 */
		if ( loop_elapsed > MAX_PAUSE ) {
			printf ("At %ld pause %ld is longer than %d\n", get_tsc(), loop_elapsed, MAX_PAUSE);
		}
	}
}
コード例 #6
0
ファイル: logging_thread.c プロジェクト: dillonhicks/ipymake
void log_admin_event(struct logging_thread *log, int id,
		int tag, size_t size, void *extradata)
{
	struct ds_event_record evt;
	evt.data_len = size;
	evt.time_stamp = get_tsc();
	evt.id = id;
	evt.event_tag = tag;

	km_mutex_lock(&log->write_lock);
	__logging_thread_write(log, &evt, sizeof(evt));
	__logging_thread_write(log, extradata, size);
	km_mutex_unlock(&log->write_lock);
}
コード例 #7
0
ファイル: threads.c プロジェクト: Sudoka/Measure
int thread_fn(void* input) {
    unsigned long t2;
    unsigned long j0,j1;
    int delay = 60*HZ;

    j0 = jiffies; 
    j1 = j0 + delay; 

    int number = (int) input;


    printk(KERN_INFO "we are scheduled\n");
    while (time_before(jiffies, j1)) 
    {
	t2 = get_tsc();
	printk("TAOI:%d:ktime=%ld\n",number, t2);
	schedule(); // force to schedule
    }

    return 0;
}
コード例 #8
0
ファイル: time.c プロジェクト: cyfdecyf/mem-order
void end_clock() {
#ifdef ENABLE_TIME
    end_tsc = get_tsc();
    printf("tsc %lf\n", (end_tsc - begin_tsc)/FREQ);
#endif
}
コード例 #9
0
ファイル: time.c プロジェクト: cyfdecyf/mem-order
void begin_clock() {
#ifdef ENABLE_TIME
    begin_tsc = get_tsc();
#endif
}
コード例 #10
0
ファイル: client.c プロジェクト: neimanra/LwIp
static int
set_tsc_freq_from_clock(void)
{
#define NS_PER_SEC 1E9

	struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */

	struct timespec t_start, t_end;

	if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) {
			uint64_t ns, end, start = get_tsc();
			nanosleep(&sleeptime,NULL);
			clock_gettime(CLOCK_MONOTONIC_RAW, &t_end);
			end = get_tsc();
			ns = ((t_end.tv_sec - t_start.tv_sec) * NS_PER_SEC);
			ns += (t_end.tv_nsec - t_start.tv_nsec);

			double secs = (double)ns/NS_PER_SEC;
			eal_tsc_resolution_hz = (uint64_t)((end - start)/secs);
			return 0;
	}

	return -1;
}


int main(int argc , char *argv[])
{
    int sock;
    struct sockaddr_in server;
    unsigned char buffer[1400] , server_reply[2000];
    unsigned long long total_rcvd = 0, rcvd;
	memset(buffer, 'A', 1400);

	printf("Clock measure:%d\n\n",set_tsc_freq_from_clock());

    //Create socket
    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");
     
    server.sin_addr.s_addr = inet_addr("10.132.251.197");
    server.sin_family = AF_INET;
    server.sin_port = htons( 80 );
 
    //Connect to remote server
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        perror("connect failed. Error");
        return 1;
    }
     
    puts("Connected\n");
     

	uint64_t  end = get_tsc() + eal_tsc_resolution_hz;


    //keep communicating with server
    while(1)
    {      
        //Send some data
        if( send(sock , buffer , 1400 , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
         
        //Receive a reply from the server
        if( (rcvd = recv(sock , server_reply , 2000 , 0)) < 0)
        {
            puts("recv failed");
            break;
        }
         
		else
		{
			total_rcvd += rcvd;
		}

		if(get_tsc() >= end)
		{
			printf("%llu \n", total_rcvd);
			total_rcvd = 0;
			end = get_tsc() + eal_tsc_resolution_hz;
		}
        //puts("Server reply :");
        //puts(server_reply);
    }
     
    close(sock);
    return 0;
}
コード例 #11
0
ファイル: recv_server.c プロジェクト: neimanra/LwIp
static int
set_tsc_freq_from_clock(void)
{
#define NS_PER_SEC 1E9

	struct timespec sleeptime = {.tv_nsec = 5E8 }; /* 1/2 second */

	struct timespec t_start, t_end;

	if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0) {
			uint64_t ns, end, start = get_tsc();
			nanosleep(&sleeptime,NULL);
			clock_gettime(CLOCK_MONOTONIC_RAW, &t_end);
			end = get_tsc();
			ns = ((t_end.tv_sec - t_start.tv_sec) * NS_PER_SEC);
			ns += (t_end.tv_nsec - t_start.tv_nsec);

			double secs = (double)ns/NS_PER_SEC;
			eal_tsc_resolution_hz = (uint64_t)((end - start)/secs);
			return 0;
	}

	return -1;
}


int main(int argc , char *argv[])
{
    int socket_desc , client_sock , c , read_size;
    unsigned long long total_rcvd = 0;
    struct sockaddr_in server , client;
    char client_message[2000];
     
    printf("Clock measure:%d\n\n",set_tsc_freq_from_clock());

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("192.168.56.101");
    server.sin_port = htons( 80 );
     
    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        //print the error message
        perror("bind failed. Error");
        return 1;
    }
    puts("bind done");
     
    //Listen
    listen(socket_desc , 3);
     
    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
     
    //accept connection from an incoming client
    client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
    if (client_sock < 0)
    {
        perror("accept failed");
        return 1;
    }
    puts("Connection accepted");
     
    uint64_t  end = get_tsc() + eal_tsc_resolution_hz;

    //Receive a message from client
    while( 1 )
    {
        read_size = recv(client_sock , client_message , 2000 , MSG_DONTWAIT );
        if (read_size > 0) 
        {
            total_rcvd += read_size;
        }

        if(get_tsc() >= end)
		{
			printf("%llu \n", total_rcvd);
			total_rcvd = 0;
			end = get_tsc() + eal_tsc_resolution_hz;
		}
    }
     
    if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }
     
    return 0;
}
コード例 #12
0
/*
 * Internal thread donation call.
 *
 * The current thread lock must be locked.
 */
int
pthread_sched_thread_donate(pthread_thread_t *pchild,
			    sched_wakecond_t wakeup_cond, oskit_s32_t timeout)
{
	pthread_thread_t	*pnext, *pthread = CURPTHREAD();
	int			enabled, preemptable;
#ifdef  MEASURE
	unsigned long		before, after;
#endif
	save_preemption_enable(preemptable);
	enabled = save_disable_interrupts();

#ifdef  MEASURE
	before = get_tsc();
#endif
	CPUDEBUG(CORE3,
		 "PSD0: 0x%x(%d) 0x%x(%d) %s\n",
		 (int) pthread, pthread->tid,
		 (int) pchild, pchild->tid, STATESTR(pchild));

	/*
	 * If the thread is not ready to accept this new donation, just
	 * return status that the donation was not accepted.
	 */
	if (pchild->schedflags != SCHED_READY) {
		CPUDEBUG(CORE3,
			 "PSD1: 0x%x(%d) 0x%x(%d) %s\n",
			 (int) pthread, pthread->tid,
			 (int) pchild, pchild->tid, STATESTR(pchild));

		restore_interrupt_enable(enabled);
		return 0;
	}

	/*
	 * Is another thread already donating to this thread? 
	 */
	if (pchild->inherits_from) {
		CPUDEBUG(CORE3,
			 "PSD2: 0x%x(%d) 0x%x(%d) 0x%x(%d)\n",
			 (int) pthread, pthread->tid,
			 (int) pchild, pchild->tid,
			 (int) pchild->inherits_from,
			 pchild->inherits_from->tid);
	}

	/*
	 * We are commited to the donation.
	 */

	/*
	 * The target thread is going to inherit from the current thread.
	 */
	pchild->inherits_from = pthread;
	pchild->nextup        = NULL_THREADPTR;
	
	/*
	 * BUT, if the thread being switched into is part of an old active
	 * chain, need to decend the chain setting each thread to DONATED.
	 * Set the back pointer too since it might no longer be valid if
	 * another thread donated to the chain at some point.
	 * 
	 * STOP when we hit a thread with WAKEUP_ALWAYS set, or at the end.
	 * This is the thread that actually gets run. Lock that thread.
	 */
	pnext = pchild;
	if (pnext->donating_to) {
		while (pnext->donating_to) {
			pthread_thread_t	*ptmp;
			
			if (pnext->schedflags != SCHED_READY)
				panic("pthread_sched_donate SCHED_READY");

			if (pnext->wakeup_cond == WAKEUP_ALWAYS)
				break;
		
			pnext->schedflags = SCHED_DONATING;

			/*
			 * Goto next in the chain. Lock the next one,
			 * unlock the current one, set the back pointer.
			 */
			ptmp = pnext->donating_to;
			ptmp->inherits_from = pnext;
			ptmp->nextup        = NULL_THREADPTR;
			
			CPUDEBUG(CORE3,
				 "PSD3: "
				 "Followed chain from 0x%x(%d) to 0x%x(%d)\n",
				 (int) pnext, pnext->tid,
				 (int) pnext->donating_to,
				 pnext->donating_to->tid);

			pnext = ptmp;
		}
	}

	/*
	 * Set up the links.
	 */
	pthread->schedflags   = SCHED_DONATING;
	pthread->donating_to  = pchild;
	pthread->wakeup_cond  = wakeup_cond;
	pthread->timeout      = timeout;
	pnext->schedflags     = SCHED_RUNNING;

#ifdef  MEASURE
	after = get_tsc();
	if (after > before) {
		stats.donations++;
		stats.donate_cycles += (after - before);
	}
#endif
	/* Don't worry about the lock */
	thread_switch(pnext, &pthread->schedlock, CURPTHREAD());

	/* Must set the current thread pointer! */
	SETCURPTHREAD(pthread);

	/*
	 * Back from donation. 
	 *
	 * Undo the donating link. Leave the back link alone since another
	 * thread could have donated to the child if the chain was preempted.
	 */
	pthread->timeout      = 0;
	pthread->donating_to  = NULL_THREADPTR;
	pthread->schedflags   = SCHED_RUNNING;

	if (pchild->inherits_from == pthread)
		pchild->inherits_from = NULL_THREADPTR;

	restore_interrupt_enable(enabled);
	/* Need to really *restore* the flag since we are in a new context */
	PREEMPT_ENABLE = preemptable;
	return 1;
}
コード例 #13
0
/*
 * Wakeup call.
 */
void
pthread_sched_wakeup(pthread_thread_t *pthread, int level)
{
	int			enabled;
	pthread_thread_t	*pscheduler = pthread->scheduler;
	pthread_thread_t	*inheritor, *ptmp;
#ifdef  MEASURE
	unsigned long		before, after;
#endif
	enabled = save_disable_interrupts();

#ifdef  MEASURE
	before = get_tsc();
#endif
	CPUDEBUG(CORE0,
		 "pthread_sched_wakeup: "
		 "C:0x%x(%d)/%s T:0x%x(%d)/%s S:0x%x(%d)/%s\n",
		 (int) CURPTHREAD(), CURPTHREAD()->tid, STATESTR(CURPTHREAD()),
		 (int) pthread, pthread->tid, STATESTR(pthread),
		 (int) pscheduler,
		 (pscheduler ? pscheduler->tid : 0),
		 (pscheduler ? STATESTR(pscheduler) : ""));


	/*
	 * Thread is currently ready to run. The wrinkle is if the thread
	 * was part of a donation chain that yielded, or a donation chain
	 * that was interrupted by a wakeup. There will be a donating_to
	 * link, which must be severed so that when the chain is run again,
	 * the thread in question will run, rather then following the
	 * chain.
	 */
	if (pthread->schedflags == SCHED_READY) {
		if (pthread->donating_to) {
			CPUDEBUG(CORE0,
				 "PSW0: 0x%x(%d) 0x%x 0x%x\n",
				 (int) pthread, pthread->tid,
				 (int) pthread->donating_to,
				 (int) pthread->scheduler);
			
			pthread->donate_rc   = SCHEDULE_PREEMPTED;
			pthread->donating_to = NULL_THREADPTR;
			pthread->wakeup_cond = WAKEUP_ALWAYS;
		}
		goto done;
	}

	/*
	 * Thread is donating, which means its on the active chain.
	 */
	if (pthread->schedflags == SCHED_DONATING) {
		pthread->schedflags = SCHED_READY;
		
		/*
		 * Follow the chain down, setting each one along the way
		 * to the ready state instead of donating. 
		 */
		inheritor = pthread->donating_to;
		
		while (inheritor->donating_to) {
			inheritor->schedflags = SCHED_READY;

			ptmp      = inheritor;
			inheritor = inheritor->donating_to;
		}
		
		/*
		 * Go to the end of the chain. Severe the chain at the
		 * thread being woken up. Point the last thread in the
		 * chain (usually the thread actually running) back at the
		 * this thread. This means that when the running thread
		 * switches out, it will follow its link back to this
		 * thread. When it runs, it will return from its donation,
		 * so set the return code so that it reruns whatever thread
		 * it was donating to.
		 */
		pthread->donating_to     = NULL_THREADPTR;
		pthread->donate_rc       = SCHEDULE_PREEMPTED;
		pthread->wakeup_cond     = WAKEUP_ALWAYS;
		inheritor->nextup        = pthread;

		/*
		 * The wrinkle is if the last thread in the chain is not
		 * the currently running thread. That means the chain
		 * below this point was already woken up (it was severed).
		 * Need to entend the backwards chain so that when the
		 * currently running thread switches out, it follows the
		 * links back to this thread (along multiple hops). The
		 * intent is to run the highest level scheduler that wants
		 * to run.
		 */
		if (inheritor != CURPTHREAD())
			inheritor->wakeup_cond = WAKEUP_NEVER;

		PREEMPT_NEEDED = CURPTHREAD()->preempt = 1;

		CPUDEBUG(CORE3,
			 "PSW1: 0x%x(%d)\n", (int) inheritor, inheritor->tid);
			
		goto done;
	}

	/*
	 * The thread is not on the active chain, and its not in the READY
	 * state (already woken up). Need to follow the chain back until we
	 * get to a thread *is* DONATING.
	 */
	CPUDEBUG(CORE1, "PSW2:\n");

	/*
	 * Want to wake up either the thread donating to it, or its scheduler.
	 * Of course, they might be the same.
	 */
	if (pthread->inherits_from &&
	    pthread->inherits_from != pscheduler) {
		/*
		 * A non-scheduler thread was donating to another thread,
		 * and the inheritor blocked. Now the inheritor is being
		 * woken up. Need to wakeup the donator in the hopes that
		 * it can provide some more CPU.
		 */
		/* cpuprintf("PSW3: 0x%x 0x%x 0x%x\n",
		       (int) pthread, (int) pscheduler,
		       (int) pthread->inherits_from); */
		
		pthread->schedflags = SCHED_READY;
		inheritor = pthread->inherits_from;
		
		pthread_sched_wakeup(inheritor, level + 1);
	}
	else if (pscheduler) {
		pthread->schedflags = SCHED_READY;
		
		/*
		 * If the thread waking up is different than the thread
		 * the scheduler is currently donating to, this implies
		 * two (or more) threads, and thus a conflict. Set the
		 * wakeup_cond back to WAKEUP_ALWAYS so that the scheduler
		 * will be woken up.
		 */
		if (pscheduler->donating_to &&
		    pscheduler->donating_to != pthread) {
			pscheduler->wakeup_cond = WAKEUP_ALWAYS;

			CPUDEBUG(CORE1,
				 "PSW4: 0x%x\n",
				 (int) pscheduler->donating_to);
		}

		/*
		 * If the scheduler is WAKEUP_ON_SWITCH, then the
		 * above case was not true, and the scheduler still has
		 * only one thread to run. The scheduler *is* woken up, 
		 * but since it will donate to that thread anyway, do
		 * not send it a message.
		 */
		if (pscheduler->wakeup_cond == WAKEUP_ALWAYS ||
		    pscheduler->wakeup_cond == WAKEUP_ON_BLOCK) {
			schedmsg_t	msg;
			
			CPUDEBUG(CORE2,
				 "PSW5: 0x%x(%d) 0x%x(%d)\n",
				 (int) pscheduler, pscheduler->tid,
				 (int) pthread, pthread->tid);

			msg.type    = MSG_SCHED_UNBLOCK;
			msg.tid     = pthread->tid;
			msg.opaque  = 0;
			pthread_sched_special_send(pscheduler, &msg);
		}
		else {
			pthread_sched_wakeup(pscheduler, level + 1);
		}
	}
	else {
		/*
		 * Hit the root scheduler, which was not running.
		 * That means the current thread (the idle thread)
		 * should switch back into the root scheduler.
		 * Set the back link on the idle thread to force this
		 * to happen.
		 */
		assert(pthread == pthread_root_scheduler);

		if (pthread->schedflags != SCHED_RUNNING) {
			pthread->schedflags         = SCHED_READY;
			CURPTHREAD()->nextup        = pthread;
			CURPTHREAD()->inherits_from = pthread;
		}
	}
   done:
#ifdef  MEASURE
	after = get_tsc();
	if (level) {
		stats.wakeup_calls++;
	}
	else if (after > before) {
		stats.wakeups++;
		stats.wakeup_cycles += (after - before);
	}
#endif
	restore_interrupt_enable(enabled);
}
コード例 #14
0
/*
 * Switch out of an application thread, back into its scheduler. Return
 * value to indicate whether a switch actually happened.
 */
int
pthread_sched_dispatch(resched_flags_t reason)
{
	pthread_thread_t	*pthread = CURPTHREAD();
	pthread_thread_t	*inheritor, *donator, *nextup;
	int			enabled, preemptable;
#ifdef  MEASURE
	unsigned long		before, after;
#endif	
	save_preemption_enable(preemptable);
	enabled = save_disable_interrupts();

#ifdef  MEASURE
	before = get_tsc();
#endif
	/*
	 * See what donator should receive the message and get restarted.
	 * Go back up the inheritance chain. Stop at the root scheduler
	 * (which will have set WAKEUP_ALWAYS) or when some intermediate
	 * thread says it wants to be woken up.
	 */
	donator   = pthread->inherits_from;
	nextup    = pthread->nextup;
	inheritor = pthread;
	assert(inheritor != donator);

	/*
	 * Better be a donator unless its the root scheduler or idlethread.
	 */
	assert(donator || ((pthread == pthread_root_scheduler) ||
			   (pthread == IDLETHREAD)));

	/*
	 * The current thread state is set accordingly.
	 */
	if (reason == RESCHED_BLOCK)
		pthread->schedflags = SCHED_WAITING;
	else
		pthread->schedflags = SCHED_READY;

	/*
	 * Go back through the inheritance links, stopping at the first
	 * thread to indicate that it wants to be woken up. That thread
	 * is left locked across the thread switch. It is responsible for
	 * unlocking itself when it gets to the other side.
	 */
	while (donator) {
		switch (reason) {
		case RESCHED_USERYIELD:
			donator->donate_rc = SCHEDULE_YIELDED;
			break;
		case RESCHED_BLOCK:
			donator->donate_rc = SCHEDULE_BLOCKED;
			break;
		case RESCHED_PREEMPT:	/* time based preemption */
			donator->donate_rc = SCHEDULE_TIMEDOUT;
			break;
		default:
			donator->donate_rc = SCHEDULE_PREEMPTED;
			break;
		}

		/*
		 * With each step back through the active chain, set
		 * the thread state accordingly. Blocks are different
		 * then yields in that another thread should be able
		 * to donate to a thread that yielded. However, blocked
		 * chains should cause a wakeup for any thread along
		 * the chain.
		 */
		if (reason == RESCHED_BLOCK)
			donator->schedflags = SCHED_WAITING;
		else
			donator->schedflags = SCHED_READY;

		if (nextup) {
			if (nextup == donator &&
			    (nextup = donator->nextup) == NULL_THREADPTR)
				break;
		}
		else {
			if (donator->wakeup_cond == WAKEUP_ALWAYS ||
			    donator->wakeup_cond == WAKEUP_ON_BLOCK)
				break;
		}

		inheritor = donator;
		donator   = donator->inherits_from;
	}
	
	if (donator == NULL_THREADPTR) {
		/*
		 * Nothing to run, not even the root scheduler has anything
		 * to do. Control reaches here when the root scheduler
		 * calls pthread_sched_wait(), or when the idle thread
		 * attempts a reschedule in hopes of finding something to
		 * do.
		 */
		if ((donator = IDLETHREAD) == pthread) {
			restore_interrupt_enable(enabled);
			return 0;
		}

		/*
		 * Rather kludgy method to keep the idle loop an orphan.
		 * The root scheduler does not know about the idle loop,
		 * so don't want to terminate its message wait when the
		 * idle loop does its yield to look for a new thread.
		 */
		donator->inherits_from = NULL_THREADPTR;
		donator->nextup        = NULL_THREADPTR;
		
		goto dispatch;
	}

#if 0
	/*
	 * Encode a return status for the donator so that it knows what
	 * to do with the thread after it switches out.
	 *
	 * special flag indicates that the donation chain was modified
	 * by a wakeup along the chain. The return code of the thread
	 * being switched into was already set in the wakeup code, and
	 * giving that thread a return code based on what the current
	 * thread is doing makes no sense.
	 *
	 * The only reason to distingiush between all these reschedule
	 * reasons is so that we can implement a POSIX style scheduler.
	 */
	switch (reason) {
	case RESCHED_USERYIELD:
		donator->donate_rc = SCHEDULE_YIELDED;
		break;
	case RESCHED_BLOCK:
		donator->donate_rc = SCHEDULE_BLOCKED;
		break;
	case RESCHED_PREEMPT:	/* time based preemption */
		donator->donate_rc = SCHEDULE_TIMEDOUT;
		break;
	default:
		donator->donate_rc = SCHEDULE_PREEMPTED;
		break;
	}
#endif

dispatch:
	/*
	 * Clear directed yield flag.
	 */
	PREEMPT_NEEDED = pthread->preempt = 0;
	assert(donator);

#ifdef  MEASURE
	after = get_tsc();
	if (after > before) {
		stats.switches++;
		stats.switch_cycles += (after - before);
	}
#endif
	/* Don't worry about the lock */
	thread_switch(donator, &pthread->schedlock, CURPTHREAD());

	/* Must set the current thread pointer! */
	SETCURPTHREAD(pthread);

	assert(pthread->inherits_from ||
	       ((pthread == pthread_root_scheduler) ||
		(pthread == IDLETHREAD)));
	
	/*
	 * Thread has switched back in. 
	 *
	 * Time to look for exceptions before letting it return to
	 * whatever it was doing before it yielded.
	 */
	pthread->schedflags = SCHED_RUNNING;
	
	if (pthread->sleeprec) {
		/*
		 * Thread is returning to an osenv_sleep. The thread must
		 * be allowed to return, even if it was killed, so the driver
		 * state can be cleaned up. The death will be noticed later.
		 */
		goto done;
	}
	else if ((pthread->flags &
		  (THREAD_KILLED|THREAD_EXITING)) == THREAD_KILLED) {
		/*
		 * Thread was canceled. Time to actually reap it, but only
		 * if its not already in the process of exiting.
		 *
		 * XXX: The problem is if the process lock is still
		 * held.  Since the rest of the oskit is not set up to
		 * handle cancelation of I/O operations, let threads
		 * continue to run until the process lock is released.
		 * At that point the death will be noticed.
		 */
		if (! osenv_process_locked()) {
			pthread_exit_locked((void *) PTHREAD_CANCELED);

			/*
			 * Never returns
			 */
		}
		else
			goto done;
	}
	
	/*
	 * Look for signals. Deliver them in the context of the thread.
	 */
	SIGCHECK(pthread);

   done:
	restore_interrupt_enable(enabled);
	/* Need to really *restore* the flag since we are in a new context */
	PREEMPT_ENABLE = preemptable;
	return 1;
}