/* src/threads/posix/thread-posix.hpp - POSIX thread functions

   Copyright (C) 1996-2011
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   This file is part of CACAO.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

*/


#ifndef _THREAD_POSIX_HPP
#define _THREAD_POSIX_HPP

#include "config.h"

#include <pthread.h>
#include <ucontext.h>

#include "vm/types.h"


// Includes required by Thread.

#if defined(ENABLE_TLH)
# include "mm/tlh.h"
#endif

#include "threads/condition.hpp"
#include "threads/mutex.hpp"

#include "vm/global.h"


/* threadobject ****************************************************************

   Struct holding thread local variables.

*******************************************************************************/

#define THREAD_FLAG_JAVA        0x01    /* a normal Java thread               */
#define THREAD_FLAG_INTERNAL    0x02    /* CACAO internal thread              */
#define THREAD_FLAG_DAEMON      0x04    /* daemon thread                      */
#define THREAD_FLAG_IN_NATIVE   0x08    /* currently executing native code    */

#define SUSPEND_REASON_NONE      0      /* no reason to suspend               */
#define SUSPEND_REASON_JAVA      1      /* suspended from java.lang.Thread    */
#define SUSPEND_REASON_STOPWORLD 2      /* suspended from stop-the-world      */
#define SUSPEND_REASON_DUMP      3      /* suspended from threadlist dumping  */
#define SUSPEND_REASON_JVMTI     4      /* suspended from JVMTI agent         */


typedef struct threadobject threadobject;

struct threadobject {
	java_object_t        *object;       /* link to java.lang.Thread object    */

	ptrint                thinlock;     /* pre-computed thin lock value       */

	s4                    index;        /* thread index, starting with 1      */
	u4                    flags;        /* flag field                         */
	u4                    state;        /* state field                        */
	bool                  is_in_active_list; /* for debugging only            */

	pthread_t             tid;          /* pthread id                         */

#if defined(__DARWIN__)
	mach_port_t           mach_thread;       /* Darwin thread id              */
#endif

	/* for the sable tasuki lock extension */
	bool                  flc_bit;
	struct threadobject  *flc_list;     /* FLC list head for this thread      */
	struct threadobject  *flc_tail;     /* tail pointer for FLC list          */
	struct threadobject  *flc_next;     /* next pointer for FLC list          */
	java_handle_t        *flc_object;
	Mutex*                flc_lock;     /* controlling access to these fields */
	Condition*            flc_cond;

	/* these are used for the wait/notify implementation                      */
	Mutex*                waitmutex;
	Condition*            waitcond;

	Mutex*                suspendmutex; /* lock before suspending this thread */
	Condition*            suspendcond;  /* notify to resume this thread       */

	bool                  interrupted;
	bool                  signaled;
	bool                  park_permit;

	bool                  suspended;    /* is this thread suspended?          */
	s4                    suspend_reason; /* reason for suspending            */

	u1                   *pc;           /* current PC (used for profiling)    */

	java_object_t        *_exceptionptr;     /* current exception             */
	struct stackframeinfo_t     *_stackframeinfo;   /* current native stackframeinfo */
	struct localref_table       *_localref_table;   /* JNI local references          */

#if defined(ENABLE_INTRP)
	Cell                 *_global_sp;        /* stack pointer for interpreter */
#endif

#if defined(ENABLE_GC_CACAO)
	bool                  gc_critical;  /* indicates a critical section       */

	sourcestate_t        *ss;
	executionstate_t     *es;
#endif

	struct DumpMemory*    _dumpmemory;     ///< Dump memory structure.

#if defined(ENABLE_DEBUG_FILTER)
	u2                    filterverbosecallctr[2]; /* counters for verbose call filter */
#endif

#if !defined(NDEBUG)
	s4                    tracejavacallindent;
	u4                    tracejavacallcount;
#endif

#if defined(ENABLE_TLH)
	tlh_t                 tlh;
#endif

#if defined(ENABLE_ESCAPE_REASON)
	void *escape_reasons;
#endif
};


/* current threadobject *******************************************************/

