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