/* thread creation and destruction functions */

#include "../fb.h"
#include "../fb_private_thread.h"

/* thread proxy to user's thread proc */
static void *threadproc( void *param )
{
	FBTHREADINFO *info = param;

	/* call the user thread */
	info->proc( info->param );
	free( info );

	/* free mem */
	fb_TlsFreeCtxTb( );

	/* don't return NULL or exit() will be called */
	return (void *)1;
}

FBCALL FBTHREAD *fb_ThreadCreate( FB_THREADPROC proc, void *param, ssize_t stack_size )
{
	FBTHREAD *thread;
	FBTHREADINFO *info;
	pthread_attr_t tattr;

	thread = (FBTHREAD *)malloc( sizeof( FBTHREAD ) );
	if( thread == NULL ) {
		return NULL;
	}

	info = (FBTHREADINFO *)malloc( sizeof( FBTHREADINFO ) );
	if( info == NULL ) {
		free( thread );
		return NULL;
	}

	info->proc = proc;
	info->param = param;

	if( pthread_attr_init( &tattr ) ) {
		free( thread );
		free( info );
		return NULL;
	}

	/* Solaris pthread.h does not define PTHREAD_STACK_MIN */
#ifdef PTHREAD_STACK_MIN
	stack_size = stack_size >= PTHREAD_STACK_MIN ? stack_size : PTHREAD_STACK_MIN;
#endif

	pthread_attr_setstacksize( &tattr, stack_size );

	if( pthread_create( &thread->id, &tattr, threadproc, info ) ) {
		free( thread );
		free( info );
		thread = NULL;
	}

	pthread_attr_destroy( &tattr );
	return thread;
}

FBCALL void fb_ThreadWait( FBTHREAD *thread )
{
	if( thread == NULL )
		return;

	pthread_join( thread->id, NULL );

	free( thread );
}
