mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
cleanup and unit test for alloc, also lock protection statements.
git-svn-id: file:///svn/unbound/trunk@168 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
138aa8eebc
commit
1ea78ab032
13 changed files with 148 additions and 31 deletions
|
|
@ -114,8 +114,9 @@ daemon_init()
|
||||||
if(!daemon)
|
if(!daemon)
|
||||||
return NULL;
|
return NULL;
|
||||||
signal_handling_record();
|
signal_handling_record();
|
||||||
lock_basic_init(&daemon->lock);
|
checklock_start();
|
||||||
daemon->need_to_exit = 0;
|
daemon->need_to_exit = 0;
|
||||||
|
alloc_init(&daemon->superalloc, NULL);
|
||||||
return daemon;
|
return daemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,8 +303,9 @@ daemon_delete(struct daemon* daemon)
|
||||||
if(!daemon)
|
if(!daemon)
|
||||||
return;
|
return;
|
||||||
listening_ports_free(daemon->ports);
|
listening_ports_free(daemon->ports);
|
||||||
lock_basic_destroy(&daemon->lock);
|
alloc_clear(&daemon->superalloc);
|
||||||
free(daemon->cwd);
|
free(daemon->cwd);
|
||||||
free(daemon->pidfile);
|
free(daemon->pidfile);
|
||||||
free(daemon);
|
free(daemon);
|
||||||
|
checklock_stop();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#define DAEMON_H
|
#define DAEMON_H
|
||||||
|
|
||||||
#include "util/locks.h"
|
#include "util/locks.h"
|
||||||
|
#include "util/alloc.h"
|
||||||
struct config_file;
|
struct config_file;
|
||||||
struct worker;
|
struct worker;
|
||||||
struct listen_port;
|
struct listen_port;
|
||||||
|
|
@ -52,8 +53,6 @@ struct listen_port;
|
||||||
* Holds globally visible information.
|
* Holds globally visible information.
|
||||||
*/
|
*/
|
||||||
struct daemon {
|
struct daemon {
|
||||||
/** mutex for exclusive access to this structure. */
|
|
||||||
lock_basic_t lock;
|
|
||||||
/** The config settings */
|
/** The config settings */
|
||||||
struct config_file* cfg;
|
struct config_file* cfg;
|
||||||
/** current working directory */
|
/** current working directory */
|
||||||
|
|
@ -70,6 +69,8 @@ struct daemon {
|
||||||
struct worker** workers;
|
struct worker** workers;
|
||||||
/** do we need to exit unbound (or is it only a reload?) */
|
/** do we need to exit unbound (or is it only a reload?) */
|
||||||
int need_to_exit;
|
int need_to_exit;
|
||||||
|
/** master allocation cache */
|
||||||
|
struct alloc_cache superalloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
#include "util/random.h"
|
#include "util/random.h"
|
||||||
#include "daemon/worker.h"
|
#include "daemon/worker.h"
|
||||||
|
#include "daemon/daemon.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
|
|
@ -387,6 +388,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||||
fatal_exit("could not set forwarder address");
|
fatal_exit("could not set forwarder address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
alloc_init(&worker->alloc, &worker->daemon->superalloc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,6 +418,7 @@ worker_delete(struct worker* worker)
|
||||||
if(worker->cmd_recv_fd != -1)
|
if(worker->cmd_recv_fd != -1)
|
||||||
close(worker->cmd_recv_fd);
|
close(worker->cmd_recv_fd);
|
||||||
worker->cmd_recv_fd = -1;
|
worker->cmd_recv_fd = -1;
|
||||||
|
alloc_clear(&worker->alloc);
|
||||||
free(worker);
|
free(worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
#include "util/locks.h"
|
#include "util/locks.h"
|
||||||
|
#include "util/alloc.h"
|
||||||
struct listen_dnsport;
|
struct listen_dnsport;
|
||||||
struct outside_network;
|
struct outside_network;
|
||||||
struct config_file;
|
struct config_file;
|
||||||
|
|
@ -105,6 +106,8 @@ struct worker {
|
||||||
struct ub_randstate* rndstate;
|
struct ub_randstate* rndstate;
|
||||||
/** do we need to restart (instead of exit) ? */
|
/** do we need to restart (instead of exit) ? */
|
||||||
int need_to_restart;
|
int need_to_restart;
|
||||||
|
/** allocation cache for this thread */
|
||||||
|
struct alloc_cache alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
- added rwlock writelock checking.
|
- added rwlock writelock checking.
|
||||||
So it will keep track of the writelock, and readlocks are enforced
|
So it will keep track of the writelock, and readlocks are enforced
|
||||||
to not change protected memory areas.
|
to not change protected memory areas.
|
||||||
|
- log_hex function to dump hex strings to the logfile.
|
||||||
|
- checklocks zeroes its destroyed lock after checking memory areas.
|
||||||
|
- unit test for alloc.
|
||||||
|
|
||||||
8 March 2007: Wouter
|
8 March 2007: Wouter
|
||||||
- Reviewed checklock code.
|
- Reviewed checklock code.
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,8 @@ static void lock_error(struct checked_lock* lock,
|
||||||
log_err("At %s %s:%d", func, file, line);
|
log_err("At %s %s:%d", func, file, line);
|
||||||
log_err("Error for %s lock: %s",
|
log_err("Error for %s lock: %s",
|
||||||
(lock->type==check_lock_mutex)?"mutex": (
|
(lock->type==check_lock_mutex)?"mutex": (
|
||||||
(lock->type==check_lock_spinlock)?"spinlock": "rwlock"), err);
|
(lock->type==check_lock_spinlock)?"spinlock": (
|
||||||
|
(lock->type==check_lock_rwlock)?"rwlock": "badtype")), err);
|
||||||
fatal_exit("bailing out");
|
fatal_exit("bailing out");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,8 +112,9 @@ acquire_locklock(struct checked_lock* lock,
|
||||||
|
|
||||||
/** add protected region */
|
/** add protected region */
|
||||||
void
|
void
|
||||||
lock_protect(struct checked_lock* lock, void* area, size_t size)
|
lock_protect(void *p, void* area, size_t size)
|
||||||
{
|
{
|
||||||
|
struct checked_lock* lock = *(struct checked_lock**)p;
|
||||||
struct protected_area* e = (struct protected_area*)malloc(
|
struct protected_area* e = (struct protected_area*)malloc(
|
||||||
sizeof(struct protected_area));
|
sizeof(struct protected_area));
|
||||||
if(!e)
|
if(!e)
|
||||||
|
|
@ -144,6 +146,8 @@ prot_check(struct checked_lock* lock,
|
||||||
struct protected_area* p = lock->prot;
|
struct protected_area* p = lock->prot;
|
||||||
while(p) {
|
while(p) {
|
||||||
if(memcmp(p->hold, p->region, p->size) != 0) {
|
if(memcmp(p->hold, p->region, p->size) != 0) {
|
||||||
|
log_hex("memory prev", p->hold, p->size);
|
||||||
|
log_hex("memory here", p->region, p->size);
|
||||||
lock_error(lock, func, file, line,
|
lock_error(lock, func, file, line,
|
||||||
"protected area modified");
|
"protected area modified");
|
||||||
}
|
}
|
||||||
|
|
@ -211,6 +215,9 @@ static void
|
||||||
checktype(enum check_lock_type type, struct checked_lock* lock,
|
checktype(enum check_lock_type type, struct checked_lock* lock,
|
||||||
const char* func, const char* file, int line)
|
const char* func, const char* file, int line)
|
||||||
{
|
{
|
||||||
|
if(!lock)
|
||||||
|
fatal_exit("use of null/deleted lock at %s %s:%d",
|
||||||
|
func, file, line);
|
||||||
if(type != lock->type) {
|
if(type != lock->type) {
|
||||||
lock_error(lock, func, file, line, "wrong lock type");
|
lock_error(lock, func, file, line, "wrong lock type");
|
||||||
}
|
}
|
||||||
|
|
@ -232,12 +239,12 @@ checklock_destroy(enum check_lock_type type, struct checked_lock** lock,
|
||||||
|
|
||||||
/* check if delete is OK */
|
/* check if delete is OK */
|
||||||
acquire_locklock(e, func, file, line);
|
acquire_locklock(e, func, file, line);
|
||||||
*lock = NULL; /* use after free will fail */
|
|
||||||
if(e->hold_count != 0)
|
if(e->hold_count != 0)
|
||||||
lock_error(e, func, file, line, "delete while locked.");
|
lock_error(e, func, file, line, "delete while locked.");
|
||||||
if(e->wait_count != 0)
|
if(e->wait_count != 0)
|
||||||
lock_error(e, func, file, line, "delete while waited on.");
|
lock_error(e, func, file, line, "delete while waited on.");
|
||||||
prot_check(e, func, file, line);
|
prot_check(e, func, file, line);
|
||||||
|
*lock = NULL; /* use after free will fail */
|
||||||
LOCKRET(pthread_mutex_unlock(&e->lock));
|
LOCKRET(pthread_mutex_unlock(&e->lock));
|
||||||
|
|
||||||
/* contention */
|
/* contention */
|
||||||
|
|
@ -521,6 +528,7 @@ static void* checklock_main(void* arg)
|
||||||
thr->id = pthread_self();
|
thr->id = pthread_self();
|
||||||
/* Hack to get same numbers as in log file */
|
/* Hack to get same numbers as in log file */
|
||||||
thr->num = *(int*)(thr->arg);
|
thr->num = *(int*)(thr->arg);
|
||||||
|
log_assert(thr->num < THRDEBUG_MAX_THREADS);
|
||||||
log_assert(thread_infos[thr->num] == NULL);
|
log_assert(thread_infos[thr->num] == NULL);
|
||||||
thread_infos[thr->num] = thr;
|
thread_infos[thr->num] = thr;
|
||||||
LOCKRET(pthread_setspecific(thr_debug_key, thr));
|
LOCKRET(pthread_setspecific(thr_debug_key, thr));
|
||||||
|
|
@ -530,6 +538,36 @@ static void* checklock_main(void* arg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** init the main thread */
|
||||||
|
void checklock_start()
|
||||||
|
{
|
||||||
|
if(!key_created) {
|
||||||
|
struct thr_check* thisthr = (struct thr_check*)calloc(1,
|
||||||
|
sizeof(struct thr_check));
|
||||||
|
if(!thisthr)
|
||||||
|
fatal_exit("thrcreate: out of memory");
|
||||||
|
key_created = 1;
|
||||||
|
LOCKRET(pthread_key_create(&thr_debug_key, NULL));
|
||||||
|
LOCKRET(pthread_setspecific(thr_debug_key, thisthr));
|
||||||
|
thread_infos[0] = thisthr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** stop checklocks */
|
||||||
|
void checklock_stop()
|
||||||
|
{
|
||||||
|
if(key_created) {
|
||||||
|
int i;
|
||||||
|
free(thread_infos[0]);
|
||||||
|
thread_infos[0] = NULL;
|
||||||
|
for(i = 0; i < THRDEBUG_MAX_THREADS; i++)
|
||||||
|
log_assert(thread_infos[i] == NULL);
|
||||||
|
/* should have been cleaned up. */
|
||||||
|
LOCKRET(pthread_key_delete(thr_debug_key));
|
||||||
|
key_created = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** allocate debug info and create thread */
|
/** allocate debug info and create thread */
|
||||||
void
|
void
|
||||||
checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
|
checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
|
||||||
|
|
@ -539,14 +577,7 @@ checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg)
|
||||||
if(!thr)
|
if(!thr)
|
||||||
fatal_exit("thrcreate: out of memory");
|
fatal_exit("thrcreate: out of memory");
|
||||||
if(!key_created) {
|
if(!key_created) {
|
||||||
struct thr_check* thisthr = (struct thr_check*)calloc(1,
|
checklock_start();
|
||||||
sizeof(struct thr_check));
|
|
||||||
if(!thisthr)
|
|
||||||
fatal_exit("thrcreate: out of memory");
|
|
||||||
key_created = 1;
|
|
||||||
LOCKRET(pthread_key_create(&thr_debug_key, NULL));
|
|
||||||
LOCKRET(pthread_setspecific(thr_debug_key, thisthr));
|
|
||||||
thread_infos[0] = thisthr;
|
|
||||||
}
|
}
|
||||||
thr->func = func;
|
thr->func = func;
|
||||||
thr->arg = arg;
|
thr->arg = arg;
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,8 @@ struct checked_lock {
|
||||||
/**
|
/**
|
||||||
* Additional call for the user to specify what areas are protected
|
* Additional call for the user to specify what areas are protected
|
||||||
* @param lock: the lock that protects the area. It can be inside the area.
|
* @param lock: the lock that protects the area. It can be inside the area.
|
||||||
* The lock must be inited.
|
* The lock must be inited. Call with user lock. (any type).
|
||||||
|
* It demangles the lock itself (struct checked_lock**).
|
||||||
* @param area: ptr to mem.
|
* @param area: ptr to mem.
|
||||||
* @param size: length of area.
|
* @param size: length of area.
|
||||||
* You can call it multiple times with the same lock to give several areas.
|
* You can call it multiple times with the same lock to give several areas.
|
||||||
|
|
@ -179,7 +180,17 @@ struct checked_lock {
|
||||||
* at this time and protected right away against unauthorised changes until
|
* at this time and protected right away against unauthorised changes until
|
||||||
* the next lock() call is done.
|
* the next lock() call is done.
|
||||||
*/
|
*/
|
||||||
void lock_protect(struct checked_lock* lock, void* area, size_t size);
|
void lock_protect(void* lock, void* area, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise checklock. Sets up internal debug structures.
|
||||||
|
*/
|
||||||
|
void checklock_start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup internal debug state.
|
||||||
|
*/
|
||||||
|
void checklock_stop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init locks.
|
* Init locks.
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,46 @@ int testcount = 0;
|
||||||
/** test bool x, exits on failure, increases testcount. */
|
/** test bool x, exits on failure, increases testcount. */
|
||||||
#define unit_assert(x) testcount++; log_assert(x);
|
#define unit_assert(x) testcount++; log_assert(x);
|
||||||
|
|
||||||
|
#include "util/alloc.h"
|
||||||
|
/** test alloc code */
|
||||||
|
static void
|
||||||
|
alloc_test() {
|
||||||
|
alloc_special_t *t1, *t2;
|
||||||
|
struct alloc_cache major, minor1, minor2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
checklock_start();
|
||||||
|
alloc_init(&major, NULL);
|
||||||
|
alloc_init(&minor1, &major);
|
||||||
|
alloc_init(&minor2, &major);
|
||||||
|
|
||||||
|
t1 = alloc_special_obtain(&minor1);
|
||||||
|
alloc_clear(&minor1);
|
||||||
|
|
||||||
|
alloc_special_release(&minor2, t1);
|
||||||
|
t2 = alloc_special_obtain(&minor2);
|
||||||
|
unit_assert( t1 == t2 ); /* reused */
|
||||||
|
alloc_special_release(&minor2, t1);
|
||||||
|
|
||||||
|
for(i=0; i<100; i++) {
|
||||||
|
t1 = alloc_special_obtain(&minor1);
|
||||||
|
alloc_special_release(&minor2, t1);
|
||||||
|
}
|
||||||
|
if(0) {
|
||||||
|
alloc_stats(&minor1);
|
||||||
|
alloc_stats(&minor2);
|
||||||
|
alloc_stats(&major);
|
||||||
|
}
|
||||||
|
/* reuse happened */
|
||||||
|
unit_assert(minor1.num_quar + minor2.num_quar + major.num_quar == 11);
|
||||||
|
|
||||||
|
alloc_clear(&minor1);
|
||||||
|
alloc_clear(&minor2);
|
||||||
|
unit_assert(major.num_quar == 11);
|
||||||
|
alloc_clear(&major);
|
||||||
|
checklock_stop();
|
||||||
|
}
|
||||||
|
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
/** test net code */
|
/** test net code */
|
||||||
static void
|
static void
|
||||||
|
|
@ -78,6 +118,7 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
printf("Start of %s unit test.\n", PACKAGE_STRING);
|
printf("Start of %s unit test.\n", PACKAGE_STRING);
|
||||||
net_test();
|
net_test();
|
||||||
|
alloc_test();
|
||||||
printf("%d tests succeeded\n", testcount);
|
printf("%d tests succeeded\n", testcount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
util/alloc.c
15
util/alloc.c
|
|
@ -65,15 +65,19 @@ alloc_init(struct alloc_cache* alloc, struct alloc_cache* super)
|
||||||
{
|
{
|
||||||
memset(alloc, 0, sizeof(*alloc));
|
memset(alloc, 0, sizeof(*alloc));
|
||||||
alloc->super = super;
|
alloc->super = super;
|
||||||
|
if(!alloc->super) {
|
||||||
lock_quick_init(&alloc->lock);
|
lock_quick_init(&alloc->lock);
|
||||||
|
lock_protect(&alloc->lock, alloc, sizeof(*alloc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
alloc_delete(struct alloc_cache* alloc)
|
alloc_clear(struct alloc_cache* alloc)
|
||||||
{
|
{
|
||||||
alloc_special_t* p, *np;
|
alloc_special_t* p, *np;
|
||||||
if(!alloc)
|
if(!alloc)
|
||||||
return;
|
return;
|
||||||
|
if(!alloc->super)
|
||||||
lock_quick_destroy(&alloc->lock);
|
lock_quick_destroy(&alloc->lock);
|
||||||
if(alloc->super && alloc->quar) {
|
if(alloc->super && alloc->quar) {
|
||||||
/* push entire list into super */
|
/* push entire list into super */
|
||||||
|
|
@ -108,7 +112,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
|
||||||
p = alloc->quar;
|
p = alloc->quar;
|
||||||
alloc->quar = alloc_special_next(p);
|
alloc->quar = alloc_special_next(p);
|
||||||
alloc->num_quar--;
|
alloc->num_quar--;
|
||||||
alloc->special_allocated++;
|
|
||||||
alloc_special_clean(p);
|
alloc_special_clean(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +126,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
|
||||||
}
|
}
|
||||||
lock_quick_unlock(&alloc->super->lock);
|
lock_quick_unlock(&alloc->super->lock);
|
||||||
if(p) {
|
if(p) {
|
||||||
alloc->special_allocated++;
|
|
||||||
alloc_special_clean(p);
|
alloc_special_clean(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +134,6 @@ alloc_special_obtain(struct alloc_cache* alloc)
|
||||||
prealloc(alloc);
|
prealloc(alloc);
|
||||||
if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t))))
|
if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t))))
|
||||||
fatal_exit("alloc_special_obtain: out of memory");
|
fatal_exit("alloc_special_obtain: out of memory");
|
||||||
alloc->special_allocated++;
|
|
||||||
alloc_special_clean(p);
|
alloc_special_clean(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +173,6 @@ alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem)
|
||||||
alloc_special_clean(mem);
|
alloc_special_clean(mem);
|
||||||
if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) {
|
if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) {
|
||||||
/* push it to the super structure */
|
/* push it to the super structure */
|
||||||
alloc->special_allocated --;
|
|
||||||
pushintosuper(alloc, mem);
|
pushintosuper(alloc, mem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -180,12 +180,11 @@ alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem)
|
||||||
alloc_special_next(mem) = alloc->quar;
|
alloc_special_next(mem) = alloc->quar;
|
||||||
alloc->quar = mem;
|
alloc->quar = mem;
|
||||||
alloc->num_quar++;
|
alloc->num_quar++;
|
||||||
alloc->special_allocated--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
alloc_stats(struct alloc_cache* alloc)
|
alloc_stats(struct alloc_cache* alloc)
|
||||||
{
|
{
|
||||||
log_info("%salloc: %d allocated, %d in cache.", alloc->super?"":"sup",
|
log_info("%salloc: %d in cache.", alloc->super?"":"sup",
|
||||||
(int)alloc->special_allocated, (int)alloc->num_quar);
|
(int)alloc->num_quar);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,9 +73,6 @@ struct alloc_cache {
|
||||||
alloc_special_t* quar;
|
alloc_special_t* quar;
|
||||||
/** number of items in quarantine. */
|
/** number of items in quarantine. */
|
||||||
size_t num_quar;
|
size_t num_quar;
|
||||||
|
|
||||||
/** number of special type allocated */
|
|
||||||
size_t special_allocated;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -92,7 +89,7 @@ void alloc_init(struct alloc_cache* alloc, struct alloc_cache* super);
|
||||||
* Does not free the alloc struct itself (it was also allocated by caller).
|
* Does not free the alloc struct itself (it was also allocated by caller).
|
||||||
* @param alloc: is almost zeroed on exit (except some stats).
|
* @param alloc: is almost zeroed on exit (except some stats).
|
||||||
*/
|
*/
|
||||||
void alloc_delete(struct alloc_cache* alloc);
|
void alloc_clear(struct alloc_cache* alloc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a new special_t element.
|
* Get a new special_t element.
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,8 @@
|
||||||
|
|
||||||
#else /* USE_THREAD_DEBUG */
|
#else /* USE_THREAD_DEBUG */
|
||||||
#define lock_protect(lock, area, size) /* nop */
|
#define lock_protect(lock, area, size) /* nop */
|
||||||
|
#define checklock_start() /* nop */
|
||||||
|
#define checklock_stop() /* nop */
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD
|
#ifdef HAVE_PTHREAD
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
|
||||||
15
util/log.c
15
util/log.c
|
|
@ -166,3 +166,18 @@ verbose(enum verbosity_value level, const char* format, ...)
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
log_hex(const char* msg, void* data, size_t length)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t* data8 = (uint8_t*)data;
|
||||||
|
const char const* hexchar = "0123456789ABCDEF";
|
||||||
|
char* buf = malloc(length*2 + 1); /* alloc hex chars + \0 */
|
||||||
|
for(i=0; i<length; i++) {
|
||||||
|
buf[i*2] = hexchar[ data8[i] >> 4 ];
|
||||||
|
buf[i*2 + 1] = hexchar[ data8[i] & 0xF ];
|
||||||
|
}
|
||||||
|
buf[length*2] = 0;
|
||||||
|
log_info("%s[%d] %s", msg, length, buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,15 @@ void log_err(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
||||||
*/
|
*/
|
||||||
void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a hex-string to the log. Can be any length.
|
||||||
|
* performs mallocs to do so, slow. But debug useful.
|
||||||
|
* @param msg: string desc to accompany the hexdump.
|
||||||
|
* @param data: data to dump in hex format.
|
||||||
|
* @param length: length of data.
|
||||||
|
*/
|
||||||
|
void log_hex(const char* msg, void* data, size_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log fatal error message, and exit the current process.
|
* Log fatal error message, and exit the current process.
|
||||||
* Pass printf formatted arguments. No trailing newline is needed.
|
* Pass printf formatted arguments. No trailing newline is needed.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue