This commit is contained in:
Yi Huang 2023-12-30 08:42:09 -08:00 коммит произвёл GitHub
Родитель 71f86a563c
Коммит b59b722b12
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 115 добавлений и 261 удалений

Просмотреть файл

@ -151,9 +151,9 @@ QuicConnAlloc(
Path->IsActive = TRUE;
Connection->PathsCount = 1;
for (uint32_t i = 0; i < ARRAYSIZE(Connection->Timers); i++) {
Connection->Timers[i].Type = (QUIC_CONN_TIMER_TYPE)i;
Connection->Timers[i].ExpirationTime = UINT64_MAX;
Connection->EarliestExpirationTime = UINT64_MAX;
for (QUIC_CONN_TIMER_TYPE Type = 0; Type < QUIC_CONN_TIMER_COUNT; ++Type) {
Connection->ExpirationTimes[Type] = UINT64_MAX;
}
if (IsServer) {
@ -1119,6 +1119,21 @@ QuicConnReplaceRetiredCids(
return TRUE;
}
_IRQL_requires_max_(DISPATCH_LEVEL)
uint64_t
QuicGetEarliestExpirationTime(
_In_ const QUIC_CONNECTION* Connection
)
{
uint64_t EarliestExpirationTime = Connection->ExpirationTimes[0];
for (QUIC_CONN_TIMER_TYPE Type = 1; Type < QUIC_CONN_TIMER_COUNT; ++Type) {
if (Connection->ExpirationTimes[Type] < EarliestExpirationTime) {
EarliestExpirationTime = Connection->ExpirationTimes[Type];
}
}
return EarliestExpirationTime;
}
_IRQL_requires_max_(PASSIVE_LEVEL)
void
QuicConnTimerSetEx(
@ -1137,56 +1152,10 @@ QuicConnTimerSetEx(
(uint8_t)Type,
Delay);
//
// Find the current and new index in the timer array for this timer.
//
uint32_t NewIndex = ARRAYSIZE(Connection->Timers);
uint32_t CurIndex = 0;
for (uint32_t i = 0; i < ARRAYSIZE(Connection->Timers); ++i) {
if (Connection->Timers[i].Type == Type) {
CurIndex = i;
}
if (i < NewIndex &&
NewExpirationTime < Connection->Timers[i].ExpirationTime) {
NewIndex = i;
}
}
if (NewIndex < CurIndex) {
//
// Need to move the timer forward in the array.
//
CxPlatMoveMemory(
Connection->Timers + NewIndex + 1,
Connection->Timers + NewIndex,
sizeof(QUIC_CONN_TIMER_ENTRY) * (CurIndex - NewIndex));
Connection->Timers[NewIndex].Type = Type;
Connection->Timers[NewIndex].ExpirationTime = NewExpirationTime;
} else if (NewIndex > CurIndex + 1) {
//
// Need to move the timer back in the array. Ignore changes that
// wouldn't actually move it at all.
//
CxPlatMoveMemory(
Connection->Timers + CurIndex,
Connection->Timers + CurIndex + 1,
sizeof(QUIC_CONN_TIMER_ENTRY) * (NewIndex - CurIndex - 1));
Connection->Timers[NewIndex - 1].Type = Type;
Connection->Timers[NewIndex - 1].ExpirationTime = NewExpirationTime;
} else {
//
// Didn't move, so just update the expiration time.
//
Connection->Timers[CurIndex].ExpirationTime = NewExpirationTime;
NewIndex = CurIndex;
}
if (NewIndex == 0 || CurIndex == 0) {
//
// The first timer was updated, so make sure the timer wheel is updated.
//
Connection->ExpirationTimes[Type] = NewExpirationTime;
uint64_t NewEarliestExpirationTime = QuicGetEarliestExpirationTime(Connection);
if (NewEarliestExpirationTime != Connection->EarliestExpirationTime) {
Connection->EarliestExpirationTime = NewEarliestExpirationTime;
QuicTimerWheelUpdateConnection(&Connection->Worker->TimerWheel, Connection);
}
}
@ -1198,66 +1167,32 @@ QuicConnTimerCancel(
_In_ QUIC_CONN_TIMER_TYPE Type
)
{
for (uint32_t i = 0;
i < ARRAYSIZE(Connection->Timers) &&
Connection->Timers[i].ExpirationTime != UINT64_MAX;
++i) {
CXPLAT_DBG_ASSERT(Connection->EarliestExpirationTime <= Connection->ExpirationTimes[Type]);
if (Connection->EarliestExpirationTime == UINT64_MAX) {
//
// Find the correct timer (by type), invalidate it, and move it past all
// the other valid timers.
// No timers are currently scheduled.
//
return;
}
if (Connection->Timers[i].Type == Type) {
if (Connection->ExpirationTimes[Type] == Connection->EarliestExpirationTime) {
//
// We might be canceling the earliest timer, so we need to find the new
// expiration time for this connection.
//
Connection->ExpirationTimes[Type] = UINT64_MAX;
uint64_t NewEarliestExpirationTime = QuicGetEarliestExpirationTime(Connection);
QuicTraceEvent(
ConnCancelTimer,
"[conn][%p] Canceling %hhu",
Connection,
(uint8_t)Type);
if (Connection->Timers[i].ExpirationTime != UINT64_MAX) {
//
// Find the end of the valid timers (if any more).
//
uint32_t j = i + 1;
while (j < ARRAYSIZE(Connection->Timers) &&
Connection->Timers[j].ExpirationTime != UINT64_MAX) {
++j;
}
if (j == i + 1) {
//
// No more valid timers, just invalidate this one and leave it
// where it is.
//
Connection->Timers[i].ExpirationTime = UINT64_MAX;
} else {
//
// Move the valid timers forward and then put this timer after
// them.
//
CxPlatMoveMemory(
Connection->Timers + i,
Connection->Timers + i + 1,
sizeof(QUIC_CONN_TIMER_ENTRY) * (j - i - 1));
Connection->Timers[j - 1].Type = Type;
Connection->Timers[j - 1].ExpirationTime = UINT64_MAX;
}
if (i == 0) {
//
// The first timer was removed, so make sure the timer wheel is updated.
//
QuicTimerWheelUpdateConnection(&Connection->Worker->TimerWheel, Connection);
}
}
break;
if (NewEarliestExpirationTime != Connection->EarliestExpirationTime) {
//
// We've either found a new earliest expiration time, or there will be no timers scheduled.
//
Connection->EarliestExpirationTime = NewEarliestExpirationTime;
QuicTimerWheelUpdateConnection(&Connection->Worker->TimerWheel, Connection);
}
} else {
Connection->ExpirationTimes[Type] = UINT64_MAX;
}
}
@ -1268,66 +1203,56 @@ QuicConnTimerExpired(
_In_ uint64_t TimeNow
)
{
uint32_t i = 0;
QUIC_CONN_TIMER_ENTRY Temp[QUIC_CONN_TIMER_COUNT];
BOOLEAN FlushSendImmediate = FALSE;
while (i < ARRAYSIZE(Connection->Timers) &&
Connection->Timers[i].ExpirationTime <= TimeNow) {
Connection->Timers[i].ExpirationTime = UINT64_MAX;
++i;
}
Connection->EarliestExpirationTime = UINT64_MAX;
CXPLAT_DBG_ASSERT(i != 0);
CxPlatCopyMemory(
Temp,
Connection->Timers,
i * sizeof(QUIC_CONN_TIMER_ENTRY));
if (i < ARRAYSIZE(Connection->Timers)) {
CxPlatMoveMemory(
Connection->Timers,
Connection->Timers + i,
(QUIC_CONN_TIMER_COUNT - i) * sizeof(QUIC_CONN_TIMER_ENTRY));
CxPlatCopyMemory(
Connection->Timers + (QUIC_CONN_TIMER_COUNT - i),
Temp,
i * sizeof(QUIC_CONN_TIMER_ENTRY));
}
for (uint32_t j = 0; j < i; ++j) {
QuicTraceEvent(
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
(uint8_t)Temp[j].Type);
if (Temp[j].Type == QUIC_CONN_TIMER_ACK_DELAY) {
//
// Queue up operations for all expired timers and update the earliest expiration time
// on the fly. Note that we must not call any functions that might update the timer wheel.
//
for (QUIC_CONN_TIMER_TYPE Type = 0; Type < QUIC_CONN_TIMER_COUNT; ++Type) {
if (Connection->ExpirationTimes[Type] <= TimeNow) {
Connection->ExpirationTimes[Type] = UINT64_MAX;
QuicTraceEvent(
ConnExecTimerOper,
"[conn][%p] Execute: %u",
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
QuicSendProcessDelayedAckTimer(&Connection->Send);
FlushSendImmediate = TRUE;
} else if (Temp[j].Type == QUIC_CONN_TIMER_PACING) {
QuicTraceEvent(
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_PACING);
FlushSendImmediate = TRUE;
} else {
QUIC_OPERATION* Oper;
if ((Oper = QuicOperationAlloc(Connection->Worker, QUIC_OPER_TYPE_TIMER_EXPIRED)) != NULL) {
Oper->TIMER_EXPIRED.Type = Temp[j].Type;
QuicConnQueueOper(Connection, Oper);
} else {
(uint8_t)Type);
if (Type == QUIC_CONN_TIMER_ACK_DELAY) {
QuicTraceEvent(
AllocFailure,
"Allocation of '%s' failed. (%llu bytes)",
"expired timer operation",
0);
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
QuicSendProcessDelayedAckTimer(&Connection->Send);
FlushSendImmediate = TRUE;
} else if (Type == QUIC_CONN_TIMER_PACING) {
QuicTraceEvent(
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_PACING);
FlushSendImmediate = TRUE;
} else {
QUIC_OPERATION* Oper;
if ((Oper = QuicOperationAlloc(Connection->Worker, QUIC_OPER_TYPE_TIMER_EXPIRED)) != NULL) {
Oper->TIMER_EXPIRED.Type = Type;
QuicConnQueueOper(Connection, Oper);
} else {
//
// TODO: ideally, we should put this event back to the timer wheel
// so it can fire again later.
//
QuicTraceEvent(
AllocFailure,
"Allocation of '%s' failed. (%llu bytes)",
"expired timer operation",
0);
}
}
} else if (Connection->ExpirationTimes[Type] < Connection->EarliestExpirationTime) {
Connection->EarliestExpirationTime = Connection->ExpirationTimes[Type];
}
}

Просмотреть файл

@ -230,23 +230,6 @@ typedef enum QUIC_CONNECTION_REF {
} QUIC_CONNECTION_REF;
//
// A single timer entry on the connection.
//
typedef struct QUIC_CONN_TIMER_ENTRY {
//
// The type of timer this entry is for.
//
QUIC_CONN_TIMER_TYPE Type;
//
// The absolute time (in us) for timer expiration.
//
uint64_t ExpirationTime;
} QUIC_CONN_TIMER_ENTRY;
//
// Per connection statistics.
//
@ -508,9 +491,15 @@ typedef struct QUIC_CONNECTION {
uint8_t CibirId[2 + QUIC_MAX_CIBIR_LENGTH];
//
// Sorted array of all timers for the connection.
// Expiration time (absolute time in us) for each timer type. We use UINT64_MAX as a sentinel
// to indicate that the timer is not set.
//
QUIC_CONN_TIMER_ENTRY Timers[QUIC_CONN_TIMER_COUNT];
uint64_t ExpirationTimes[QUIC_CONN_TIMER_COUNT];
//
// Earliest expiration time of all timers types.
//
uint64_t EarliestExpirationTime;
//
// Receive packet queue.
@ -727,18 +716,6 @@ QuicConnIsClosed(
return Connection->State.ClosedLocally || Connection->State.ClosedRemotely;
}
//
// Returns the earliest expiration time across all timers for the connection.
//
inline
uint64_t
QuicConnGetNextExpirationTime(
_In_ const QUIC_CONNECTION * const Connection
)
{
return Connection->Timers[0].ExpirationTime;
}
//
// Helper to get the owning QUIC_CONNECTION for the stream set module.
//

Просмотреть файл

@ -653,11 +653,6 @@ QuicRangeCompare(
const QUIC_SUBRANGE* Sub
);
uint64_t
QuicConnGetNextExpirationTime(
_In_ const QUIC_CONNECTION * const Connection
);
BOOLEAN
QuicPacketIsHandshake(
_In_ const QUIC_HEADER_INVARIANT* Packet

Просмотреть файл

@ -174,7 +174,7 @@ QuicTimerWheelResize(
CxPlatListRemoveHead(&OldSlots[i]),
QUIC_CONNECTION,
TimerLink);
uint64_t ExpirationTime = QuicConnGetNextExpirationTime(Connection);
uint64_t ExpirationTime = Connection->EarliestExpirationTime;
CXPLAT_DBG_ASSERT(TimerWheel->SlotCount != 0);
uint32_t SlotIndex = TIME_TO_SLOT_INDEX(TimerWheel, ExpirationTime);
@ -189,7 +189,7 @@ QuicTimerWheelResize(
while (Entry != ListHead) {
QUIC_CONNECTION* ConnectionEntry =
CXPLAT_CONTAINING_RECORD(Entry, QUIC_CONNECTION, TimerLink);
uint64_t EntryExpirationTime = QuicConnGetNextExpirationTime(ConnectionEntry);
uint64_t EntryExpirationTime = ConnectionEntry->EarliestExpirationTime;
if (ExpirationTime > EntryExpirationTime) {
break;
@ -231,7 +231,7 @@ QuicTimerWheelUpdate(
TimerWheel->Slots[i].Flink,
QUIC_CONNECTION,
TimerLink);
uint64_t EntryExpirationTime = QuicConnGetNextExpirationTime(ConnectionEntry);
uint64_t EntryExpirationTime = ConnectionEntry->EarliestExpirationTime;
if (EntryExpirationTime < TimerWheel->NextExpirationTime) {
TimerWheel->NextExpirationTime = EntryExpirationTime;
TimerWheel->NextConnection = ConnectionEntry;
@ -290,7 +290,7 @@ QuicTimerWheelUpdateConnection(
_Inout_ QUIC_CONNECTION* Connection
)
{
uint64_t ExpirationTime = QuicConnGetNextExpirationTime(Connection);
uint64_t ExpirationTime = Connection->EarliestExpirationTime;
if (Connection->TimerLink.Flink != NULL) {
//
@ -349,7 +349,7 @@ QuicTimerWheelUpdateConnection(
while (Entry != ListHead) {
QUIC_CONNECTION* ConnectionEntry =
CXPLAT_CONTAINING_RECORD(Entry, QUIC_CONNECTION, TimerLink);
uint64_t EntryExpirationTime = QuicConnGetNextExpirationTime(ConnectionEntry);
uint64_t EntryExpirationTime = ConnectionEntry->EarliestExpirationTime;
if (ExpirationTime > EntryExpirationTime) {
break;
@ -414,7 +414,7 @@ QuicTimerWheelGetExpired(
while (Entry != ListHead) {
QUIC_CONNECTION* ConnectionEntry =
CXPLAT_CONTAINING_RECORD(Entry, QUIC_CONNECTION, TimerLink);
uint64_t EntryExpirationTime = QuicConnGetNextExpirationTime(ConnectionEntry);
uint64_t EntryExpirationTime = ConnectionEntry->EarliestExpirationTime;
if (EntryExpirationTime > TimeNow) {
break;
}

Просмотреть файл

@ -1919,36 +1919,16 @@ tracepoint(CLOG_CONNECTION_C, ConnSetTimer , arg2, arg3, arg4);\
/*----------------------------------------------------------
// Decoder Ring for ConnCancelTimer
// [conn][%p] Canceling %hhu
// Decoder Ring for ConnExpiredTimer
// [conn][%p] %hhu expired
// QuicTraceEvent(
ConnCancelTimer,
"[conn][%p] Canceling %hhu",
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
(uint8_t)Type);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = (uint8_t)Type = arg3
----------------------------------------------------------*/
#ifndef _clog_4_ARGS_TRACE_ConnCancelTimer
#define _clog_4_ARGS_TRACE_ConnCancelTimer(uniqueId, encoded_arg_string, arg2, arg3)\
tracepoint(CLOG_CONNECTION_C, ConnCancelTimer , arg2, arg3);\
#endif
/*----------------------------------------------------------
// Decoder Ring for ConnExpiredTimer
// [conn][%p] %hhu expired
// QuicTraceEvent(
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
(uint8_t)Temp[j].Type);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = (uint8_t)Temp[j].Type = arg3
----------------------------------------------------------*/
#ifndef _clog_4_ARGS_TRACE_ConnExpiredTimer
#define _clog_4_ARGS_TRACE_ConnExpiredTimer(uniqueId, encoded_arg_string, arg2, arg3)\
tracepoint(CLOG_CONNECTION_C, ConnExpiredTimer , arg2, arg3);\
@ -1962,10 +1942,10 @@ tracepoint(CLOG_CONNECTION_C, ConnExpiredTimer , arg2, arg3);\
// Decoder Ring for ConnExecTimerOper
// [conn][%p] Execute: %u
// QuicTraceEvent(
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = QUIC_CONN_TIMER_ACK_DELAY = arg3
----------------------------------------------------------*/

Просмотреть файл

@ -2154,39 +2154,16 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnSetTimer,
/*----------------------------------------------------------
// Decoder Ring for ConnCancelTimer
// [conn][%p] Canceling %hhu
// Decoder Ring for ConnExpiredTimer
// [conn][%p] %hhu expired
// QuicTraceEvent(
ConnCancelTimer,
"[conn][%p] Canceling %hhu",
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
(uint8_t)Type);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = (uint8_t)Type = arg3
----------------------------------------------------------*/
TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnCancelTimer,
TP_ARGS(
const void *, arg2,
unsigned char, arg3),
TP_FIELDS(
ctf_integer_hex(uint64_t, arg2, arg2)
ctf_integer(unsigned char, arg3, arg3)
)
)
/*----------------------------------------------------------
// Decoder Ring for ConnExpiredTimer
// [conn][%p] %hhu expired
// QuicTraceEvent(
ConnExpiredTimer,
"[conn][%p] %hhu expired",
Connection,
(uint8_t)Temp[j].Type);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = (uint8_t)Temp[j].Type = arg3
----------------------------------------------------------*/
TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnExpiredTimer,
TP_ARGS(
const void *, arg2,
@ -2203,10 +2180,10 @@ TRACEPOINT_EVENT(CLOG_CONNECTION_C, ConnExpiredTimer,
// Decoder Ring for ConnExecTimerOper
// [conn][%p] Execute: %u
// QuicTraceEvent(
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
ConnExecTimerOper,
"[conn][%p] Execute: %u",
Connection,
QUIC_CONN_TIMER_ACK_DELAY);
// arg2 = arg2 = Connection = arg2
// arg3 = arg3 = QUIC_CONN_TIMER_ACK_DELAY = arg3
----------------------------------------------------------*/