
#include <os/Thread.h>
#include <kernel/Thread.h>
#include <kernel/Scheduler.h>
#include <kernel/Heap.h>

namespace OS {

/* Thread */
Thread::Thread(const char *name)
{
	mKThread = new Kernel::Thread(this, &ThreadStartRoutine, (unsigned long)this, name);
}

Thread::~Thread()
{
	if (IsCurrent()) {
		panic("%s: cannot delete current thread\n", __PRETTY_FUNCTION__);	
	}
	Exit();

	/* free the stack */
	Kernel::Heap::Free((void *)mKThread->GetStackBase());	

	/* delete the kernel thread */
	delete mKThread;
}

void Thread::SetCustomStack(vaddr_t base, vaddr_t size)
{
	mKThread->SetCustomStack(base, size);
}

status_t Thread::Start(bool now)
{
	if (mKThread->GetStackSize() == 0) {
		void *stack = Kernel::Heap::Alloc(kDefaultThreadStackSize);
		if (stack == NULL)
			panic("could not allocate new stack\n");

		mKThread->SetCustomStack((vaddr_t)stack, kDefaultThreadStackSize);
	}
	
	return mKThread->Run(now);
}

void Thread::Exit()
{
	mKThread->Kill();
}

void Thread::Yield()
{
	Kernel::Scheduler::Yield();
}

int Thread::SetPriority(int priority)
{
	return mKThread->SetPriority(priority);
}

void Thread::ThreadStartRoutine(unsigned long arg)
{
	Thread *t = reinterpret_cast<Thread *>(arg);

	ASSERT(t);

	t->Run();
}

Thread *Thread::GetCurrent()
{
	return static_cast<Thread *>(Kernel::Thread::GetCurrent()->GetContainer());
}

void Thread::YieldCurrent()
{
	GetCurrent()->Yield();
}

void Thread::ExitCurrent()
{
	GetCurrent()->Exit();
}

int Thread::SetCurrentPriority(int priority)
{
	return GetCurrent()->SetPriority(priority);
}

/* Generic Thread */
GenericThread::GenericThread(int (*startRoutine)(), const char *name)
	: Thread(name),
	mStartRoutine(startRoutine)
{
}

GenericThread::~GenericThread()
{
}

int GenericThread::Run()
{
	return mStartRoutine();
}

} // namespace OS
