PFUNC 1.0
|
00001 #ifndef PFUNC_THREAD_HPP 00002 #define PFUNC_THREAD_HPP 00003 00009 #include <pfunc/config.h> 00010 #include <pfunc/pfunc_common.h> 00011 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00012 #include <Windows.h> 00013 #elif PFUNC_HAVE_PTHREADS == 1 00014 #include<pthread.h> 00015 #if PFUNC_HAVE_SCHED_AFFINITY == 1 00016 #include <sched.h> 00017 #endif 00018 #else 00019 #error "Windows threads or pthreads are required" 00020 #endif 00021 00022 #include <pfunc/no_copy.hpp> 00023 #include <pfunc/exception.hpp> 00024 #include <pfunc/mutex.hpp> 00025 00026 #if PFUNC_HAVE_TLS == 1 00027 #include <vector> 00028 __thread volatile unsigned int pfunc_thread_self_id; 00029 #elif PFUNC_HAVE_HASH_MAP_H == 1 00030 #include <ext/hash_map> 00031 namespace std { using namespace __gnu_cxx; } 00032 #else 00033 #include <map> 00034 #endif 00035 00036 #if PFUNC_DARWIN == 1 && PFUNC_HAVE_SYSCTL_H == 1 00037 #include <sys/sysctl.h> 00038 #endif 00039 00040 namespace pfunc { namespace detail { 00041 static const unsigned int PFUNC_STACK_MIN = 2048*2048; 00042 static const unsigned int PFUNC_STACK_MAX = 4096*4096; 00043 static const unsigned int PFUNC_STACK_AVG = 2048*4096; 00044 static const unsigned int PFUNC_NO_AFFINITY = ~0x0; 00045 00054 struct thread_attr : no_copy { 00055 private: 00056 const unsigned int stack_size; 00057 const unsigned int thread_id; 00058 const unsigned int thread_affinity; 00059 const unsigned int task_queue_number; 00060 void* user_data; 00062 public: 00073 thread_attr (const unsigned int& stack_size, 00074 const unsigned int& thread_id, 00075 const unsigned int& thread_affinity, 00076 const unsigned int& task_queue_number) : 00077 stack_size (stack_size), 00078 thread_id (thread_id), 00079 thread_affinity (thread_affinity), 00080 task_queue_number (task_queue_number) {} 00081 00085 unsigned int get_stack_size () const { return stack_size; } 00086 00090 unsigned int get_thread_id () const { return thread_id; } 00091 00095 unsigned int get_thread_affinity () const {return thread_affinity; } 00096 00100 unsigned int get_task_queue_number () const { 00101 return task_queue_number; 00102 } 00103 }; 00104 00105 /*****************************************************************************************/ 00112 struct thread : public no_copy { 00113 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00114 typedef HANDLE thread_handle_type; 00115 typedef DWORD (__stdcall *start_func_type)(void*); 00116 typedef DWORD native_thread_id_type; 00117 #elif PFUNC_HAVE_PTHREADS == 1 00118 typedef pthread_t thread_handle_type; 00119 typedef void* (*start_func_type)(void*); 00120 typedef pthread_t native_thread_id_type; 00121 #endif 00122 00123 #if PFUNC_HAVE_TLS == 1 00124 typedef std::vector<thread_attr*> tls_attribute_map_type; 00125 #elif PFUNC_HAVE_HASH_MAP_H == 1 00126 00130 struct my_hash_function { 00131 typedef size_t result_type; 00132 std::hash<size_t> my_hash; 00142 result_type operator () (const native_thread_id_type& key) const { 00143 #if PFUNC_DARWIN == 1 00144 return my_hash(reinterpret_cast<size_t>(key)); 00145 #else 00146 return my_hash(key); 00147 #endif /* if defined(__DARWIN__) */ 00148 } 00149 }; 00150 typedef std::hash_map <native_thread_id_type, 00151 thread_attr*, 00152 my_hash_function> tls_attribute_map_type; 00153 #else 00154 typedef std::map <native_thread_id_type, thread_attr*> 00155 tls_attribute_map_type; 00156 #endif 00157 00158 typedef tls_attribute_map_type::value_type tls_value_type; 00159 tls_attribute_map_type tls_attr_map; 00161 #if PFUNC_HAVE_TLS == 1 00162 00167 void initialize (const unsigned int& nthreads) { 00168 tls_attr_map.resize (nthreads); 00169 } 00170 #endif 00171 00181 void create_thread (thread_handle_type& handle, 00182 thread_attr* attr, 00183 start_func_type start_func_ptr, 00184 void* start_func_arg) { 00185 00186 #if PFUNC_USE_EXCEPTIONS == 1 00187 00190 if (NULL == attr) 00191 throw exception_generic_impl ("pfunc::detail::thread::create_thread", 00192 "NULL attribute provided", 00193 PFUNC_INVALID_ATTR); 00194 00196 if (NULL == start_func_ptr) 00197 throw exception_generic_impl ("pfunc::detail::thread::create_thread", 00198 "NULL start function for thread", 00199 PFUNC_INVALID_ARGUMENTS); 00200 00202 if (NULL == start_func_arg) 00203 throw exception_generic_impl ("pfunc::detail::thread::create_thread", 00204 "NULL argument for thread start function", 00205 PFUNC_INVALID_ARGUMENTS); 00206 #endif 00207 00208 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00209 handle = CreateThread (NULL, /* Security Attributes */ 00210 attr->get_stack_size(), /* dwStackSize */ 00211 start_func_ptr, /* StartRoutine */ 00212 start_func_arg, /* Function Argument */ 00213 0, /* CreationFlags */ 00214 NULL); /* ThreadId */ 00215 #if PFUNC_USE_EXCEPTIONS == 1 00216 00217 if (NULL == handle) 00218 throw exception_generic_impl 00219 ("pfunc::detail::thread::create_thread::CreateThread", 00220 "Could not create the thread", 00221 GetLastError ()); 00222 #endif 00223 00224 #elif PFUNC_HAVE_PTHREADS == 1 00225 error_code_type error; 00226 00227 /* The only thing that we need to set is the stacksize */ 00228 pthread_attr_t my_attr; 00229 00230 /* Iniitalize the attribute */ 00231 error = pthread_attr_init (&my_attr); 00232 #if PFUNC_USE_EXCEPTIONS == 1 00233 if (error) 00234 throw exception_generic_impl 00235 ("pfunc::detail::thread::create_thread::pthread_attr_init", 00236 "Could not initialize the attribute", 00237 error); 00238 #endif 00239 00240 size_t stack_size = static_cast <size_t> (attr->get_stack_size()); 00241 error = pthread_attr_setstacksize (&my_attr, stack_size); 00242 #if PFUNC_USE_EXCEPTIONS == 1 00243 if (error) 00244 throw exception_generic_impl 00245 ("pfunc::detail::thread::create_thread::pthread_attr_init", 00246 "Could not set the stacksize", 00247 error); 00248 #endif 00249 00250 error = pthread_attr_setscope (&my_attr, PTHREAD_SCOPE_SYSTEM); 00251 #if PFUNC_USE_EXCEPTIONS == 1 00252 if (error) 00253 throw exception_generic_impl 00254 ("pfunc::detail::thread::create_thread::pthread_attr_init", 00255 "Could not set thread scope", 00256 error); 00257 #endif 00258 00259 /* Create the thread now */ 00260 error = pthread_create 00261 (&handle, &my_attr, start_func_ptr, start_func_arg); 00262 #if PFUNC_USE_EXCEPTIONS == 1 00263 if (error) 00264 throw exception_generic_impl 00265 ("pfunc::detail::thread::create_thread::pthread_attr_init", 00266 "Could not create the thread", 00267 error); 00268 #endif 00269 00270 /* Free the attribute */ 00271 error = pthread_attr_destroy (&my_attr); 00272 #if PFUNC_USE_EXCEPTIONS == 1 00273 if (error) 00274 throw exception_generic_impl 00275 ("pfunc::detail::thread::create_thread::pthread_attr_init", 00276 "Could not destroy the attribute", 00277 error); 00278 #endif 00279 00280 #else 00281 #error "Windows threads or pthreads are required" 00282 #endif 00283 } 00284 00288 void exit_thread () const { 00289 #if PFUNC_HAVE_WINDOWS_THREADS 00290 ExitThread (0); 00291 #elif PFUNC_HAVE_PTHREADS 00292 pthread_exit (NULL); 00293 #else 00294 #error "Windows threads or pthreads are required" 00295 #endif 00296 } 00297 00303 void join_thread (const thread_handle_type& handle) const { 00304 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00305 WaitForSingleObject (handle, INFINITE); 00306 #elif PFUNC_HAVE_PTHREADS == 1 00307 PFUNC_CAPTURE_RETURN_VALUE(error) pthread_join (handle, NULL); 00308 #if PFUNC_USE_EXCEPTIONS == 1 00309 if (error) 00310 throw exception_generic_impl 00311 ("pfunc::detail::thread::join_thread::pthread_join", 00312 "Could not join on the thread", 00313 error); 00314 #endif 00315 #else 00316 #error "Windows threads or pthreads are required" 00317 #endif 00318 } 00319 00329 native_thread_id_type get_native_id(const thread_handle_type& handle)const{ 00330 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00331 return GetThreadId (handle); 00332 #elif PFUNC_HAVE_PTHREADS == 1 00333 return handle; 00334 #else 00335 #error "Windows threads or pthreads are required" 00336 #endif 00337 } 00338 00344 native_thread_id_type get_native_id () const { 00345 #if PFUNC_HAVE_WINDOWS_THREADS == 1 00346 return GetCurrentThreadId (); 00347 #elif PFUNC_HAVE_PTHREADS == 1 00348 return pthread_self (); 00349 #else 00350 #error "Windows threads or pthreads are required" 00351 #endif 00352 } 00353 00359 void tls_set (thread_attr* attr) { 00360 #if PFUNC_HAVE_TLS == 1 00361 tls_attr_map[pfunc_thread_self_id] = attr; 00362 #else 00363 tls_attr_map [get_native_id()] = attr; 00364 #endif 00365 } 00366 00372 thread_attr* tls_get () { 00373 #if PFUNC_HAVE_TLS == 1 00374 return tls_attr_map [pfunc_thread_self_id]; 00375 #else 00376 return tls_attr_map [get_native_id ()]; 00377 #endif 00378 } 00379 00380 #if PFUNC_HAVE_SCHED_AFFINITY == 1 && PFUNC_HAVE_SCHED_H == 1 00381 00387 int get_num_procs () const { 00388 int num_procs = 0; 00389 error_code_type error; 00390 cpu_set_t orig_set; 00391 cpu_set_t my_set; 00392 if (0 > (error=sched_getaffinity (0, sizeof(my_set), &orig_set))) 00393 #if PFUNC_USE_EXCEPTIONS == 1 00394 throw exception_generic_impl 00395 ("pfunc::detail::thread::get_num_procs:", 00396 "Could not get the current thread affinities", 00397 error); 00398 #else 00399 return num_procs; 00400 #endif 00401 for (num_procs=0; ;++num_procs) { 00402 CPU_ZERO (&my_set); 00403 CPU_SET(num_procs, &my_set); 00404 if (0 > sched_setaffinity (0, sizeof(my_set), &my_set)) break; 00405 } 00406 error = sched_setaffinity (0, sizeof(my_set), &orig_set); 00407 #if PFUNC_USE_EXCEPTIONS == 1 00408 if (error) 00409 throw exception_generic_impl 00410 ("pfunc::detail::thread::get_num_procs:", 00411 "Could not reset the affinities back to the original", 00412 error); 00413 #endif 00414 return num_procs; 00415 } 00416 00422 void set_affinity (const int& proc_id) const { 00423 error_code_type error; 00424 cpu_set_t my_set; 00425 CPU_ZERO (&my_set); 00426 CPU_SET (proc_id, &my_set); 00427 error = sched_setaffinity (0, sizeof(my_set), &my_set); 00428 #if PFUNC_USE_EXCEPTIONS == 1 00429 if (error) 00430 throw exception_generic_impl 00431 ("pfunc::detail::thread::get_num_procs:", 00432 "Could not set thread affinity", 00433 error); 00434 #endif 00435 } 00436 00437 #elif PFUNC_DARWIN == 1 && PFUNC_HAVE_SYSCTL_H == 1 00438 00444 int get_num_procs () const { 00445 int num_procs = 0; 00446 error_code_type error; 00447 int mib[] = {CTL_HW, HW_NCPU}; 00448 size_t len = sizeof(int); 00449 error = sysctl(mib, 2, &num_procs, &len, NULL, 0); 00450 #if PFUNC_USE_EXCEPTIONS == 1 00451 if (error) 00452 throw exception_generic_impl 00453 ("pfunc::detail::thread::get_num_procs:", 00454 "Could not get the number of processors", 00455 error); 00456 #endif 00457 return num_procs; 00458 } 00459 00465 void set_affinity (const int& proc_id) const { 00467 } 00468 00469 #elif PFUNC_WINDOWS == 1 00470 00476 int get_num_procs () const { 00477 int num_procs = 0; 00478 error_code_type error; 00479 num_procs = error = GetActiveProcessorCount (ALL_PROCESSOR_GROUPS); 00480 #if PFUNC_USE_EXCEPTIONS == 1 00481 if (0 == error) 00482 throw exception_generic_impl 00483 ("pfunc::detail::thread::get_num_procs:", 00484 "Could not get the number of processors", 00485 error); 00486 #endif 00487 } 00488 00494 void set_affinity (const int& proc_id) const { 00496 } 00497 00498 #else /* NONE of the systems that we know of */ 00499 00506 int get_num_procs () const { 00507 return 0; 00508 } 00509 00515 void set_affinity (const int& proc_id) const { 00517 } 00518 #endif 00519 00520 00524 void yield () { 00525 #if PFUNC_LINUX == 1 00526 pthread_yield(); 00527 #elif PFUNC_DARWIN == 1 00528 pthread_yield_np(); 00529 #elif PFUNC_WINDOWS == 1 00530 SwitchToThread(); 00531 #elif PFUNC_AIX == 1 && PFUNC_HAVE_SCHED_H 00532 sched_yield(); 00533 #else 00534 00535 #endif 00536 } 00537 }; 00538 } /* namespace detail */ } /* namespace pfunc */ 00539 00540 #endif // PFUNC_THREAD_HPP