/* Copyright (c) 2000 Sinby.com
   All Rights Reserved

   This project is covered by the GNU General Public License. */

/* $Id: jthread.h,v 1.1.1.1 2000/12/22 07:22:06 ryos Exp $ */

#ifndef __ecos_native_jthread_h
#define __ecos_native_jthread_h

#include "config.h"
#include "config-setjmp.h"
#include "config-std.h"
#include "config-mem.h"
#include "config-io.h"
#include "jtypes.h"
#include "gtypes.h"
#include "thread.h"
#include "support.h"
#include "md.h"
#include "lerrno.h"

#include <cyg/kernel/kapi.h>

typedef struct jthread {
	struct jthread *next;
	struct jthread *prev;

	unsigned long status;
	int daemon;

	unsigned int stopCount;

	cyg_handle_t thread_handle;
	cyg_thread thread;

	void *cookie;
	void *func;

} *jthread_t;

#define CHANGE_PRIORITY_JAVA2CYG(priority) (20 - priority)
#define MILLISEC_TO_TICK(msec) ((msec)*10)
#define JTHREAD_INDEX 4

/* thread status */
#define THREAD_STAT_ALIVE				0x0001
#define THREAD_STAT_ALIVE_DONTSTOP		0x0002
#define THREAD_STAT_IWANTTO_STOP		0x0004
#define THREAD_STAT_DEAD				0x0008

#define THREAD_STAT_INIT_THREAD			0xFFFF

#define THREAD_STAT_MASK				0x000F
#define THREAD_STAT_SIZE				4

#define THREAD_EVENT_DISABLE_STOP		0
#define THREAD_EVENT_ENABLE_STOP		1
#define THREAD_EVENT_SUDDEN_DEATH		2

#define THREAD_EVENT_MASK				0xF
#define THREAD_EVENT_SIZE				4

struct jthread_link {
	struct jthread *next;
	struct jthread *prev;
};

#ifdef DEBUG
typedef struct jthread jthread_link_t;
#else
typedef struct jthread_link jthread_link_t;
#endif


struct jthread_system {
	int  max_priority;
	int  min_priority;
	void *(*allocator)(size_t);
	void (*deallocator)(void*);
	void (*destructorl)(void*);
	void (*onstop)(void);
	void (*ondeadlock)(void);

	void (*runOnExit)(void);

	cyg_mutex_t threadLock;

	jthread_link_t terminal;
	jthread_link_t anchor;

	unsigned int threadN;
	unsigned int daemonN;
};

extern struct jthread_system jthread_system;

void
jthread_init(
	int preemptive,			/* preemptive scheduling */
	int maxpr, 			/* maximum priority */
	int minpr, 			/* minimum priority */
	void *(*_allocator)(size_t),	/* memory allocator */
	void (*_deallocator)(void*),	/* memory deallocator */
	void (*_destructor1)(void*),	/* called when a thread exits */ 
	void (*_onstop)(void),		/* called when a thread is stopped */
	void (*_ondeadlock)(void));     /* called on deadlock */

jthread_t
jthread_create(unsigned int pri,void (*func)(void *),int daemon,void *cookie,size_t threadStackSize);

struct _exceptionFrame;
typedef void (*exchandler_t)(struct _exceptionFrame*);

void 	jthread_initexceptions(exchandler_t _nullHandler, exchandler_t _floatingHandler);
void 	jthread_atexit(void (*f)(void));
void 	jthread_walkLiveThreads(void (*func)(void *jlThread));

void	jthread_destroy(jthread_t jtid);

void	jthread_setpriority(jthread_t jtid, int prio);


void 	jthread_yield(void);
void 	jthread_sleep(jlong time);

jthread_t jthread_createfirst(size_t mainThreadStackSize,unsigned char prio,void* jlThread);


static inline jthread_t jthread_current(void)
{
	jthread_t tid,iter;
	cyg_handle_t thread_handle;
	int i,index;
	int found;

	thread_handle = cyg_thread_self();
	tid = ( jthread_t )cyg_thread_get_data(JTHREAD_INDEX);
	if ( tid != NULL ) {
		assert( tid->thread_handle == thread_handle );
		return tid;
	}

	found = 0;
	cyg_mutex_lock(&jthread_system.threadLock);
	iter = jthread_system.terminal.next;
	for( i = 0 ; i < jthread_system.threadN ; i++ , iter = iter->next) {
		if ( iter->thread_handle == thread_handle ) {
			found++;
			break;
		}
	}
	cyg_mutex_unlock(&jthread_system.threadLock);

	if ( !found ) {
		//diag_printf("Not Found in find_my_jthread(N == %d)\n",jthread_system.threadN);
		return NULL;
	}

	index = cyg_thread_new_data_index();
	cyg_thread_set_data(index,(CYG_ADDRWORD)iter);

	return iter;
}

int 	jthread_frames(jthread_t thrd);
int 	jthread_alive(jthread_t jtid);

void 	jthread_stop(jthread_t jtid);
void 	jthread_interrupt(jthread_t jtid);
void 	jthread_exit(void) __NORETURN__;

int 	jthread_on_current_stack(void *bp);
int 	jthread_stackcheck(int left);
void*	jthread_stacklimit(void);
int jthread_extract_stack(jthread_t jtid, void **from, unsigned *len);

void jthread_disable_stop(void);
void jthread_enable_stop(void);

void jthread_dumpthreadinfo(jthread_t tid);

void jthread_spinon(void *arg);
void jthread_spinoff(void *arg);

void jthread_suspendall(void);
void jthread_unsuspendall(void);
void* jthread_getcookie(jthread_t tid);

#endif
