#include "SCK.H"

#ifdef use_llseek

#include <asm/unistd.h>
static _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);

ssize_t xpread(int h, void *buf, size_t count, __u64 off)
{
	loff_t res;
	if (__unlikely(_llseek(h, off >> 32, off & 0xFFFFFFFF, &res, SEEK_SET) != 0)) return -1;
	return read(h, buf, count);
}

ssize_t xpwrite(int h, void *buf, size_t count, __u64 off)
{
	loff_t res;
	if (__unlikely(_llseek(h, off >> 32, off & 0xFFFFFFFF, &res, SEEK_SET) != 0)) return -1;
	return write(h, buf, count);
}

#endif

#ifdef TESTCODE

typedef struct {
	LIST_ENTRY list;
	size_t size;
	void *fn;
	unsigned magic;
} MALLOC_BLOCK;

#define MALLOC_MAGIC	0xa110c
#define FREE_MAGIC	0xf4ee
#define REDZONE		'R'

static DECL_XLIST(alloc_list);

#endif

void *mem_alloc(size_t s)
{
#ifdef TESTCODE
	if (__unlikely(debug_malloc)) {
		MALLOC_BLOCK *m = __sync_malloc(s + sizeof(MALLOC_BLOCK) + 1);
		if (__unlikely(!m)) return NULL;
		m->size = s;
#if defined(__GNUC__)
		m->fn = __builtin_return_address(0);
#else
		m->fn = NULL;
#endif
		m->magic = MALLOC_MAGIC;
		ADD_TO_XLIST(&alloc_list, &m->list);
		((unsigned char *)(m + 1))[s] = REDZONE;
		return m + 1;
#if defined(__GNUC__) && (__GNUC__ <= 2)
		alloca(1);	/* GCC 2.7.2.1 has broken __builtin_return_address with -fomit-frame-pointer, force frame pointer */
#endif
	}
#endif
	return __sync_malloc(s);
}

void mem_free(void *p)
{
	if (__unlikely(!p)) return;
#ifdef TESTCODE
	if (__unlikely(debug_malloc)) {
		MALLOC_BLOCK *m = (MALLOC_BLOCK *)p - 1;
		if (__unlikely(m->magic != MALLOC_MAGIC)) KERNEL$SUICIDE("mem_free: INVALID BLOCK %p, MAGIC %X, SIZE %lX, ALLOCATED AT %p", m, m->magic, (unsigned long)m->size, m->fn);
		if (__unlikely(((unsigned char *)(m + 1))[m->size] != REDZONE)) KERNEL$SUICIDE("mem_free: REDZONE DAMAGED, BLOCK %p, SIZE %lX, ZONE %02X, ALLOCATED AT %p", m, (unsigned long)m->size, ((unsigned char *)(m + 1))[m->size], m->fn);
		DEL_FROM_LIST(&m->list);
		m->magic = FREE_MAGIC;
		p = m;
	}
#endif
	free(p);
}

void mem_done(void)
{
#ifdef TESTCODE
	if (__unlikely(debug_malloc)) {
		if (__unlikely(!XLIST_EMPTY(&alloc_list))) {
			char badmem = 0;
			MALLOC_BLOCK *m;
			_eprintf("MEMORY LEAKED:\n");
			XLIST_FOR_EACH(m, &alloc_list, MALLOC_BLOCK, list) {
				_eprintf(" %p:%lX @ %p ", m, (unsigned long)m->size, m->fn);
				if (__unlikely(m->magic != MALLOC_MAGIC)) _eprintf("BAD MAGIC %X!!! ", m->magic), badmem = 1;
				if (__unlikely(((unsigned char *)(m + 1))[m->size] != REDZONE)) _eprintf("BAD REDZONE %02X!!! ", ((unsigned char *)(m + 1))[m->size]), badmem = 1;
			}
			_eprintf("\n");
			if (__unlikely(badmem)) KERNEL$SUICIDE("mem_done: MEMORY CORRUPTED");
		} else {
			_eprintf("memory ok.\n");
		}
	}
#endif
}
