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 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 72 status_t 73 GenericThread::ThreadStartup(void) 74 { 75 // This function is virtual. 76 // Subclass and override this function. 77 78 return B_OK; 79 } 80 81 82 status_t 83 GenericThread::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 95 status_t 96 GenericThread::ThreadShutdown(void) 97 { 98 // This function is virtual. 99 // Subclass and override this function. 100 101 return B_OK; 102 } 103 104 105 void 106 GenericThread::ThreadStartupFailed(status_t a_status) 107 { 108 // This function is virtual. 109 // Subclass and override this function. 110 111 Quit(); 112 } 113 114 115 void 116 GenericThread::ExecuteUnitFailed(status_t a_status) 117 { 118 // This function is virtual. 119 // Subclass and override this function. 120 121 Quit(); 122 } 123 124 125 void 126 GenericThread::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 135 status_t 136 GenericThread::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 155 int32 156 GenericThread::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 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 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 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); // to counteract Pause() 234 fThreadIsPaused = false; 235 236 return (resume_thread(fThreadId)); // to counteract Suspend() 237 } 238 239 240 status_t 241 GenericThread::Kill(void) 242 { 243 return (kill_thread(fThreadId)); 244 } 245 246 247 void 248 GenericThread::ExitWithReturnValue(status_t a_return_value) 249 { 250 exit_thread(a_return_value); 251 } 252 253 254 status_t 255 GenericThread::SetExitCallback(void(*a_callback)(void*), void * a_data) 256 { 257 return (on_exit_thread(a_callback, a_data)); 258 } 259 260 261 status_t 262 GenericThread::WaitForThread(status_t * a_exit_value) 263 { 264 return (wait_for_thread(fThreadId, a_exit_value)); 265 } 266 267 268 status_t 269 GenericThread::Rename(char * a_name) 270 { 271 return (rename_thread(fThreadId, a_name)); 272 } 273 274 275 status_t 276 GenericThread::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 282 int32 283 GenericThread::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 289 bool 290 GenericThread::HasData(void) 291 { 292 return (has_data(fThreadId)); 293 } 294 295 296 status_t 297 GenericThread::SetPriority(int32 a_new_priority) 298 { 299 return (set_thread_priority(fThreadId, a_new_priority)); 300 } 301 302 303 void 304 GenericThread::Snooze(bigtime_t a_microseconds) 305 { 306 Suspend(); 307 snooze(a_microseconds); 308 Resume(); 309 } 310 311 312 void 313 GenericThread::SnoozeUntil(bigtime_t a_microseconds, int a_timebase) 314 { 315 Suspend(); 316 snooze_until(a_microseconds, a_timebase); 317 Resume(); 318 } 319 320 321 status_t 322 GenericThread::GetInfo(thread_info * thread_info) 323 { 324 return (get_thread_info(fThreadId, thread_info)); 325 } 326 327 328 thread_id 329 GenericThread::GetThread(void) 330 { 331 thread_info t_thread_info; 332 GetInfo(& t_thread_info); 333 return (t_thread_info.thread); 334 } 335 336 337 team_id 338 GenericThread::GetTeam(void) 339 { 340 thread_info t_thread_info; 341 GetInfo(& t_thread_info); 342 return (t_thread_info.team); 343 } 344 345 346 char * 347 GenericThread::GetName(void) 348 { 349 thread_info t_thread_info; 350 GetInfo(& t_thread_info); 351 return strdup(t_thread_info.name); 352 } 353 354 355 thread_state 356 GenericThread::GetState(void) 357 { 358 thread_info t_thread_info; 359 GetInfo(& t_thread_info); 360 return (t_thread_info.state); 361 } 362 363 364 sem_id 365 GenericThread::GetSemaphore(void) 366 { 367 thread_info t_thread_info; 368 GetInfo(& t_thread_info); 369 return (t_thread_info.sem); 370 } 371 372 373 int32 374 GenericThread::GetPriority(void) 375 { 376 thread_info t_thread_info; 377 GetInfo(& t_thread_info); 378 return (t_thread_info.priority); 379 } 380 381 382 bigtime_t 383 GenericThread::GetUserTime(void) 384 { 385 thread_info t_thread_info; 386 GetInfo(& t_thread_info); 387 return (t_thread_info.user_time); 388 } 389 390 391 bigtime_t 392 GenericThread::GetKernelTime(void) 393 { 394 thread_info t_thread_info; 395 GetInfo(& t_thread_info); 396 return (t_thread_info.kernel_time); 397 } 398 399 400 void * 401 GenericThread::GetStackBase(void) 402 { 403 thread_info t_thread_info; 404 GetInfo(& t_thread_info); 405 return (t_thread_info.stack_base); 406 } 407 408 409 void * 410 GenericThread::GetStackEnd(void) 411 { 412 thread_info t_thread_info; 413 GetInfo(& t_thread_info); 414 return (t_thread_info.stack_end); 415 } 416 417 418 void 419 GenericThread::BeginUnit(void) 420 { 421 acquire_sem(fExecuteUnit); // thread can not be paused until it releases semaphore 422 } 423 424 425 void 426 GenericThread::EndUnit(void) 427 { 428 release_sem(fExecuteUnit); // thread can now be paused 429 } 430 431