#ifndef _DWC_THREAD_C
#define _DWC_THREAD_C

#if defined(__THREAD_BASED_DW)

/*--------------------------------------------------------------------------
 *  Copyright (c) 2001-2004 Igor Daniloff. 
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at this directory.
 *------------------------------------------------------------------------*/
 
#ifndef lint
static const char rcsid[] = "$Id: dwc_thread.c,v 1.21 2005/09/21 09:20:44 asv Exp $";
#endif

#ifdef __UNIX_DW
#include <signal.h>
#include "dwc_err.h"
#include "dwc_lib.h"
#endif /* __UNIX_DW */
#ifdef __WIN32_DW
#include <process.h>
#include "dw_winlib.h"
#endif /* __WIN32_DW */
#include "dwc_thread.h"
#include "dwc_macro.h"

#if defined(__UNIX_DW)
#define DW_THREAD_RET_TYPE  void*
#define DW_THREAD_RET_MOD   
#define DW_THREAD_ARG_TYPE  void*
#define DW_THREAD_EXIT      pthread_exit(NULL)
#define DW_THREAD_ID_TYPE   pthread_t
#endif /* UNIX */

#if defined(__WIN32_DW)
#define DW_THREAD_RET_TYPE  unsigned 
#define DW_THREAD_RET_MOD   __cdecl
#define DW_THREAD_ARG_TYPE  void*
#define DW_THREAD_EXIT      return 0
#define DW_THREAD_ID_TYPE   unsigned
#endif /* WIN32 */

struct DWC_int_thread_t {
    DWC_thread_func_t func;
    DWC_thread_arg_t  arg;
};
typedef struct DWC_int_thread_t*   DWC_thread_t;

DW_THREAD_RET_TYPE DW_THREAD_RET_MOD dw_thread_runner( DW_THREAD_ARG_TYPE thread );

/* -------------------------------------------------------------------- */
DW_THREAD_RET_TYPE DW_THREAD_RET_MOD dw_thread_runner( DW_THREAD_ARG_TYPE thread )
{
    DWC_thread_func_t routine;
    DWC_thread_arg_t  argument;

    if( thread )
    {
        routine = ((DWC_thread_t)thread)->func;
        argument = ((DWC_thread_t)thread)->arg;
        printLib( DW_LL_DEBUG, "dwlib: thread::runner - thread = %p, routine = %p, arg = %p", thread, routine, argument );
        DWC_Free( thread );
        (*routine)( argument );
    }
    else
    {
        printLib( DW_LL_ERROR, "dwlib: thread::runner - null thread was passed" );
    }
    DW_THREAD_EXIT;
    return 0; /* never execute */
}

/* -------------------------------------------------------------------- */
DWC_error_code_t dwc_thread_create( DWC_thread_func_t func, DWC_thread_arg_t arg )
{
    int                error;
    DWC_thread_t       thread;
    DW_THREAD_ID_TYPE  handle;
#if defined(__UNIX_DW)
    pthread_attr_t     attr;
#endif /* __UNIX_DW */

    if( !func )
    {
        printLib( DW_LL_ERROR, "dwlib: thread::create failed - no thread routine" );    
        return DWC_BADPARAMS;
    }
    thread = DWC_Malloc( DWC_thread_t, sizeof(struct DWC_int_thread_t) );
    if( !thread )
    {
        printLib( DW_LL_ERROR, "dwlib: thread: creating failed - no memory" );
        return DWC_NOMEMORY;
    }
    thread->func = func;
    thread->arg = arg;
#if defined(__UNIX_DW)
    if( (0 == (error = pthread_attr_init( &attr )))
        &&
        (0 == (error = pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED )) ) )
    {
        error = pthread_create( &handle, &attr, dw_thread_runner, (void*) thread );
    }
    pthread_attr_destroy( &attr );
#endif /* __UNIX_DW */
#if defined(__WIN32_DW)
    handle = _beginthread( dw_thread_runner, 0, (void*) thread );
    if( handle < 0 )
        error = errno;
    else  
        error = 0;
#endif /* __WIN32_DW */
    if( 0 != error )
    {
        printLib( DW_LL_ERROR, "dwlib: thread: creating failed - %s", stdlib_error( error ) );
        DWC_Free( thread );
        return DWC_COMMONERROR;
    }
    return DWC_NOERROR;
}

#endif /* __THREAD_BASED_DW */

#endif /* _DWC_THREAD_H */
