#include "refcnt.h"
#include "thread.h"
#include "emsg.h"
#include "lib.h"
#define DMID 9
#include "debug.h"

struct refcnt {
	Mutex *m;
	int n;
};

RefCnt *refcnt_new_real(char *name, char *file, int line)
{
	RefCnt *r = calloc(1,sizeof(RefCnt));
	r->m = th_mutex_new_remember(name,file,line);
	return r;
}

void refcnt_free_real(RefCnt **r, char *file, int line)
{
	if (!r || !*r) return ;
	th_mutex_get((*r)->m);
	if ((*r)->n != 0) {
		emsg("RefCnt (%s) isn't zero at %s:%d",(*r)->m->name,file,line);
		lib_abort();
	}
	th_mutex_release((*r)->m);
	th_mutex_free((*r)->m);
	free(*r);
}

int refcnt_is_real(RefCnt *r, char *file, int line)
{
	int i;

	if (!r) return 0;
	th_mutex_get(r->m);
	dmsg("RefCnt (%s) is (%d) at (%s:%d)",r->m->name,r->n,file,line);
	i = r->n;
	th_mutex_release(r->m);
	return i;
}

int refcnt_inc_real(RefCnt *r, char *file, int line)
{
	int i;

	if (!r) return 0;
	th_mutex_get(r->m);
	i = ++r->n;
	dmsg("RefCnt (%s) increases to (%d) at (%s:%d)",r->m->name,r->n,file,line);
	th_mutex_release(r->m);
	return i;
}

int refcnt_dec_real(RefCnt *r, char *file, int line)
{
	int i;

	if (!r) return 0;
	th_mutex_get(r->m);
	if (r->n == 0) {
		emsg("RefCnt (%s) already zero (%s:%d)",r->m->name,file,line);
		lib_abort();
	}
	i = --r->n;
	dmsg("RefCnt (%s) decreases to (%d) at (%s:%d)",r->m->name,r->n,file,line);
	th_mutex_release(r->m);
	return i;
}
