The call to MPI_GR_MARK_COMPLETE(request) has a well-defined behavior if it
is passed a valid request handle, and it is up to the user to make sure it
is so.
The call to MPI_Request_Free(request) has a well-defined behavior if it is
passed a valid handle, and it is up to the user to make sure it is so.
MPI_REQUEST_FREE(request) will nullify the handle to the request, but will
not necessarily delete the request itself. The request will be deallocated
by MPI only after the user deallocated all its data structures in the
free_fn callback.
So, suppose that the model is that the user runs in one thread, perhaps
calling MPI_REQUEST_FREE, and a server runs on another thread, eventually
calling MPI_GR_MARK_COMPLETE. Then, the routine that starts the user
defined operation will call MPI_GR_START, will stash away a copy
request_copy of the request handle on the heap, perhaps in extra_state, and
will return to the user the value of the request handle. If the user calls
MPI_REQUEST_FREE(request) before the request was marked complete by a call
to MPI_GR_MARK_COMPLETE then nothing happens, except that MPI records the
fact that the user freed the request, and nullifies the user copy of the
request handle. When the server thread calls MPI_
GR_MARK_COMPLETE(request_copy), then the request is marked complete,
free_fn is invoked to do the cleanup, and the request is deallocated by
MPI. If the user calls MPI_REQUEST_FREE after MPI_GR_MARK_COMPLETE was
called, then the free-fn function is invoked, and the request is
deallocated next.