comm_get_attr.c 10.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* -*- Mode: C; c-basic-offset:4 ; -*- */
/*
 *
 *  (C) 2001 by Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */

#include "mpiimpl.h"

/* -- Begin Profiling Symbol Block for routine MPI_Comm_get_attr */
#if defined(HAVE_PRAGMA_WEAK)
#pragma weak MPI_Comm_get_attr = PMPI_Comm_get_attr
#elif defined(HAVE_PRAGMA_HP_SEC_DEF)
#pragma _HP_SECONDARY_DEF PMPI_Comm_get_attr  MPI_Comm_get_attr
#elif defined(HAVE_PRAGMA_CRI_DUP)
#pragma _CRI duplicate MPI_Comm_get_attr as PMPI_Comm_get_attr
#endif
/* -- End Profiling Symbol Block */

/* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
   the MPI routines */
#ifndef MPICH_MPI_FROM_PMPI
#undef MPI_Comm_get_attr
#define MPI_Comm_get_attr PMPI_Comm_get_attr

26
27
28
#undef FUNCNAME
#define FUNCNAME MPIR_CommGetAttr

29
30
31
32
/* Find the requested attribute.  If it exists, return either the attribute
   entry or the address of the entry, based on whether the request is for 
   a pointer-valued attribute (C or C++) or an integer-valued attribute
   (Fortran, either 77 or 90).
33

34
35
36
37
38
   If the attribute has the same type as the request, it is returned as-is.
   Otherwise, the address of the attribute is returned.
*/
int MPIR_CommGetAttr( MPI_Comm comm, int comm_keyval, void *attribute_val, 
		      int *flag, MPIR_AttrType outAttrType )
