Commit | Line | Data |
---|---|---|
ba3814c1 PC |
1 | #include <lightning.h> |
2 | #include <pthread.h> | |
3 | #include <stdio.h> | |
4 | #include <unistd.h> | |
5 | #include <signal.h> | |
6 | ||
c0c16242 PC |
7 | #if DEBUG |
8 | volatile | |
9 | #endif | |
10 | jit_word_t lock; | |
11 | pthread_t tids[4]; | |
12 | ||
13 | #if DEBUG | |
14 | int debug_offset(void) | |
15 | { | |
16 | int i; | |
17 | pthread_t self = pthread_self(); | |
18 | for (i = 0; i < 4; ++i) | |
19 | if (tids[i] == self) | |
20 | return i; | |
21 | return -1; | |
22 | } | |
23 | ||
24 | void debug_spin(void) | |
25 | { | |
26 | printf(" spin %d : %ld\n", debug_offset(), lock); | |
27 | } | |
28 | ||
29 | void debug_lock(void) | |
30 | { | |
31 | printf(" lock %d : %ld\n", debug_offset(), lock); | |
32 | } | |
33 | ||
34 | void debug_unlock(void) | |
35 | { | |
36 | printf("unlock %d : %ld\n", debug_offset(), lock); | |
37 | } | |
38 | #define DEBUG_SPIN() jit_calli(debug_spin) | |
39 | #define DEBUG_LOCK() jit_calli(debug_lock) | |
40 | #define DEBUG_UNLOCK() jit_calli(debug_unlock) | |
41 | #else | |
42 | #define DEBUG_SPIN() /**/ | |
43 | #define DEBUG_LOCK() /**/ | |
44 | #define DEBUG_UNLOCK() /**/ | |
45 | #endif | |
46 | ||
ba3814c1 PC |
47 | void alarm_handler(int unused) |
48 | { | |
49 | _exit(1); | |
50 | } | |
51 | ||
52 | int | |
53 | main(int argc, char *argv[]) | |
54 | { | |
55 | jit_state_t *_jit; | |
56 | void (*code)(void); | |
57 | jit_node_t *jmpi_main, *label; | |
58 | jit_node_t *func0, *func1, *func2, *func3; | |
59 | jit_node_t *patch0, *patch1, *patch2, *patch3; | |
ba3814c1 PC |
60 | |
61 | /* If there is any bug, do not hang in "make check" */ | |
62 | signal(SIGALRM, alarm_handler); | |
63 | alarm(5); | |
64 | ||
65 | init_jit(argv[0]); | |
66 | _jit = jit_new_state(); | |
67 | ||
68 | jmpi_main = jit_jmpi(); | |
69 | ||
70 | #define defun(name, line) \ | |
71 | jit_name(#name); \ | |
72 | jit_note("catomic.c", line); \ | |
73 | name = jit_label(); \ | |
74 | jit_prolog(); \ | |
75 | jit_movi(JIT_V0, (jit_word_t)&lock); \ | |
c0c16242 PC |
76 | jit_movi(JIT_V1, 0); \ |
77 | jit_movi(JIT_V2, line); \ | |
ba3814c1 | 78 | /* spin until get the lock */ \ |
c0c16242 | 79 | DEBUG_SPIN(); \ |
ba3814c1 | 80 | label = jit_label(); \ |
c0c16242 | 81 | jit_casr(JIT_R0, JIT_V0, JIT_V1, JIT_V2); \ |
ba3814c1 PC |
82 | jit_patch_at(jit_beqi(JIT_R0, 0), label); \ |
83 | /* lock acquired */ \ | |
c0c16242 | 84 | DEBUG_LOCK(); \ |
ba3814c1 | 85 | jit_prepare(); \ |
c0c16242 | 86 | /* pretend to be doing something useful for 0.01 sec |
ba3814c1 PC |
87 | * while holding the lock */ \ |
88 | jit_pushargi(10000); \ | |
89 | jit_finishi(usleep); \ | |
90 | /* release lock */ \ | |
c0c16242 PC |
91 | DEBUG_UNLOCK(); \ |
92 | jit_movi(JIT_V1, 0); \ | |
93 | jit_str(JIT_V0, JIT_V1); \ | |
ba3814c1 | 94 | /* Now test casi */ \ |
c0c16242 PC |
95 | jit_movi(JIT_V1, 0); \ |
96 | jit_movi(JIT_V2, line); \ | |
ba3814c1 | 97 | /* spin until get the lock */ \ |
c0c16242 | 98 | DEBUG_SPIN(); \ |
ba3814c1 | 99 | label = jit_label(); \ |
c0c16242 | 100 | jit_casi(JIT_R0, (jit_word_t)&lock, JIT_V1, JIT_V2); \ |
ba3814c1 PC |
101 | jit_patch_at(jit_beqi(JIT_R0, 0), label); \ |
102 | /* lock acquired */ \ | |
c0c16242 | 103 | DEBUG_LOCK(); \ |
ba3814c1 | 104 | jit_prepare(); \ |
c0c16242 | 105 | /* pretend to be doing something useful for 0.01 sec |
ba3814c1 PC |
106 | * while holding the lock */ \ |
107 | jit_pushargi(10000); \ | |
108 | jit_finishi(usleep); \ | |
109 | jit_prepare(); \ | |
110 | /* for make check, just print "ok" */ \ | |
111 | jit_pushargi((jit_word_t)"ok"); \ | |
112 | /*jit_pushargi((jit_word_t)#name);*/ \ | |
113 | jit_finishi(puts); \ | |
114 | /* release lock */ \ | |
c0c16242 PC |
115 | DEBUG_UNLOCK(); \ |
116 | jit_movi(JIT_V1, 0); \ | |
117 | jit_str(JIT_V0, JIT_V1); \ | |
ba3814c1 PC |
118 | jit_ret(); \ |
119 | jit_epilog(); | |
120 | defun(func0, __LINE__); | |
121 | defun(func1, __LINE__); | |
122 | defun(func2, __LINE__); | |
123 | defun(func3, __LINE__); | |
124 | ||
125 | jit_patch(jmpi_main); | |
126 | jit_name("main"); | |
127 | jit_note("catomic.c", __LINE__); | |
128 | jit_prolog(); | |
129 | ||
130 | #define start(tid) \ | |
131 | /* set JIT_R0 to thread function */ \ | |
132 | jit_patch_at(jit_movi(JIT_R0, 0), func##tid); \ | |
133 | jit_prepare(); \ | |
134 | /* pthread_t first argument */ \ | |
135 | jit_pushargi((jit_word_t)(tids + tid)); \ | |
136 | /* pthread_attr_t second argument */ \ | |
137 | jit_pushargi((jit_word_t)NULL); \ | |
138 | /* start routine third argument */ \ | |
139 | jit_pushargr(JIT_R0); \ | |
140 | /* argument to start routine fourth argument */ \ | |
141 | jit_pushargi((jit_word_t)NULL); \ | |
142 | /* start thread */ \ | |
143 | jit_finishi(pthread_create); | |
144 | /* spawn four threads */ | |
145 | start(0); | |
146 | start(1); | |
147 | start(2); | |
148 | start(3); | |
149 | ||
150 | #define join(tid) \ | |
151 | /* load pthread_t value in JIT_R0 */ \ | |
152 | jit_movi(JIT_R0, (jit_word_t)tids); \ | |
79bfeef6 PC |
153 | if (__WORDSIZE == 64 && sizeof(pthread_t) == 4) \ |
154 | jit_ldxi_i(JIT_R0, JIT_R0, tid * sizeof(pthread_t)); \ | |
155 | else \ | |
156 | jit_ldxi(JIT_R0, JIT_R0, tid * sizeof(pthread_t)); \ | |
ba3814c1 PC |
157 | jit_prepare(); \ |
158 | jit_pushargr(JIT_R0); \ | |
159 | jit_pushargi((jit_word_t)NULL); \ | |
160 | jit_finishi(pthread_join); | |
161 | /* wait for threads to finish */ | |
162 | join(0); | |
163 | join(1); | |
164 | join(2); | |
165 | join(3); | |
166 | ||
167 | jit_prepare(); | |
168 | jit_pushargi((jit_word_t)"ok"); | |
169 | jit_finishi(puts); | |
170 | ||
171 | jit_ret(); | |
172 | jit_epilog(); | |
173 | ||
174 | code = jit_emit(); | |
175 | ||
c0c16242 | 176 | #if DEBUG |
ba3814c1 PC |
177 | jit_disassemble(); |
178 | #endif | |
179 | ||
180 | jit_clear_state(); | |
181 | ||
182 | /* let first thread acquire the lock */ | |
183 | lock = 0; | |
184 | ||
185 | (*code)(); | |
186 | jit_destroy_state(); | |
187 | ||
188 | finish_jit(); | |
189 | ||
190 | return (0); | |
191 | } |