/* * libwebsockets - lws alloc chunk * * Copyright (C) 2018 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "core/private.h" #include "misc/lwsac/private.h" void lws_list_ptr_insert(lws_list_ptr *head, lws_list_ptr *add, lws_list_ptr_sort_func_t sort_func) { while (sort_func && *head) { if (sort_func(add, *head) <= 0) break; head = *head; } *add = *head; *head = add; } size_t lwsac_align(size_t length) { size_t align = sizeof(int *); if (length & (align - 1)) length += align - (length & (align - 1)); return length; } size_t lwsac_sizeof(void) { return sizeof(struct lwsac); } size_t lwsac_get_tail_pos(struct lwsac *lac) { return lac->ofs; } struct lwsac * lwsac_get_next(struct lwsac *lac) { return lac->next; } void * lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size) { struct lwsac *chunk; size_t ofs, alloc; /* ensure there's a chunk and enough space in it for this name */ if (!*head || (*head)->curr->alloc_size - (*head)->curr->ofs < ensure) { if (!chunk_size) alloc = LWSAC_CHUNK_SIZE + sizeof(*chunk); else alloc = chunk_size + sizeof(*chunk); /* * If we get asked for something outside our expectation, * allocate to meet it */ if (ensure >= alloc - sizeof(*chunk)) alloc = ensure + sizeof(*chunk); chunk = malloc(alloc); if (!chunk) { lwsl_err("%s: OOM trying to alloc %llud\n", __func__, (unsigned long long)alloc); return NULL; } if (!*head) { *head = chunk; chunk->total_alloc_size = 0; chunk->total_blocks = 0; } else (*head)->curr->next = chunk; (*head)->curr = chunk; (*head)->curr->head = *head; chunk->next = NULL; chunk->alloc_size = alloc; chunk->detached = 0; chunk->refcount = 0; (*head)->total_alloc_size += alloc; (*head)->total_blocks++; /* * belabouring the point... ofs is aligned to the platform's * generic struct alignment at the start then */ (*head)->curr->ofs = sizeof(*chunk); } ofs = (*head)->curr->ofs; (*head)->curr->ofs += lwsac_align(ensure); if ((*head)->curr->ofs >= (*head)->curr->alloc_size) (*head)->curr->ofs = (*head)->curr->alloc_size; return (char *)(*head)->curr + ofs; } void * lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size) { void *p = lwsac_use(head, ensure, chunk_size); if (p) memset(p, 0, ensure); return p; } void * lwsac_use_zeroed(struct lwsac **head, size_t ensure, size_t chunk_size) { void *r = lwsac_use(head, ensure, chunk_size); if (r) memset(r, 0, ensure); return r; } void lwsac_free(struct lwsac **head) { struct lwsac *it = *head; *head = NULL; lwsl_debug("%s: head %p\n", __func__, *head); while (it) { struct lwsac *tmp = it->next; free(it); it = tmp; } } void lwsac_info(struct lwsac *head) { if (!head) lwsl_debug("%s: empty\n", __func__); else lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head, (int)(head->total_alloc_size >> 10), head->total_blocks); } uint64_t lwsac_total_alloc(struct lwsac *head) { return head->total_alloc_size; } void lwsac_reference(struct lwsac *head) { head->refcount++; lwsl_debug("%s: head %p: (det %d) refcount -> %d\n", __func__, head, head->detached, head->refcount); } void lwsac_unreference(struct lwsac **head) { if (!(*head)) return; if (!(*head)->refcount) lwsl_warn("%s: refcount going below zero\n", __func__); (*head)->refcount--; lwsl_debug("%s: head %p: (det %d) refcount -> %d\n", __func__, *head, (*head)->detached, (*head)->refcount); if ((*head)->detached && !(*head)->refcount) { lwsl_debug("%s: head %p: FREED\n", __func__, *head); lwsac_free(head); } } void lwsac_detach(struct lwsac **head) { (*head)->detached = 1; if (!(*head)->refcount) { lwsl_debug("%s: head %p: FREED\n", __func__, *head); lwsac_free(head); } else lwsl_debug("%s: head %p: refcount %d: Marked as detached\n", __func__, *head, (*head)->refcount); }