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