222 lines
5.2 KiB
C
222 lines
5.2 KiB
C
/*
|
|
* mc_buffer.c
|
|
*
|
|
* Author Karsten Keil <kkeil@linux-pingi.de>
|
|
*
|
|
* Copyright 2011 by Karsten Keil <kkeil@linux-pingi.de>
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
|
|
* version 2.1 as published by the Free Software Foundation.
|
|
*
|
|
* This code 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.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "mc_buffer.h"
|
|
|
|
#ifdef MI_MCBUFFER_DEBUG
|
|
#include "m_capi.h"
|
|
#define MI_MCBUFFER_DEBUG_BACKLOG 100 /* number of buffers before reuse */
|
|
static pthread_mutex_t mcb_lock;
|
|
|
|
static struct mc_buf *mcb_lost_start = NULL;
|
|
static struct mc_buf *mcb_lost_last = NULL;
|
|
static struct mc_buf *mcb_free_start = NULL;
|
|
static struct mc_buf *mcb_free_last = NULL;
|
|
static int mcb_alloc_count = 0;
|
|
static int mcb_free_count = 0;
|
|
static int *crash = NULL;
|
|
|
|
void mc_buffer_init(void)
|
|
{
|
|
pthread_mutex_init(&mcb_lock, NULL);
|
|
iprint("Setup mc buffer MI_MCBUFFER_DEBUG\n");
|
|
}
|
|
|
|
void mc_buffer_cleanup(void)
|
|
{
|
|
struct mc_buf *mc;
|
|
const char *deb;
|
|
struct mISDNhead *hh;
|
|
|
|
iprint("Clean up mc buffers %d (min backlog %d) buffers alloc %d lost %d\n",
|
|
mcb_free_count, MI_MCBUFFER_DEBUG_BACKLOG, mcb_alloc_count,
|
|
mcb_alloc_count - mcb_free_count);
|
|
pthread_mutex_lock(&mcb_lock);
|
|
mI_debug_mask |= MIDEBUG_CAPIMSG;
|
|
while (mcb_lost_start) {
|
|
mc = mcb_lost_start;
|
|
mcb_lost_start = mc->next;
|
|
eprint("Buffer %p state %x len:%d refcnt:%d allocated at %s:%d not freed\n",
|
|
mc, mc->state, mc->len, mc->refcnt, mc->filename, mc->line);
|
|
hh = (struct mISDNhead *)mc->rb;
|
|
deb = mi_msg_type2str(hh->prim);
|
|
if (deb)
|
|
eprint("Buffer: prim %s (%x) pid = %x\n", deb, hh->prim, hh->id);
|
|
if (mc->cmsg.Command != 0) /* it may crash if Command is undefined */
|
|
mCapi_cmsg2str(mc);
|
|
if (mc->l3m) {
|
|
deb = mi_msg_type2str(mc->l3m->type);
|
|
eprint("l3m: prim %s pid: %x\n", deb, mc->l3m->pid);
|
|
free_l3_msg(mc->l3m);
|
|
}
|
|
free(mc);
|
|
mcb_alloc_count--;
|
|
}
|
|
while (mcb_free_start) {
|
|
mc = mcb_free_start;
|
|
mcb_free_start = mc->next;
|
|
free(mc);
|
|
mcb_free_count--;
|
|
}
|
|
mcb_free_last = NULL;
|
|
pthread_mutex_unlock(&mcb_lock);
|
|
iprint("Clean up mc buffers finished count %d\n", mcb_free_count);
|
|
}
|
|
|
|
void mc_buffer_dump_status(void)
|
|
{
|
|
iprint("mc buffer status: %d (min backlog %d) buffers allocated %d free %d in use\n",
|
|
mcb_alloc_count, MI_MCBUFFER_DEBUG_BACKLOG, mcb_free_count, mcb_alloc_count - mcb_free_count);
|
|
}
|
|
|
|
struct mc_buf *__alloc_mc_buf(const char *file, int lineno, const char *func)
|
|
{
|
|
struct mc_buf *mc;
|
|
|
|
pthread_mutex_lock(&mcb_lock);
|
|
if (mcb_free_count > MI_MCBUFFER_DEBUG_BACKLOG) {
|
|
mc = mcb_free_start;
|
|
mcb_free_start = mc->next;
|
|
mcb_free_count--;
|
|
memset(mc, 0, sizeof(*mc));
|
|
mc->state = MSt_reused;
|
|
} else {
|
|
#ifdef MEMLEAK_DEBUG
|
|
mc = __mi_calloc(1, sizeof(struct mc_buf), __FILE__, __LINE__, __PRETTY_FUNCTION__);
|
|
#else
|
|
mc = calloc(1, sizeof(struct mc_buf));
|
|
#endif
|
|
mc->state = MSt_fresh;
|
|
mcb_alloc_count++;
|
|
}
|
|
strncpy(mc->filename, file, 79);
|
|
mc->line = lineno;
|
|
if (mcb_lost_last)
|
|
mcb_lost_last->next = mc;
|
|
mc->prev = mcb_lost_last;
|
|
mc->next = NULL;
|
|
mcb_lost_last = mc;
|
|
if (!mcb_lost_start)
|
|
mcb_lost_start = mc;
|
|
pthread_mutex_unlock(&mcb_lock);
|
|
return mc;
|
|
}
|
|
|
|
void __free_mc_buf(struct mc_buf *mc, const char *file, int lineno, const char *func)
|
|
{
|
|
/* Best we can do on free error is crash (dump core) to analyse via debugger */
|
|
if (!mc)
|
|
*crash = 99; /* crash NULL msg*/
|
|
else if (mc->state == MSt_free)
|
|
*crash = 100; /* crash double free */
|
|
else if (mc->state == Mst_NoAlloc)
|
|
*crash = 101; /* crash not allocated buffer */
|
|
else if (mc->refcnt < 0)
|
|
*crash = 102; /* crash negative refcnt */
|
|
if (mc->refcnt) {
|
|
iprint("buffer %p refcnt %d not freed at %s:%d\n", mc, mc->refcnt, file, lineno);
|
|
mc->refcnt--;
|
|
return;
|
|
}
|
|
if (mc->l3m) {
|
|
#ifdef MEMLEAK_DEBUG
|
|
__free_l3_msg(mc->l3m, file, lineno, func);
|
|
#else
|
|
free_l3_msg(mc->l3m);
|
|
#endif
|
|
mc->l3m = NULL;
|
|
}
|
|
strncpy(mc->filename, file, 79);
|
|
mc->line = lineno;
|
|
mc->state = MSt_free;
|
|
pthread_mutex_lock(&mcb_lock);
|
|
if (mc->prev)
|
|
mc->prev->next = mc->next;
|
|
if (mc->next)
|
|
mc->next->prev = mc->prev;
|
|
if (mcb_lost_last == mc)
|
|
mcb_lost_last = mc->prev;
|
|
if (mcb_lost_start == mc)
|
|
mcb_lost_start = mc->next;
|
|
|
|
if (mcb_free_last)
|
|
mcb_free_last->next = mc;
|
|
mc->prev = mcb_free_last;
|
|
mc->next = NULL;
|
|
mcb_free_last = mc;
|
|
if (!mcb_free_start)
|
|
mcb_free_start = mc;
|
|
mcb_free_count++;
|
|
pthread_mutex_unlock(&mcb_lock);
|
|
}
|
|
|
|
#else
|
|
|
|
void mc_buffer_init(void)
|
|
{
|
|
}
|
|
|
|
void mc_buffer_cleanup(void)
|
|
{
|
|
}
|
|
|
|
void mc_buffer_dump_status(void)
|
|
{
|
|
}
|
|
|
|
|
|
#ifdef MEMLEAK_DEBUG
|
|
/*
|
|
* free the message
|
|
*/
|
|
void __free_mc_buf(struct mc_buf *mc, const char *file, int lineno, const char *func)
|
|
{
|
|
if (mc->refcnt) {
|
|
mc->refcnt--;
|
|
return;
|
|
}
|
|
if (mc->l3m)
|
|
__free_l3_msg(mc->l3m, file, lineno, func);
|
|
__mi_free(mc, file, lineno, func);
|
|
}
|
|
|
|
#else
|
|
/*
|
|
* free the message
|
|
*/
|
|
void free_mc_buf(struct mc_buf *mc)
|
|
{
|
|
if (mc->refcnt) {
|
|
mc->refcnt--;
|
|
return;
|
|
}
|
|
if (mc->l3m)
|
|
free_l3_msg(mc->l3m);
|
|
free(mc);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void mc_clear_cmsg(struct mc_buf *mc)
|
|
{
|
|
memset(&mc->cmsg, 0, sizeof(mc->cmsg));
|
|
}
|