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