git subrepo pull --force deps/lightning
[pcsx_rearmed.git] / deps / lightning / check / catomic.c
1 #include <lightning.h>
2 #include <pthread.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6
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
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;
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);                        \
76     jit_movi(JIT_V1, 0);                                        \
77     jit_movi(JIT_V2, line);                                     \
78     /* spin until get the lock */                               \
79     DEBUG_SPIN();                                               \
80     label = jit_label();                                        \
81     jit_casr(JIT_R0, JIT_V0, JIT_V1, JIT_V2);                   \
82     jit_patch_at(jit_beqi(JIT_R0, 0), label);                   \
83     /* lock acquired */                                         \
84     DEBUG_LOCK();                                               \
85     jit_prepare();                                              \
86     /* pretend to be doing something useful for 0.01 sec
87      * while holding the lock */                                \
88     jit_pushargi(10000);                                        \
89     jit_finishi(usleep);                                        \
90     /* release lock */                                          \
91     DEBUG_UNLOCK();                                             \
92     jit_movi(JIT_V1, 0);                                        \
93     jit_str(JIT_V0, JIT_V1);                                    \
94     /* Now test casi */                                         \
95     jit_movi(JIT_V1, 0);                                        \
96     jit_movi(JIT_V2, line);                                     \
97     /* spin until get the lock */                               \
98     DEBUG_SPIN();                                               \
99     label = jit_label();                                        \
100     jit_casi(JIT_R0, (jit_word_t)&lock, JIT_V1, JIT_V2);        \
101     jit_patch_at(jit_beqi(JIT_R0, 0), label);                   \
102     /* lock acquired */                                         \
103     DEBUG_LOCK();                                               \
104     jit_prepare();                                              \
105     /* pretend to be doing something useful for 0.01 sec
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 */                                          \
115     DEBUG_UNLOCK();                                             \
116     jit_movi(JIT_V1, 0);                                        \
117     jit_str(JIT_V0, JIT_V1);                                    \
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);                         \
153     jit_ldxi(JIT_R0, JIT_R0, tid * sizeof(pthread_t));          \
154     jit_prepare();                                              \
155     jit_pushargr(JIT_R0);                                       \
156     jit_pushargi((jit_word_t)NULL);                             \
157     jit_finishi(pthread_join);
158     /* wait for threads to finish */
159     join(0);
160     join(1);
161     join(2);
162     join(3);
163
164     jit_prepare();
165     jit_pushargi((jit_word_t)"ok");
166     jit_finishi(puts);
167
168     jit_ret();
169     jit_epilog();
170
171     code = jit_emit();
172
173 #if DEBUG
174     jit_disassemble();
175 #endif
176
177     jit_clear_state();
178
179     /* let first thread acquire the lock */
180     lock = 0;
181     
182     (*code)();
183     jit_destroy_state();
184
185     finish_jit();
186
187     return (0);
188 }