| #include <stdio.h> | 
 | #include <pthread.h> | 
 | #include <stdlib.h> | 
 | #include <unistd.h> | 
 | #include <sys/time.h> | 
 |  | 
 | /* OS dependent #incs */ | 
 | #include <parlib.h> | 
 | #include <vcore.h> | 
 | #include <timing.h> | 
 |  | 
 | #define MAX_NR_TEST_THREADS 1000 | 
 |  | 
 | pthread_t my_threads[MAX_NR_TEST_THREADS]; | 
 | void *my_retvals[MAX_NR_TEST_THREADS]; | 
 |  | 
 |  | 
 | /* Funcs and global vars for test_cv() */ | 
 | pthread_cond_t local_cv; | 
 | pthread_cond_t *cv = &local_cv; | 
 | pthread_mutex_t local_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 | pthread_mutex_t *pth_m = &local_mutex; | 
 |  | 
 | atomic_t counter; | 
 | volatile bool state = FALSE;		/* for test 3 */ | 
 |  | 
 | void *__test_pthread_cond_signal(void *arg) | 
 | { | 
 | 	if (atomic_read(&counter) % 4) | 
 | 		pthread_cond_signal(cv); | 
 | 	else | 
 | 		pthread_cond_broadcast(cv); | 
 | 	atomic_dec(&counter); | 
 | } | 
 |  | 
 | void *__test_pthread_cond_waiter(void *arg) | 
 | { | 
 | 	pthread_mutex_lock(pth_m); | 
 | 	/* check state, etc */ | 
 | 	pthread_cond_wait(cv, pth_m); | 
 | 	pthread_mutex_unlock(pth_m); | 
 | 	atomic_dec(&counter); | 
 | } | 
 |  | 
 | void *__test_pthread_cond_waiter_t3(void *arg) | 
 | { | 
 | 	udelay((long)arg); | 
 | 	/* if state == false, we haven't seen the signal yet */ | 
 | 	pthread_mutex_lock(pth_m); | 
 | 	printd("Came in, saw state %d\n", state); | 
 | 	while (!state) { | 
 | 		cpu_relax(); | 
 | 		pthread_cond_wait(cv, pth_m);	/* unlocks and relocks */ | 
 | 	} | 
 | 	pthread_mutex_unlock(pth_m); | 
 | 	/* Make sure we are done, tell the controller we are done */ | 
 | 	cmb(); | 
 | 	assert(state); | 
 | 	atomic_dec(&counter); | 
 | } | 
 |  | 
 | int main(void) | 
 | { | 
 | 	int nr_msgs; | 
 | 	pthread_lib_init(); | 
 | 	pthread_cond_init(cv, 0); | 
 | 	pthread_mutex_init(pth_m, 0); | 
 |  | 
 | 	/* Test 0: signal without waiting */ | 
 | 	pthread_cond_broadcast(cv); | 
 | 	pthread_cond_signal(cv); | 
 | 	printf("test_cv: signal without waiting complete\n"); | 
 |  | 
 | 	/* Test 1: single / minimal shit */ | 
 | 	nr_msgs = max_vcores() - 1; | 
 | 	atomic_init(&counter, nr_msgs); | 
 | 	for (int i = 0; i < nr_msgs; i++) { | 
 | 		if (pthread_create(&my_threads[i], NULL, &__test_pthread_cond_waiter, | 
 | 		    NULL)) | 
 | 			perror("pth_create failed"); | 
 | 	} | 
 | 	udelay(1000000); | 
 | 	pthread_cond_signal(cv); | 
 | 	/* wait for one to make it */ | 
 | 	while (atomic_read(&counter) != nr_msgs - 1) | 
 | 		pthread_yield(); | 
 | 	printf("test_cv: single signal complete\n"); | 
 | 	pthread_cond_broadcast(cv); | 
 | 	for (int i = 0; i < nr_msgs; i++) | 
 | 		pthread_join(my_threads[i], &my_retvals[i]); | 
 | 	printf("test_cv: broadcast signal complete\n"); | 
 |  | 
 | 	/* Test 2: shitloads of waiters and signalers */ | 
 | 	nr_msgs = MAX_NR_TEST_THREADS; | 
 | 	atomic_init(&counter, nr_msgs); | 
 | 	for (int i = 0; i < nr_msgs; i++) { | 
 | 		if (i % 5) { | 
 | 			if (pthread_create(&my_threads[i], NULL, | 
 | 			    &__test_pthread_cond_waiter, NULL)) | 
 | 				perror("pth_create failed"); | 
 | 		} else { | 
 | 			if (pthread_create(&my_threads[i], NULL, | 
 | 			    &__test_pthread_cond_signal, NULL)) | 
 | 				perror("pth_create failed"); | 
 | 		} | 
 | 	} | 
 | 	pthread_yield(); | 
 | 	while (atomic_read(&counter)) { | 
 | 		cpu_relax(); | 
 | 		pthread_cond_broadcast(cv); | 
 | 		pthread_yield(); | 
 | 	} | 
 | 	for (int i = 0; i < nr_msgs; i++) | 
 | 		pthread_join(my_threads[i], &my_retvals[i]); | 
 | 	printf("test_cv: massive message storm complete\n"); | 
 |  | 
 | 	/* Test 3: basic one signaller, one receiver.  we want to vary the amount of | 
 | 	 * time the sender and receiver delays, starting with (1ms, 0ms) and ending | 
 | 	 * with (0ms, 1ms).  At each extreme, such as with the sender waiting 1ms, | 
 | 	 * the receiver/waiter should hit the "check and wait" point well before the | 
 | 	 * sender/signaller hits the "change state and signal" point. | 
 | 	 * | 
 | 	 * Need to make sure we are running in parallel here.  Temp turned off the | 
 | 	 * 2LSs VC management and got up to 2 VC.  Assuming no preemption. */ | 
 | 	pthread_can_vcore_request(FALSE);	/* 2LS won't manage vcores */ | 
 | 	while (num_vcores() < 2) | 
 | 		vcore_request(1); | 
 | 	for (long i = 0; i < 1000; i++) { | 
 | 		for (int j = 0; j < 10; j++) {	/* some extra chances at each point */ | 
 | 			state = FALSE; | 
 | 			/* client waits for i usec */ | 
 | 			if (pthread_create(&my_threads[0], NULL, | 
 | 			    &__test_pthread_cond_waiter_t3, (void*)i)) | 
 | 				perror("pth_create failed"); | 
 | 			cmb(); | 
 | 			udelay(1000 - i);	/* senders wait time: 1000..0 */ | 
 | 			/* Need to lock the mutex when touching state and signalling about | 
 | 			 * that state (atomically touch and signal).  Thanks pthreads, for | 
 | 			 * mandating a cond_signal that doesn't require locking. */ | 
 | 			pthread_mutex_lock(pth_m); | 
 | 			state = TRUE; | 
 | 			pthread_cond_signal(cv); | 
 | 			pthread_mutex_unlock(pth_m); | 
 | 			/* they might not have run at all yet (in which case they lost the | 
 | 			 * race and don't need the signal).  but we need to wait til they're | 
 | 			 * done */ | 
 | 			pthread_join(my_threads[0], my_retvals[0]); | 
 | 		} | 
 | 	} | 
 | 	pthread_can_vcore_request(TRUE);	/* 2LS controls VCs again */ | 
 | 	printf("test_cv: single sender/receiver complete\n"); | 
 | } |