#if defined(HAVE___THREAD)

#define THREADOBJECT      thread_current

extern __thread threadobject *thread_current;

#else /* defined(HAVE___THREAD) */

#define THREADOBJECT \
	((threadobject *) pthread_getspecific(thread_current_key))

extern pthread_key_t thread_current_key;

#endif /* defined(HAVE___THREAD) */


/* native-world flags *********************************************************/

#if defined(ENABLE_GC_CACAO)
# define THREAD_NATIVEWORLD_ENTER THREADOBJECT->flags |=  THREAD_FLAG_IN_NATIVE
# define THREAD_NATIVEWORLD_EXIT  THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE
#else
# define THREAD_NATIVEWORLD_ENTER /*nop*/
# define THREAD_NATIVEWORLD_EXIT  /*nop*/
#endif


/* counter for verbose call filter ********************************************/

#if defined(ENABLE_DEBUG_FILTER)
#	define FILTERVERBOSECALLCTR (THREADOBJECT->filterverbosecallctr)
#endif

/* state for trace java call **************************************************/

#if !defined(NDEBUG)
#	define TRACEJAVACALLINDENT (THREADOBJECT->tracejavacallindent)
#	define TRACEJAVACALLCOUNT (THREADOBJECT->tracejavacallcount)
#endif


// FIXME
#ifdef __cplusplus
extern "C" {
#endif
inline static threadobject* thread_get_current(void);
#ifdef __cplusplus
}
#endif


// Includes.
#include "mm/memory.hpp"

#include "native/localref.hpp"

#include "threads/lock.hpp"

#include "vm/global.h"
#include "vm/vm.hpp"

#if defined(ENABLE_GC_CACAO)
# include "vm/jit/executionstate.h"
# include "vm/jit/replace.hpp"
#endif

#if defined(ENABLE_INTRP)
#include "vm/jit/intrp/intrp.h"
#endif


// FIXME
#ifdef __cplusplus
extern "C" {
#endif

/* inline functions ***********************************************************/

/**
 * Return the Thread object of the current thread.
 *
 * @return The current Thread object.
 */
inline static threadobject* thread_get_current(void)
{
	threadobject *t;

#if defined(HAVE___THREAD)
	t = thread_current;
#else
	t = (threadobject *) pthread_getspecific(thread_current_key);
#endif

	return t;
}


/**
 * Set the current Thread object.
 *
 * @param t The thread object to set.
 */
inline static void thread_set_current(threadobject* t)
{
#if defined(HAVE___THREAD)
	thread_current = t;
#else
	int result;

	result = pthread_setspecific(thread_current_key, t);

	if (result != 0)
		//os::abort_errnum(result, "thread_set_current: pthread_setspecific failed");
		vm_abort("thread_set_current: pthread_setspecific failed");
#endif
}


inline static struct stackframeinfo_t* threads_get_current_stackframeinfo(void)
{
	return THREADOBJECT->_stackframeinfo;
}

inline static void threads_set_current_stackframeinfo(struct stackframeinfo_t* sfi)
{
	THREADOBJECT->_stackframeinfo = sfi;
}


/* functions ******************************************************************/

void threads_start_thread(threadobject *thread, functionptr function);

void threads_set_thread_priority(pthread_t tid, int priority);

bool threads_suspend_thread(threadobject *thread, int32_t reason);
bool threads_resume_thread(threadobject *thread, int32_t reason);
void threads_suspend_ack();

void threads_join_all_threads(void);

void threads_sleep(int64_t millis, int32_t nanos);

void threads_wait_with_timeout_relative(threadobject *t, s8 millis, s4 nanos);

void threads_thread_interrupt(threadobject *thread);

void threads_park(bool absolute, int64_t nanos);
void threads_unpark(threadobject *thread);

#if defined(ENABLE_TLH)
void threads_tlh_add_frame();
void threads_tlh_remove_frame();
#endif

#ifdef __cplusplus
} // extern "C"
#endif

#endif // _THREAD_POSIX_HPP


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c++
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim:noexpandtab:sw=4:ts=4:
 */
