1 // license: public domain 2 // authors: jonas.sundstrom@kirilla.com 3 4 5 #include "GenericThread.h" 6 7 #include <string.h> 8 9 10 GenericThread::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 25 GenericThread::~GenericThread() 26 { 27 kill_thread(fThreadId); 28 29 delete_sem(fExecuteUnit); 30 } 31 32 33 status_t 34 GenericThread::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 77 status_t 78 GenericThread::ThreadStartup(void) 79 { 80 // This function is virtual. 81 // Subclass and override this function. 82 83 return B_OK; 84 } 85 86 87 status_t 88 GenericThread::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 100 status_t 101 GenericThread::ThreadShutdown(void) 102 { 103 // This function is virtual. 104 // Subclass and override this function. 105 106 return B_OK; 107 } 108 109 110 void 111 GenericThread::ThreadStartupFailed(status_t status) 112 { 113 // This function is virtual. 114 // Subclass and override this function. 115 116 Quit(); 117 } 118 119 120 void 121 GenericThread::ExecuteUnitFailed(status_t status) 122 { 123 // This function is virtual. 124 // Subclass and override this function. 125 126 Quit(); 127 } 128 129 130 void 131 GenericThread::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 140 status_t 141 GenericThread::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 159 int32 160 GenericThread::private_thread_function(void* pointer) 161 { 162 return ((GenericThread*)pointer)->ThreadFunction(); 163 } 164 165 166 BMessage* 167 GenericThread::GetDataStore(void) 168 { 169 return fThreadDataStore; 170 } 171 172 173 void 174 GenericThread::SetDataStore(BMessage* message) 175 { 176 fThreadDataStore = message; 177 } 178 179 180 status_t 181 GenericThread::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 202 void 203 GenericThread::Quit(void) 204 { 205 fQuitRequested = true; 206 } 207 208 209 bool 210 GenericThread::HasQuitBeenRequested(void) 211 { 212 return fQuitRequested; 213 } 214 215 216 bool 217 GenericThread::IsPaused(void) 218 { 219 return fThreadIsPaused; 220 } 221 222 223 status_t 224 GenericThread::Suspend(void) 225 { 226 return suspend_thread(fThreadId); 227 } 228 229 230 status_t 231 GenericThread::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 242 status_t 243 GenericThread::Kill(void) 244 { 245 return (kill_thread(fThreadId)); 246 } 247 248 249 void 250 GenericThread::ExitWithReturnValue(status_t returnValue) 251 { 252 exit_thread(returnValue); 253 } 254 255 256 status_t 257 GenericThread::SetExitCallback(void (*callback)(void*), void* data) 258 { 259 return (on_exit_thread(callback, data)); 260 } 261 262 263 status_t 264 GenericThread::WaitForThread(status_t* exitValue) 265 { 266 return (wait_for_thread(fThreadId, exitValue)); 267 } 268 269 270 status_t 271 GenericThread::Rename(char* name) 272 { 273 return (rename_thread(fThreadId, name)); 274 } 275 276 277 status_t 278 GenericThread::SendData(int32 code, void* buffer, size_t size) 279 { 280 return (send_data(fThreadId, code, buffer, size)); 281 } 282 283 284 int32 285 GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t size) 286 { 287 return (receive_data(sender, buffer, size)); 288 } 289 290 291 bool 292 GenericThread::HasData(void) 293 { 294 return (has_data(fThreadId)); 295 } 296 297 298 status_t 299 GenericThread::SetPriority(int32 priority) 300 { 301 return (set_thread_priority(fThreadId, priority)); 302 } 303 304 305 void 306 GenericThread::Snooze(bigtime_t delay) 307 { 308 Suspend(); 309 snooze(delay); 310 Resume(); 311 } 312 313 314 void 315 GenericThread::SnoozeUntil(bigtime_t delay, int timeBase) 316 { 317 Suspend(); 318 snooze_until(delay, timeBase); 319 Resume(); 320 } 321 322 323 status_t 324 GenericThread::GetInfo(thread_info* info) 325 { 326 return get_thread_info(fThreadId, info); 327 } 328 329 330 thread_id 331 GenericThread::GetThread(void) 332 { 333 thread_info info; 334 GetInfo(&info); 335 return info.thread; 336 } 337 338 339 team_id 340 GenericThread::GetTeam(void) 341 { 342 thread_info info; 343 GetInfo(&info); 344 return info.team; 345 } 346 347 348 char* 349 GenericThread::GetName(void) 350 { 351 thread_info info; 352 GetInfo(&info); 353 return strdup(info.name); 354 } 355 356 357 thread_state 358 GenericThread::GetState(void) 359 { 360 thread_info info; 361 GetInfo(&info); 362 return info.state; 363 } 364 365 366 sem_id 367 GenericThread::GetSemaphore(void) 368 { 369 thread_info info; 370 GetInfo(&info); 371 return info.sem; 372 } 373 374 375 int32 376 GenericThread::GetPriority(void) 377 { 378 thread_info info; 379 GetInfo(&info); 380 return info.priority; 381 } 382 383 384 bigtime_t 385 GenericThread::GetUserTime(void) 386 { 387 thread_info info; 388 GetInfo(&info); 389 return info.user_time; 390 } 391 392 393 bigtime_t 394 GenericThread::GetKernelTime(void) 395 { 396 thread_info info; 397 GetInfo(&info); 398 return info.kernel_time; 399 } 400 401 402 void* 403 GenericThread::GetStackBase(void) 404 { 405 thread_info info; 406 GetInfo(&info); 407 return info.stack_base; 408 } 409 410 411 void* 412 GenericThread::GetStackEnd(void) 413 { 414 thread_info info; 415 GetInfo(&info); 416 return info.stack_end; 417 } 418 419 420 void 421 GenericThread::BeginUnit(void) 422 { 423 acquire_sem(fExecuteUnit); 424 // thread can not be paused until it releases semaphore 425 } 426 427 428 void 429 GenericThread::EndUnit(void) 430 { 431 release_sem(fExecuteUnit); 432 // thread can now be paused 433 } 434