00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <basix/threads.hpp>
00014 #include <basix/port.hpp>
00015 #ifdef __linux__
00016 #include <unistd.h>
00017 #else
00018 # ifdef __APPLE__
00019 # include <sys/types.h>
00020 # include <sys/sysctl.h>
00021 # endif
00022 #endif
00023
00024 namespace mmx {
00025
00026 mutex memory_lock;
00027
00028 #ifdef BASIX_ENABLE_THREADS
00029
00030
00031
00032
00033
00034 struct thread_data {
00035 pthread_t th;
00036 nat id;
00037 task_rep* t;
00038 };
00039
00040 bool threads_busy = false;
00041 bool threads_active = false;
00042 nat threads_number = 0;
00043 thread_data* threads_data = NULL;
00044
00045 task* threads_task = NULL;
00046 nat threads_nr_tasks = 0;
00047 nat threads_index = 0;
00048 nat threads_todo = 0;
00049
00050 pthread_mutex_t threads_task_lock;
00051 pthread_mutex_t threads_idle_lock;
00052 pthread_cond_t threads_idle_cond;
00053 pthread_mutex_t threads_busy_lock;
00054 pthread_cond_t threads_busy_cond;
00055
00056
00057
00058
00059
00060 void*
00061 threads_worker (void* ptr) {
00062 thread_data* data= (thread_data*) ptr;
00063
00064
00065
00066
00067 while (threads_busy) {
00068
00069 pthread_mutex_lock (&threads_idle_lock);
00070
00071 pthread_cond_wait (&threads_idle_cond, &threads_idle_lock);
00072 pthread_mutex_unlock (&threads_idle_lock);
00073 if (!threads_busy) break;
00074
00075 while (true) {
00076
00077 pthread_mutex_lock (&threads_task_lock);
00078 if (threads_index == threads_nr_tasks) {
00079 pthread_mutex_unlock (&threads_task_lock);
00080 break;
00081 }
00082
00083
00084 data->t= inside (threads_task[threads_index]);
00085 threads_index++;
00086 pthread_mutex_unlock (&threads_task_lock);
00087
00088
00089 if (data->t != NULL) data->t->execute ();
00090
00091
00092 data->t= NULL;
00093 pthread_mutex_lock (&threads_busy_lock);
00094 threads_todo--;
00095
00096
00097 if (threads_todo == 0)
00098 pthread_cond_signal (&threads_busy_cond);
00099 pthread_mutex_unlock (&threads_busy_lock);
00100 }
00101 }
00102
00103 pthread_mutex_lock (&threads_busy_lock);
00104 threads_todo--;
00105
00106
00107 if (threads_todo == 0)
00108 pthread_cond_signal (&threads_busy_cond);
00109 pthread_mutex_unlock (&threads_busy_lock);
00110 pthread_exit (NULL);
00111 }
00112
00113
00114
00115
00116
00117 void
00118 threads_execute (task* ts, nat n) {
00119 threads_task = ts;
00120 threads_nr_tasks= n;
00121 threads_index = 0;
00122 threads_todo = n;
00123
00124 threads_active = true;
00125 pthread_mutex_lock (&threads_busy_lock);
00126 pthread_mutex_lock (&threads_idle_lock);
00127 pthread_cond_broadcast (&threads_idle_cond);
00128 pthread_mutex_unlock (&threads_idle_lock);
00129
00130 pthread_cond_wait (&threads_busy_cond, &threads_busy_lock);
00131 pthread_mutex_unlock (&threads_busy_lock);
00132 threads_active = false;
00133 }
00134
00135
00136
00137
00138
00139 void
00140 threads_initialize (nat n) {
00141 pthread_mutex_init (&threads_task_lock, NULL);
00142 pthread_mutex_init (&threads_idle_lock, NULL);
00143 pthread_cond_init (&threads_idle_cond, NULL);
00144 pthread_mutex_init (&threads_busy_lock, NULL);
00145 pthread_cond_init (&threads_busy_cond, NULL);
00146
00147 threads_busy = true;
00148 threads_number = n;
00149 threads_data = new thread_data[threads_number];
00150 for (nat id=0; id<threads_number; id++) {
00151
00152
00153
00154 threads_data[id].id= id;
00155 threads_data[id].t = NULL;
00156 if (pthread_create(&(threads_data[id].th), NULL ,
00157 threads_worker, (void *) (threads_data + id)))
00158 ERROR ("failed to create thread");
00159 }
00160 }
00161
00162 void
00163 threads_terminate () {
00164 threads_busy = false;
00165 threads_todo = threads_number;
00166
00167 pthread_mutex_lock (&threads_busy_lock);
00168 pthread_mutex_lock (&threads_idle_lock);
00169 pthread_cond_broadcast (&threads_idle_cond);
00170 pthread_mutex_unlock (&threads_idle_lock);
00171
00172 pthread_cond_wait (&threads_busy_cond, &threads_busy_lock);
00173 pthread_mutex_unlock (&threads_busy_lock);
00174
00175 void* exit_status;
00176 for (nat id=0; id<threads_number; id++)
00177 pthread_join (threads_data[id].th, &exit_status);
00178
00179 delete[] threads_data;
00180 threads_data = NULL;
00181 threads_number = 0;
00182
00183 pthread_mutex_destroy (&threads_task_lock);
00184 pthread_mutex_destroy (&threads_idle_lock);
00185 pthread_cond_destroy (&threads_idle_cond);
00186 pthread_mutex_destroy (&threads_busy_lock);
00187 pthread_cond_destroy (&threads_busy_cond);
00188 }
00189
00190 struct threads_instance {
00191 threads_instance (nat n) {
00192 threads_initialize (n); }
00193 ~threads_instance () {
00194 threads_terminate (); }
00195 };
00196
00197 threads_instance threads_inst (BASIX_ENABLE_THREADS);
00198
00199 int
00200 threads_get_number () {
00201 return threads_number;
00202 }
00203
00204 void
00205 threads_set_number (const int& n) {
00206 threads_terminate ();
00207 threads_initialize (n);
00208 }
00209
00210
00211
00212
00213
00214 #else // ifndef BASIX_ENABLE_THREADS
00215
00216 nat threads_number= 1;
00217 void threads_initialize (nat n) { (void) n; }
00218 void threads_terminate () {}
00219 int threads_get_number () { return 1; }
00220 void threads_set_number (const int& n) {
00221 ASSERT (n == 1, "multithreading disabled"); }
00222 void init_threads () {}
00223 void term_threads () {}
00224 void threads_execute (task* ts, nat n) {
00225 for (nat i=0; i<n; i++) inside (ts[i]) -> execute (); }
00226
00227 #endif // BASIX_ENABLE_THREADS
00228
00229
00230
00231
00232
00233 int
00234 get_number_cores () {
00235 #ifdef __linux__ // also to be used for Solaris, AIX, ...
00236 int nr1= sysconf (_SC_NPROCESSORS_ONLN);
00237 if (nr1 >= 1) return nr1;
00238 #endif
00239
00240 #ifdef __APPLE__ // also to be used for BSD system
00241 int mib[2] = { CTL_HW, HW_AVAILCPU };
00242
00243 int nr2;
00244 size_t len;
00245 len = sizeof (nr2);
00246 sysctl (mib, 2, &nr2, &len, NULL, 0);
00247 if (nr2 >= 1) return nr2;
00248 #endif
00249
00250 #ifdef __WINDOW__upcoming
00251 SYSTEM_INFO sysinfo;
00252 GetSystemInfo( &sysinfo );
00253 int nr3= sysinfo.dwNumberOfProcessors;
00254 if (nr3 >= 1) return nr3;
00255 #endif
00256
00257 #ifdef __HPUX__upcoming
00258 int nr4= mpctl (MPC_GETNUMSPUS, NULL, NULL);
00259 if (nr4 >= 1) return nr4;
00260 #endif
00261
00262 #ifdef __IRIX__upcoming
00263 int nr5= sysconf (_SC_NPROC_ONLN);
00264 if (nr5 >= 1) return nr5;
00265 #endif
00266
00267 return 1;
00268 }
00269
00270
00271
00272
00273
00274 struct loop_task_rep: public task_rep {
00275 nat iterations;
00276 public:
00277 inline loop_task_rep (nat its): iterations (its) {}
00278 void execute () { for (nat i=0; i<iterations; i++) noop (); }
00279 };
00280
00281 void
00282 threads_simple_loop (nat nr_instances, nat nr_iterations) {
00283 task ts[nr_instances];
00284 for (nat id=0; id<nr_instances; id++)
00285 ts[id]= new loop_task_rep (nr_iterations);
00286 threads_execute (ts, nr_instances);
00287 }
00288
00289 }