aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2012-10-25 19:37:32 +0000
committerLRN <lrn1986@gmail.com>2012-10-25 19:37:32 +0000
commit7241118c298760e054ecd66a1436a63926fa4172 (patch)
tree77097b53ece1a34cb972550130d7b3d0a762414b
parent86d07616fcf20cb2d10d9ebe9e0d695d7a727a10 (diff)
downloadgnunet-7241118c298760e054ecd66a1436a63926fa4172.tar.gz
gnunet-7241118c298760e054ecd66a1436a63926fa4172.zip
bratao: W32: Optimize ..._select() implementation
Begin with a quick sequential check of sockets and pipes, and bail out if something is selected already, or if timeout is zero, avoiding overhead of setting up all the stuff necessary to sleep until either a socket or a pipe wakes us up.
-rw-r--r--src/util/network.c197
1 files changed, 194 insertions, 3 deletions
diff --git a/src/util/network.c b/src/util/network.c
index 86bc47677..491e4fffd 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1221,6 +1221,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1221 struct GNUNET_CONTAINER_SList *handles_write; 1221 struct GNUNET_CONTAINER_SList *handles_write;
1222 struct GNUNET_CONTAINER_SList *handles_except; 1222 struct GNUNET_CONTAINER_SList *handles_except;
1223 1223
1224 int selectret = 0;
1225
1224 fd_set aread; 1226 fd_set aread;
1225 fd_set awrite; 1227 fd_set awrite;
1226 fd_set aexcept; 1228 fd_set aexcept;
@@ -1364,6 +1366,196 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1364 select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL); 1366 select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL);
1365 } 1367 }
1366 1368
1369
1370 handles_read = GNUNET_CONTAINER_slist_create ();
1371 handles_write = GNUNET_CONTAINER_slist_create ();
1372 handles_except = GNUNET_CONTAINER_slist_create ();
1373 FD_ZERO (&aread);
1374 FD_ZERO (&awrite);
1375 FD_ZERO (&aexcept);
1376#if DEBUG_NETWORK
1377 FD_ZERO (&bread);
1378 FD_ZERO (&bwrite);
1379 FD_ZERO (&bexcept);
1380#endif
1381 if (rfds)
1382 {
1383 FD_COPY (&rfds->sds, &aread);
1384#if DEBUG_NETWORK
1385 FD_COPY (&rfds->sds, &bread);
1386#endif
1387 }
1388 if (wfds)
1389 {
1390 FD_COPY (&wfds->sds, &awrite);
1391#if DEBUG_NETWORK
1392 FD_COPY (&wfds->sds, &bwrite);
1393#endif
1394 }
1395 if (efds)
1396 {
1397 FD_COPY (&efds->sds, &aexcept);
1398#if DEBUG_NETWORK
1399 FD_COPY (&efds->sds, &bexcept);
1400#endif
1401 }
1402
1403 /* Start by doing a fast check on sockets and pipes (without waiting). It is cheap, and is sufficient most of the time.
1404 By profiling we detected that to be true in 90% of the cases.
1405 */
1406
1407 /* Do the select now */
1408 select_timeout.tv_sec = 0;
1409 select_timeout.tv_usec = 0;
1410
1411 /* Copy all the writes to the except, so we can detect connect() errors */
1412 for (i = 0; i < awrite.fd_count; i++)
1413 {
1414 if (awrite.fd_array[i] != 0 && awrite.fd_array[i] != -1)
1415 FD_SET (awrite.fd_array[i], &aexcept);
1416 }
1417 if (aread.fd_count > 0 || awrite.fd_count > 0 || aexcept.fd_count > 0)
1418 selectret = select (1, (rfds != NULL) ? &aread : NULL,
1419 (wfds != NULL) ? &awrite : NULL, &aexcept, &select_timeout);
1420 else
1421 selectret = 0;
1422 if (selectret == -1)
1423 {
1424 /* Throw an error early on, while we still have the context. */
1425 LOG (GNUNET_ERROR_TYPE_ERROR, "W32 select(%d, %d, %d) failed: %lu\n",
1426 rfds ? aread.fd_count : 0, wfds ? awrite.fd_count : 0, aexcept.fd_count, GetLastError ());
1427 GNUNET_abort ();
1428 }
1429
1430 /* Check aexcept, add its contents to awrite
1431 This is technically wrong (aexcept might have its own descriptors), we should
1432 have checked that descriptors were in awrite originally before re-adding them from
1433 aexcept. Luckily, GNUnet never uses aexcept for anything, so this does not become a problem (yet). */
1434 for (i = 0; i < aexcept.fd_count; i++)
1435 {
1436 if (aexcept.fd_array[i] != 0 && aexcept.fd_array[i] != -1)
1437 FD_SET (aexcept.fd_array[i], &awrite);
1438 }
1439
1440 /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */
1441 /* Sadly, it means code duplication :( */
1442 if ((selectret > 0) || (ms_total == 0))
1443 {
1444 /* Read Pipes */
1445 if (rfds && read_handles)
1446 {
1447 struct GNUNET_CONTAINER_SList_Iterator i;
1448
1449 for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1450 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1451 GNUNET_CONTAINER_slist_next (&i))
1452 {
1453 struct GNUNET_DISK_FileHandle *fh;
1454
1455 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,NULL);
1456 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1457 {
1458 DWORD error;
1459 BOOL bret;
1460
1461 SetLastError (0);
1462 DWORD waitstatus = 0;
1463 bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
1464 error = GetLastError ();
1465 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
1466 i, fh->h, bret, waitstatus, error);
1467 if (bret == 0)
1468 {
1469 /* TODO: either add more errors to this condition, or eliminate it
1470 * entirely (failed to peek -> pipe is in serious trouble, should
1471 * be selected as readable).
1472 */
1473 if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
1474 continue;
1475 }
1476 else if (waitstatus <= 0)
1477 continue;
1478 GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1479 fh, sizeof (struct GNUNET_DISK_FileHandle));
1480 retcode++;
1481 LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
1482 fh, fh->h);
1483 }
1484 else
1485 {
1486 GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1487 fh, sizeof (struct GNUNET_DISK_FileHandle));
1488 retcode++;
1489 }
1490 }
1491 }
1492 if (wfds && write_handles)
1493 {
1494 LOG (GNUNET_ERROR_TYPE_DEBUG,
1495 "Adding the write ready event to the array as %d\n", nhandles);
1496 GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
1497 retcode += write_handles;
1498 }
1499 if (efds && ex_handles)
1500 {
1501 struct GNUNET_CONTAINER_SList_Iterator i;
1502
1503 for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
1504 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1505 GNUNET_CONTAINER_slist_next (&i))
1506 {
1507 struct GNUNET_DISK_FileHandle *fh;
1508 DWORD dwBytes;
1509
1510 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL);
1511 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1512 {
1513 if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1514 continue;
1515 GNUNET_CONTAINER_slist_add (handles_except, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1516 fh, sizeof (struct GNUNET_DISK_FileHandle));
1517 retcode++;
1518 }
1519 }
1520 }
1521
1522 /* Add our select() result.*/
1523 if (selectret >= 0)
1524 retcode += selectret;
1525
1526 if (rfds)
1527 {
1528 GNUNET_NETWORK_fdset_zero (rfds);
1529 if (selectret != -1)
1530 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret);
1531 GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1532 }
1533 if (wfds)
1534 {
1535 GNUNET_NETWORK_fdset_zero (wfds);
1536 if (selectret != -1)
1537 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret);
1538 GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1539 }
1540 if (efds)
1541 {
1542 GNUNET_NETWORK_fdset_zero (efds);
1543 if (selectret != -1)
1544 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret);
1545 GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1546 }
1547 GNUNET_CONTAINER_slist_destroy (handles_read);
1548 GNUNET_CONTAINER_slist_destroy (handles_write);
1549 GNUNET_CONTAINER_slist_destroy (handles_except);
1550
1551 if (selectret == -1)
1552 return -1;
1553 return retcode;
1554 }
1555
1556 /* If we got this far, use slower implementation that is able to do a waiting select
1557 on both sockets and pipes simultaneously */
1558
1367 /* Events for pipes */ 1559 /* Events for pipes */
1368 if (!hEventReadReady) 1560 if (!hEventReadReady)
1369 hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); 1561 hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
@@ -1372,9 +1564,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1372 readPipes = 0; 1564 readPipes = 0;
1373 writePipePos = -1; 1565 writePipePos = -1;
1374 1566
1375 handles_read = GNUNET_CONTAINER_slist_create (); 1567 retcode = 0;
1376 handles_write = GNUNET_CONTAINER_slist_create (); 1568
1377 handles_except = GNUNET_CONTAINER_slist_create ();
1378 FD_ZERO (&aread); 1569 FD_ZERO (&aread);
1379 FD_ZERO (&awrite); 1570 FD_ZERO (&awrite);
1380 FD_ZERO (&aexcept); 1571 FD_ZERO (&aexcept);