blob: 927338dcc3841d687cfba14e71d12f835be60a20 [file] [log] [blame]
#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");
}