[Sockets]: Always reset internal SAEA completion when reattempting connection in...
[mono-project.git] / mono / unit-tests / test-conc-hashtable.c
bloba1e843e237ad5d73ba62352fd8d831bbd11aacae
1 /*
2 * test-conc-hashtable.c: Unit test for the concurrent hashtable.
4 * Copyright (C) 2014 Xamarin Inc
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7 */
9 #include "config.h"
11 #include "utils/mono-threads.h"
12 #include "utils/mono-conc-hashtable.h"
13 #include "utils/checked-build.h"
14 #include "metadata/w32handle.h"
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19 #include <assert.h>
21 #include <pthread.h>
23 static int
24 single_writer_single_reader (void)
26 mono_mutex_t mutex;
27 MonoConcurrentHashTable *h;
28 int res = 0;
30 mono_os_mutex_init (&mutex);
31 h = mono_conc_hashtable_new (NULL, NULL);
33 mono_os_mutex_lock (&mutex);
34 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (10), GUINT_TO_POINTER (20));
35 mono_os_mutex_unlock (&mutex);
37 mono_os_mutex_lock (&mutex);
38 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (30), GUINT_TO_POINTER (40));
39 mono_os_mutex_unlock (&mutex);
41 mono_os_mutex_lock (&mutex);
42 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (50), GUINT_TO_POINTER (60));
43 mono_os_mutex_unlock (&mutex);
45 mono_os_mutex_lock (&mutex);
46 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (2), GUINT_TO_POINTER (3));
47 mono_os_mutex_unlock (&mutex);
49 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (30)) != GUINT_TO_POINTER (40))
50 res = 1;
51 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (10)) != GUINT_TO_POINTER (20))
52 res = 2;
53 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (2)) != GUINT_TO_POINTER (3))
54 res = 3;
55 if (mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (50)) != GUINT_TO_POINTER (60))
56 res = 4;
58 mono_conc_hashtable_destroy (h);
59 mono_os_mutex_destroy (&mutex);
60 if (res)
61 printf ("SERIAL TEST FAILED %d\n", res);
62 return res;
65 static MonoConcurrentHashTable *hash;
66 static mono_mutex_t global_mutex;
68 static void*
69 pw_sr_thread (void *arg)
71 int i, idx = 1000 * GPOINTER_TO_INT (arg);
72 mono_thread_info_attach ();
74 for (i = 0; i < 1000; ++i) {
75 mono_os_mutex_lock (&global_mutex);
76 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + idx), GINT_TO_POINTER (i + 1));
77 mono_os_mutex_unlock (&global_mutex);
79 return NULL;
82 static int
83 parallel_writer_single_reader (void)
85 pthread_t a,b,c;
86 int i, j, res = 0;
88 mono_os_mutex_init (&global_mutex);
89 hash = mono_conc_hashtable_new (NULL, NULL);
91 pthread_create (&a, NULL, pw_sr_thread, GINT_TO_POINTER (1));
92 pthread_create (&b, NULL, pw_sr_thread, GINT_TO_POINTER (2));
93 pthread_create (&c, NULL, pw_sr_thread, GINT_TO_POINTER (3));
95 pthread_join (a, NULL);
96 pthread_join (b, NULL);
97 pthread_join (c, NULL);
99 for (i = 0; i < 1000; ++i) {
100 for (j = 1; j < 4; ++j) {
101 if (mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (j * 1000 + i)) != GINT_TO_POINTER (i + 1)) {
102 res = j + 1;
103 goto done;
108 done:
109 mono_conc_hashtable_destroy (hash);
110 mono_os_mutex_destroy (&global_mutex);
111 if (res)
112 printf ("PAR_WRITER_SINGLE_READER TEST FAILED %d\n", res);
113 return res;
117 static void*
118 pr_sw_thread (void *arg)
120 int i = 0, idx = 100 * GPOINTER_TO_INT (arg);
121 mono_thread_info_attach ();
123 while (i < 100) {
124 gpointer res = mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (i + idx + 1));
125 if (!res)
126 continue;
127 if (res != GINT_TO_POINTER ((i + idx) * 2 + 1))
128 return GINT_TO_POINTER (i);
129 ++i;
131 return NULL;
134 static int
135 single_writer_parallel_reader (void)
137 pthread_t a,b,c;
138 gpointer ra, rb, rc;
139 int i, res = 0;
140 ra = rb = rc = GINT_TO_POINTER (1);
142 mono_os_mutex_init (&global_mutex);
143 hash = mono_conc_hashtable_new (NULL, NULL);
145 pthread_create (&a, NULL, pr_sw_thread, GINT_TO_POINTER (0));
146 pthread_create (&b, NULL, pr_sw_thread, GINT_TO_POINTER (1));
147 pthread_create (&c, NULL, pr_sw_thread, GINT_TO_POINTER (2));
149 for (i = 0; i < 100; ++i) {
150 mono_os_mutex_lock (&global_mutex);
151 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 0 + 1), GINT_TO_POINTER ((i + 0) * 2 + 1));
152 mono_os_mutex_unlock (&global_mutex);
154 mono_os_mutex_lock (&global_mutex);
155 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 100 + 1), GINT_TO_POINTER ((i + 100) * 2 + 1));
156 mono_os_mutex_unlock (&global_mutex);
158 mono_os_mutex_lock (&global_mutex);
159 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 200 + 1), GINT_TO_POINTER ((i + 200) * 2 + 1));
160 mono_os_mutex_unlock (&global_mutex);
163 pthread_join (a, &ra);
164 pthread_join (b, &rb);
165 pthread_join (c, &rc);
166 res = GPOINTER_TO_INT (ra) + GPOINTER_TO_INT (rb) + GPOINTER_TO_INT (rc);
168 mono_conc_hashtable_destroy (hash);
169 mono_os_mutex_destroy (&global_mutex);
170 if (res)
171 printf ("SINGLE_WRITER_PAR_READER TEST FAILED %d\n", res);
172 return res;
175 int running = 1;
177 static void*
178 pw_pr_r_thread (void *arg)
180 int key, val, i;
181 mono_thread_info_attach ();
183 /* i will not be incremented as long as running is set to 1, this guarantee that
184 we loop over all the keys at least once after the writer threads have finished */
185 for (i = 0; i < 2; i += 1 - running) {
186 for (key = 1; key < 3 * 1000 + 1; key++) {
187 val = GPOINTER_TO_INT (mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (key)));
189 if (!val)
190 continue;
191 if (key != val)
192 return GINT_TO_POINTER (key);
195 return NULL;
198 static void*
199 pw_pr_w_add_thread (void *arg)
201 int i, idx = 1000 * GPOINTER_TO_INT (arg);
203 mono_thread_info_attach ();
205 for (i = idx; i < idx + 1000; i++) {
206 mono_os_mutex_lock (&global_mutex);
207 mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + 1), GINT_TO_POINTER (i + 1));
208 mono_os_mutex_unlock (&global_mutex);
210 return NULL;
213 static void*
214 pw_pr_w_del_thread (void *arg)
216 int i, idx = 1000 * GPOINTER_TO_INT (arg);
218 mono_thread_info_attach ();
220 for (i = idx; i < idx + 1000; i++) {
221 mono_os_mutex_lock (&global_mutex);
222 mono_conc_hashtable_remove (hash, GINT_TO_POINTER (i + 1));
223 mono_os_mutex_unlock (&global_mutex);
225 return NULL;
228 static int
229 parallel_writer_parallel_reader (void)
231 pthread_t wa, wb, wc, ra, rb, rc;
232 gpointer a, b, c;
233 int res = 0, i;
235 srand(time(NULL));
237 mono_os_mutex_init (&global_mutex);
238 hash = mono_conc_hashtable_new (NULL, NULL);
240 for (i = 0; i < 2; i++) {
241 running = 1;
243 pthread_create (&ra, NULL, pw_pr_r_thread, NULL);
244 pthread_create (&rb, NULL, pw_pr_r_thread, NULL);
245 pthread_create (&rc, NULL, pw_pr_r_thread, NULL);
247 switch (i) {
248 case 0:
249 pthread_create (&wa, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (0));
250 pthread_create (&wb, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (1));
251 pthread_create (&wc, NULL, pw_pr_w_add_thread, GINT_TO_POINTER (2));
252 break;
253 case 1:
254 pthread_create (&wa, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (0));
255 pthread_create (&wb, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (1));
256 pthread_create (&wc, NULL, pw_pr_w_del_thread, GINT_TO_POINTER (2));
257 break;
260 pthread_join (wa, NULL);
261 pthread_join (wb, NULL);
262 pthread_join (wc, NULL);
264 running = 0;
266 pthread_join (ra, &a);
267 pthread_join (rb, &b);
268 pthread_join (rc, &c);
270 res += GPOINTER_TO_INT (a) + GPOINTER_TO_INT (b) + GPOINTER_TO_INT (c);
273 if (res)
274 printf ("PAR_WRITER_PAR_READER TEST FAILED %d %d %d\n", GPOINTER_TO_INT (a), GPOINTER_TO_INT (b), GPOINTER_TO_INT (c));
276 mono_conc_hashtable_destroy (hash);
277 mono_os_mutex_destroy (&global_mutex);
279 return res;
282 static void G_GNUC_UNUSED
283 benchmark_conc (void)
285 MonoConcurrentHashTable *h;
286 int i, j;
288 h = mono_conc_hashtable_new (NULL, NULL);
290 for (i = 1; i < 10 * 1000; ++i) {
291 mono_conc_hashtable_insert (h, GUINT_TO_POINTER (i), GUINT_TO_POINTER (i));
295 for (j = 0; j < 100000; ++j)
296 for (i = 1; i < 10 * 105; ++i)
297 mono_conc_hashtable_lookup (h, GUINT_TO_POINTER (i));
299 mono_conc_hashtable_destroy (h);
302 static void G_GNUC_UNUSED
303 benchmark_glib (void)
305 GHashTable *h;
306 int i, j;
308 h = g_hash_table_new (NULL, NULL);
310 for (i = 1; i < 10 * 1000; ++i)
311 g_hash_table_insert (h, GUINT_TO_POINTER (i), GUINT_TO_POINTER (i));
314 for (j = 0; j < 100000; ++j)
315 for (i = 1; i < 10 * 105; ++i)
316 g_hash_table_lookup (h, GUINT_TO_POINTER (i));
318 g_hash_table_destroy (h);
321 static void
322 monotest_thread_state_init (MonoThreadUnwindState *ctx)
326 #ifdef __cplusplus
327 extern "C"
328 #endif
330 test_conc_hashtable_main (void);
333 #define monotest_setup_async_callback NULL
334 #define monotest_thread_state_init_from_sigctx NULL
335 #define monotest_thread_state_init_from_handle NULL
338 test_conc_hashtable_main (void)
340 static const MonoThreadInfoRuntimeCallbacks ticallbacks = {
341 MONO_THREAD_INFO_RUNTIME_CALLBACKS (MONO_INIT_CALLBACK, monotest)
344 int res = 0;
346 CHECKED_MONO_INIT ();
347 mono_thread_info_init (sizeof (MonoThreadInfo));
348 mono_thread_info_runtime_init (&ticallbacks);
349 #ifndef HOST_WIN32
350 mono_w32handle_init ();
351 #endif
353 mono_thread_info_attach ();
355 // benchmark_conc ();
356 // benchmark_glib ();
358 res += single_writer_single_reader ();
359 res += parallel_writer_single_reader ();
360 res += single_writer_parallel_reader ();
361 res += parallel_writer_parallel_reader ();
363 return res;