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,&param1,&param2,&param3,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