MPI supports two types of attributes: address valued (pointer) attributes,
and integer valued attributes. C attribute functions put and get address
valued attributes. Fortran attribute functions put and get integer valued
attributes. When an integer valued attribute is accessed from C, then
MPI_xxx_get_attr will return the address of (a pointer to) the integer
valued attribute. When an address valued attribute is accessed from
Fortran, then MPI_xxx_GET_ATTR will convert the address into an integer and
return the result of this conversion. This conversion is lossless if new
style attribute functions are used, and an integer of kind MPI_ADDRESS_KIND
is returned. The conversion may cause truncation if old style attribute
functions are used.
Examples
A. C to Fortran
() C code
void *p;
p = (void *)5;
MPI_Comm_put_attr(..., p);
....
() Fortran code
INTEGER(kind = MPI_ADDRESS_KIND) val
CALL MPI_COMM_GET_ATTR(...,val,...)
IF(val.NE.5) THEN CALL ERROR
B. Fortran to C
() Fortran code
INTEGER(kind=MPI_ADDRESS_KIND) val
val = 5
CALL MPI_COMM_PUT_ATTR(...,val)
() C code
int *p;
MPI_Comm_put_attr(...,(void *)(&p), ...);
if (*p != 5) error();
The predefined MPI attributes can be integer valued or address valued.
Predefined integer valued attributes, such as MPI_TAG_UB, behave as if they
were put by a Fortran call. I.e., in Fortran,
MPI_COMM_GET_ATTR(MPI_COMM_WORLD, MPI_TAG_UB, val, flag) will return in val
the upper bound for tag value; in C, MPI_Comm_get_attr(MPI_COMM_WORLD,
MPI_TAG_UB, &p, flag) will return in p a pointer to an int containing the
upper bound for tag value.
Address valued predefined attributes, such as MPI_WIN_BASE behave as if
they were put by a C call. I.e., in Fortran, MPI_WIN_GET_ATTR(win,
MPI_WIN_BASE, val, flag) will return in val the base address of the window,
converted to an integer. In C, MPI_Win_get_attr(win, MPI_WIN_BASE, &p,
flag) will return in p a pointer to the window base, cast to (void *).
Rationale:
The design is consistent with the behavior specified in MPI1 for predefined
attributes, and ensures that no information is lost when attributes are
passed from language to language.
Implementors:
Implementations should tag attributes either as address attributes or as
integer attributes, according as they were put in C or in Fortran. Thus,
the right choice can be made when the attribute is retrieved.
--------
new text
------------
The same approach is followed for the "extra-state" that is associated with
attribute keys. Namely, this extra-state can be integer valued or address
valued. The FORTRAM version of MPI_KEYVAL_CREATE stores an integer value
in the extra state associated with the newly created attribute key; the C
version of MPI_Keyval_create stores an address (a value of type void*) in
the the extra state associated with the newly created attribute key. A C
attribute copy or delete function is passed an address value in
"extra_state"; a FORTRAN attribute copy or delete function is passed an
integer value in "extra-state". When an address-valued extra_state is
accessed from FORTRAN, then the address is converted to an integer; wehen
an integer valued extra_state is accessed from C, then the function is
retuirned a pointer to (the address of) the integer extra_state.
Thus
A. C to Fortran
() C code
void *p;
p = (void *)5;
MPI_Comm_keyval_create(... keyval, p);
....
() Fortran code
SUBROUTINE comm_copy_fn(...., extra_state,...)
INTEGER(kind = MPI_ADDRESS_KIND) extra_state
...
! The copy function is passed the value 5 in extra_state, if invoked by
MPI_COMM_DUP on
! a communicator that has an attribute value associated with keyval.
B. Fortran to C
() Fortran code
INTEGER(kind=MPI_ADDRESS_KIND) val
val = 5
CALL MPI_COMM_KEYVAL_CREATE(..., keyval,val)
() C code
void Comm_copy_fn(..., void *extra_state,....);
/* The copy function is passed in extra_state a pointer to a location where
5 is stored,
if invoked by MPI_Comm_dup on a communicator that has an attribute
associated with keyval */
The extra_state cannot be modified by the attribute copy and delete
functions. However, these functions can modify state
that can be accessed indirectly from extra_state. E.g., in C, extra_state
can be a pointer to a data structure that is modified by
the attribute copy or delete functions; in Fortran at can be an index in a
COMMON array.
Rationale: The solution is consistent with the solution used for attribute
values. Note that, in general, the attribute copy and delete functions are
not supposed to modify extra_state. These is one extra_state that is
associated with each attribute key; there can be multiple instances of
attributes associated with teis key, one for each communicator, or other
opaque object that supports caching. The callback functions are used to
create/delete attributes, not to modify the extra_state.
------
2. MPI_KEYVAL_DELETE
The MPI-1 text on MPI_KEYVAL_FREE is quite clear, I believe: It assumes the
usual "lazy deallocation", as for all opaque objects: "...the key value is
not actually deallocated until after no attribute values are locally
attached to the key." Thus, even though a user called
MPI_Keyval_free(...,keyval), following callbacks on attributes associated
with keyval should go as usual. This, until there is no more instances of
attributes associated with keyval; at which time, the attribute key may be
deleted. Since there are no attributes associated with keyval when keyval
is deleted, then the copy and delete callback functions cannot be invoked
with keyval after keyval is deleted. A call MPI_ATTR_PUT(...,keyval,...)
or MPI_ATTR_GET(...,keyval,...) or MPI_ATTR_DELETE(...,keyval) after
MPI_KEYVAL_FREE(keyval) was invoked is erroneous. (We don't say this
apropos key values, but this is the usual statement about free functions:
it's erronoues to access, explicitly, an opaque object that has been freed.
We can add this as a clarification).
----------
3. Threaded MPI and callbacks.
I see no reason to guarantee serialization of callback functions. They are
not, normally, used to update shared state. If two threads try to free the
same communicator, then the program is erroneous. If two threads dup the
same communicator, then both will read the attributes of the old
communicators, and create distinct attribute copies for the new
communicators. If, instead of actual copying, the user prefers to
increment a reference count, then we have a mutual exclusion problem in our
hands. But this is a user code problem, not an MPI problem: the user
provided the comm_copy_fn callback function that does the the reference
count increment. This is a function that explicitly updates state that is
shared by mutlple threads. If the user wants this callback to work in a
multithreaded environment he/she should take care of mutual exclusion.