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/>.
22 #define NUM_POLLEES 63
23 #define NUM_POLLFDS 64
25 #define ASYNC_CONNECT_OK(r) (r == 0 || (r < 0 && GetLastError () == WSAEWOULDBLOCK))
30 init_networking (void)
34 if (WSAStartup (MAKEWORD (2, 0), &wsadata
) != 0)
35 g_error ("Windows Sockets could not be initialized");
39 prepare_fds (SOCKET sockets
[],
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);
53 reset_fds (GPollFD fds
[],
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
;
67 reset_fds_msg (GPollFD fds
[],
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;
76 check_fds (SOCKET sockets
[],
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);
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
;
97 /* We have called WSAEnumNetworkEvents() above but it didn't
100 if (events
.lNetworkEvents
& FD_CONNECT
)
102 if (events
.iErrorCode
[FD_CONNECT_BIT
] == 0)
103 fds
[i
].revents
|= G_IO_OUT
;
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
;
115 prepare_sockets (SOCKET sockets
[],
116 SOCKET opp_sockets
[],
122 struct sockaddr_in sa
;
123 unsigned long ul
= 1;
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
;
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
);
159 cleanup_sockets (SOCKET sockets
[],
160 SOCKET opp_sockets
[],
165 for (i
= 0; i
< num_pollees
; i
++)
167 closesocket (sockets
[i
]);
168 closesocket (opp_sockets
[i
]);
173 bucketize (gint64 val
,
175 gint64 bucket_limits
[],
180 if (val
> bucket_limits
[count
- 1])
182 buckets
[count
- 1] += 1;
186 for (i
= count
- 1; i
> 0; i
--)
187 if (val
< bucket_limits
[i
] && val
>= bucket_limits
[i
- 1])
197 print_buckets (gint buckets
[],
198 gint64 bucket_limits
[],
203 for (i
= 0; i
< count
; i
++)
205 g_print ("%-4lld-%4lld|", i
== 0 ? 0 : bucket_limits
[i
- 1], bucket_limits
[i
] - 1);
207 g_print (" >= %-4lld|", bucket_limits
[i
- 1]);
211 for (i
= 0; i
< count
; i
++)
218 else if (buckets
[i
] < 100)
220 else if (buckets
[i
] < 1000)
225 for (j
= 0; j
< padding
/ 2; j
++)
228 g_print ("%*d", len
, buckets
[i
]);
231 for (j
= padding
/ 2; j
< padding
; j
++)
242 SOCKET sockets
[NUM_POLLEES
];
243 GPollFD fds
[NUM_POLLFDS
];
244 SOCKET opp_sockets
[NUM_POLLEES
];
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
);
257 times_min
= G_MAXINT64
;
259 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
261 for (i
= 0; i
< REPEAT
; i
++)
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 ();
272 diff
= times
[i
][1] - times
[i
][0];
273 if (times_min
> diff
)
275 if (times_max
< 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
);
286 times_min
= G_MAXINT64
;
288 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
292 for (i
= 0; i
< REPEAT
; i
++)
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);
313 while (!found_app
&& PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
))
314 if (msg
.message
== WM_APP
&& msg
.wParam
== 1 && msg
.lParam
== 2)
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
);
326 diff
= times
[i
][1] - times
[i
][0];
327 if (times_min
> diff
)
329 if (times_max
< 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
);
341 times_min
= G_MAXINT64
;
343 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
347 for (i
= 0; i
< REPEAT
; i
++)
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);
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
);
374 diff
= times
[i
][1] - times
[i
][0];
375 if (times_min
> diff
)
377 if (times_max
< 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
);
389 times_min
= G_MAXINT64
;
391 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
393 for (i
= 0; i
< REPEAT
; i
++)
399 reset_fds (fds
, NUM_POLLEES
);
400 reset_fds_msg (fds
, NUM_POLLFDS
);
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
);
424 diff
= times
[i
][1] - times
[i
][0];
425 if (times_min
> diff
)
427 if (times_max
< 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
);
438 times_min
= G_MAXINT64
;
440 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
442 for (i
= 0; i
< REPEAT
; i
++)
450 reset_fds (fds
, NUM_POLLEES
);
451 reset_fds_msg (fds
, NUM_POLLFDS
);
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;
468 while (!found_app
&& PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
))
469 if (msg
.message
== WM_APP
&& msg
.wParam
== 1 && msg
.lParam
== 2)
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
);
482 diff
= times
[i
][1] - times
[i
][0];
483 if (times_min
> diff
)
485 if (times_max
< 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
);
496 times_min
= G_MAXINT64
;
498 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
500 for (i
= 0; i
< REPEAT
; i
++)
506 reset_fds (fds
, NUM_POLLEES
);
507 reset_fds_msg (fds
, NUM_POLLFDS
);
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
);
531 diff
= times
[i
][1] - times
[i
][0];
532 if (times_min
> diff
)
534 if (times_max
< 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
);
546 times_min
= G_MAXINT64
;
548 memset (buckets
, 0, sizeof (gint
) * BUCKET_COUNT
);
550 for (i
= 0; i
< REPEAT
; i
++)
558 reset_fds (fds
, NUM_POLLEES
);
559 reset_fds_msg (fds
, NUM_POLLFDS
);
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;
575 while (!found_app
&& PeekMessage (&msg
, NULL
, 0, 0, PM_REMOVE
))
576 if (msg
.message
== WM_APP
&& msg
.wParam
== 1 && msg
.lParam
== 2)
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
);
589 diff
= times
[i
][1] - times
[i
][0];
590 if (times_min
> diff
)
592 if (times_max
< 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
);
613 g_test_init (&argc
, &argv
, NULL
);
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
);