39
{
40
    static const char FCNAME[] = "MPIR_CommGetAttr";
41
42
43
44
    int mpi_errno = MPI_SUCCESS;
    MPID_Comm *comm_ptr = NULL;
    static PreDefined_attrs attr_copy;    /* Used to provide a copy of the
					     predefined attributes */
45
    MPIU_THREADPRIV_DECL;
46
    MPID_MPI_STATE_DECL(MPID_STATE_MPIR_COMM_GET_ATTR);
47
48
49

    MPIR_ERRTEST_INITIALIZED_ORDIE();
    
50
    MPIU_THREAD_CS_ENTER(ALLFUNC,);
51
    MPID_MPI_FUNC_ENTER(MPID_STATE_MPIR_COMM_GET_ATTR);
52
53
54
55
56
57
58
59
60
61
62
63
    
    /* Validate parameters, especially handles needing to be converted */
#   ifdef HAVE_ERROR_CHECKING
    {
        MPID_BEGIN_ERROR_CHECKS;
        {
	    MPIR_ERRTEST_COMM(comm, mpi_errno);
	    MPIR_ERRTEST_KEYVAL(comm_keyval, MPID_COMM, "communicator", mpi_errno);
#           ifdef NEEDS_POINTER_ALIGNMENT_ADJUST
            /* A common user error is to pass the address of a 4-byte
	       int when the address of a pointer (or an address-sized int)
	       should have been used.  We can test for this specific
64
	       case.  Note that this code assumes sizeof(MPIR_Pint) is 
65
	       a power of 2. */
66
	    if ((MPIR_Pint)attribute_val & (sizeof(MPIR_Pint)-1)) {
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
		MPIU_ERR_SET(mpi_errno,MPI_ERR_ARG,"**attrnotptr");
	    }
#           endif
            if (mpi_errno != MPI_SUCCESS) goto fn_fail;
        }
        MPID_END_ERROR_CHECKS;
    }
#   endif

    /* Convert MPI object handles to object pointers */
    MPID_Comm_get_ptr( comm, comm_ptr );

    /* Validate parameters and objects (post conversion) */
#   ifdef HAVE_ERROR_CHECKING
    {
        MPID_BEGIN_ERROR_CHECKS;
        {
            /* Validate comm_ptr */
            MPID_Comm_valid_ptr( comm_ptr, mpi_errno );
	    /* If comm_ptr is not valid, it will be reset to null */
	    MPIR_ERRTEST_ARGNULL(attribute_val, "attr_val", mpi_errno);
	    MPIR_ERRTEST_ARGNULL(flag, "flag", mpi_errno);
            if (mpi_errno) goto fn_fail;
        }
        MPID_END_ERROR_CHECKS;
    }
#   endif /* HAVE_ERROR_CHECKING */

    /* ... body of routine ...  */
    
    /* Check for builtin attribute */
    /* This code is ok for correct programs, but it would be better
       to copy the values from the per-process block and pass the user
       a pointer to a copy */
    /* Note that if we are called from Fortran, we must return the values,
       not the addresses, of these attributes */
    if (HANDLE_GET_KIND(comm_keyval) == HANDLE_KIND_BUILTIN) {
	int attr_idx = comm_keyval & 0x0000000f;
	void **attr_val_p = (void **)attribute_val;
#ifdef HAVE_FORTRAN_BINDING
	/* This is an address-sized int instead of a Fortran (MPI_Fint)
	   integer because, even for the Fortran keyvals, the C interface is 
	   used which stores the result in a pointer (hence we need a
110
	   pointer-sized int).  Thus we use MPIR_Pint instead of MPI_Fint.
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
	   On some 64-bit plaforms, such as Solaris-SPARC, using an MPI_Fint
	   will cause the value to placed into the high, rather than low,
	   end of the output value. */
#endif
	*flag = 1;

	/* FIXME : We could initialize some of these here; only tag_ub is 
	 used in the error checking. */
	/* 
	 * The C versions of the attributes return the address of a 
	 * *COPY* of the value (to prevent the user from changing it)
	 * and the Fortran versions provide the actual value (as an Fint)
	 */
	attr_copy = MPIR_Process.attrs;
	switch (attr_idx) {
	case 1: /* TAG_UB */
127
	case 2:
128
129
130
	    *attr_val_p = &attr_copy.tag_ub;
	    break;
	case 3: /* HOST */
131
	case 4:
132
133
134
	    *attr_val_p = &attr_copy.host;
	    break;
	case 5: /* IO */
135
	case 6:
136
137
138
	    *attr_val_p = &attr_copy.io;
	    break;
	case 7: /* WTIME */
139
	case 8:
140
141
142
	    *attr_val_p = &attr_copy.wtime_is_global;
	    break;
	case 9: /* UNIVERSE_SIZE */
143
	case 10:
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
	    /* This is a special case.  If universe is not set, then we
	       attempt to get it from the device.  If the device is doesn't
	       supply a value, then we set the flag accordingly */
	    if (attr_copy.universe >= 0)
	    { 
		*attr_val_p = &attr_copy.universe;
	    }
	    else if (attr_copy.universe == MPIR_UNIVERSE_SIZE_NOT_AVAILABLE)
	    {
		*flag = 0;
	    }
	    else
	    {
		mpi_errno = MPID_Get_universe_size(&attr_copy.universe);
		/* --BEGIN ERROR HANDLING-- */
		if (mpi_errno != MPI_SUCCESS)
		{
		    attr_copy.universe = MPIR_UNIVERSE_SIZE_NOT_AVAILABLE;
		    goto fn_fail;
		}
		/* --END ERROR HANDLING-- */
		
		if (attr_copy.universe >= 0)
		{
		    *attr_val_p = &attr_copy.universe;
		}
		else
		{
		    attr_copy.universe = MPIR_UNIVERSE_SIZE_NOT_AVAILABLE;
		    *flag = 0;
		}
	    }
	    break;
	case 11: /* LASTUSEDCODE */
178
	case 12:
179
180
181
	    *attr_val_p = &attr_copy.lastusedcode;
	    break;
	case 13: /* APPNUM */
182
	case 14:
183
184
185
186
187
188
189
190
191
192
193
	    /* This is another special case.  If appnum is negative,
	       we take that as indicating no value of APPNUM, and set
	       the flag accordingly */
	    if (attr_copy.appnum < 0) {
		*flag = 0;
	    }
	    else {
		*attr_val_p = &attr_copy.appnum;
	    }
	    break;
	}
194
195
196
	/* All of the predefined attributes are INTEGER; since we've set 
	   the output value as the pointer to these, we need to dereference
	   it here. */
197
	if (*flag) {
198
199
            /* Use the internal pointer-sized-int for systems (e.g., BG/P)
 *             that define MPI_Aint as a different size that MPIR_Pint */
200
	    if (outAttrType == MPIR_ATTR_AINT)
201
		*(MPIR_Pint*)attr_val_p = *(MPIR_Pint*)*(void **)attr_val_p;
202
	    else if (outAttrType == MPIR_ATTR_INT)
203
		*(MPIR_Pint*)attr_val_p = *(int *)*(void **)attr_val_p;
204
	}
205
206
207
208
    }
    else {
	MPID_Attribute *p = comm_ptr->attributes;

209
	/*   */
210
211
212
	*flag = 0;
	while (p) {
	    if (p->keyval->handle == comm_keyval) {
213
		*flag                  = 1;
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
		if (outAttrType == MPIR_ATTR_PTR) {
		    if (p->attrType == MPIR_ATTR_INT) {
			/* This is the tricky case: if the system is
			 bigendian, and we have to return a pointer to
			 an int, then we may need to point to the 
			 correct location in the word. */
#if defined(WORDS_LITTLEENDIAN) || (SIZEOF_VOID_P == SIZEOF_INT)
			*(void**)attribute_val = &(p->value);
#else
			int *p_loc = (int *)&(p->value);
#if SIZEOF_VOID_P == 2 * SIZEOF_INT
			p_loc++;
#else 
#error Expected sizeof(void*) to be either sizeof(int) or 2*sizeof(int)
#endif
			*(void **)attribute_val = p_loc;
#endif
		    }
		    else if (p->attrType == MPIR_ATTR_AINT) {
			*(void**)attribute_val = &(p->value);
		    }
		    else {
			*(void**)attribute_val = (p->value);
		    }
		}
239
240
		else
		    *(void**)attribute_val = (p->value);
241

242
243
244
245
246
247
248
249
		break;
	    }
	    p = p->next;
	}
    }
    /* ... end of body of routine ... */

  fn_exit:
250
    MPID_MPI_FUNC_EXIT(MPID_STATE_MPIR_COMM_GET_ATTR);
251
    MPIU_THREAD_CS_EXIT(ALLFUNC,);
252
253
    return mpi_errno;

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  fn_fail:
    /* --BEGIN ERROR HANDLING-- */
#   ifdef HAVE_ERROR_CHECKING
    {
	mpi_errno = MPIR_Err_create_code(
	    mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpir_comm_get_attr",
	    "**mpir_comm_get_attr %C %d %p %p", comm, comm_keyval, attribute_val, flag);
    }
#   endif
    mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno );
    goto fn_exit;
    /* --END ERROR HANDLING-- */
}
#endif /* MPICH_MPI_FROM_PMPI */

