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 15GenericThread::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 29GenericThread::~GenericThread() 30{ 31 kill_thread(fThreadId); 32 33 delete_sem(fExecuteUnitSem); 34} 35 36 37status_t 38GenericThread::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 81status_t 82GenericThread::ThreadStartup() 83{ 84 // This function is virtual. 85 // Subclass and override this function. 86 87 return B_OK; 88} 89 90 91status_t 92GenericThread::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 104status_t 105GenericThread::ThreadShutdown() 106{ 107 // This function is virtual. 108 // Subclass and override this function. 109 110 return B_OK; 111} 112 113 114void 115GenericThread::ThreadStartupFailed(status_t status) 116{ 117 // This function is virtual. 118 // Subclass and override this function. 119 120 Quit(); 121} 122 123 124void 125GenericThread::ExecuteUnitFailed(status_t status) 126{ 127 // This function is virtual. 128 // Subclass and override this function. 129 130 Quit(); 131} 132 133 134void 135GenericThread::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 144status_t 145GenericThread::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 163int32 164GenericThread::_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 174BMessage* 175GenericThread::GetDataStore() 176{ 177 return fThreadDataStore; 178} 179 180 181void 182GenericThread::SetDataStore(BMessage* message) 183{ 184 fThreadDataStore = message; 185} 186 187 188status_t 189GenericThread::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 210void 211GenericThread::Quit() 212{ 213 fQuitRequested = true; 214} 215 216 217bool 218GenericThread::HasQuitBeenRequested() 219{ 220 return fQuitRequested; 221} 222 223 224bool 225GenericThread::IsPaused() 226{ 227 return fThreadIsPaused; 228} 229 230 231status_t 232GenericThread::Suspend() 233{ 234 return suspend_thread(fThreadId); 235} 236 237 238status_t 239GenericThread::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 250status_t 251GenericThread::Kill() 252{ 253 return kill_thread(fThreadId); 254} 255 256 257void 258GenericThread::ExitWithReturnValue(status_t return_value) 259{ 260 exit_thread(return_value); 261} 262 263 264status_t 265GenericThread::SetExitCallback(void (*callback)(void*), void* data) 266{ 267 return on_exit_thread(callback, data); 268} 269 270 271status_t 272GenericThread::WaitForThread(status_t* exitValue) 273{ 274 return wait_for_thread(fThreadId, exitValue); 275} 276 277 278status_t 279GenericThread::Rename(char* name) 280{ 281 return rename_thread(fThreadId, name); 282} 283 284 285status_t 286GenericThread::SendData(int32 code, void* buffer, size_t buffer_size) 287{ 288 return send_data(fThreadId, code, buffer, buffer_size); 289} 290 291 292int32 293GenericThread::ReceiveData(thread_id* sender, void* buffer, size_t buffer_size) 294{ 295 return receive_data(sender, buffer, buffer_size); 296} 297 298 299bool 300GenericThread::HasData() 301{ 302 return has_data(fThreadId); 303} 304 305 306status_t 307GenericThread::SetPriority(int32 newPriority) 308{ 309 return set_thread_priority(fThreadId, newPriority); 310} 311 312 313void 314GenericThread::Snooze(bigtime_t microseconds) 315{ 316 Suspend(); 317 snooze(microseconds); 318 Resume(); 319} 320 321 322void 323GenericThread::SnoozeUntil(bigtime_t microseconds, int timebase) 324{ 325 Suspend(); 326 snooze_until(microseconds, timebase); 327 Resume(); 328} 329 330 331status_t 332GenericThread::GetInfo(thread_info* threadInfo) 333{ 334 return get_thread_info(fThreadId, threadInfo); 335} 336 337 338thread_id 339GenericThread::GetThread() 340{ 341 thread_info threadInfo; 342 GetInfo(&threadInfo); 343 return threadInfo.thread; 344} 345 346 347team_id 348GenericThread::GetTeam() 349{ 350 thread_info threadInfo; 351 GetInfo(&threadInfo); 352 return threadInfo.team; 353} 354 355 356char* 357GenericThread::GetName() 358{ 359 thread_info threadInfo; 360 GetInfo(&threadInfo); 361 return strdup(threadInfo.name); 362} 363 364 365thread_state 366GenericThread::GetState() 367{ 368 thread_info threadInfo; 369 GetInfo(&threadInfo); 370 return threadInfo.state; 371} 372 373 374sem_id 375GenericThread::GetSemaphore() 376{ 377 thread_info threadInfo; 378 GetInfo(&threadInfo); 379 return threadInfo.sem; 380} 381 382 383int32 384GenericThread::GetPriority() 385{ 386 thread_info threadInfo; 387 GetInfo(&threadInfo); 388 return threadInfo.priority; 389} 390 391 392bigtime_t 393GenericThread::GetUserTime() 394{ 395 thread_info threadInfo; 396 GetInfo(&threadInfo); 397 return threadInfo.user_time; 398} 399 400 401bigtime_t 402GenericThread::GetKernelTime() 403{ 404 thread_info threadInfo; 405 GetInfo(&threadInfo); 406 return threadInfo.kernel_time; 407} 408 409 410void* 411GenericThread::GetStackBase() 412{ 413 thread_info threadInfo; 414 GetInfo(&threadInfo); 415 return threadInfo.stack_base; 416} 417 418 419void* 420GenericThread::GetStackEnd() 421{ 422 thread_info threadInfo; 423 GetInfo(&threadInfo); 424 return threadInfo.stack_end; 425} 426 427 428void 429GenericThread::BeginUnit() 430{ 431 acquire_sem(fExecuteUnitSem); 432 // thread can not be paused until it releases semaphore 433} 434 435 436void 437GenericThread::EndUnit() 438{ 439 release_sem(fExecuteUnitSem); 440 // thread can now be paused 441} 442 443