Merge branch 'test-ip_mreq_source-android-only' into 'master'
[glib.git] / glib / tests / gpoll.c
blob58656d3f118f92971d7d7314bac8efbd1f3a03e2
1 /* Unit test for W32 version of g_poll()
3 * Copyright © 2017 Руслан Ижбулатов <lrn1986@gmail.com>
5 * This is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include <glib.h>
20 #include <Winsock2.h>
22 #define NUM_POLLEES 63
23 #define NUM_POLLFDS 64
25 #define ASYNC_CONNECT_OK(r) (r == 0 || (r < 0 && GetLastError () == WSAEWOULDBLOCK))
27 #define REPEAT 1000
29 static void
30 init_networking (void)
32 WSADATA wsadata;
34 if (WSAStartup (MAKEWORD (2, 0), &wsadata) != 0)
35 g_error ("Windows Sockets could not be initialized");
38 static void
39 prepare_fds (SOCKET sockets[],
40 GPollFD fds[],
41 int num_pollees)
43 gint i;
45 for (i = 0; i < num_pollees; i++)
47 fds[i].fd = (gintptr) WSACreateEvent ();
48 g_assert (WSAEventSelect (sockets[i], (HANDLE) fds[i].fd, FD_READ | FD_CLOSE) == 0);
52 static void
53 reset_fds (GPollFD fds[],
54 int num_pollees)
56 gint i;
58 for (i = 0; i < num_pollees; i++)
60 WSAResetEvent ((HANDLE) fds[i].fd);
61 fds[i].events = G_IO_IN | G_IO_OUT | G_IO_ERR;
62 fds[i].revents = 0;
66 static void
67 reset_fds_msg (GPollFD fds[],
68 int num_pollfds)
70 fds[num_pollfds - 1].fd = G_WIN32_MSG_HANDLE;
71 fds[num_pollfds - 1].events = G_IO_IN;
72 fds[num_pollfds - 1].revents = 0;
75 static void
76 check_fds (SOCKET sockets[],
77 GPollFD fds[],
78 int num_pollees)
80 gint i;
82 for (i = 0; i < num_pollees; i++)
84 if (fds[i].revents != 0)
86 WSANETWORKEVENTS events;
87 g_assert (WSAEnumNetworkEvents (sockets[i], 0, &events) == 0);
89 fds[i].revents = 0;
90 if (events.lNetworkEvents & (FD_READ | FD_ACCEPT))
91 fds[i].revents |= G_IO_IN;
93 if (events.lNetworkEvents & FD_WRITE)
94 fds[i].revents |= G_IO_OUT;
95 else
97 /* We have called WSAEnumNetworkEvents() above but it didn't
98 * set FD_WRITE.
100 if (events.lNetworkEvents & FD_CONNECT)
102 if (events.iErrorCode[FD_CONNECT_BIT] == 0)
103 fds[i].revents |= G_IO_OUT;
104 else
105 fds[i].revents |= (G_IO_HUP | G_IO_ERR);
107 if (fds[i].revents == 0 && (events.lNetworkEvents & (FD_CLOSE)))
108 fds[i].revents |= G_IO_HUP;
114 static void
115 prepare_sockets (SOCKET sockets[],
116 SOCKET opp_sockets[],
117 GPollFD fds[],
118 int num_pollees)
120 gint i;
121 SOCKET server;
122 struct sockaddr_in sa;
123 unsigned long ul = 1;
124 int sa_size;
125 int r;
127 server = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
128 g_assert (server != INVALID_SOCKET);
130 memset(&sa, 0, sizeof sa);
132 sa.sin_family = AF_INET;
133 sa.sin_port = 0;
134 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
135 sa_size = sizeof (sa);
137 g_assert (bind (server, (const struct sockaddr *) &sa, sa_size) == 0);
138 g_assert (getsockname (server, (struct sockaddr *) &sa, &sa_size) == 0);
139 g_assert (listen (server, 1) == 0);
141 for (i = 0; i < num_pollees; i++)
143 opp_sockets[i] = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
144 g_assert (opp_sockets[i] != INVALID_SOCKET);
145 g_assert (ioctlsocket (opp_sockets[i], FIONBIO, &ul) == 0);
147 r = connect (opp_sockets[i], (const struct sockaddr *) &sa, sizeof (sa));
148 g_assert (ASYNC_CONNECT_OK (r));
150 sockets[i] = accept (server, NULL, NULL);
151 g_assert (sockets[i] != INVALID_SOCKET);
152 g_assert (ioctlsocket (sockets[i], FIONBIO, &ul) == 0);
155 closesocket (server);
158 static void
159 cleanup_sockets (SOCKET sockets[],
160 SOCKET opp_sockets[],
161 int num_pollees)
163 gint i;
165 for (i = 0; i < num_pollees; i++)
167 closesocket (sockets[i]);
168 closesocket (opp_sockets[i]);
172 static void
173 bucketize (gint64 val,
174 gint buckets[],
175 gint64 bucket_limits[],
176 gint count)
178 gint i;
180 if (val > bucket_limits[count - 1])
182 buckets[count - 1] += 1;
183 return;
186 for (i = count - 1; i > 0; i--)
187 if (val < bucket_limits[i] && val >= bucket_limits[i - 1])
189 buckets[i] += 1;
190 return;
193 buckets[0] += 1;
196 static void
197 print_buckets (gint buckets[],
198 gint64 bucket_limits[],
199 gint count)
201 gint i;
203 for (i = 0; i < count; i++)
204 if (i < count - 1)
205 g_print ("%-4lld-%4lld|", i == 0 ? 0 : bucket_limits[i - 1], bucket_limits[i] - 1);
206 else
207 g_print (" >= %-4lld|", bucket_limits[i - 1]);
209 g_print ("\n");
211 for (i = 0; i < count; i++)
213 gint len;
214 gint padding;
215 gint j;
216 if (buckets[i] < 10)
217 len = 1;
218 else if (buckets[i] < 100)
219 len = 2;
220 else if (buckets[i] < 1000)
221 len = 3;
222 else
223 len = 4;
224 padding = 9 - len;
225 for (j = 0; j < padding / 2; j++)
226 g_print (" ");
227 if (buckets[i] != 0)
228 g_print ("%*d", len, buckets[i]);
229 else
230 g_print (" ");
231 for (j = padding / 2; j < padding; j++)
232 g_print (" ");
233 g_print (" ");
236 g_print ("\n\n");
239 static void
240 test_gpoll (void)
242 SOCKET sockets[NUM_POLLEES];
243 GPollFD fds[NUM_POLLFDS];
244 SOCKET opp_sockets[NUM_POLLEES];
245 gint i;
246 gint activatable;
247 gint64 times[REPEAT][2];
248 #define BUCKET_COUNT 25
249 gint64 bucket_limits[BUCKET_COUNT] = {3, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100, 120, 150, 180, 220, 280, 350, 450, 600, 800, 1000};
250 gint buckets[BUCKET_COUNT];
251 gint64 times_avg = 0, times_min = G_MAXINT64, times_max = 0;
253 prepare_sockets (sockets, opp_sockets, fds, NUM_POLLEES);
254 prepare_fds (sockets, fds, NUM_POLLEES);
256 times_avg = 0;
257 times_min = G_MAXINT64;
258 times_max = 0;
259 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
261 for (i = 0; i < REPEAT; i++)
263 gint r;
264 gint64 diff;
266 reset_fds (fds, NUM_POLLEES);
267 reset_fds_msg (fds, NUM_POLLFDS);
268 times[i][0] = g_get_monotonic_time ();
269 r = g_poll (fds, NUM_POLLFDS, 0);
270 times[i][1] = g_get_monotonic_time ();
271 g_assert (r == 0);
272 diff = times[i][1] - times[i][0];
273 if (times_min > diff)
274 times_min = diff;
275 if (times_max < diff)
276 times_max = diff;
277 times_avg += diff;
278 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
281 times_avg /= NUM_POLLEES;
282 g_print ("\nempty poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
283 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
285 times_avg = 0;
286 times_min = G_MAXINT64;
287 times_max = 0;
288 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
290 activatable = 0;
292 for (i = 0; i < REPEAT; i++)
294 gint r, s, v, t;
295 gint64 diff;
296 MSG msg;
297 gboolean found_app;
299 reset_fds (fds, NUM_POLLEES);
300 reset_fds_msg (fds, NUM_POLLFDS);
301 s = send (opp_sockets[activatable], (const char *) &t, 1, 0);
302 g_assert (PostMessage (NULL, WM_APP, 1, 2));
303 /* This is to ensure that all sockets catch up, otherwise some might not poll active */
304 g_usleep (G_USEC_PER_SEC / 1000);
306 times[i][0] = g_get_monotonic_time ();
307 r = g_poll (fds, NUM_POLLFDS, 1000);
308 times[i][1] = g_get_monotonic_time ();
310 check_fds (sockets, fds, NUM_POLLEES);
311 v = recv (sockets[activatable], (char *) &t, 1, 0);
312 found_app = FALSE;
313 while (!found_app && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
314 if (msg.message == WM_APP && msg.wParam == 1 && msg.lParam == 2)
315 found_app = TRUE;
316 g_assert (s == 1);
317 g_assert (r == 2);
318 g_assert (v == 1);
319 g_assert (found_app);
321 reset_fds (fds, NUM_POLLEES);
322 reset_fds_msg (fds, NUM_POLLFDS);
323 r = g_poll (fds, NUM_POLLFDS, 0);
324 check_fds (sockets, fds, NUM_POLLEES);
325 g_assert (r == 0);
326 diff = times[i][1] - times[i][0];
327 if (times_min > diff)
328 times_min = diff;
329 if (times_max < diff)
330 times_max = diff;
331 times_avg += diff;
332 activatable = (activatable + 1) % NUM_POLLEES;
333 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
336 times_avg /= NUM_POLLEES;
337 g_print ("1-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
338 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
340 times_avg = 0;
341 times_min = G_MAXINT64;
342 times_max = 0;
343 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
345 activatable = 0;
347 for (i = 0; i < REPEAT; i++)
349 gint r, s, v, t;
350 gint64 diff;
352 reset_fds (fds, NUM_POLLEES);
353 reset_fds_msg (fds, NUM_POLLFDS);
354 s = send (opp_sockets[activatable], (const char *) &t, 1, 0);
356 g_usleep (G_USEC_PER_SEC / 1000);
358 times[i][0] = g_get_monotonic_time ();
359 r = g_poll (fds, NUM_POLLFDS, 1000);
360 times[i][1] = g_get_monotonic_time ();
362 check_fds (sockets, fds, NUM_POLLEES);
363 v = recv (sockets[activatable], (char *) &t, 1, 0);
364 g_assert (s == 1);
365 g_assert (r == 1);
366 g_assert (v == 1);
368 reset_fds (fds, NUM_POLLEES);
369 reset_fds_msg (fds, NUM_POLLFDS);
370 r = g_poll (fds, NUM_POLLFDS, 0);
371 check_fds (sockets, fds, NUM_POLLEES);
372 g_assert (r == 0);
374 diff = times[i][1] - times[i][0];
375 if (times_min > diff)
376 times_min = diff;
377 if (times_max < diff)
378 times_max = diff;
379 times_avg += diff;
380 activatable = (activatable + 1) % NUM_POLLEES;
381 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
384 times_avg /= NUM_POLLEES;
385 g_print ("1-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
386 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
388 times_avg = 0;
389 times_min = G_MAXINT64;
390 times_max = 0;
391 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
393 for (i = 0; i < REPEAT; i++)
395 gint r, s, v, t;
396 gint64 diff;
397 gint j;
399 reset_fds (fds, NUM_POLLEES);
400 reset_fds_msg (fds, NUM_POLLFDS);
401 s = v = 0;
403 for (j = 0; j < NUM_POLLEES / 2; j++)
404 s += send (opp_sockets[j], (const char *) &t, 1, 0) == 1 ? 1 : 0;
406 g_usleep (G_USEC_PER_SEC / 1000);
408 times[i][0] = g_get_monotonic_time ();
409 r = g_poll (fds, NUM_POLLFDS, 1000);
410 times[i][1] = g_get_monotonic_time ();
411 check_fds (sockets, fds, NUM_POLLEES);
412 for (j = 0; j < NUM_POLLEES / 2; j++)
413 v += recv (sockets[j], (char *) &t, 1, 0) == 1 ? 1 : 0;
414 g_assert (s == NUM_POLLEES / 2);
415 g_assert (r == NUM_POLLEES / 2);
416 g_assert (v == NUM_POLLEES / 2);
418 reset_fds (fds, NUM_POLLEES);
419 reset_fds_msg (fds, NUM_POLLFDS);
420 r = g_poll (fds, NUM_POLLFDS, 0);
421 check_fds (sockets, fds, NUM_POLLEES);
422 g_assert (r == 0);
424 diff = times[i][1] - times[i][0];
425 if (times_min > diff)
426 times_min = diff;
427 if (times_max < diff)
428 times_max = diff;
429 times_avg += diff;
430 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
433 times_avg /= NUM_POLLEES;
434 g_print ("half-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
435 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
437 times_avg = 0;
438 times_min = G_MAXINT64;
439 times_max = 0;
440 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
442 for (i = 0; i < REPEAT; i++)
444 gint r, s, v, t;
445 gint64 diff;
446 gint j;
447 MSG msg;
448 gboolean found_app;
450 reset_fds (fds, NUM_POLLEES);
451 reset_fds_msg (fds, NUM_POLLFDS);
452 s = v = 0;
454 for (j = 0; j < NUM_POLLEES / 2; j++)
455 s += send (opp_sockets[j], (const char *) &t, 1, 0) == 1 ? 1 : 0;
456 g_assert (PostMessage (NULL, WM_APP, 1, 2));
458 /* This is to ensure that all sockets catch up, otherwise some might not poll active */
459 g_usleep (G_USEC_PER_SEC / 1000);
461 times[i][0] = g_get_monotonic_time ();
462 r = g_poll (fds, NUM_POLLFDS, 1000);
463 times[i][1] = g_get_monotonic_time ();
464 check_fds (sockets, fds, NUM_POLLEES);
465 for (j = 0; j < NUM_POLLEES / 2; j++)
466 v += recv (sockets[j], (char *) &t, 1, 0) == 1 ? 1 : 0;
467 found_app = FALSE;
468 while (!found_app && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
469 if (msg.message == WM_APP && msg.wParam == 1 && msg.lParam == 2)
470 found_app = TRUE;
471 g_assert (s == NUM_POLLEES / 2);
472 g_assert (r == NUM_POLLEES / 2 + 1);
473 g_assert (v == NUM_POLLEES / 2);
474 g_assert (found_app);
476 reset_fds (fds, NUM_POLLEES);
477 reset_fds_msg (fds, NUM_POLLFDS);
478 r = g_poll (fds, NUM_POLLFDS, 0);
479 check_fds (sockets, fds, NUM_POLLEES);
480 g_assert (r == 0);
482 diff = times[i][1] - times[i][0];
483 if (times_min > diff)
484 times_min = diff;
485 if (times_max < diff)
486 times_max = diff;
487 times_avg += diff;
488 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
491 times_avg /= NUM_POLLEES;
492 g_print ("half-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
493 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
495 times_avg = 0;
496 times_min = G_MAXINT64;
497 times_max = 0;
498 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
500 for (i = 0; i < REPEAT; i++)
502 gint r, s, v, t;
503 gint64 diff;
504 gint j;
506 reset_fds (fds, NUM_POLLEES);
507 reset_fds_msg (fds, NUM_POLLFDS);
508 s = v = 0;
510 for (j = 0; j < NUM_POLLEES; j++)
511 s += send (opp_sockets[j], (const char *) &t, 1, 0) == 1 ? 1 : 0;
513 g_usleep (G_USEC_PER_SEC / 1000);
515 times[i][0] = g_get_monotonic_time ();
516 r = g_poll (fds, NUM_POLLFDS, 1000);
517 times[i][1] = g_get_monotonic_time ();
518 check_fds (sockets, fds, NUM_POLLEES);
519 for (j = 0; j < NUM_POLLEES; j++)
520 v += recv (sockets[j], (char *) &t, 1, 0) == 1 ? 1 : 0;
521 g_assert (s == NUM_POLLEES);
522 g_assert (r == NUM_POLLEES);
523 g_assert (v == NUM_POLLEES);
525 reset_fds (fds, NUM_POLLEES);
526 reset_fds_msg (fds, NUM_POLLFDS);
527 r = g_poll (fds, NUM_POLLFDS, 0);
528 check_fds (sockets, fds, NUM_POLLEES);
529 g_assert (r == 0);
531 diff = times[i][1] - times[i][0];
532 if (times_min > diff)
533 times_min = diff;
534 if (times_max < diff)
535 times_max = diff;
536 times_avg += diff;
537 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
540 times_avg /= NUM_POLLEES;
541 g_print ("%d-socket poll time: \n%4lldns - %4lldns, average %4lldns\n", NUM_POLLEES, times_min, times_max, times_avg);
542 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
544 activatable = 0;
545 times_avg = 0;
546 times_min = G_MAXINT64;
547 times_max = 0;
548 memset (buckets, 0, sizeof (gint) * BUCKET_COUNT);
550 for (i = 0; i < REPEAT; i++)
552 gint r, s, v, t;
553 gint64 diff;
554 gint j;
555 MSG msg;
556 gboolean found_app;
558 reset_fds (fds, NUM_POLLEES);
559 reset_fds_msg (fds, NUM_POLLFDS);
560 s = v = 0;
562 for (j = 0; j < activatable; j++)
563 s += send (opp_sockets[j], (const char *) &t, 1, 0) == 1 ? 1 : 0;
564 g_assert (PostMessage (NULL, WM_APP, 1, 2));
566 g_usleep (G_USEC_PER_SEC / 1000);
568 times[i][0] = g_get_monotonic_time ();
569 r = g_poll (fds, NUM_POLLFDS, 1000);
570 times[i][1] = g_get_monotonic_time ();
571 check_fds (sockets, fds, NUM_POLLEES);
572 for (j = 0; j < activatable; j++)
573 v += recv (sockets[j], (char *) &t, 1, 0) == 1 ? 1 : 0;
574 found_app = FALSE;
575 while (!found_app && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
576 if (msg.message == WM_APP && msg.wParam == 1 && msg.lParam == 2)
577 found_app = TRUE;
578 g_assert (s == activatable);
579 g_assert (r == activatable + 1);
580 g_assert (v == activatable);
581 g_assert (found_app);
583 reset_fds (fds, NUM_POLLEES);
584 reset_fds_msg (fds, NUM_POLLFDS);
585 r = g_poll (fds, NUM_POLLFDS, 0);
586 check_fds (sockets, fds, NUM_POLLEES);
587 g_assert (r == 0);
589 diff = times[i][1] - times[i][0];
590 if (times_min > diff)
591 times_min = diff;
592 if (times_max < diff)
593 times_max = diff;
594 times_avg += diff;
595 bucketize (diff, buckets, bucket_limits, BUCKET_COUNT);
596 activatable = (activatable + 1) % NUM_POLLEES;
599 times_avg /= NUM_POLLEES;
600 g_print ("variable socket number + msg poll time: \n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg);
601 print_buckets (buckets, bucket_limits, BUCKET_COUNT);
603 cleanup_sockets (sockets, opp_sockets, NUM_POLLEES);
607 main (int argc,
608 char *argv[])
610 int result;
611 GMainContext *ctx;
613 g_test_init (&argc, &argv, NULL);
614 init_networking ();
615 ctx = g_main_context_new ();
617 g_test_add_func ("/gpoll/gpoll", test_gpoll);
619 result = g_test_run ();
621 g_main_context_unref (ctx);
623 return result;