// license: public domain // authors: jonas.sundstrom@kirilla.com #include GenericThread::GenericThread(const char * a_thread_name, int32 a_priority, BMessage * a_message) : m_thread_data_store (a_message), m_thread_id (spawn_thread (private_thread_function, a_thread_name, a_priority, this)), m_execute_unit (create_sem(1, "m_execute_unit")), m_quit_requested (false), m_thread_is_paused (false) { if (m_thread_data_store == NULL) m_thread_data_store = new BMessage(); } GenericThread::~GenericThread() { kill_thread(m_thread_id); delete_sem(m_execute_unit); } 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 } BeginUnit(); status = ExecuteUnit(); // Subclass and override if (status != B_OK) ExecuteUnitFailed (status); // Subclass and override 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 a_status) { // This function is virtual. // Subclass and override this function. Quit(); } void GenericThread::ExecuteUnitFailed (status_t a_status) { // This function is virtual. // Subclass and override this function. Quit(); } void GenericThread::ThreadShutdownFailed (status_t a_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 (m_execute_unit); if (status != B_OK) return status; m_thread_is_paused = false; } status = resume_thread (m_thread_id); return status; } int32 GenericThread::private_thread_function (void * a_simple_thread_ptr) { status_t status = B_OK; status = ((GenericThread *) a_simple_thread_ptr)-> ThreadFunction(); return (status); } BMessage * GenericThread::GetDataStore (void) { return (m_thread_data_store); } void GenericThread::SetDataStore (BMessage * a_message) { m_thread_data_store = a_message; } status_t GenericThread::Pause (bool a_do_block, bigtime_t a_timeout) { status_t status = B_OK; if (a_do_block) status = acquire_sem(m_execute_unit); // thread will wait on semaphore else status = acquire_sem_etc(m_execute_unit, 1, B_RELATIVE_TIMEOUT, a_timeout); // thread will timeout if (status == B_OK) { m_thread_is_paused = true; return (B_OK); } return status; } void GenericThread::Quit (void) { m_quit_requested = true; } bool GenericThread::HasQuitBeenRequested (void) { return (m_quit_requested); } bool GenericThread::IsPaused (void) { return (m_thread_is_paused); } status_t GenericThread::Suspend (void) { return (suspend_thread(m_thread_id)); } status_t GenericThread::Resume (void) { release_sem(m_execute_unit); // to counteract Pause() m_thread_is_paused = false; return (resume_thread(m_thread_id)); // to counteract Suspend() } status_t GenericThread::Kill (void) { return (kill_thread(m_thread_id)); } void GenericThread::ExitWithReturnValue (status_t a_return_value) { exit_thread(a_return_value); } status_t GenericThread::SetExitCallback (void (*a_callback)(void*), void * a_data) { return (on_exit_thread(a_callback, a_data)); } status_t GenericThread::WaitForThread (status_t * a_exit_value) { return (wait_for_thread(m_thread_id, a_exit_value)); } status_t GenericThread::Rename (char * a_name) { return (rename_thread(m_thread_id, a_name)); } status_t GenericThread::SendData (int32 a_code, void * a_buffer, size_t a_buffer_size) { return (send_data(m_thread_id, a_code, a_buffer, a_buffer_size)); } int32 GenericThread::ReceiveData (thread_id * a_sender, void * a_buffer, size_t a_buffer_size) { return (receive_data(a_sender, a_buffer, a_buffer_size)); } bool GenericThread::HasData (void) { return (has_data(m_thread_id)); } status_t GenericThread::SetPriority (int32 a_new_priority) { return (set_thread_priority(m_thread_id, a_new_priority)); } void GenericThread::Snooze (bigtime_t a_microseconds) { Suspend(); snooze(a_microseconds); Resume(); } void GenericThread::SnoozeUntil (bigtime_t a_microseconds, int a_timebase) { Suspend(); snooze_until(a_microseconds, a_timebase); Resume(); } status_t GenericThread::GetInfo (thread_info * a_thread_info) { return (get_thread_info(m_thread_id, a_thread_info)); } thread_id GenericThread::GetThread (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.thread); } team_id GenericThread::GetTeam (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.team); } char * GenericThread::GetName (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.name); } thread_state GenericThread::GetState (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.state); } sem_id GenericThread::GetSemaphore (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.sem); } int32 GenericThread::GetPriority (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.priority); } bigtime_t GenericThread::GetUserTime (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.user_time); } bigtime_t GenericThread::GetKernelTime (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.kernel_time); } void * GenericThread::GetStackBase (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.stack_base); } void * GenericThread::GetStackEnd (void) { thread_info t_thread_info; GetInfo (& t_thread_info); return (t_thread_info.stack_end); } void GenericThread::BeginUnit (void) { acquire_sem(m_execute_unit); // thread can not be paused until it releases semaphore } void GenericThread::EndUnit (void) { release_sem(m_execute_unit); // thread can now be paused }