Pthread cond_broadcast amortizes 2LS runnable ops
[akaros.git] / tests / condvar_test.c
1 #include <stdio.h>
2 #include <pthread.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6
7 /* OS dependent #incs */
8 #include <parlib.h>
9 #include <vcore.h>
10 #include <timing.h>
11
12 #define MAX_NR_TEST_THREADS 1000
13
14 pthread_t my_threads[MAX_NR_TEST_THREADS];
15 void *my_retvals[MAX_NR_TEST_THREADS];
16
17
18 /* Funcs and global vars for test_cv() */
19 pthread_cond_t local_cv;
20 pthread_cond_t *cv = &local_cv;
21 pthread_mutex_t local_mutex = PTHREAD_MUTEX_INITIALIZER;
22 pthread_mutex_t *pth_m = &local_mutex;
23
24 atomic_t counter;
25 volatile bool state = FALSE;            /* for test 3 */
26
27 void *__test_pthread_cond_signal(void *arg)
28 {
29         if (atomic_read(&counter) % 4)
30                 pthread_cond_signal(cv);
31         else
32                 pthread_cond_broadcast(cv);
33         atomic_dec(&counter);
34 }
35
36 void *__test_pthread_cond_waiter(void *arg)
37 {
38         pthread_mutex_lock(pth_m);
39         /* check state, etc */
40         pthread_cond_wait(cv, pth_m);
41         pthread_mutex_unlock(pth_m);
42         atomic_dec(&counter);
43 }
44
45 void *__test_pthread_cond_waiter_t3(void *arg)
46 {
47         udelay((int)arg);
48         /* if state == false, we haven't seen the signal yet */
49         pthread_mutex_lock(pth_m);
50         printd("Came in, saw state %d\n", state);
51         while (!state) {
52                 cpu_relax();
53                 pthread_cond_wait(cv, pth_m);   /* unlocks and relocks */
54         }
55         pthread_mutex_unlock(pth_m);
56         /* Make sure we are done, tell the controller we are done */
57         cmb();
58         assert(state);
59         atomic_dec(&counter);
60 }
61
62 int main(void)
63 {
64         int nr_msgs;
65         pthread_lib_init();
66         pthread_cond_init(cv, 0);
67         pthread_mutex_init(pth_m, 0);
68
69         /* Test 0: signal without waiting */
70         pthread_cond_broadcast(cv);
71         pthread_cond_signal(cv);
72         printf("test_cv: signal without waiting complete\n");
73
74         /* Test 1: single / minimal shit */
75         nr_msgs = max_vcores() - 1;
76         atomic_init(&counter, nr_msgs);
77         for (int i = 0; i < nr_msgs; i++) {
78                 if (pthread_create(&my_threads[i], NULL, &__test_pthread_cond_waiter,
79                     NULL))
80                         perror("pth_create failed");
81         }
82         udelay(1000000);
83         pthread_cond_signal(cv);
84         /* wait for one to make it */
85         while (atomic_read(&counter) != nr_msgs - 1)
86                 pthread_yield();
87         printf("test_cv: single signal complete\n");
88         pthread_cond_broadcast(cv);
89         for (int i = 0; i < nr_msgs; i++)
90                 pthread_join(my_threads[i], &my_retvals[i]);
91         printf("test_cv: broadcast signal complete\n");
92
93         /* Test 2: shitloads of waiters and signalers */
94         nr_msgs = MAX_NR_TEST_THREADS;
95         atomic_init(&counter, nr_msgs);
96         for (int i = 0; i < nr_msgs; i++) {
97                 if (i % 5) {
98                         if (pthread_create(&my_threads[i], NULL,
99                             &__test_pthread_cond_waiter, NULL))
100                                 perror("pth_create failed");
101                 } else {
102                         if (pthread_create(&my_threads[i], NULL,
103                             &__test_pthread_cond_signal, NULL))
104                                 perror("pth_create failed");
105                 }
106         }
107         pthread_yield();
108         while (atomic_read(&counter)) {
109                 cpu_relax();
110                 pthread_cond_broadcast(cv);
111                 pthread_yield();
112         }
113         for (int i = 0; i < nr_msgs; i++)
114                 pthread_join(my_threads[i], &my_retvals[i]);
115         printf("test_cv: massive message storm complete\n");
116
117         /* Test 3: basic one signaller, one receiver.  we want to vary the amount of
118          * time the sender and receiver delays, starting with (1ms, 0ms) and ending
119          * with (0ms, 1ms).  At each extreme, such as with the sender waiting 1ms,
120          * the receiver/waiter should hit the "check and wait" point well before the
121          * sender/signaller hits the "change state and signal" point.
122          *
123          * Need to make sure we are running in parallel here.  Temp turned off the
124          * 2LSs VC management and got up to 2 VC.  Assuming no preemption. */
125         pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
126         while (num_vcores() < 2)
127                 vcore_request(1);
128         for (int i = 0; i < 1000; i++) {
129                 for (int j = 0; j < 10; j++) {  /* some extra chances at each point */
130                         state = FALSE;
131                         /* client waits for i usec */
132                         if (pthread_create(&my_threads[0], NULL,
133                             &__test_pthread_cond_waiter_t3, (void*)i))
134                                 perror("pth_create failed");
135                         cmb();
136                         udelay(1000 - i);       /* senders wait time: 1000..0 */
137                         /* Need to lock the mutex when touching state and signalling about
138                          * that state (atomically touch and signal).  Thanks pthreads, for
139                          * mandating a cond_signal that doesn't require locking. */
140                         pthread_mutex_lock(pth_m);
141                         state = TRUE;
142                         pthread_cond_signal(cv);
143                         pthread_mutex_unlock(pth_m);
144                         /* they might not have run at all yet (in which case they lost the
145                          * race and don't need the signal).  but we need to wait til they're
146                          * done */
147                         pthread_join(my_threads[0], my_retvals[0]);
148                 }
149         }
150         pthread_can_vcore_request(TRUE);        /* 2LS controls VCs again */
151         printf("test_cv: single sender/receiver complete\n");
152 }