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