diff options
author | LRN <lrn1986@gmail.com> | 2013-09-08 17:37:37 +0000 |
---|---|---|
committer | LRN <lrn1986@gmail.com> | 2013-09-08 17:37:37 +0000 |
commit | 8171f4b6fc461182023f2f3ffaa82e52d2561b44 (patch) | |
tree | a035b9784d029d5db52f538d58070215506a3dc5 /src/util | |
parent | 294d9ff5696c57f64f9e42109f387d28afbebb03 (diff) | |
download | gnunet-8171f4b6fc461182023f2f3ffaa82e52d2561b44.tar.gz gnunet-8171f4b6fc461182023f2f3ffaa82e52d2561b44.zip |
Fix timing problems in *_select() on W32
1) If timeout is < 1ms, round it up to 1ms, because WaitForMultipleObjects()
can't wait for time shorter than 1ms (0ms means "don't wait at all").
2) Read data from the wakeup socket before commanding the select thread to
start selecting. For some reason the socket would be in signalled state
by the time winsock's select() runs, even though we emptied it the last
time. So now we empty it beforehand.
This should prevent us from returning early in some cases.
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/network.c | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/src/util/network.c b/src/util/network.c index d36f49cbb..a9aa4394f 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -1274,7 +1274,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1274 | 1274 | ||
1275 | int i = 0; | 1275 | int i = 0; |
1276 | int retcode = 0; | 1276 | int retcode = 0; |
1277 | DWORD ms_total = 0; | 1277 | uint64_t mcs_total = 0; |
1278 | DWORD ms_rounded = 0; | ||
1278 | 1279 | ||
1279 | int nhandles = 0; | 1280 | int nhandles = 0; |
1280 | 1281 | ||
@@ -1383,22 +1384,23 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1383 | 1384 | ||
1384 | #else | 1385 | #else |
1385 | #define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) | 1386 | #define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) |
1386 | /* calculate how long we need to wait in milliseconds */ | 1387 | /* calculate how long we need to wait in microseconds */ |
1387 | if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) | 1388 | if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) |
1388 | ms_total = INFINITE; | 1389 | { |
1390 | mcs_total = INFINITE; | ||
1391 | ms_rounded = INFINITE; | ||
1392 | } | ||
1389 | else | 1393 | else |
1390 | { | 1394 | { |
1391 | ms_total = timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; | 1395 | mcs_total = timeout.rel_value_us / GNUNET_TIME_UNIT_MICROSECONDS.rel_value_us; |
1392 | if (timeout.rel_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us > 0xFFFFFFFFLL - 1) | 1396 | ms_rounded = (DWORD) (mcs_total / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us); |
1393 | { | 1397 | if (mcs_total > 0 && ms_rounded == 0) |
1394 | GNUNET_break (0); | 1398 | ms_rounded = 1; |
1395 | ms_total = 0xFFFFFFFF - 1; | ||
1396 | } | ||
1397 | } | 1399 | } |
1398 | /* select() may be used as a portable way to sleep */ | 1400 | /* select() may be used as a portable way to sleep */ |
1399 | if (!(rfds || wfds || efds)) | 1401 | if (!(rfds || wfds || efds)) |
1400 | { | 1402 | { |
1401 | Sleep (ms_total); | 1403 | Sleep (ms_rounded); |
1402 | return 0; | 1404 | return 0; |
1403 | } | 1405 | } |
1404 | 1406 | ||
@@ -1413,9 +1415,9 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1413 | select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL); | 1415 | select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL); |
1414 | select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL); | 1416 | select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL); |
1415 | 1417 | ||
1416 | select_wakeup_socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); | 1418 | select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); |
1417 | 1419 | ||
1418 | select_listening_socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); | 1420 | select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); |
1419 | 1421 | ||
1420 | p = 1; | 1422 | p = 1; |
1421 | res = ioctlsocket (select_wakeup_socket, FIONBIO, &p); | 1423 | res = ioctlsocket (select_wakeup_socket, FIONBIO, &p); |
@@ -1518,7 +1520,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1518 | 1520 | ||
1519 | /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */ | 1521 | /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */ |
1520 | /* Sadly, it means code duplication :( */ | 1522 | /* Sadly, it means code duplication :( */ |
1521 | if ((selectret > 0) || (ms_total == 0)) | 1523 | if ((selectret > 0) || (mcs_total == 0)) |
1522 | { | 1524 | { |
1523 | /* Read Pipes */ | 1525 | /* Read Pipes */ |
1524 | if (rfds && read_handles) | 1526 | if (rfds && read_handles) |
@@ -1781,6 +1783,10 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1781 | sp.tv = &select_timeout; | 1783 | sp.tv = &select_timeout; |
1782 | } | 1784 | } |
1783 | FD_SET (select_wakeup_socket, &aread); | 1785 | FD_SET (select_wakeup_socket, &aread); |
1786 | do | ||
1787 | { | ||
1788 | i = recv (select_wakeup_socket, (char *) &returnedpos, 1, 0); | ||
1789 | } while (i == 1); | ||
1784 | sp.r = &aread; | 1790 | sp.r = &aread; |
1785 | sp.w = &awrite; | 1791 | sp.w = &awrite; |
1786 | sp.e = &aexcept; | 1792 | sp.e = &aexcept; |
@@ -1798,17 +1804,17 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1798 | } | 1804 | } |
1799 | 1805 | ||
1800 | handle_array[nhandles] = NULL; | 1806 | handle_array[nhandles] = NULL; |
1801 | LOG (GNUNET_ERROR_TYPE_DEBUG, "nfds: %d, handles: %d, will wait: %llu ms\n", | 1807 | LOG (GNUNET_ERROR_TYPE_DEBUG, "nfds: %d, handles: %d, will wait: %llu mcs\n", |
1802 | nfds, nhandles, (unsigned long long) ms_total); | 1808 | nfds, nhandles, mcs_total); |
1803 | if (nhandles) | 1809 | if (nhandles) |
1804 | { | 1810 | { |
1805 | returncode = | 1811 | returncode = |
1806 | WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_total); | 1812 | WaitForMultipleObjects (nhandles, handle_array, FALSE, ms_rounded); |
1807 | LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", | 1813 | LOG (GNUNET_ERROR_TYPE_DEBUG, "WaitForMultipleObjects Returned : %d\n", returncode); |
1808 | returncode); | ||
1809 | } | 1814 | } |
1810 | else if (nfds > 0) | 1815 | else if (nfds > 0) |
1811 | { | 1816 | { |
1817 | GNUNET_break (0); /* This branch shouldn't actually be executed...*/ | ||
1812 | i = (int) WaitForSingleObject (select_finished_event, INFINITE); | 1818 | i = (int) WaitForSingleObject (select_finished_event, INFINITE); |
1813 | returncode = WAIT_TIMEOUT; | 1819 | returncode = WAIT_TIMEOUT; |
1814 | } | 1820 | } |
@@ -1823,11 +1829,11 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1823 | /* Don't wake up select-thread when delay is 0, it should return immediately | 1829 | /* Don't wake up select-thread when delay is 0, it should return immediately |
1824 | * and wake up by itself. | 1830 | * and wake up by itself. |
1825 | */ | 1831 | */ |
1826 | if (ms_total != 0) | 1832 | if (mcs_total != 0) |
1827 | i = send (select_send_socket, (const char *) &returnedpos, 1, 0); | 1833 | i = send (select_send_socket, (const char *) &returnedpos, 1, 0); |
1828 | i = (int) WaitForSingleObject (select_finished_event, INFINITE); | 1834 | i = (int) WaitForSingleObject (select_finished_event, INFINITE); |
1829 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished waiting for the select thread: %d %d\n", i, sp.status); | 1835 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Finished waiting for the select thread: %d %d\n", i, sp.status); |
1830 | if (ms_total != 0) | 1836 | if (mcs_total != 0) |
1831 | { | 1837 | { |
1832 | do | 1838 | do |
1833 | { | 1839 | { |