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