Skip to content

Commit

Permalink
Support custom memory allocator
Browse files Browse the repository at this point in the history
nghttp2_mem structure is introduced to hold custom memory allocator
functions and user supplied pointer.  nghttp2_mem object can be passed
to nghttp2_session_client_new3(), nghttp2_session_server_new3(),
nghttp2_hd_deflate_new2() and nghttp2_hd_inflate_new2() to replace
standard malloc(), free(), calloc() and realloc().  nghttp2_mem
structure has user supplied pointer mem_user_data which can be used as
per session/object memory pool.
  • Loading branch information
tatsuhiro-t committed Dec 7, 2014
1 parent 21b48d2 commit c0ffed7
Show file tree
Hide file tree
Showing 31 changed files with 993 additions and 443 deletions.
6 changes: 4 additions & 2 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_version.c \
nghttp2_priority_spec.c \
nghttp2_option.c \
nghttp2_callbacks.c
nghttp2_callbacks.c \
nghttp2_mem.c

HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
Expand All @@ -56,7 +57,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_hd.h nghttp2_hd_huffman.h \
nghttp2_priority_spec.h \
nghttp2_option.h \
nghttp2_callbacks.h
nghttp2_callbacks.h \
nghttp2_mem.h

libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = -no-undefined \
Expand Down
152 changes: 152 additions & 0 deletions lib/includes/nghttp2/nghttp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,69 @@ void nghttp2_session_callbacks_set_on_begin_frame_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_begin_frame_callback on_begin_frame_callback);

/**
* @functypedef
*
* Custom memory allocator to replace malloc(). The |mem_user_data|
* is the mem_user_data member of :type:`nghttp2_mem` structure.
*/
typedef void *(*nghttp2_malloc)(size_t size, void *mem_user_data);

/**
* @functypedef
*
* Custom memory allocator to replace free(). The |mem_user_data| is
* the mem_user_data member of :type:`nghttp2_mem` structure.
*/
typedef void (*nghttp2_free)(void *ptr, void *mem_user_data);

/**
* @functypedef
*
* Custom memory allocator to replace calloc(). The |mem_user_data|
* is the mem_user_data member of :type:`nghttp2_mem` structure.
*/
typedef void *(*nghttp2_calloc)(size_t nmemb, size_t size, void *mem_user_data);

/**
* @functypedef
*
* Custom memory allocator to replace realloc(). The |mem_user_data|
* is the mem_user_data member of :type:`nghttp2_mem` structure.
*/
typedef void *(*nghttp2_realloc)(void *ptr, size_t size, void *mem_user_data);

/**
* @struct
*
* Custom memory allocator functions and user defined pointer. The
* |mem_user_data| member is passed to each allocator function. This
* can be used, for example, to achieve per-session memory pool.
*/
typedef struct {
/**
* An arbitrary user supplied data. This is passed to each
* allocator function.
*/
void *mem_user_data;
/**
* Custom allocator function to replace malloc().
*/
nghttp2_malloc malloc;
/**
* Custom allocator function to replace free().
*/
nghttp2_free free;
/**
* Custom allocator function to replace calloc().
*/
nghttp2_calloc calloc;
/**
* Custom allocator function to replace realloc().
*/
nghttp2_realloc realloc;
} nghttp2_mem;

struct nghttp2_option;

/**
Expand Down Expand Up @@ -1869,6 +1932,58 @@ int nghttp2_session_server_new2(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks,
void *user_data, const nghttp2_option *option);

/**
* @function
*
* Like `nghttp2_session_client_new2()`, but with additional custom
* memory allocator specified in the |mem|.
*
* The |mem| can be ``NULL`` and the call is equivalent to
* `nghttp2_session_client_new2()`.
*
* This function does not take ownership |mem|. The application is
* responsible for freeing |mem|.
*
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
int nghttp2_session_client_new3(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks,
void *user_data, const nghttp2_option *option,
nghttp2_mem *mem);

/**
* @function
*
* Like `nghttp2_session_server_new2()`, but with additional custom
* memory allocator specified in the |mem|.
*
* The |mem| can be ``NULL`` and the call is equivalent to
* `nghttp2_session_server_new2()`.
*
* This function does not take ownership |mem|. The application is
* responsible for freeing |mem|.
*
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
int nghttp2_session_server_new3(nghttp2_session **session_ptr,
const nghttp2_session_callbacks *callbacks,
void *user_data, const nghttp2_option *option,
nghttp2_mem *mem);

/**
* @function
*
Expand Down Expand Up @@ -3079,6 +3194,25 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
size_t deflate_hd_table_bufsize_max);

/**
* @function
*
* Like `nghttp2_hd_deflate_new()`, but with additional custom memory
* allocator specified in the |mem|.
*
* The |mem| can be ``NULL`` and the call is equivalent to
* `nghttp2_hd_deflate_new()`.
*
* This function does not take ownership |mem|. The application is
* responsible for freeing |mem|.
*
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*/
int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
size_t deflate_hd_table_bufsize_max,
nghttp2_mem *mem);

