294 lines
6.7 KiB
C
294 lines
6.7 KiB
C
|
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
||
|
/*
|
||
|
* lsquic_mm.c -- Memory manager.
|
||
|
*/
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <errno.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/queue.h>
|
||
|
|
||
|
#include "fiu-local.h"
|
||
|
|
||
|
#include "lsquic.h"
|
||
|
#include "lsquic_int_types.h"
|
||
|
#include "lsquic_malo.h"
|
||
|
#include "lsquic_conn.h"
|
||
|
#include "lsquic_rtt.h"
|
||
|
#include "lsquic_packet_common.h"
|
||
|
#include "lsquic_packet_in.h"
|
||
|
#include "lsquic_packet_out.h"
|
||
|
#include "lsquic_parse.h"
|
||
|
#include "lsquic_mm.h"
|
||
|
#include "lsquic_engine_public.h"
|
||
|
|
||
|
#define FAIL_NOMEM do { errno = ENOMEM; return NULL; } while (0)
|
||
|
|
||
|
|
||
|
struct payload_buf
|
||
|
{
|
||
|
SLIST_ENTRY(payload_buf) next_pb;
|
||
|
};
|
||
|
|
||
|
struct packet_out_buf
|
||
|
{
|
||
|
SLIST_ENTRY(packet_out_buf) next_pob;
|
||
|
};
|
||
|
|
||
|
struct four_k_page
|
||
|
{
|
||
|
SLIST_ENTRY(four_k_page) next_fkp;
|
||
|
};
|
||
|
|
||
|
struct sixteen_k_page
|
||
|
{
|
||
|
SLIST_ENTRY(sixteen_k_page) next_skp;
|
||
|
};
|
||
|
|
||
|
|
||
|
int
|
||
|
lsquic_mm_init (struct lsquic_mm *mm)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
mm->acki = malloc(sizeof(*mm->acki));
|
||
|
mm->malo.stream_frame = lsquic_malo_create(sizeof(struct stream_frame));
|
||
|
mm->malo.stream_rec_arr = lsquic_malo_create(sizeof(struct stream_rec_arr));
|
||
|
mm->malo.packet_in = lsquic_malo_create(sizeof(struct lsquic_packet_in));
|
||
|
mm->malo.packet_out = lsquic_malo_create(sizeof(struct lsquic_packet_out));
|
||
|
TAILQ_INIT(&mm->free_packets_in);
|
||
|
for (i = 0; i < MM_N_OUT_BUCKETS; ++i)
|
||
|
SLIST_INIT(&mm->packet_out_bufs[i]);
|
||
|
SLIST_INIT(&mm->payload_bufs);
|
||
|
SLIST_INIT(&mm->four_k_pages);
|
||
|
SLIST_INIT(&mm->sixteen_k_pages);
|
||
|
if (mm->acki && mm->malo.stream_frame && mm->malo.stream_rec_arr &&
|
||
|
mm->malo.packet_in)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_cleanup (struct lsquic_mm *mm)
|
||
|
{
|
||
|
int i;
|
||
|
struct packet_out_buf *pob;
|
||
|
struct payload_buf *pb;
|
||
|
struct four_k_page *fkp;
|
||
|
struct sixteen_k_page *skp;
|
||
|
|
||
|
free(mm->acki);
|
||
|
lsquic_malo_destroy(mm->malo.packet_in);
|
||
|
lsquic_malo_destroy(mm->malo.packet_out);
|
||
|
lsquic_malo_destroy(mm->malo.stream_frame);
|
||
|
lsquic_malo_destroy(mm->malo.stream_rec_arr);
|
||
|
|
||
|
for (i = 0; i < MM_N_OUT_BUCKETS; ++i)
|
||
|
while ((pob = SLIST_FIRST(&mm->packet_out_bufs[i])))
|
||
|
{
|
||
|
SLIST_REMOVE_HEAD(&mm->packet_out_bufs[i], next_pob);
|
||
|
free(pob);
|
||
|
}
|
||
|
|
||
|
while ((pb = SLIST_FIRST(&mm->payload_bufs)))
|
||
|
{
|
||
|
SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb);
|
||
|
free(pb);
|
||
|
}
|
||
|
|
||
|
while ((fkp = SLIST_FIRST(&mm->four_k_pages)))
|
||
|
{
|
||
|
SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp);
|
||
|
free(fkp);
|
||
|
}
|
||
|
|
||
|
while ((skp = SLIST_FIRST(&mm->sixteen_k_pages)))
|
||
|
{
|
||
|
SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp);
|
||
|
free(skp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
struct lsquic_packet_in *
|
||
|
lsquic_mm_get_packet_in (struct lsquic_mm *mm)
|
||
|
{
|
||
|
struct lsquic_packet_in *packet_in;
|
||
|
|
||
|
fiu_do_on("mm/packet_in", FAIL_NOMEM);
|
||
|
|
||
|
packet_in = TAILQ_FIRST(&mm->free_packets_in);
|
||
|
if (packet_in)
|
||
|
{
|
||
|
assert(0 == packet_in->pi_refcnt);
|
||
|
TAILQ_REMOVE(&mm->free_packets_in, packet_in, pi_next);
|
||
|
}
|
||
|
else
|
||
|
packet_in = lsquic_malo_get(mm->malo.packet_in);
|
||
|
|
||
|
if (packet_in)
|
||
|
memset(packet_in, 0, sizeof(*packet_in));
|
||
|
|
||
|
return packet_in;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Based on commonly used MTUs, ordered from small to large: */
|
||
|
enum {
|
||
|
PACKET_OUT_PAYLOAD_0 = 1280 - QUIC_MIN_PACKET_OVERHEAD,
|
||
|
PACKET_OUT_PAYLOAD_1 = QUIC_MAX_IPv6_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD,
|
||
|
PACKET_OUT_PAYLOAD_2 = QUIC_MAX_IPv4_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD,
|
||
|
};
|
||
|
|
||
|
|
||
|
static const unsigned packet_out_sizes[] = {
|
||
|
PACKET_OUT_PAYLOAD_0,
|
||
|
PACKET_OUT_PAYLOAD_1,
|
||
|
PACKET_OUT_PAYLOAD_2,
|
||
|
};
|
||
|
|
||
|
|
||
|
static unsigned
|
||
|
packet_out_index (unsigned size)
|
||
|
{
|
||
|
unsigned idx = (size > PACKET_OUT_PAYLOAD_0)
|
||
|
+ (size > PACKET_OUT_PAYLOAD_1);
|
||
|
return idx;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_put_packet_out (struct lsquic_mm *mm,
|
||
|
struct lsquic_packet_out *packet_out)
|
||
|
{
|
||
|
struct packet_out_buf *pob;
|
||
|
unsigned idx;
|
||
|
|
||
|
assert(packet_out->po_data);
|
||
|
pob = (struct packet_out_buf *) packet_out->po_data;
|
||
|
idx = packet_out_index(packet_out->po_n_alloc);
|
||
|
SLIST_INSERT_HEAD(&mm->packet_out_bufs[idx], pob, next_pob);
|
||
|
lsquic_malo_put(packet_out);
|
||
|
}
|
||
|
|
||
|
|
||
|
struct lsquic_packet_out *
|
||
|
lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
||
|
unsigned short size)
|
||
|
{
|
||
|
struct lsquic_packet_out *packet_out;
|
||
|
struct packet_out_buf *pob;
|
||
|
unsigned idx;
|
||
|
|
||
|
assert(size <= QUIC_MAX_PAYLOAD_SZ);
|
||
|
|
||
|
fiu_do_on("mm/packet_out", FAIL_NOMEM);
|
||
|
|
||
|
packet_out = lsquic_malo_get(malo ? malo : mm->malo.packet_out);
|
||
|
if (!packet_out)
|
||
|
return NULL;
|
||
|
|
||
|
idx = packet_out_index(size);
|
||
|
pob = SLIST_FIRST(&mm->packet_out_bufs[idx]);
|
||
|
if (pob)
|
||
|
SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob);
|
||
|
else
|
||
|
{
|
||
|
pob = malloc(packet_out_sizes[idx]);
|
||
|
if (!pob)
|
||
|
{
|
||
|
lsquic_malo_put(packet_out);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memset(packet_out, 0, sizeof(*packet_out));
|
||
|
STAILQ_INIT(&packet_out->po_srec_arrs);
|
||
|
packet_out->po_n_alloc = size;
|
||
|
packet_out->po_data = (unsigned char *) pob;
|
||
|
|
||
|
return packet_out;
|
||
|
}
|
||
|
|
||
|
|
||
|
void *
|
||
|
lsquic_mm_get_1370 (struct lsquic_mm *mm)
|
||
|
{
|
||
|
struct payload_buf *pb = SLIST_FIRST(&mm->payload_bufs);
|
||
|
fiu_do_on("mm/1370", FAIL_NOMEM);
|
||
|
if (pb)
|
||
|
SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb);
|
||
|
else
|
||
|
pb = malloc(1370);
|
||
|
return pb;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_put_1370 (struct lsquic_mm *mm, void *mem)
|
||
|
{
|
||
|
struct payload_buf *pb = mem;
|
||
|
SLIST_INSERT_HEAD(&mm->payload_bufs, pb, next_pb);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *
|
||
|
lsquic_mm_get_4k (struct lsquic_mm *mm)
|
||
|
{
|
||
|
struct four_k_page *fkp = SLIST_FIRST(&mm->four_k_pages);
|
||
|
fiu_do_on("mm/4k", FAIL_NOMEM);
|
||
|
if (fkp)
|
||
|
SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp);
|
||
|
else
|
||
|
fkp = malloc(0x1000);
|
||
|
return fkp;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_put_4k (struct lsquic_mm *mm, void *mem)
|
||
|
{
|
||
|
struct four_k_page *fkp = mem;
|
||
|
SLIST_INSERT_HEAD(&mm->four_k_pages, fkp, next_fkp);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *
|
||
|
lsquic_mm_get_16k (struct lsquic_mm *mm)
|
||
|
{
|
||
|
struct sixteen_k_page *skp = SLIST_FIRST(&mm->sixteen_k_pages);
|
||
|
fiu_do_on("mm/16k", FAIL_NOMEM);
|
||
|
if (skp)
|
||
|
SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp);
|
||
|
else
|
||
|
skp = malloc(16 * 1024);
|
||
|
return skp;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_put_16k (struct lsquic_mm *mm, void *mem)
|
||
|
{
|
||
|
struct sixteen_k_page *skp = mem;
|
||
|
SLIST_INSERT_HEAD(&mm->sixteen_k_pages, skp, next_skp);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
lsquic_mm_put_packet_in (struct lsquic_mm *mm,
|
||
|
struct lsquic_packet_in *packet_in)
|
||
|
{
|
||
|
assert(0 == packet_in->pi_refcnt);
|
||
|
if (packet_in->pi_flags & PI_OWN_DATA)
|
||
|
lsquic_mm_put_1370(mm, packet_in->pi_data);
|
||
|
TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next);
|
||
|
}
|
||
|
|
||
|
|