Remove return that ended up with a memory leak in cs.c
[akaros.git] / tests / pthread_switch.c
1 /* Copyright (c) 2014 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Basic pthread switcher, bypassing the 2LS.  Use for benchmarking and
6  * 2LS-inspiration. */
7
8 #include <stdio.h>
9 #include <pthread.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13 #include "misc-compat.h"
14
15 pthread_t th1, th2;
16 int nr_switch_loops = 100;
17 bool ready = FALSE;
18 bool should_exit = FALSE;
19
20 static void __pth_switch_cb(struct uthread *uthread, void *target)
21 {
22         /* by not returning, this bypasses vcore entry and event checks, though when
23          * we pop back out of the 2LS, we'll check notif pending.  think about this
24          * if you put this into your 2LS. */
25         current_uthread = NULL;
26         run_uthread((struct uthread*)target);
27         assert(0);
28 }
29
30 static void pth_switch_to(struct pthread_tcb *target)
31 {
32         uthread_yield(TRUE, __pth_switch_cb, target);
33 }
34
35 void *switch_thread(void *arg)
36 {       
37         pthread_t other_thr = *(pthread_t*)arg;
38
39         while (!ready)
40                 cpu_relax();
41         for (int i = 0; i < nr_switch_loops; i++) {
42                 cmb();
43                 if (should_exit)
44                         return 0;
45                 pth_switch_to(other_thr);
46         }
47         if (pthread_self() == th1) {
48                 /* we need to break out of the switching cycle.  when th2 runs again,
49                  * it'll know to stop.  but th1 needs to both exit and switch to th2.
50                  * we do this by making th2 runnable by the pth schedop, then exiting */
51                 should_exit = TRUE;
52                 /* we also need to do this to th2 before it tries to exit, o/w we'll PF
53                  * in __pthread_generic_yield. */
54                 sched_ops->thread_runnable((struct uthread*)th2);
55         }
56         return 0;
57 }
58
59 int main(int argc, char** argv) 
60 {
61         struct timeval start_tv = {0};
62         struct timeval end_tv = {0};
63         long usec_diff;
64         long nr_ctx_switches;
65         void *join_ret;
66
67         if (argc > 1)
68                 nr_switch_loops = strtol(argv[1], 0, 10);
69         printf("Making 2 threads of %d switches each\n", nr_switch_loops);
70
71         pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
72         pthread_need_tls(FALSE);
73         pthread_lib_init();                                     /* gives us one vcore */
74
75         /* each is passed the other's pthread_t.  th1 starts the switching. */
76         if (pthread_create(&th1, NULL, &switch_thread, &th2))
77                 perror("pth_create 1 failed");
78         /* thread 2 is created, but not put on the runnable list */
79         if (__pthread_create(&th2, NULL, &switch_thread, &th1))
80                 perror("pth_create 2 failed");
81
82         if (gettimeofday(&start_tv, 0))
83                 perror("Start time error...");
84
85         ready = TRUE;                   /* signal to any spinning uthreads to start */
86
87         pthread_join(th1, &join_ret);
88         pthread_join(th2, &join_ret);
89
90         if (gettimeofday(&end_tv, 0))
91                 perror("End time error...");
92         nr_ctx_switches = 2 * nr_switch_loops;
93         usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
94                     (end_tv.tv_usec - start_tv.tv_usec);
95         printf("Done: %d loops\n", nr_switch_loops);
96         printf("Nr context switches: %ld\n", nr_ctx_switches);
97         printf("Time to run: %ld usec\n", usec_diff);
98         printf("Context switch latency: %d nsec\n",
99                (int)(1000LL*usec_diff / nr_ctx_switches));
100         printf("Context switches / sec: %d\n\n",
101                (int)(1000000LL*nr_ctx_switches / usec_diff));
102