#ifndef __KERNEL_THREAD_H
#define __KERNEL_THREAD_H

#include <sys/types.h>
#include <list.h>
#include <compiler.h>
#include <arch/ops.h>
#include <arch/thread.h>

enum thread_state {
	THREAD_SUSPENDED = 0,
	THREAD_READY,
	THREAD_RUNNING,
	THREAD_BLOCKED,
	THREAD_SLEEPING,
	THREAD_DEATH,
};

typedef int (*thread_start_routine)(void *arg);

#define THREAD_MAGIC 'thrd'

struct thread {
	int magic;
	struct list_node thread_list_node;

	/* active bits */
	struct list_node queue_node;
	int priority;
	enum thread_state state;	
	int critical_section_count;

	/* architecture stuff */
	struct arch_thread arch;

	/* stack stuff */
	void *stack;
	size_t stack_size;

	/* entry point */
	thread_start_routine entry;
	void *arg;

	/* return code */
	int retcode;

	char name[32];
};

/* thread priority */
#define LOWEST_PRIORITY 0
#define HIGHEST_PRIORITY 31
#define IDLE_PRIORITY LOWEST_PRIORITY
#define DEFAULT_PRIORITY 16

#define NUM_PRIORITIES (HIGHEST_PRIORITY + 1)

/* stack size */
#define DEFAULT_STACK_SIZE 4096

/* functions */
void thread_init(void);
struct thread *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size);
status_t thread_resume(struct thread *);
void thread_exit(int retcode) __NO_RETURN;
void dump_thread(struct thread *t);
void thread_sleep(time_t delay);

/* scheduler routines */
void thread_yield(void); /* give up the cpu voluntarily */
void thread_preempt(void); /* get preempted (inserted into head of run queue) */
void thread_block(void); /* block on something and reschedule */

/* the current thread */
struct thread *current_thread;

/* critical sections */
static inline void enter_critical_section(void)
{
	current_thread->critical_section_count++;
	if (current_thread->critical_section_count == 1)
		arch_disable_ints();
}

static inline void exit_critical_section(void)
{
	current_thread->critical_section_count--;
	if (current_thread->critical_section_count == 0)
		arch_enable_ints();
}

static inline bool in_critical_section(void)
{
	return current_thread->critical_section_count > 0;
}

/* only used by interrupt glue */
static inline void inc_critical_section(void) { current_thread->critical_section_count++; }
static inline void dec_critical_section(void) { current_thread->critical_section_count--; }

/* wait queue stuff */
#define WAIT_QUEUE_MAGIC 'wait'

struct wait_queue {
	int magic;
	struct list_node list;
	int count;
};

void wait_queue_init(struct wait_queue *);
void wait_queue_block(struct wait_queue *);
int wait_queue_wake_one(struct wait_queue *, bool reschedule);
int wait_queue_wake_all(struct wait_queue *, bool reschedule);
void wait_queue_destroy(struct wait_queue *, bool reschedule);

#endif

