Fix use of inline in IMD
[alexxy/gromacs.git] / src / gromacs / gmxlib / thread_mpi / type.c
1 /*
2    This source code file is part of thread_mpi.
3    Written by Sander Pronk, Erik Lindahl, and possibly others.
4
5    Copyright (c) 2009, Sander Pronk, Erik Lindahl.
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions are met:
10    1) Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15    3) Neither the name of the copyright holders nor the
16    names of its contributors may be used to endorse or promote products
17    derived from this software without specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30    If you want to redistribute modifications, please consider that
31    scientific software is very special. Version control is crucial -
32    bugs must be traceable. We will be happy to consider code for
33    inclusion in the official distribution, but derived work should not
34    be called official thread_mpi. Details are found in the README & COPYING
35    files.
36  */
37
38 #ifdef HAVE_TMPI_CONFIG_H
39 #include "tmpi_config.h"
40 #endif
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46
47
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include <errno.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #if !(defined( _WIN32 ) || defined( _WIN64 ) )
57 #include <sys/time.h>
58 #endif
59
60 #include "impl.h"
61
62
63 /* this is where all the tMPI_Reduce ops are included from tmpi_ops.h */
64 #define THREAD_MPI_OPS 1
65
66 #define TYPE char
67 #define TYPENM CHAR
68 #define INTTYPE 1
69 #include "tmpi_ops.h"
70
71 #define TYPE short
72 #define TYPENM SHORT
73 #define INTTYPE 1
74 #include "tmpi_ops.h"
75
76 #define TYPE int
77 #define TYPENM INT
78 #define INTTYPE 1
79 #include "tmpi_ops.h"
80
81 #define TYPE long
82 #define TYPENM LONG
83 #define INTTYPE 1
84 #include "tmpi_ops.h"
85
86 #ifdef SIZEOF_LONG_LONG_INT
87
88 #define TYPE long long
89 #define TYPENM L_LONG
90 #define INTTYPE 1
91 #include "tmpi_ops.h"
92
93 #define TYPE long long int
94 #define TYPENM L_L_INT
95 #define INTTYPE 1
96 #include "tmpi_ops.h"
97
98 #endif
99
100 #define TYPE signed char
101 #define TYPENM S_CHAR
102 #define INTTYPE 1
103 #include "tmpi_ops.h"
104
105 #define TYPE unsigned char
106 #define TYPENM U_CHAR
107 #define INTTYPE 1
108 #include "tmpi_ops.h"
109
110 #define TYPE unsigned short
111 #define TYPENM U_SHORT
112 #define INTTYPE 1
113 #include "tmpi_ops.h"
114
115 #define TYPE unsigned
116 #define TYPENM UNSIGNED
117 #define INTTYPE 1
118 #include "tmpi_ops.h"
119
120 #define TYPE unsigned long
121 #define TYPENM U_LONG
122 #define INTTYPE 1
123 #include "tmpi_ops.h"
124
125 #ifdef SIZEOF_LONG_LONG_INT
126
127 #define TYPE unsigned long long
128 #define TYPENM U_L_LONG
129 #define INTTYPE 1
130 #include "tmpi_ops.h"
131
132 #endif
133
134 #define TYPE float
135 #define TYPENM FLOAT
136 #define INTTYPE 0
137 #include "tmpi_ops.h"
138
139 #define TYPE double
140 #define TYPENM DOUBLE
141 #define INTTYPE 0
142 #include "tmpi_ops.h"
143
144 #define TYPE long double
145 #define TYPENM L_DOUBLE
146 #define INTTYPE 0
147 #include "tmpi_ops.h"
148
149 #define TYPE char
150 #define TYPENM BYTE
151 #define INTTYPE 1
152 #include "tmpi_ops.h"
153
154 #ifdef _MSC_VER
155 #define TYPE __int64
156 #else
157 #define TYPE int64_t
158 #endif
159 #define TYPENM INT64_T
160 #define INTTYPE 1
161 #include "tmpi_ops.h"
162
163
164 /* These are the fundamental data types. They exist as global variables */
165 tmpi_dt tmpi_char    = {sizeof(char),              oplist_CHAR,     0, NULL, TRUE};
166 tmpi_dt tmpi_short   = {sizeof(short),             oplist_SHORT,    0, NULL, TRUE};
167 tmpi_dt tmpi_int     = {sizeof(int),               oplist_INT,      0, NULL, TRUE};
168 tmpi_dt tmpi_long    = {sizeof(long),              oplist_LONG,     0, NULL, TRUE};
169 #ifdef SIZEOF_LONG_LONG_INT
170 tmpi_dt tmpi_l_long  = {sizeof(long long),         oplist_L_LONG,   0, NULL, TRUE};
171 tmpi_dt tmpi_l_l_int = {sizeof(long long int),     oplist_L_L_INT,  0, NULL, TRUE};
172 #endif
173 tmpi_dt tmpi_s_char  = {sizeof(signed char),       oplist_S_CHAR,   0, NULL, TRUE};
174 tmpi_dt tmpi_u_char  = {sizeof(unsigned char),     oplist_U_CHAR,   0, NULL, TRUE};
175 tmpi_dt tmpi_u_short = {sizeof(unsigned short),    oplist_U_SHORT,  0, NULL, TRUE};
176 tmpi_dt tmpi_unsigned = {sizeof(unsigned),          oplist_UNSIGNED, 0, NULL, TRUE};
177 tmpi_dt tmpi_u_long  = {sizeof(unsigned long),     oplist_U_LONG,   0, NULL, TRUE};
178 #ifdef SIZEOF_LONG_LONG_INT
179 tmpi_dt tmpi_u_l_long = {sizeof(unsigned long long), oplist_U_L_LONG, 0, NULL, TRUE};
180 #endif
181 tmpi_dt tmpi_float   = {sizeof(float),             oplist_FLOAT,    0, NULL, TRUE};
182 tmpi_dt tmpi_double  = {sizeof(double),            oplist_DOUBLE,   0, NULL, TRUE};
183 tmpi_dt tmpi_l_double = {sizeof(long double),       oplist_L_DOUBLE, 0, NULL, TRUE};
184 tmpi_dt tmpi_byte    = {sizeof(char),              oplist_CHAR,     0, NULL, TRUE};
185 tmpi_dt tmpi_pointer = {sizeof(void*),             NULL,            0, NULL, TRUE};
186 tmpi_dt tmpi_int64_t = {8,                         oplist_INT64_T,  0, NULL, TRUE};
187
188
189 /* the variable types as they are referred to from MPI */
190 const tMPI_Datatype TMPI_CHAR               = &tmpi_char;
191 const tMPI_Datatype TMPI_SHORT              = &tmpi_short;
192 const tMPI_Datatype TMPI_INT                = &tmpi_int;
193 const tMPI_Datatype TMPI_LONG               = &tmpi_long;
194 #ifdef SIZEOF_LONG_LONG_INT
195 const tMPI_Datatype TMPI_LONG_LONG          = &tmpi_l_long;
196 const tMPI_Datatype TMPI_LONG_LONG_INT      = &tmpi_l_l_int;
197 #endif
198 const tMPI_Datatype TMPI_SIGNED_CHAR        = &tmpi_s_char;
199 const tMPI_Datatype TMPI_UNSIGNED_CHAR      = &tmpi_u_char;
200 const tMPI_Datatype TMPI_UNSIGNED_SHORT     = &tmpi_u_short;
201 const tMPI_Datatype TMPI_UNSIGNED           = &tmpi_unsigned;
202 const tMPI_Datatype TMPI_UNSIGNED_LONG      = &tmpi_u_long;
203 #ifdef SIZEOF_LONG_LONG_INT
204 const tMPI_Datatype TMPI_UNSIGNED_LONG_LONG = &tmpi_u_l_long;
205 #endif
206
207 const tMPI_Datatype TMPI_FLOAT              = &tmpi_float;
208 const tMPI_Datatype TMPI_DOUBLE             = &tmpi_double;
209 const tMPI_Datatype TMPI_LONG_DOUBLE        = &tmpi_l_double;
210
211 /*extern tMPI_Datatype tMPI_UNSIGNED_WCHAR*/
212 const tMPI_Datatype TMPI_BYTE               = &tmpi_byte;
213
214 const tMPI_Datatype TMPI_POINTER            = &tmpi_pointer;
215
216 const tMPI_Datatype TMPI_INT64_T            = &tmpi_int64_t;
217
218
219
220
221
222 int tMPI_Type_contiguous(int count, tMPI_Datatype oldtype,
223                          tMPI_Datatype *newtype)
224 {
225     struct tmpi_datatype_ *ntp;
226
227 #ifdef TMPI_TRACE
228     tMPI_Trace_print("tMPI_Type_contiguous(%d, %p, %p)", count, oldtype,
229                      newtype);
230 #endif
231     ntp               = (struct tmpi_datatype_*)tMPI_Malloc(sizeof(struct tmpi_datatype_));
232     ntp->size         = count*oldtype->size;
233     ntp->op_functions = NULL;
234
235     /* establish components */
236     ntp->N_comp = 1;
237     ntp->comps  = (struct tmpi_datatype_component*)tMPI_Malloc(
238                 sizeof(struct tmpi_datatype_component)*1);
239     ntp->comps[0].type  = oldtype;
240     ntp->comps[0].count = 1;
241     ntp->committed      = FALSE;
242
243     /* now add it to the list.  */
244     tMPI_Spinlock_lock(&(tmpi_global->datatype_lock));
245     /* check whether there's space */
246     if (tmpi_global->N_usertypes + 1 >= tmpi_global->Nalloc_usertypes)
247     {
248         /* make space */
249         tmpi_global->Nalloc_usertypes = Nthreads*(tmpi_global->N_usertypes) + 1;
250         tmpi_global->usertypes        = (struct tmpi_datatype_**)
251             tMPI_Realloc(tmpi_global->usertypes,
252                          (sizeof(struct tmpi_datatype_ *)*
253                           tmpi_global->Nalloc_usertypes)
254                          );
255
256     }
257     /* add to the list */
258     tmpi_global->usertypes[tmpi_global->N_usertypes] = ntp;
259     tmpi_global->N_usertypes++;
260     *newtype = ntp;
261     tMPI_Spinlock_unlock(&(tmpi_global->datatype_lock));
262
263     return TMPI_SUCCESS;
264 }
265
266
267 int tMPI_Type_commit(tMPI_Datatype *datatype)
268 {
269     int                    i, j;
270     struct tmpi_datatype_ *dt = *datatype;
271
272 #ifdef TMPI_TRACE
273     tMPI_Trace_print("tMPI_Type_commit(%p)", datatype);
274 #endif
275     if (dt->committed)
276     {
277         return TMPI_SUCCESS;
278     }
279
280     /* search the list for a matching committed type, because if there's
281        already a committed type that has the same composition, we just
282        make the datatype pointer point to it, ensuring we share datatype
283        information across threads. */
284     tMPI_Spinlock_lock(&(tmpi_global->datatype_lock));
285     for (i = 0; i < tmpi_global->N_usertypes; i++)
286     {
287         struct tmpi_datatype_ *lt = tmpi_global->usertypes[i];
288         if (lt->committed && lt->N_comp == dt->N_comp)
289         {
290             tmpi_bool found = TRUE;
291             for (j = 0; j < lt->N_comp; j++)
292             {
293                 if ( (lt->comps[j].type  != dt->comps[j].type) ||
294                      (lt->comps[j].count != dt->comps[j].count) )
295                 {
296                     found = FALSE;
297                     break;
298                 }
299             }
300             if (found)
301             {
302                 dt = lt;
303             }
304         }
305     }
306     if (dt != *datatype)
307     {
308         tmpi_bool found = FALSE;
309         /* we remove the old one from the list */
310         for (i = 0; i < tmpi_global->N_usertypes; i++)
311         {
312             if (tmpi_global->usertypes[i] == *datatype)
313             {
314                 found = TRUE;
315                 break;
316             }
317         }
318         if (found)
319         {
320             /* we put the last one in the list in our slot */
321             tmpi_global->usertypes[i] = tmpi_global->
322                     usertypes[tmpi_global->N_usertypes-1];
323             tmpi_global->N_usertypes--;
324         }
325         free( (*datatype)->comps);
326         free(  *datatype );
327
328         /* and overwrite the pointer with the new data type */
329         *datatype = dt;
330     }
331     else
332     {
333         /* it was the first one of its type */
334         dt->committed = TRUE;
335     }
336     tMPI_Spinlock_unlock(&(tmpi_global->datatype_lock));
337     return TMPI_SUCCESS;
338 }