aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2013-09-08 17:37:37 +0000
committerLRN <lrn1986@gmail.com>2013-09-08 17:37:37 +0000
commit8171f4b6fc461182023f2f3ffaa82e52d2561b44 (patch)
treea035b9784d029d5db52f538d58070215506a3dc5 /src/util
parent294d9ff5696c57f64f9e42109f387d28afbebb03 (diff)
downloadgnunet-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.c46
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 {