Commit 05e69227 authored by Jan Včelák's avatar Jan Včelák 🚀

move generic memory functions from mempattern to common

parent 4cbbb0ed
......@@ -108,13 +108,14 @@ libknotcs_la_SOURCES = \
common/errors.h \
common/getline.c \
common/getline.h \
common/mem.c \
common/mem.h \
common/memdup.h \
common/mempool.c \
common/mempool.h \
common/log.c \
common/log.h
# static: utilities shared
libknotus_la_SOURCES = \
utils/common/exec.c \
......@@ -134,7 +135,7 @@ libknotus_la_SOURCES = \
libknot_la_LDFLAGS = \
$(AM_LDFLAGS) \
-version-info 0:1:0 \
-export-symbols-regex '^(knot|KNOT|rrset|tsig|zone)_'
-export-symbols-regex '^(knot|KNOT|rrset|tsig|zone|mm)_'
libknot_la_SOURCES = \
libknot/binary.c \
......
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include "common/mem.h"
uint8_t *knot_memdup(const uint8_t *data, size_t data_size)
{
uint8_t *result = (uint8_t *)malloc(data_size);
if (!result) {
return NULL;
}
return memcpy(result, data, data_size);
}
void* xmalloc(size_t l)
{
void *p = malloc(l);
if (p == NULL) {
abort();
}
return p;
}
void *xrealloc(void *p, size_t l)
{
p = realloc(p, l);
if (p == NULL) {
abort();
}
return p;
}
int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved)
{
/* Trim excessive memory if possible. */
size_t maxlen = min + allow;
if (maxlen < min) {
return -2; /* size_t overflow */
}
/* Meet target size but trim excessive amounts. */
if (*reserved < min || *reserved > maxlen) {
void *trimmed = realloc(*p, maxlen * tlen);
if (trimmed != NULL) {
*p = trimmed;
*reserved = maxlen;
} else {
return -1;
}
}
return 0;
}
char *sprintf_alloc(const char *fmt, ...)
{
int size = 100;
char *p = NULL, *np = NULL;
va_list ap;
if ((p = malloc(size)) == NULL)
return NULL;
while (1) {
/* Try to print in the allocated space. */
va_start(ap, fmt);
int n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
return p;
/* Else try again with more space. */
if (n > -1) { /* glibc 2.1 */
size = n+1; /* precisely what is needed */
} else { /* glibc 2.0 */
size *= 2; /* twice the old size */
}
if ((np = realloc (p, size)) == NULL) {
free(p);
return NULL;
} else {
p = np;
}
}
/* Should never get here. */
return p;
}
char *strcdup(const char *s1, const char *s2)
{
if (!s1 || !s2) {
return NULL;
}
size_t s1len = strlen(s1);
size_t s2len = strlen(s2);
size_t nlen = s1len + s2len + 1;
char* dst = malloc(nlen);
if (dst == NULL) {
return NULL;
}
memcpy(dst, s1, s1len);
memcpy(dst + s1len, s2, s2len + 1);
return dst;
}
#ifdef MEM_DEBUG
/*
* ((destructor)) attribute executes this function after main().
* \see http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
*/
void __attribute__ ((destructor)) usage_dump()
#else
void usage_dump()
#endif
{
/* Get resource usage. */
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) < 0) {
memset(&usage, 0, sizeof(struct rusage));
}
fprintf(stderr, "\nMemory statistics:");
fprintf(stderr, "\n==================\n");
fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n",
usage.ru_utime.tv_sec * (double) 1000.0
+ usage.ru_utime.tv_usec / (double)1000.0,
usage.ru_stime.tv_sec * (double) 1000.0
+ usage.ru_stime.tv_usec / (double)1000.0);
fprintf(stderr, "Major page faults: %lu (required I/O)\nMinor page faults: %lu\n",
usage.ru_majflt, usage.ru_minflt);
fprintf(stderr, "Number of swaps: %lu\n",
usage.ru_nswap);
fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n",
usage.ru_nvcsw,
usage.ru_nivcsw);
fprintf(stderr, "==================\n");
}
......@@ -20,12 +20,63 @@
#include <stdlib.h>
#include <string.h>
static uint8_t *knot_memdup(const uint8_t *data, size_t data_size)
{
uint8_t *result = (uint8_t *)malloc(data_size);
if (!result) {
return NULL;
}
return memcpy(result, data, data_size);
}
/*!
* \brief Create a copy of a binary buffer.
*
* Like \c strdup, but for binary data.
*/
uint8_t *knot_memdup(const uint8_t *data, size_t data_size);
/*! \brief Allocate memory or die. */
void* xmalloc(size_t l);
/*! \brief Reallocate memory or die. */
void *xrealloc(void *p, size_t l);
/*!
* \brief Reserve new or trim excessive memory.
*
* \param p Double-pointer to memory region.
* \param tlen Memory unit (f.e. sizeof(int) for int* array)
* \param min Minimum number of items required.
* \param allow Maximum extra items to keep (for trimming).
* \param reserved Pointer to number of already reserved items.
*
* \note Example usage:
* char *buf = NULL; size_t len = 0;
* if (mreserve(&buf, sizeof(char), 6, 0, &len) == 0) {
* memcpy(buf, "hello", strlen("hello");
* if (mreserve(&buf, sizeof(char), 20, 0, &len) == 0) {
* strncat(buf, "!", 1);
* mreserve(&buf, sizeof(char), strlen("hello!")+1, 0, &len);
* }
* }
* free(buf);
*
* \retval 0 on success.
* \retval -1 on error.
*
* \note Memory region will be left untouched if function fails.
*/
int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved);
/*!
* \brief Format string and take care of allocating memory.
*
* \note sprintf(3) manual page reference implementation.
*
* \param fmt Message format.
* \return formatted message or NULL.
*/
char *sprintf_alloc(const char *fmt, ...);
/*!
* \brief Create new string from a concatenation of s1 and s2.
*
* \param s1 First string.
* \param s2 Second string.
*
* \retval Newly allocated string on success.
* \retval NULL on error.
*/
char *strcdup(const char *s1, const char *s2);
......@@ -11,6 +11,7 @@
#undef LOCAL_DEBUG
#include "common/mem.h"
#include "common/mempool.h"
#include "libknot/mempattern.h"
......
......@@ -27,6 +27,7 @@
#include <urcu.h>
#include "common-knot/strlcat.h"
#include "common-knot/strlcpy.h"
#include "common/mem.h"
#include "knot/conf/conf.h"
#include "knot/conf/extra.h"
#include "knot/knot.h"
......
......@@ -19,6 +19,7 @@
#include "knot/ctl/estimator.h"
#include "libknot/dname.h"
#include "common-knot/lists.h"
#include "common/mem.h"
#include "knot/zone/node.h"
#include "zscanner/zscanner.h"
#include "libknot/descriptor.h"
......
......@@ -26,6 +26,7 @@
#endif
#include "knot/knot.h"
#include "common/mem.h"
#include "libknot/descriptor.h"
#include "knot/ctl/process.h"
#include "knot/ctl/remote.h"
......
......@@ -29,10 +29,10 @@
#include <sys/types.h>
#include <pwd.h>
#include "common/mem.h"
#include "knot/knot.h"
#include "knot/ctl/process.h"
#include "knot/conf/conf.h"
#include "libknot/mempattern.h"
char* pid_filename()
{
......
......@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include "knot/ctl/remote.h"
#include "common/log.h"
#include "common/mem.h"
#include "common-knot/fdset.h"
#include "knot/knot.h"
#include "knot/conf/conf.h"
......
......@@ -16,6 +16,8 @@
#include <assert.h>
#include <time.h>
#include "common/mem.h"
#include "knot/conf/conf.h"
#include "libknot/dnssec/policy.h"
#include "knot/dnssec/zone-events.h"
......
......@@ -20,8 +20,8 @@
#include <inttypes.h>
#include "common/debug.h"
#include "common/mem.h"
#include "libknot/errcode.h"
#include "libknot/mempattern.h"
#include "libknot/common.h"
#include "libknot/dname.h"
#include "libknot/consts.h"
......
......@@ -19,6 +19,7 @@
#include "common-knot/evsched.h"
#include "common-knot/trim.h"
#include "common/mem.h"
#include "common/mempool.h"
#include "knot/server/server.h"
#include "knot/server/udp-handler.h"
......@@ -114,7 +115,7 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
/* Create a memory pool for this task. */
int ret = KNOT_EOK;
mm_ctx_t mm;
mm_ctx_mempool(&mm, DEFAULT_BLKSIZE);
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
/* Create a query message. */
knot_pkt_t *query = zone_query(zone, pkt_type, &mm);
......
......@@ -56,7 +56,7 @@ knot_zonedb_t *knot_zonedb_new(uint32_t size)
{
/* Create memory pool context. */
mm_ctx_t mm = {0};
mm_ctx_mempool(&mm, DEFAULT_BLKSIZE);
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
knot_zonedb_t *db = mm.alloc(mm.ctx, sizeof(knot_zonedb_t));
if (db == NULL) {
return NULL;
......
......@@ -19,7 +19,7 @@
#include "common/base64.h"
#include "libknot/errcode.h"
#include "common/memdup.h"
#include "common/mem.h"
#include "libknot/binary.h"
int knot_binary_from_base64(const char *base64, knot_binary_t *to)
......
......@@ -15,14 +15,15 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <stdarg.h>
#include "libknot/mempattern.h"
#include "common/mempool.h"
static void mm_nofree(void *p)
{
/* nop */
}
static void *mm_malloc(void *ctx, size_t n)
{
(void)ctx;
......@@ -62,141 +63,3 @@ void mm_ctx_mempool(mm_ctx_t *mm, size_t chunk_size)
mm->alloc = (mm_alloc_t)mp_alloc;
mm->free = mm_nofree;
}
void* xmalloc(size_t l)
{
void *p = malloc(l);
if (p == NULL) {
// Dependency on server
// log_server_fatal("Failed to allocate %zu bytes.\n", l);
abort();
}
return p;
}
void *xrealloc(void *p, size_t l)
{
p = realloc(p, l);
if (p == NULL) {
// Dependency on server
// log_server_fatal("Failed to reallocate to %zu bytes from %p.\n",
// l, p);
abort();
}
return p;
}
int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved)
{
/* Trim excessive memory if possible. */
size_t maxlen = min + allow;
if (maxlen < min) {
return -2; /* size_t overflow */
}
/* Meet target size but trim excessive amounts. */
if (*reserved < min || *reserved > maxlen) {
void *trimmed = realloc(*p, maxlen * tlen);
if (trimmed != NULL) {
*p = trimmed;
*reserved = maxlen;
} else {
return -1;
}
}
return 0;
}
char* sprintf_alloc(const char *fmt, ...)
{
int size = 100;
char *p = NULL, *np = NULL;
va_list ap;
if ((p = malloc(size)) == NULL)
return NULL;
while (1) {
/* Try to print in the allocated space. */
va_start(ap, fmt);
int n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
return p;
/* Else try again with more space. */
if (n > -1) { /* glibc 2.1 */
size = n+1; /* precisely what is needed */
} else { /* glibc 2.0 */
size *= 2; /* twice the old size */
}
if ((np = realloc (p, size)) == NULL) {
free(p);
return NULL;
} else {
p = np;
}
}
/* Should never get here. */
return p;
}
char* strcdup(const char *s1, const char *s2)
{
if (!s1 || !s2) {
return NULL;
}
size_t s1len = strlen(s1);
size_t s2len = strlen(s2);
size_t nlen = s1len + s2len + 1;
char* dst = malloc(nlen);
if (dst == NULL) {
return NULL;
}
memcpy(dst, s1, s1len);
memcpy(dst + s1len, s2, s2len + 1);
return dst;
}
#ifdef MEM_DEBUG
/*
* ((destructor)) attribute executes this function after main().
* \see http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
*/
void __attribute__ ((destructor)) usage_dump()
#else
void usage_dump()
#endif
{
/* Get resource usage. */
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) < 0) {
memset(&usage, 0, sizeof(struct rusage));
}
fprintf(stderr, "\nMemory statistics:");
fprintf(stderr, "\n==================\n");
fprintf(stderr, "User time: %.03lf ms\nSystem time: %.03lf ms\n",
usage.ru_utime.tv_sec * (double) 1000.0
+ usage.ru_utime.tv_usec / (double)1000.0,
usage.ru_stime.tv_sec * (double) 1000.0
+ usage.ru_stime.tv_usec / (double)1000.0);
fprintf(stderr, "Major page faults: %lu (required I/O)\nMinor page faults: %lu\n",
usage.ru_majflt, usage.ru_minflt);
fprintf(stderr, "Number of swaps: %lu\n",
usage.ru_nswap);
fprintf(stderr, "Voluntary context switches: %lu\nInvoluntary context switches: %lu\n",
usage.ru_nvcsw,
usage.ru_nivcsw);
fprintf(stderr, "==================\n");
}
......@@ -29,22 +29,20 @@
#include <stddef.h>
/* Default memory block size. */
#define DEFAULT_BLKSIZE 4096
#define MM_DEFAULT_BLKSIZE 4096
/* Memory allocation function prototypes. */
typedef void* (*mm_alloc_t)(void* ctx, size_t len);
typedef void (*mm_free_t)(void *p);
typedef void (*mm_flush_t)(void *p);
/* Reusable functions. */
static inline void mm_nofree(void *p) {}
/* Memory allocation context. */
typedef struct mm_ctx {
void *ctx; /* \note Must be first */
mm_alloc_t alloc;
mm_free_t free;
} mm_ctx_t;
/*! \brief Allocs using 'mm' if any, uses system malloc() otherwise. */
void *mm_alloc(mm_ctx_t *mm, size_t size);
/*! \brief Reallocs using 'mm' if any, uses system realloc() otherwise. */
......@@ -56,58 +54,4 @@ void mm_ctx_init(mm_ctx_t *mm);
/*! \brief Memory pool context. */
void mm_ctx_mempool(mm_ctx_t *mm, size_t chunk_size);
/*! \brief Allocate memory or die. */
void* xmalloc(size_t l);
/*! \brief Reallocate memory or die. */
void *xrealloc(void *p, size_t l);
/*!
* \brief Reserve new or trim excessive memory.
*
* \param p Double-pointer to memory region.
* \param tlen Memory unit (f.e. sizeof(int) for int* array)
* \param min Minimum number of items required.
* \param allow Maximum extra items to keep (for trimming).
* \param reserved Pointer to number of already reserved items.
*
* \note Example usage:
* char *buf = NULL; size_t len = 0;
* if (mreserve(&buf, sizeof(char), 6, 0, &len) == 0) {
* memcpy(buf, "hello", strlen("hello");
* if (mreserve(&buf, sizeof(char), 20, 0, &len) == 0) {
* strncat(buf, "!", 1);
* mreserve(&buf, sizeof(char), strlen("hello!")+1, 0, &len);
* }
* }
* free(buf);
*
* \retval 0 on success.
* \retval -1 on error.
*
* \note Memory region will be left untouched if function fails.
*/
int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved);
/*!
* \brief Format string and take care of allocating memory.
*
* \note sprintf(3) manual page reference implementation.
*
* \param fmt Message format.
* \return formatted message or NULL.
*/
char *sprintf_alloc(const char *fmt, ...);
/*!
* \brief Create new string from a concatenation of s1 and s2.
*
* \param s1 First string.
* \param s2 Second string.
*
* \retval Newly allocated string on success.
* \retval NULL on error.
*/
char *strcdup(const char *s1, const char *s2);
/*! @} */
......@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/memdup.h"
#include "common/mem.h"
#include "libknot/errcode.h"
#include "libknot/rrtype/nsec3param.h"
......
......@@ -28,8 +28,8 @@
#include "utils/common/exec.h"
#include "utils/common/netio.h"
#include "utils/common/token.h"
#include "common/mem.h"
#include "libknot/errcode.h"
#include "libknot/mempattern.h"
#include "libknot/descriptor.h"
#include "common-knot/strlcpy.h"
#include "libknot/common.h"
......
......@@ -90,7 +90,7 @@ static int nsupdate_init(nsupdate_params_t *params)
init_list(&params->prereq_list);
/* Initialize memory context. */
mm_ctx_mempool(&params->mm, DEFAULT_BLKSIZE);
mm_ctx_mempool(&params->mm, MM_DEFAULT_BLKSIZE);
/* Default server. */
params->server = srv_info_create(DEFAULT_IPV4_NAME, DEFAULT_DNS_PORT);
......
......@@ -101,7 +101,7 @@ int main(int argc, char *argv[])
*/
/* Create packet. */
knot_pkt_t *out = knot_pkt_new(NULL, DEFAULT_BLKSIZE, &mm);
knot_pkt_t *out = knot_pkt_new(NULL, MM_DEFAULT_BLKSIZE, &mm);
ok(out != NULL, "pkt: new");
/* Mark as response (not part of the test). */
......
......@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
/* Create processing context. */
mm_ctx_t mm;
mm_ctx_mempool(&mm, DEFAULT_BLKSIZE);
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
/* Create a map of expected steps. */
bool state_map[QUERY_PLAN_STAGES] = { false };
......
......@@ -116,7 +116,7 @@ int main(int argc, char *argv[])
plan(TESTS_COUNT + 1);
mm_ctx_t mm;
mm_ctx_mempool(&mm, DEFAULT_BLKSIZE);
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
conf_iface_t remote;
memset(&remote, 0, sizeof(conf_iface_t));
sockaddr_set(&remote.addr, AF_INET, "127.0.0.1", 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment