1 /* 2 * Copyright (c) 1997-1999, 2003 Massachusetts Institute of Technology 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 */ 19 20 #ifndef FFTW_THREADS_INT_H 21 #define FFTW_THREADS_INT_H 22 23 /***** alloca declarations, as recommended by the autoconf manual: *****/ 24 25 /* We have to include config.h here for the alloca stuff, which (due 26 to AIX lossage) must be the first thing in the file) */ 27 #include "config.h" 28 29 /* AIX requires this to be the first thing in the file. */ 30 #ifndef __GNUC__ 31 # if HAVE_ALLOCA_H 32 # include <alloca.h> 33 # else 34 # ifdef _AIX 35 #pragma alloca 36 # else 37 # ifndef alloca /* predefined by HP cc +Olibcalls */ 38 # ifdef __cplusplus 39 extern "C" 40 # endif /* __cplusplus */ 41 char *alloca (); 42 # endif 43 # endif 44 # endif 45 #endif 46 47 /***********************************************************************/ 48 49 #include "fftw-int.h" 50 #include "fftw_threads.h" 51 52 #ifdef __cplusplus 53 extern "C" { 54 #endif /* __cplusplus */ 55 56 /************************* Thread Glue *************************/ 57 58 /* Adding support for a new shared memory thread API should be easy. You 59 simply do the following things (look at the POSIX and Solaris 60 threads code for examples): 61 62 * Invent a symbol of the form FFTW_USING_FOO_THREADS to denote 63 the use of your thread API, and add an 64 #elif defined(FFTW_USING_FOO_THREADS) 65 before the #else clause below. This is where you will put 66 your thread definitions. In this #elif, insert the following: 67 68 -- #include any header files needed to use the thread API. 69 70 -- Typedef fftw_thread_function to be a function pointer 71 of the type used as a argument to fftw_thread_spawn 72 (i.e. the entry function for a thread). 73 74 -- Define fftw_thread_id, via a typedef, to be the type 75 that is used for thread identifiers. 76 77 -- #define fftw_thread_spawn(tid_ptr, proc, data) to 78 call whatever function to spawn a new thread. The 79 new thread should call proc(data) as its starting point, 80 and tid_ptr is a pointer to a fftw_thread_id that 81 is set to an identifier for the thread. You can also 82 define this as a subroutine (put it in fftw_threads.c) 83 if it is too complicated for a macro. The prototype should 84 be: 85 86 void fftw_thread_spawn(fftw_thread_id *tid_ptr, 87 fftw_thread_function proc, 88 void *data); 89 90 -- #define fftw_thread_wait(tid) to block until the thread 91 whose identifier is tid has terminated. You can also 92 define this as a subroutine (put it in fftw_threads.c) if 93 it is too complicated for a macro. The prototype should be: 94 95 void fftw_thread_wait(fftw_thread_id tid); 96 97 * If you need to perform any initialization before using threads, 98 put your initialization code in the fftw_threads_init() function 99 in fftw_threads.c, bracketed by the appropriate #ifdef of course. 100 101 * Also, of course, you should modify fftw/config.h to #define 102 FFTW_USING_FOO_THREADS, or better yet modify config.h.in 103 and configure.in so that autoconf can automatically detect 104 your threads library. 105 106 * Finally, if you do implement support for a new threads API, be 107 sure to let us know at fftw@fftw.org so that we can distribute 108 your code to others! 109 110 */ 111 112 /************************** Solaris Threads ****************************/ 113 114 #if defined(FFTW_USING_SOLARIS_THREADS) 115 116 /* Solaris threads glue. Tested. */ 117 118 /* link with -lthread */ 119 120 #include <thread.h> 121 122 /* Thread entry point: */ 123 typedef void * (*fftw_thread_function) (void *); 124 125 typedef thread_t fftw_thread_id; 126 127 #define fftw_thread_spawn(tid_ptr, proc, data) \ 128 thr_create(0,0,proc,data,THR_BOUND,tid_ptr) 129 130 #define fftw_thread_wait(tid) thr_join(tid,0,0) 131 132 /************************** BeOS Threads ****************************/ 133 134 #elif defined(FFTW_USING_BEOS_THREADS) 135 136 /* BeOS threads glue. Tested for DR8.2. */ 137 138 #include <OS.h> 139 140 /* Thread entry point: */ 141 typedef thread_entry fftw_thread_function; 142 143 typedef thread_id fftw_thread_id; 144 145 #define fftw_thread_spawn(tid_ptr, proc, data) { \ 146 *(tid_ptr) = spawn_thread(proc,"FFTW",B_NORMAL_PRIORITY,data); \ 147 resume_thread(*(tid_ptr)); \ 148 } 149 150 /* wait_for_thread requires that we pass a valid pointer as the 151 second argument, even if we're not interested in the result. */ 152 #define fftw_thread_wait(tid) {long exit_val;wait_for_thread(tid, &exit_val);} 153 154 /************************** MacOS Threads ****************************/ 155 156 #elif defined(FFTW_USING_MACOS_THREADS) 157 158 /* MacOS MP threads glue. Experimental, untested! I do not have an 159 MP MacOS system available to me...I just read the documentation. 160 There is actually a good chance that this will work (since the 161 code below is so short), but I make no guarantees. Consider 162 it to be a starting point for your own implementation. 163 164 I also had to insert some code in fftw_threads.c. 165 166 MacOS X will have real SMP support, thank goodness. */ 167 168 /* Using this code in the MacOS: (See the README file for general 169 documenation on the FFTW threads code.) To use this code, you have 170 to do two things. First of all, you have to #define the symbol 171 FFTW_USING_MACOS_THREADS. This can be done at the top of this file 172 or perhaps in your compiler options. Second, you have to weak-link 173 your project to the MP library. 174 175 In your code, you should check at run-time with MPLibraryIsLoaded() 176 to see if the MP library is available. If it is not, it is 177 still safe to call the fftw_threads routines...in this case, 178 however, you must always pass 1 for the nthreads parameter! 179 (Otherwise, you will probably want to pass the value of 180 MPProcessors() for the nthreads parameter.) */ 181 182 #include <MP.h> 183 184 typedef TaskProc fftw_thread_function; 185 186 typedef MPQueueID fftw_thread_id; 187 188 #define fftw_thread_spawn(tid_ptr, proc, data) { \ 189 MPTaskID task; \ 190 MPCreateQueue(tid_ptr); \ 191 MPCreateTask(proc,data,kMPUseDefaultStackSize,*(tid_ptr),0,0, \ 192 kMPNormalTaskOptions,&task); \ 193 } 194 195 #define fftw_thread_wait(tid) { \ 196 void *param1,*param2,*param3; \ 197 MPWaitOnQueue(tid,¶m1,¶m2,¶m3,kDurationForever); \ 198 MPDeleteQueue(tid); \ 199 } 200 201 /************************** Win32 Threads ****************************/ 202 203 #elif defined(FFTW_USING_WIN32_THREADS) 204 205 /* Win32 threads glue. We have not tested this code! (I just implemented 206 it by looking at a Win32 threads manual.) Users have reported that this 207 code works under NT using Microsoft compilers. 208 209 To use it, you should #define the symbol FFTW_USING_WIN32_THREADS. */ 210 211 #include <windows.h> 212 213 typedef LPTHREAD_START_ROUTINE fftw_thread_function; 214 typedef HANDLE fftw_thread_id; 215 216 #define fftw_thread_spawn(tid_ptr, proc, data) { \ 217 DWORD thrid; \ 218 *(tid_ptr) = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0, \ 219 (fftw_thread_function) proc, (LPVOID) data, \ 220 0, &thrid); \ 221 } 222 223 #define fftw_thread_wait(tid) { \ 224 WaitForSingleObject(tid, INFINITE); \ 225 CloseHandle(tid); \ 226 } 227 228 /************************** Mach cthreads ****************************/ 229 230 #elif defined(FFTW_USING_MACH_THREADS) 231 232 #ifdef HAVE_MACH_CTHREADS_H 233 #include <mach/cthreads.h> 234 #elif defined(HAVE_CTHREADS_H) 235 #include <cthreads.h> 236 #elif defined(HAVE_CTHREAD_H) 237 #include <cthread.h> 238 #endif 239 240 typedef cthread_fn_t fftw_thread_function; 241 242 typedef cthread_t fftw_thread_id; 243 244 #define fftw_thread_spawn(tid_ptr, proc, data) \ 245 *(tid_ptr) = cthread_fork(proc, (any_t) (data)) 246 247 #define fftw_thread_wait(tid) cthread_join(tid) 248 249 /************************** MP directive Threads ****************************/ 250 251 #elif defined(FFTW_USING_OPENMP_THREADS) || defined(FFTW_USING_SGIMP_THREADS) 252 253 /* Use MP compiler directives to induce parallelism, in which case 254 we don't need any of the thread spawning/waiting macros: */ 255 256 typedef void * (*fftw_thread_function) (void *); 257 258 typedef char fftw_thread_id; /* dummy */ 259 260 #define fftw_thread_spawn(tid_ptr, proc, data) ((proc)(data)) 261 #define fftw_thread_wait(tid) (0) /* do nothing */ 262 263 #define FFTW_USING_COMPILER_THREADS 1 264 265 /************************** POSIX Threads ****************************/ 266 267 #else /* use the default, POSIX threads: */ 268 269 /* POSIX threads glue. Tested. */ 270 271 #ifndef FFTW_USING_POSIX_THREADS 272 #define FFTW_USING_POSIX_THREADS 273 #endif 274 275 /* link with -lpthread */ 276 277 #include <pthread.h> 278 279 /* Thread entry point: */ 280 typedef void * (*fftw_thread_function) (void *); 281 282 extern pthread_attr_t *fftw_pthread_attributes_p; 283 284 typedef pthread_t fftw_thread_id; 285 286 #define fftw_thread_spawn(tid_ptr, proc, data) { \ 287 if (pthread_create(tid_ptr,fftw_pthread_attributes_p,proc,data)) \ 288 fftw_die("error in pthread_create"); \ 289 } 290 291 #define fftw_thread_wait(tid) { \ 292 if (pthread_join(tid,0)) \ 293 fftw_die("error in pthread_join"); \ 294 } 295 296 #endif 297 298 /************************ Function prototypes ***********************/ 299 300 /* Use alloca instead of malloc, if possible, in the hope that alloca 301 will be faster at allocating the small blocks we need. (In principle, 302 alloca just needs to increment the stack pointer.) */ 303 #ifdef HAVE_ALLOCA 304 # define ALLOCA(n) alloca(n) 305 # define ALLOCA_CLEANUP(p) ; 306 #else 307 # define ALLOCA(n) fftw_malloc(n) 308 # define ALLOCA_CLEANUP(p) fftw_free(p); 309 #endif 310 311 typedef struct { 312 int min, max, thread_num; 313 void *data; 314 } fftw_loop_data; 315 316 typedef void *(*fftw_loop_function) (fftw_loop_data *); 317 318 extern void fftw_thread_spawn_loop(int loopmax, int nthreads, 319 fftw_loop_function proc, void *data); 320 321 extern void fftw_executor_many_inplace_threads(int n, fftw_complex *in, 322 fftw_complex *work, 323 fftw_plan_node *p, 324 int istride, 325 int howmany, int idist, 326 int nthreads); 327 328 #ifdef __cplusplus 329 } /* extern "C" */ 330 #endif /* __cplusplus */ 331 332 #endif /* FFTW_THREADS_INT_H */ 333