Packages
hackney
2.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_attq.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_attq.c -- Advisory Tick Time Queue
*
* This is a collection of connections kept in a binary heap, the top
* element having the minimum advsory time. To speed up removal, each
* element has an index it has in the heap array. The index is updated
* as elements are moved around in the array when heap is updated.
*/
#include <assert.h>
#include <stdlib.h>
#ifdef WIN32
#include <vc_compat.h>
#endif
#include <sys/queue.h>
#include "lsquic.h"
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_attq.h"
#include "lsquic_packet_common.h"
#include "lsquic_alarmset.h"
#include "lsquic_malo.h"
#include "lsquic_hash.h"
#include "lsquic_conn.h"
struct attq
{
struct malo *aq_elem_malo;
struct attq_elem **aq_heap;
unsigned aq_nelem;
unsigned aq_nalloc;
};
struct attq *
lsquic_attq_create (void)
{
struct attq *q;
struct malo *malo;
malo = lsquic_malo_create(sizeof(struct attq_elem));
if (!malo)
return NULL;
q = calloc(1, sizeof(*q));
if (!q)
{
lsquic_malo_destroy(malo);
return NULL;
}
q->aq_elem_malo = malo;
return q;
}
void
lsquic_attq_destroy (struct attq *q)
{
lsquic_malo_destroy(q->aq_elem_malo);
free(q->aq_heap);
free(q);
}
#define AE_PARENT(i) ((i - 1) / 2)
#define AE_LCHILD(i) (2 * i + 1)
#define AE_RCHILD(i) (2 * i + 2)
#if LSQUIC_EXTRA_CHECKS && !defined(NDEBUG)
static void
attq_verify (struct attq *q)
{
unsigned i;
for (i = 0; i < q->aq_nelem; ++i)
{
assert(q->aq_heap[i]->ae_heap_idx == i);
if (AE_LCHILD(i) < q->aq_nelem)
assert(q->aq_heap[i]->ae_adv_time <=
q->aq_heap[AE_LCHILD(i)]->ae_adv_time);
if (AE_RCHILD(i) < q->aq_nelem)
assert(q->aq_heap[i]->ae_adv_time <=
q->aq_heap[AE_RCHILD(i)]->ae_adv_time);
}
}
#else
#define attq_verify(q)
#endif
static void
attq_swap (struct attq *q, unsigned a, unsigned b)
{
struct attq_elem *el;
el = q->aq_heap[ a ];
q->aq_heap[ a ] = q->aq_heap[ b ];
q->aq_heap[ b ] = el;
q->aq_heap[ a ]->ae_heap_idx = a;
q->aq_heap[ b ]->ae_heap_idx = b;
}
int
lsquic_attq_add (struct attq *q, struct lsquic_conn *conn,
lsquic_time_t advisory_time, enum ae_why why)
{
struct attq_elem *el, **heap;
unsigned n, i;
if (q->aq_nelem >= q->aq_nalloc)
{
if (q->aq_nalloc > 0)
n = q->aq_nalloc * 2;
else
n = 8;
heap = realloc(q->aq_heap, n * sizeof(q->aq_heap[0]));
if (!heap)
return -1;
q->aq_heap = heap;
q->aq_nalloc = n;
}
el = lsquic_malo_get(q->aq_elem_malo);
if (!el)
return -1;
el->ae_adv_time = advisory_time;
el->ae_why = why;
/* The only place linkage between conn and attq_elem occurs: */
el->ae_conn = conn;
conn->cn_attq_elem = el;
el->ae_heap_idx = q->aq_nelem;
q->aq_heap[ q->aq_nelem++ ] = el;
i = q->aq_nelem - 1;
while (i > 0 && q->aq_heap[ AE_PARENT(i) ]->ae_adv_time >=
q->aq_heap[ i ]->ae_adv_time)
{
attq_swap(q, i, AE_PARENT(i));
i = AE_PARENT(i);
}
attq_verify(q);
return 0;
}
struct lsquic_conn *
lsquic_attq_pop (struct attq *q, lsquic_time_t cutoff)
{
struct lsquic_conn *conn;
struct attq_elem *el;
if (q->aq_nelem == 0)
return NULL;
el = q->aq_heap[0];
if (el->ae_adv_time >= cutoff)
return NULL;
conn = el->ae_conn;
lsquic_attq_remove(q, conn);
return conn;
}
static void
attq_heapify (struct attq *q, unsigned i)
{
unsigned smallest;
assert(i < q->aq_nelem);
if (AE_LCHILD(i) < q->aq_nelem)
{
if (q->aq_heap[ AE_LCHILD(i) ]->ae_adv_time <
q->aq_heap[ i ]->ae_adv_time)
smallest = AE_LCHILD(i);
else
smallest = i;
if (AE_RCHILD(i) < q->aq_nelem &&
q->aq_heap[ AE_RCHILD(i) ]->ae_adv_time <
q->aq_heap[ smallest ]->ae_adv_time)
smallest = AE_RCHILD(i);
}
else
smallest = i;
if (smallest != i)
{
attq_swap(q, smallest, i);
attq_heapify(q, smallest);
}
}
void
lsquic_attq_remove (struct attq *q, struct lsquic_conn *conn)
{
struct attq_elem *el;
unsigned idx;
el = conn->cn_attq_elem;
idx = el->ae_heap_idx;
assert(q->aq_nelem > 0);
assert(q->aq_heap[idx] == el);
assert(conn->cn_attq_elem == el);
conn->cn_attq_elem = NULL;
q->aq_heap[ idx ] = q->aq_heap[ --q->aq_nelem ];
q->aq_heap[ idx ]->ae_heap_idx = idx;
if (idx > 0 && q->aq_heap[ idx ]->ae_adv_time <
q->aq_heap[ AE_PARENT(idx) ]->ae_adv_time)
{
do
{
attq_swap(q, idx, AE_PARENT(idx));
idx = AE_PARENT(idx);
}
while (idx > 0 && q->aq_heap[ idx ]->ae_adv_time <
q->aq_heap[ AE_PARENT(idx) ]->ae_adv_time);
}
else if (q->aq_nelem > 1 && idx < q->aq_nelem)
attq_heapify(q, idx);
lsquic_malo_put(el);
attq_verify(q);
}
unsigned
lsquic_attq_count_before (struct attq *q, lsquic_time_t cutoff)
{
unsigned level, total_count, level_count, i, level_max;
total_count = 0;
for (i = 0, level = 0;; ++level)
{
level_count = 0;
level_max = i + (1U << level);
for ( ; i < level_max && i < q->aq_nelem; ++i)
level_count += q->aq_heap[i]->ae_adv_time < cutoff;
total_count += level_count;
if (level_count < (1U << level))
return total_count;
}
assert(0);
return total_count;
}
const struct attq_elem *
lsquic_attq_next (struct attq *q)
{
if (q->aq_nelem > 0)
return q->aq_heap[0];
else
return NULL;
}
const char *
lsquic_attq_why2str (enum ae_why why)
{
switch (why)
{
case AEW_PACER:
return "PACER";
case AEW_MINI_EXPIRE:
return "MINI-EXPIRE";
default:
why -= N_AEWS;
if ((unsigned) why < (unsigned) MAX_LSQUIC_ALARMS)
return lsquic_alid2str[why];
return "UNKNOWN";
}
}