/**
* @function
*
Expand Down Expand Up @@ -3176,6 +3310,24 @@ typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
*/
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);

/**
* @function
*
* Like `nghttp2_hd_inflate_new()`, but with additional custom memory
* allocator specified in the |mem|.
*
* The |mem| can be ``NULL`` and the call is equivalent to
* `nghttp2_hd_inflate_new()`.
*
* This function does not take ownership |mem|. The application is
* responsible for freeing |mem|.
*
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*/
int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
nghttp2_mem *mem);

/**
* @function
*
Expand Down
62 changes: 34 additions & 28 deletions lib/nghttp2_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ void nghttp2_buf_init(nghttp2_buf *buf) {
buf->mark = NULL;
}

int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial) {
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
nghttp2_buf_init(buf);
return nghttp2_buf_reserve(buf, initial);
return nghttp2_buf_reserve(buf, initial, mem);
}

void nghttp2_buf_free(nghttp2_buf *buf) {
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
if (buf == NULL) {
return;
}

free(buf->begin);
nghttp2_mem_free(mem, buf->begin);
buf->begin = NULL;
}

int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap) {
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
uint8_t *ptr;
size_t cap;

Expand All @@ -62,7 +62,7 @@ int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap) {

new_cap = nghttp2_max(new_cap, cap * 2);

ptr = realloc(buf->begin, new_cap);
ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
if (ptr == NULL) {
return NGHTTP2_ERR_NOMEM;
}
Expand All @@ -85,54 +85,58 @@ void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
buf->end = begin + len;
}

static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length) {
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
nghttp2_mem *mem) {
int rv;

*chain = malloc(sizeof(nghttp2_buf_chain));
*chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
if (*chain == NULL) {
return NGHTTP2_ERR_NOMEM;
}

(*chain)->next = NULL;

rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length);
rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
if (rv != 0) {
free(*chain);
nghttp2_mem_free(mem, *chain);
return NGHTTP2_ERR_NOMEM;
}

return 0;
}

static void buf_chain_del(nghttp2_buf_chain *chain) {
nghttp2_buf_free(&chain->buf);
free(chain);
static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
nghttp2_buf_free(&chain->buf, mem);
nghttp2_mem_free(mem, chain);
}

int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk) {
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0);
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
nghttp2_mem *mem) {
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
}

int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset) {
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset);
size_t max_chunk, size_t offset, nghttp2_mem *mem) {
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
mem);
}

int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t chunk_keep, size_t offset) {
size_t max_chunk, size_t chunk_keep, size_t offset,
nghttp2_mem *mem) {
int rv;
nghttp2_buf_chain *chain;

if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}

rv = buf_chain_new(&chain, chunk_length);
rv = buf_chain_new(&chain, chunk_length, mem);
if (rv != 0) {
return rv;
}

bufs->mem = mem;
bufs->offset = offset;

bufs->head = chain;
Expand All @@ -156,7 +160,7 @@ int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}

rv = buf_chain_new(&chain, chunk_length);
rv = buf_chain_new(&chain, chunk_length, bufs->mem);
if (rv != 0) {
return rv;
}
Expand Down Expand Up @@ -184,18 +188,19 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs) {
for (chain = bufs->head; chain;) {
next_chain = chain->next;

buf_chain_del(chain);
buf_chain_del(chain, bufs->mem);

chain = next_chain;
}

bufs->head = NULL;
}

int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len) {
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_mem *mem) {
nghttp2_buf_chain *chain;

chain = malloc(sizeof(nghttp2_buf_chain));
chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
if (chain == NULL) {
return NGHTTP2_ERR_NOMEM;
}
Expand All @@ -204,6 +209,7 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len) {

nghttp2_buf_wrap_init(&chain->buf, begin, len);

bufs->mem = mem;
bufs->offset = 0;

bufs->head = chain;
Expand All @@ -222,7 +228,7 @@ void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
return;
}

free(bufs->head);
nghttp2_mem_free(bufs->mem, bufs->head);
bufs->head = NULL;
}

Expand Down Expand Up @@ -270,7 +276,7 @@ static int bufs_alloc_chain(nghttp2_bufs *bufs) {
return NGHTTP2_ERR_BUFFER_ERROR;
}

rv = buf_chain_new(&chain, bufs->chunk_length);
rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
if (rv != 0) {
return rv;
}
Expand Down Expand Up @@ -407,7 +413,7 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
if (!len) {
res = NULL;
} else {
res = malloc(len);
res = nghttp2_mem_malloc(bufs->mem, len);

if (res == NULL) {
return NGHTTP2_ERR_NOMEM;
Expand Down Expand Up @@ -456,7 +462,7 @@ void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
for (ci = chain; ci;) {
chain = ci->next;

buf_chain_del(ci);
buf_chain_del(ci, bufs->mem);

ci = chain;
}
Expand Down
Loading

0 comments on commit c0ffed7

Please sign in to comment.