#undef FUNCNAME
#define FUNCNAME MPI_Comm_get_attr
271
272
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

/* FIXME: Attributes must be visable from all languages */
/*@
   MPI_Comm_get_attr - Retrieves attribute value by key

Input Parameters:
+ comm - communicator to which attribute is attached (handle) 
- keyval - key value (integer) 

Output Parameters:
+ attr_value - attribute value, unless 'flag' = false 
- flag -  true if an attribute value was extracted;  false if no attribute is
  associated with the key 

   Notes:
    Attributes must be extracted from the same language as they were inserted  
    in with 'MPI_Comm_set_attr'.  The notes for C and Fortran below explain 
    why. 

Notes for C:
    Even though the 'attr_value' arguement is declared as 'void *', it is
    really the address of a void pointer.  See the rationale in the 
    standard for more details. 

.N ThreadSafe

.N Fortran

.N Errors
.N MPI_SUCCESS
.N MPI_ERR_COMM
.N MPI_ERR_KEYVAL
@*/
int MPI_Comm_get_attr(MPI_Comm comm, int comm_keyval, void *attribute_val, 
		      int *flag)
{
    int mpi_errno = MPI_SUCCESS;
    MPID_MPI_STATE_DECL(MPID_STATE_MPI_COMM_GET_ATTR);

    MPIR_ERRTEST_INITIALIZED_ORDIE();
    
    MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_COMM_GET_ATTR);

    /* Instead, ask for a desired type. */
    mpi_errno = MPIR_CommGetAttr( comm, comm_keyval, attribute_val, flag, 
				  MPIR_ATTR_PTR );
    if (mpi_errno) goto fn_fail;
    /* printf( "attr value = %x\n", *(void**)attribute_val ); */
    /* ... end of body of routine ... */

  fn_exit:
    MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_COMM_GET_ATTR);
    return mpi_errno;

327
328
329
330
331
332
333
334
335
336
337
338
  fn_fail:
    /* --BEGIN ERROR HANDLING-- */
#   ifdef HAVE_ERROR_CHECKING
    {
	mpi_errno = MPIR_Err_create_code(
	    mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_comm_get_attr",
	    "**mpi_comm_get_attr %C %d %p %p", comm, comm_keyval, attribute_val, flag);
    }
#   endif
    goto fn_exit;
    /* --END ERROR HANDLING-- */
}