|
@@ -1501,13 +1501,68 @@ struct cache_discarder tcp_discarder __cache_discarder ( CACHE_NORMAL ) = {
|
1501
|
1501
|
.discard = tcp_discard,
|
1502
|
1502
|
};
|
1503
|
1503
|
|
|
1504
|
+/**
|
|
1505
|
+ * Find first TCP connection that has not yet been closed
|
|
1506
|
+ *
|
|
1507
|
+ * @ret tcp First unclosed connection, or NULL
|
|
1508
|
+ */
|
|
1509
|
+static struct tcp_connection * tcp_first_unclosed ( void ) {
|
|
1510
|
+ struct tcp_connection *tcp;
|
|
1511
|
+
|
|
1512
|
+ /* Find first connection which has not yet been closed */
|
|
1513
|
+ list_for_each_entry ( tcp, &tcp_conns, list ) {
|
|
1514
|
+ if ( ! ( tcp->flags & TCP_XFER_CLOSED ) )
|
|
1515
|
+ return tcp;
|
|
1516
|
+ }
|
|
1517
|
+ return NULL;
|
|
1518
|
+}
|
|
1519
|
+
|
|
1520
|
+/**
|
|
1521
|
+ * Find first TCP connection that has not yet finished all operations
|
|
1522
|
+ *
|
|
1523
|
+ * @ret tcp First unfinished connection, or NULL
|
|
1524
|
+ */
|
|
1525
|
+static struct tcp_connection * tcp_first_unfinished ( void ) {
|
|
1526
|
+ struct tcp_connection *tcp;
|
|
1527
|
+
|
|
1528
|
+ /* Find first connection which has not yet closed gracefully,
|
|
1529
|
+ * or which still has a pending transmission (e.g. to ACK the
|
|
1530
|
+ * received FIN).
|
|
1531
|
+ */
|
|
1532
|
+ list_for_each_entry ( tcp, &tcp_conns, list ) {
|
|
1533
|
+ if ( ( ! TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) ||
|
|
1534
|
+ process_running ( &tcp->process ) ) {
|
|
1535
|
+ return tcp;
|
|
1536
|
+ }
|
|
1537
|
+ }
|
|
1538
|
+ return NULL;
|
|
1539
|
+}
|
|
1540
|
+
|
1504
|
1541
|
/**
|
1505
|
1542
|
* Shut down all TCP connections
|
1506
|
1543
|
*
|
1507
|
1544
|
*/
|
1508
|
1545
|
static void tcp_shutdown ( int booting __unused ) {
|
1509
|
1546
|
struct tcp_connection *tcp;
|
|
1547
|
+ unsigned long start;
|
|
1548
|
+ unsigned long elapsed;
|
|
1549
|
+
|
|
1550
|
+ /* Initiate a graceful close of all connections, allowing for
|
|
1551
|
+ * the fact that the connection list may change as we do so.
|
|
1552
|
+ */
|
|
1553
|
+ while ( ( tcp = tcp_first_unclosed() ) ) {
|
|
1554
|
+ DBGC ( tcp, "TCP %p closing for shutdown\n", tcp );
|
|
1555
|
+ tcp_close ( tcp, -ECANCELED );
|
|
1556
|
+ }
|
|
1557
|
+
|
|
1558
|
+ /* Wait for all connections to finish closing gracefully */
|
|
1559
|
+ start = currticks();
|
|
1560
|
+ while ( ( tcp = tcp_first_unfinished() ) &&
|
|
1561
|
+ ( ( elapsed = ( currticks() - start ) ) < TCP_FINISH_TIMEOUT )){
|
|
1562
|
+ step();
|
|
1563
|
+ }
|
1510
|
1564
|
|
|
1565
|
+ /* Forcibly close any remaining connections */
|
1511
|
1566
|
while ( ( tcp = list_first_entry ( &tcp_conns, struct tcp_connection,
|
1512
|
1567
|
list ) ) != NULL ) {
|
1513
|
1568
|
tcp->tcp_state = TCP_CLOSED;
|
|
@@ -1517,7 +1572,7 @@ static void tcp_shutdown ( int booting __unused ) {
|
1517
|
1572
|
}
|
1518
|
1573
|
|
1519
|
1574
|
/** TCP shutdown function */
|
1520
|
|
-struct startup_fn tcp_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
|
1575
|
+struct startup_fn tcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
1521
|
1576
|
.shutdown = tcp_shutdown,
|
1522
|
1577
|
};
|
1523
|
1578
|
|