434 lines
6.1 KiB
C++
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
|
|
}
|