⛏️ index : haiku.git

/*
 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Jonas SundstrΓΆm, jonas@kirilla.com
 */


#include "GenericThread.h"

#include <string.h>


GenericThread::GenericThread(const char* thread_name, int32 priority,
	BMessage* message)	
	:
	fThreadDataStore(message),
	fThreadId(spawn_thread(_ThreadFunction, thread_name, priority, this)),
	fExecuteUnitSem(create_sem(1, "fExecuteUnitSem")),
	fQuitRequested(false),
	fThreadIsPaused(false)
{
	if (fThreadDataStore == NULL)
		fThreadDataStore = new BMessage();
}


GenericThread::~GenericThread()
{
	kill_thread(fThreadId);
	
	delete_sem(fExecuteUnitSem);
}


status_t 
GenericThread::ThreadFunction()
{
	status_t status = B_OK;
	
	status = ThreadStartup();
		// Subclass and override this function
		
	if (status != B_OK) {
		ThreadStartupFailed(status);
		return status;
		// is this the right thing to do?
	}
	
	while (1) {
		if (HasQuitBeenRequested()) {
			status = ThreadShutdown();
				// Subclass and override this function
				
			if (status != B_OK) {
				ThreadShutdownFailed(status);
				return status;
			}
			
			delete this;
			return B_OK;
		}

		BeginUnit();

		status = ExecuteUnit();
			// Subclass and override

		if (status != B_OK)
			ExecuteUnitFailed(status);
				// Subclass and override
		
		EndUnit();	
	}

	return B_OK;
}


status_t 
GenericThread::ThreadStartup()
{
	// This function is virtual.
	// Subclass and override this function.

	return B_OK;
}


status_t 
GenericThread::ExecuteUnit()
{
	// This function is virtual.

	// You would normally subclass and override this function
	// as it will provide you with Pause and Quit functionality
	// thanks to the unit management done by GenericThread::ThreadFunction()

	return B_OK;
}


status_t 
GenericThread::ThreadShutdown()
{
	// This function is virtual.
	// Subclass and override this function.

	return B_OK;
}


void 
GenericThread::ThreadStartupFailed(status_t status)
{
	// This function is virtual.
	// Subclass and override this function.
	
	Quit();
}


void 
GenericThread::ExecuteUnitFailed(status_t status)
{
	// This function is virtual.
	// Subclass and override this function.
	
	Quit();
}


void 
GenericThread::ThreadShutdownFailed(status_t status)
{
	// This function is virtual.
	// Subclass and override this function.
	
	// (is this good default behaviour?)
}


status_t 
GenericThread::Start()
{
	status_t status = B_OK;
	
	if (IsPaused()) {
		status = release_sem(fExecuteUnitSem);
		if (status != B_OK)
			return status;

		fThreadIsPaused = false;
	}
	
	status = resume_thread(fThreadId);
	
	return status;
}


int32 
GenericThread::_ThreadFunction(void* simple_thread_ptr)
{
	status_t status = B_OK;

	status = ((GenericThread*) simple_thread_ptr)->ThreadFunction();

	return status;
}


BMessage*	
GenericThread::GetDataStore()
{
	return fThreadDataStore;
}


void
GenericThread::SetDataStore(BMessage* message)
{
	fThreadDataStore = message;
}


status_t	
GenericThread::Pause(bool doBlock, bigtime_t timeout)
{
	status_t status = B_OK;
	
	if (doBlock)
		status = acquire_sem(fExecuteUnitSem); 
			// thread will wait on semaphore
	else
		status = acquire_sem_etc(fExecuteUnitSem, 1, B_RELATIVE_TIMEOUT,
			timeout); 
			// thread will timeout

	if (status == B_OK) {
		fThreadIsPaused = true;
		return B_OK;
	}
	
	return status;
}


void	
GenericThread::Quit()
{
	fQuitRequested = true;
}


bool 
GenericThread::HasQuitBeenRequested()
{
	return fQuitRequested;
}


bool	
GenericThread::IsPaused()
{
	return fThreadIsPaused;
}


status_t	
GenericThread::Suspend()
{
	return suspend_thread(fThreadId);
}


status_t	
GenericThread::Resume()
{
	release_sem(fExecuteUnitSem);
		// to counteract Pause()
	fThreadIsPaused = false;
	
	return resume_thread(fThreadId);
		// to counteract Suspend()
}


status_t	
GenericThread::Kill()
{
	return kill_thread(fThreadId);
}


void	
GenericThread::ExitWithReturnValue(status_t return_value)
{
	exit_thread(return_value);
}


status_t	
GenericThread::SetExitCallback(void (*callback)(void*), void* data)
{
	return on_exit_thread(callback, data);
}


status_t	
GenericThread::WaitForThread(status_t* exitValue)
{
	return wait_for_thread(fThreadId, exitValue);
}


status_t	
GenericThread::Rename(char* name)
{
	return rename_thread(fThreadId, name);
}


status_t	
GenericThread::SendData(int32 code, void* buffer, size_t buffer_size)
{
	return send_data(fThreadId, code, buffer, buffer_size);
}


int32	
GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t buffer_size)
{
	return receive_data(sender, buffer, buffer_size);
}


bool	
GenericThread::HasData()
{
	return has_data(fThreadId);
}


status_t	
GenericThread::SetPriority(int32 newPriority)
{
	return set_thread_priority(fThreadId, newPriority);
}


void	
GenericThread::Snooze(bigtime_t microseconds)
{
	Suspend();
	snooze(microseconds);
	Resume();
}


void	
GenericThread::SnoozeUntil(bigtime_t microseconds, int timebase)
{
	Suspend();
	snooze_until(microseconds, timebase);
	Resume();
}


status_t	
GenericThread::GetInfo(thread_info* threadInfo)
{
	return get_thread_info(fThreadId, threadInfo);
}


thread_id	
GenericThread::GetThread()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.thread;
}


team_id	
GenericThread::GetTeam()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.team;
}


char*	
GenericThread::GetName()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return strdup(threadInfo.name);
}


thread_state	
GenericThread::GetState()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.state;
}


sem_id	
GenericThread::GetSemaphore()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.sem;
}


int32	
GenericThread::GetPriority()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.priority;
}


bigtime_t	
GenericThread::GetUserTime()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.user_time;
}


bigtime_t	
GenericThread::GetKernelTime()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.kernel_time;
}


void*	
GenericThread::GetStackBase()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.stack_base;
}


void*	
GenericThread::GetStackEnd()
{
	thread_info	threadInfo;
	GetInfo(&threadInfo);
	return threadInfo.stack_end;
}


void	
GenericThread::BeginUnit()
{
	acquire_sem(fExecuteUnitSem);
		// thread can not be paused until it releases semaphore
}


void	
GenericThread::EndUnit()
{
	release_sem(fExecuteUnitSem);
		// thread can now be paused
}