| #include <stdio.h> |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <sys/time.h> |
| |
| /* OS dependent #incs */ |
| #include <parlib/parlib.h> |
| #include <parlib/vcore.h> |
| #include <parlib/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_mcp_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. */ |
| parlib_never_yield = TRUE; |
| while (num_vcores() < 2) |
| vcore_request_more(1); |
| parlib_never_vc_request = TRUE; |
| 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]); |
| } |
| } |
| parlib_never_yield = FALSE; |
| parlib_never_vc_request = FALSE; |
| printf("test_cv: single sender/receiver complete\n"); |
| } |