lsquic_mm.c revision 50aadb33
1/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_mm.c -- Memory manager. 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <stddef.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/queue.h> 12 13#include "fiu-local.h" 14 15#include "lsquic.h" 16#include "lsquic_int_types.h" 17#include "lsquic_malo.h" 18#include "lsquic_conn.h" 19#include "lsquic_rtt.h" 20#include "lsquic_packet_common.h" 21#include "lsquic_packet_in.h" 22#include "lsquic_packet_out.h" 23#include "lsquic_parse.h" 24#include "lsquic_mm.h" 25#include "lsquic_engine_public.h" 26 27#define FAIL_NOMEM do { errno = ENOMEM; return NULL; } while (0) 28 29 30struct payload_buf 31{ 32 SLIST_ENTRY(payload_buf) next_pb; 33}; 34 35struct packet_out_buf 36{ 37 SLIST_ENTRY(packet_out_buf) next_pob; 38}; 39 40struct four_k_page 41{ 42 SLIST_ENTRY(four_k_page) next_fkp; 43}; 44 45struct sixteen_k_page 46{ 47 SLIST_ENTRY(sixteen_k_page) next_skp; 48}; 49 50 51int 52lsquic_mm_init (struct lsquic_mm *mm) 53{ 54 int i; 55 56 mm->acki = malloc(sizeof(*mm->acki)); 57 mm->malo.stream_frame = lsquic_malo_create(sizeof(struct stream_frame)); 58 mm->malo.stream_rec_arr = lsquic_malo_create(sizeof(struct stream_rec_arr)); 59 mm->malo.packet_in = lsquic_malo_create(sizeof(struct lsquic_packet_in)); 60 mm->malo.packet_out = lsquic_malo_create(sizeof(struct lsquic_packet_out)); 61 TAILQ_INIT(&mm->free_packets_in); 62 for (i = 0; i < MM_N_OUT_BUCKETS; ++i) 63 SLIST_INIT(&mm->packet_out_bufs[i]); 64 SLIST_INIT(&mm->payload_bufs); 65 SLIST_INIT(&mm->four_k_pages); 66 SLIST_INIT(&mm->sixteen_k_pages); 67 if (mm->acki && mm->malo.stream_frame && mm->malo.stream_rec_arr && 68 mm->malo.packet_in) 69 { 70 return 0; 71 } 72 else 73 return -1; 74} 75 76 77void 78lsquic_mm_cleanup (struct lsquic_mm *mm) 79{ 80 int i; 81 struct packet_out_buf *pob; 82 struct payload_buf *pb; 83 struct four_k_page *fkp; 84 struct sixteen_k_page *skp; 85 86 free(mm->acki); 87 lsquic_malo_destroy(mm->malo.packet_in); 88 lsquic_malo_destroy(mm->malo.packet_out); 89 lsquic_malo_destroy(mm->malo.stream_frame); 90 lsquic_malo_destroy(mm->malo.stream_rec_arr); 91 92 for (i = 0; i < MM_N_OUT_BUCKETS; ++i) 93 while ((pob = SLIST_FIRST(&mm->packet_out_bufs[i]))) 94 { 95 SLIST_REMOVE_HEAD(&mm->packet_out_bufs[i], next_pob); 96 free(pob); 97 } 98 99 while ((pb = SLIST_FIRST(&mm->payload_bufs))) 100 { 101 SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb); 102 free(pb); 103 } 104 105 while ((fkp = SLIST_FIRST(&mm->four_k_pages))) 106 { 107 SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp); 108 free(fkp); 109 } 110 111 while ((skp = SLIST_FIRST(&mm->sixteen_k_pages))) 112 { 113 SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp); 114 free(skp); 115 } 116} 117 118 119struct lsquic_packet_in * 120lsquic_mm_get_packet_in (struct lsquic_mm *mm) 121{ 122 struct lsquic_packet_in *packet_in; 123 124 fiu_do_on("mm/packet_in", FAIL_NOMEM); 125 126 packet_in = TAILQ_FIRST(&mm->free_packets_in); 127 if (packet_in) 128 { 129 assert(0 == packet_in->pi_refcnt); 130 TAILQ_REMOVE(&mm->free_packets_in, packet_in, pi_next); 131 } 132 else 133 packet_in = lsquic_malo_get(mm->malo.packet_in); 134 135 if (packet_in) 136 memset(packet_in, 0, sizeof(*packet_in)); 137 138 return packet_in; 139} 140 141 142/* Based on commonly used MTUs, ordered from small to large: */ 143enum { 144 PACKET_OUT_PAYLOAD_0 = 1280 - QUIC_MIN_PACKET_OVERHEAD, 145 PACKET_OUT_PAYLOAD_1 = QUIC_MAX_IPv6_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD, 146 PACKET_OUT_PAYLOAD_2 = QUIC_MAX_IPv4_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD, 147}; 148 149 150static const unsigned packet_out_sizes[] = { 151 PACKET_OUT_PAYLOAD_0, 152 PACKET_OUT_PAYLOAD_1, 153 PACKET_OUT_PAYLOAD_2, 154}; 155 156 157static unsigned 158packet_out_index (unsigned size) 159{ 160 unsigned idx = (size > PACKET_OUT_PAYLOAD_0) 161 + (size > PACKET_OUT_PAYLOAD_1); 162 return idx; 163} 164 165 166void 167lsquic_mm_put_packet_out (struct lsquic_mm *mm, 168 struct lsquic_packet_out *packet_out) 169{ 170 struct packet_out_buf *pob; 171 unsigned idx; 172 173 assert(packet_out->po_data); 174 pob = (struct packet_out_buf *) packet_out->po_data; 175 idx = packet_out_index(packet_out->po_n_alloc); 176 SLIST_INSERT_HEAD(&mm->packet_out_bufs[idx], pob, next_pob); 177 lsquic_malo_put(packet_out); 178} 179 180 181struct lsquic_packet_out * 182lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo, 183 unsigned short size) 184{ 185 struct lsquic_packet_out *packet_out; 186 struct packet_out_buf *pob; 187 unsigned idx; 188 189 assert(size <= QUIC_MAX_PAYLOAD_SZ); 190 191 fiu_do_on("mm/packet_out", FAIL_NOMEM); 192 193 packet_out = lsquic_malo_get(malo ? malo : mm->malo.packet_out); 194 if (!packet_out) 195 return NULL; 196 197 idx = packet_out_index(size); 198 pob = SLIST_FIRST(&mm->packet_out_bufs[idx]); 199 if (pob) 200 SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob); 201 else 202 { 203 pob = malloc(packet_out_sizes[idx]); 204 if (!pob) 205 { 206 lsquic_malo_put(packet_out); 207 return NULL; 208 } 209 } 210 211 memset(packet_out, 0, sizeof(*packet_out)); 212 STAILQ_INIT(&packet_out->po_srec_arrs); 213 packet_out->po_n_alloc = size; 214 packet_out->po_data = (unsigned char *) pob; 215 216 return packet_out; 217} 218 219 220void * 221lsquic_mm_get_1370 (struct lsquic_mm *mm) 222{ 223 struct payload_buf *pb = SLIST_FIRST(&mm->payload_bufs); 224 fiu_do_on("mm/1370", FAIL_NOMEM); 225 if (pb) 226 SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb); 227 else 228 pb = malloc(1370); 229 return pb; 230} 231 232 233void 234lsquic_mm_put_1370 (struct lsquic_mm *mm, void *mem) 235{ 236 struct payload_buf *pb = mem; 237 SLIST_INSERT_HEAD(&mm->payload_bufs, pb, next_pb); 238} 239 240 241void * 242lsquic_mm_get_4k (struct lsquic_mm *mm) 243{ 244 struct four_k_page *fkp = SLIST_FIRST(&mm->four_k_pages); 245 fiu_do_on("mm/4k", FAIL_NOMEM); 246 if (fkp) 247 SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp); 248 else 249 fkp = malloc(0x1000); 250 return fkp; 251} 252 253 254void 255lsquic_mm_put_4k (struct lsquic_mm *mm, void *mem) 256{ 257 struct four_k_page *fkp = mem; 258 SLIST_INSERT_HEAD(&mm->four_k_pages, fkp, next_fkp); 259} 260 261 262void * 263lsquic_mm_get_16k (struct lsquic_mm *mm) 264{ 265 struct sixteen_k_page *skp = SLIST_FIRST(&mm->sixteen_k_pages); 266 fiu_do_on("mm/16k", FAIL_NOMEM); 267 if (skp) 268 SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp); 269 else 270 skp = malloc(16 * 1024); 271 return skp; 272} 273 274 275void 276lsquic_mm_put_16k (struct lsquic_mm *mm, void *mem) 277{ 278 struct sixteen_k_page *skp = mem; 279 SLIST_INSERT_HEAD(&mm->sixteen_k_pages, skp, next_skp); 280} 281 282 283void 284lsquic_mm_put_packet_in (struct lsquic_mm *mm, 285 struct lsquic_packet_in *packet_in) 286{ 287 assert(0 == packet_in->pi_refcnt); 288 if (packet_in->pi_flags & PI_OWN_DATA) 289 lsquic_mm_put_1370(mm, packet_in->pi_data); 290 TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next); 291} 292 293 294