1// license: public domain 2// authors: jonas.sundstrom@kirilla.com 3 4#include "GenericThread.h" 5 6#include <string.h> 7 8GenericThread::GenericThread(const char * thread_name, int32 a_priority, BMessage * message) 9 : 10 fThreadDataStore(message), 11 fThreadId(spawn_thread(private_thread_function, thread_name, a_priority, this)), 12 fExecuteUnit(create_sem(1, "ExecuteUnit sem")), 13 fQuitRequested(false), 14 fThreadIsPaused(false) 15{ 16 if (fThreadDataStore == NULL) 17 fThreadDataStore = new BMessage(); 18} 19 20 21GenericThread::~GenericThread() 22{ 23 kill_thread(fThreadId); 24 25 delete_sem(fExecuteUnit); 26} 27 28 29status_t 30GenericThread::ThreadFunction(void) 31{ 32 status_t status = B_OK; 33 34 status = ThreadStartup(); // Subclass and override this function 35 if (status != B_OK) 36 { 37 ThreadStartupFailed(status); 38 return (status); 39 // is this the right thing to do? 40 } 41 42 while (1) 43 { 44 if (HasQuitBeenRequested()) 45 { 46 status = ThreadShutdown(); // Subclass and override this function 47 if (status != B_OK) 48 { 49 ThreadShutdownFailed(status); 50 return (status); 51 // what do we do? 52 } 53 54 delete this; // destructor 55 return B_OK; 56 } 57 58 BeginUnit(); 59 60 status = ExecuteUnit(); // Subclass and override 61 62 if (status != B_OK) 63 ExecuteUnitFailed(status); // Subclass and override 64 65 EndUnit(); 66 } 67 68 return (B_OK); 69} 70 71 72status_t 73GenericThread::ThreadStartup(void) 74{ 75 // This function is virtual. 76 // Subclass and override this function. 77 78 return B_OK; 79} 80 81 82status_t 83GenericThread::ExecuteUnit(void) 84{ 85 // This function is virtual. 86 87 // You would normally subclass and override this function 88 // as it will provide you with Pause and Quit functionality 89 // thanks to the unit management done by GenericThread::ThreadFunction() 90 91 return B_OK; 92} 93 94 95status_t 96GenericThread::ThreadShutdown(void) 97{ 98 // This function is virtual. 99 // Subclass and override this function. 100 101 return B_OK; 102} 103 104 105void 106GenericThread::ThreadStartupFailed(status_t a_status) 107{ 108 // This function is virtual. 109 // Subclass and override this function. 110 111 Quit(); 112} 113 114 115void 116GenericThread::ExecuteUnitFailed(status_t a_status) 117{ 118 // This function is virtual. 119 // Subclass and override this function. 120 121 Quit(); 122} 123 124 125void 126GenericThread::ThreadShutdownFailed(status_t a_status) 127{ 128 // This function is virtual. 129 // Subclass and override this function. 130 131 // (is this good default behaviour?) 132} 133 134 135status_t 136GenericThread::Start(void) 137{ 138 status_t status = B_OK; 139 140 if (IsPaused()) 141 { 142 status = release_sem(fExecuteUnit); 143 if (status != B_OK) 144 return status; 145 146 fThreadIsPaused = false; 147 } 148 149 status = resume_thread(fThreadId); 150 151 return status; 152} 153 154 155int32 156GenericThread::private_thread_function(void * a_simple_thread_ptr) 157{ 158 status_t status = B_OK; 159 160 status = ((GenericThread *) a_simple_thread_ptr)-> ThreadFunction(); 161 162 return (status); 163} 164 165 166BMessage * 167GenericThread::GetDataStore(void) 168{ 169 return (fThreadDataStore); 170} 171 172 173void 174GenericThread::SetDataStore(BMessage * message) 175{ 176 fThreadDataStore = message; 177} 178 179 180status_t 181GenericThread::Pause(bool a_do_block, bigtime_t a_timeout) 182{ 183 status_t status = B_OK; 184 185 if (a_do_block) 186 status = acquire_sem(fExecuteUnit); 187 // thread will wait on semaphore 188 else 189 status = acquire_sem_etc(fExecuteUnit, 1, B_RELATIVE_TIMEOUT, a_timeout); 190 // thread will timeout 191 192 if (status == B_OK) 193 { 194 fThreadIsPaused = true; 195 return (B_OK); 196 } 197 198 return status; 199} 200 201 202void 203GenericThread::Quit(void) 204{ 205 fQuitRequested = true; 206} 207 208 209bool 210GenericThread::HasQuitBeenRequested(void) 211{ 212 return (fQuitRequested); 213} 214 215 216bool 217GenericThread::IsPaused(void) 218{ 219 return (fThreadIsPaused); 220} 221 222 223status_t 224GenericThread::Suspend(void) 225{ 226 return (suspend_thread(fThreadId)); 227} 228 229 230status_t 231GenericThread::Resume(void) 232{ 233 release_sem(fExecuteUnit); // to counteract Pause() 234 fThreadIsPaused = false; 235 236 return (resume_thread(fThreadId)); // to counteract Suspend() 237} 238 239 240status_t 241GenericThread::Kill(void) 242{ 243 return (kill_thread(fThreadId)); 244} 245 246 247void 248GenericThread::ExitWithReturnValue(status_t a_return_value) 249{ 250 exit_thread(a_return_value); 251} 252 253 254status_t 255GenericThread::SetExitCallback(void(*a_callback)(void*), void * a_data) 256{ 257 return (on_exit_thread(a_callback, a_data)); 258} 259 260 261status_t 262GenericThread::WaitForThread(status_t * a_exit_value) 263{ 264 return (wait_for_thread(fThreadId, a_exit_value)); 265} 266 267 268status_t 269GenericThread::Rename(char * a_name) 270{ 271 return (rename_thread(fThreadId, a_name)); 272} 273 274 275status_t 276GenericThread::SendData(int32 a_code, void * a_buffer, size_t a_buffer_size) 277{ 278 return (send_data(fThreadId, a_code, a_buffer, a_buffer_size)); 279} 280 281 282int32 283GenericThread::ReceiveData(thread_id * a_sender, void * a_buffer, size_t a_buffer_size) 284{ 285 return (receive_data(a_sender, a_buffer, a_buffer_size)); 286} 287 288 289bool 290GenericThread::HasData(void) 291{ 292 return (has_data(fThreadId)); 293} 294 295 296status_t 297GenericThread::SetPriority(int32 a_new_priority) 298{ 299 return (set_thread_priority(fThreadId, a_new_priority)); 300} 301 302 303void 304GenericThread::Snooze(bigtime_t a_microseconds) 305{ 306 Suspend(); 307 snooze(a_microseconds); 308 Resume(); 309} 310 311 312void 313GenericThread::SnoozeUntil(bigtime_t a_microseconds, int a_timebase) 314{ 315 Suspend(); 316 snooze_until(a_microseconds, a_timebase); 317 Resume(); 318} 319 320 321status_t 322GenericThread::GetInfo(thread_info * thread_info) 323{ 324 return (get_thread_info(fThreadId, thread_info)); 325} 326 327 328thread_id 329GenericThread::GetThread(void) 330{ 331 thread_info t_thread_info; 332 GetInfo(& t_thread_info); 333 return (t_thread_info.thread); 334} 335 336 337team_id 338GenericThread::GetTeam(void) 339{ 340 thread_info t_thread_info; 341 GetInfo(& t_thread_info); 342 return (t_thread_info.team); 343} 344 345 346char * 347GenericThread::GetName(void) 348{ 349 thread_info t_thread_info; 350 GetInfo(& t_thread_info); 351 return strdup(t_thread_info.name); 352} 353 354 355thread_state 356GenericThread::GetState(void) 357{ 358 thread_info t_thread_info; 359 GetInfo(& t_thread_info); 360 return (t_thread_info.state); 361} 362 363 364sem_id 365GenericThread::GetSemaphore(void) 366{ 367 thread_info t_thread_info; 368 GetInfo(& t_thread_info); 369 return (t_thread_info.sem); 370} 371 372 373int32 374GenericThread::GetPriority(void) 375{ 376 thread_info t_thread_info; 377 GetInfo(& t_thread_info); 378 return (t_thread_info.priority); 379} 380 381 382bigtime_t 383GenericThread::GetUserTime(void) 384{ 385 thread_info t_thread_info; 386 GetInfo(& t_thread_info); 387 return (t_thread_info.user_time); 388} 389 390 391bigtime_t 392GenericThread::GetKernelTime(void) 393{ 394 thread_info t_thread_info; 395 GetInfo(& t_thread_info); 396 return (t_thread_info.kernel_time); 397} 398 399 400void * 401GenericThread::GetStackBase(void) 402{ 403 thread_info t_thread_info; 404 GetInfo(& t_thread_info); 405 return (t_thread_info.stack_base); 406} 407 408 409void * 410GenericThread::GetStackEnd(void) 411{ 412 thread_info t_thread_info; 413 GetInfo(& t_thread_info); 414 return (t_thread_info.stack_end); 415} 416 417 418void 419GenericThread::BeginUnit(void) 420{ 421 acquire_sem(fExecuteUnit); // thread can not be paused until it releases semaphore 422} 423 424 425void 426GenericThread::EndUnit(void) 427{ 428 release_sem(fExecuteUnit); // thread can now be paused 429} 430 431