#
# This file defines probes for local features that vmalloc requires.
# Such probes are interpreted by the "iffe" language interpreter.
# Results are stored in the FEATURE directory. Some of the
# {lib,hdr,sys,typ} tests may also be done in the AST features/lib;
# repeating them here allows for single standalone and AST sources.
#

ref	-D_def_map_ast=1

lib	atexit,getpagesize,mallinfo,mallopt,memalign,mstats
lib	onexit,pvalloc,strdup,valloc,vmalloc
lib	_malloc,__malloc,__libc_malloc
hdr	alloca,malloc,stat,stdlib,unistd,sys/shm
mem	mallinfo.arena,mstats.bytes_total malloc.h
sys	stat
typ	ssize_t

tst	mem_sbrk note{ brk()/sbrk() work as expected }end execute{
	#include        <sys/types.h>
	#include        <unistd.h>
	#undef	uchar
	#define	uchar	unsigned char
	int main()
	{	uchar	*brk0, *brk1;

		/* allocate a big chunk */
		if(!(brk0 = (uchar*)sbrk(0)) || brk0 == (uchar*)(-1))
			return 1;
		brk0 += 256*1024;
		if(brk(brk0) != 0)
			return 1;
		if((brk1 = (uchar*)sbrk(0)) != brk0)
			return 1;

		/* now return half of it */
		brk1 -= 128*1024;
		if(brk(brk1) != 0 )
			return 1;
		if((brk0 = (uchar*)sbrk(0)) != brk1)
			return 1;

		return 0;
	}
}end

tst	map_malloc note{ map malloc to _ast_malloc }end noexecute{
	#if __CYGWIN__
	int main() { return 1; }
	#else
	static int user = 0;
	#if _lib_strdup
	extern char* strdup(const char*);
	#define LOCAL()	strdup("s")
	#else
	extern void* calloc(unsigned int, unsigned int);
	#define LOCAL()	calloc(1,1)
	#endif
	#define HT double
	static HT heap[1024 * 4];
	static HT* hp = &heap[1];
	static HT* op;
	#define MALLOC(n) if(user)return&heap[0];op=hp;hp+=(n+sizeof(HT)-1)/sizeof(HT);return(void*)op;
	#define INTERCEPTED(p) (((char*)(p))==((char*)&heap[0]))
	extern void free(void* p) { }
	extern void _free(void* p) { }
	extern void __free(void* p) { }
	extern void __libc_free(void* p) { }
	extern void* malloc(unsigned int n) { MALLOC(n); }
	extern void* _malloc(unsigned int n) { MALLOC(n); }
	extern void* __malloc(unsigned int n) { MALLOC(n); }
	extern void* __libc_malloc(unsigned int n) { MALLOC(n); }
	int main() { user = 1; return !INTERCEPTED(LOCAL()); }
	#endif
}end

tst	map_malloc note{ map malloc to _ast_malloc -- wimp-o mach? }end noexecute{
	#if _map_malloc
	int main() { return 0; }
	#else
	#include <stdlib.h>
	void* calloc(size_t n, size_t m) { exit(1); }
	int main() { return 0; }
	#endif
}end

lib	alloca note{ alloca exists }end link{
	#if _hdr_alloca
	#include	<alloca.h>
	#endif
	int
	main()
	{	alloca(10);
	}
}end

tst	mal_alloca note{ alloca is based on malloc() }end execute{
	#if __CYGWIN__
	int main() { return 1; }
	#else
	#if _hdr_alloca
	#include	<alloca.h>
	#endif
	#include <stdlib.h>
	void* malloc(size_t size)
	{	exit(0);
		return 0;
	}
	int main()
	{	alloca(10);
		return 1;
	}
	#endif
}end

tst	stk_down note{ stack grows downward }end execute{
	static growdown()
	{	static char*	addr = 0;
		char		array[4];
		if(!addr)
		{	addr = &array[0];
			return growdown();
		}
		else if(addr < &array[0])
			return 0;
		else	return 1;	
	}
	int main() { return growdown() ? 0 : 1; }
}end

tst	malloc_hook note{ GNU malloc hooks work }end execute{
	#include <malloc.h>

	static int      	test_free_hit = 0;
	static int      	test_malloc_hit = 0;
	static int      	test_memalign_hit = 0;
	static int      	test_realloc_hit = 0;

	static void test_free_hook(void* ptr, const void* caller)
	{
	        test_free_hit++;
	}

	static void* test_malloc_hook(size_t size, const void* caller)
	{
	        test_malloc_hit++;
	        return 0;
	}

	static void* test_memalign_hook(size_t align, size_t size, const void* caller)
	{
	        test_memalign_hit++;
	        return 0;
	}

	static void* test_realloc_hook(void* ptr, size_t size, const void* caller)
	{
	        test_realloc_hit++;
	        return 0;
	}

	static void test_initialize_hook(void)
	{
	        __free_hook = test_free_hook;
	        __malloc_hook = test_malloc_hook;
	        __memalign_hook = test_memalign_hook;
	        __realloc_hook = test_realloc_hook;
	}

	void    (*__malloc_initialize_hook)(void) = test_initialize_hook;

	int main()
	{
	        void*   p;

	        p = malloc(16);
	        p = realloc(p, 32);
	        free(p);
	        p = memalign(32, 32);
	        return !test_free_hit || !test_malloc_hit || !test_memalign_hit || !test_realloc_hit;
	}
}end

cat{
	#include "FEATURE/mmap"
	/* AST vmalloc is deprecated for being crashy and wasteful; ksh 93u+m uses the OS's malloc by default */
	#undef _std_malloc
	#undef _AST_std_malloc
	#if !_AST_vmalloc
	#undef	_map_malloc
	#define _std_malloc	1	/* defer to standard malloc */
	#define _AST_std_malloc	1
	#endif
	#if _mmap_anon
	#define _mem_mmap_anon	1
	#endif
	#if _mmap_devzero
	#define _mem_mmap_zero	1
	#endif
}end
