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