haiku/src/apps/expander/GenericThread.cpp

434 lines
6.1 KiB
C++

// license: public domain
// authors: jonas.sundstrom@kirilla.com
#include "GenericThread.h"
#include <string.h>
GenericThread::GenericThread(const char* threadName, int32 priority,
BMessage* message)
:
fThreadDataStore(message),
fThreadId(spawn_thread(private_thread_function, threadName, priority,
this)),
fExecuteUnit(create_sem(1, "ExecuteUnit sem")),
fQuitRequested(false),
fThreadIsPaused(false)
{
if (fThreadDataStore == NULL)
fThreadDataStore = new BMessage();
}
GenericThread::~GenericThread()
{
kill_thread(fThreadId);
delete_sem(fExecuteUnit);
}
status_t
GenericThread::ThreadFunction(void)
{
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);
// what do we do?
}
delete this;
// destructor
return B_OK;
}
BeginUnit();
status = ExecuteUnit();
// Subclass and override
// Subclass and override
if (status != B_OK)
ExecuteUnitFailed(status);
EndUnit();
}
return (B_OK);
}
status_t
GenericThread::ThreadStartup(void)
{
// This function is virtual.
// Subclass and override this function.
return B_OK;
}
status_t
GenericThread::ExecuteUnit(void)
{
// 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(void)
{
// 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(void)
{
status_t status = B_OK;
if (IsPaused()) {
status = release_sem(fExecuteUnit);
if (status != B_OK)
return status;
fThreadIsPaused = false;
}
status = resume_thread(fThreadId);
return status;
}
int32
GenericThread::private_thread_function(void* pointer)
{
return ((GenericThread*)pointer)->ThreadFunction();
}
BMessage*
GenericThread::GetDataStore(void)
{
return fThreadDataStore;
}
void
GenericThread::SetDataStore(BMessage* message)
{
fThreadDataStore = message;
}
status_t
GenericThread::Pause(bool shouldBlock, bigtime_t timeout)
{
status_t status = B_OK;
if (shouldBlock) {
// thread will wait on semaphore
status = acquire_sem(fExecuteUnit);
} else {
// thread will timeout
status = acquire_sem_etc(fExecuteUnit, 1, B_RELATIVE_TIMEOUT, timeout);
}
if (status == B_OK) {
fThreadIsPaused = true;
return B_OK;
}
return status;
}
void
GenericThread::Quit(void)
{
fQuitRequested = true;
}
bool
GenericThread::HasQuitBeenRequested(void)
{
return fQuitRequested;
}
bool
GenericThread::IsPaused(void)
{
return fThreadIsPaused;
}
status_t
GenericThread::Suspend(void)
{
return suspend_thread(fThreadId);
}
status_t
GenericThread::Resume(void)
{
release_sem(fExecuteUnit);
// to counteract Pause()
fThreadIsPaused = false;
return (resume_thread(fThreadId));
// to counteract Suspend()
}
status_t
GenericThread::Kill(void)
{
return (kill_thread(fThreadId));
}
void
GenericThread::ExitWithReturnValue(status_t returnValue)
{
exit_thread(returnValue);
}
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 size)
{
return (send_data(fThreadId, code, buffer, size));
}
int32
GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t size)
{
return (receive_data(sender, buffer, size));
}
bool
GenericThread::HasData(void)
{
return (has_data(fThreadId));
}
status_t
GenericThread::SetPriority(int32 priority)
{
return (set_thread_priority(fThreadId, priority));
}
void
GenericThread::Snooze(bigtime_t delay)
{
Suspend();
snooze(delay);
Resume();
}
void
GenericThread::SnoozeUntil(bigtime_t delay, int timeBase)
{
Suspend();
snooze_until(delay, timeBase);
Resume();
}
status_t
GenericThread::GetInfo(thread_info* info)
{
return get_thread_info(fThreadId, info);
}
thread_id
GenericThread::GetThread(void)
{
thread_info info;
GetInfo(&info);
return info.thread;
}
team_id
GenericThread::GetTeam(void)
{
thread_info info;
GetInfo(&info);
return info.team;
}
char*
GenericThread::GetName(void)
{
thread_info info;
GetInfo(&info);
return strdup(info.name);
}
thread_state
GenericThread::GetState(void)
{
thread_info info;
GetInfo(&info);
return info.state;
}
sem_id
GenericThread::GetSemaphore(void)
{
thread_info info;
GetInfo(&info);
return info.sem;
}
int32
GenericThread::GetPriority(void)
{
thread_info info;
GetInfo(&info);
return info.priority;
}
bigtime_t
GenericThread::GetUserTime(void)
{
thread_info info;
GetInfo(&info);
return info.user_time;
}
bigtime_t
GenericThread::GetKernelTime(void)
{
thread_info info;
GetInfo(&info);
return info.kernel_time;
}
void*
GenericThread::GetStackBase(void)
{
thread_info info;
GetInfo(&info);
return info.stack_base;
}
void*
GenericThread::GetStackEnd(void)
{
thread_info info;
GetInfo(&info);
return info.stack_end;
}
void
GenericThread::BeginUnit(void)
{
acquire_sem(fExecuteUnit);
// thread can not be paused until it releases semaphore
}
void
GenericThread::EndUnit(void)
{
release_sem(fExecuteUnit);
// thread can now be paused
}