Skip to content

CHAR () and Rmpi

4 messages · Hao Yu, Brian Ripley, Martin Morgan

#
Hi. I am the maintainer of Rmpi package. Now I have a problem regarding
the change of CHAR () in R 2.6.0. According to R 2.6.0 NEWS:
*******
CHAR() now returns (const char *) since CHARSXPs should no
        longer be modified in place.  This change allows compilers to
        warn or error about improper modification.  Thanks to Herve
        Pages for the suggestion.
*******
Unfortunately this causes Rmpi to fail since MPI requires char pointers
rather than const char pointers. Normally I use
    CHAR(STRING_ELT((sexp_rdata),0))
to get the pointer to MPI where a R character vector (C sense) is stored.
Because of the change, all character messengers fail. Is there an easy way
to get a char pointer to STRING_ELT((sexp_rdata),0) and is also backward
compatible to old R versions. BTW Rmpi does not do any modification of
characters at C level.

Thanks
Hao Yu
#
I'm not sure what your sticking point here is.  If mpi does not modify 
data in a (char *) pointer, then that really is a (const char *) pointer 
and the headers are being unhelpful in not telling the compiler that 
the data are constant.

If that is the case you need to use casts to (char *) and the following 
private define may be useful to you:

#define CHAR_RW(x) ((char *) CHAR(x))


However, you ask
and the answer is that there is no such way, since (const char *) and 
(char *) are not the same thing and any package that wants to alter the 
contents of a string element needs to create a new CHARSXP to be that 
element.


BTW, you still have not changed Rmpi to remove the configure problems on 
64-bit systems (including assuming libs are in /usr/lib not /usr/lib64) I 
pointed out a long time ago.
On Fri, 28 Sep 2007, Hao Yu wrote:

            

  
    
#
Hao Yu,

I spot two types of problematic code. Certainly the memcpy in
conversions.c:54 and 56 will cause problems, but I'm not sure whether
those functions are actually used?

The second paradigm is, e.g., Rmpi.c:561

    MPI_Recv(CHAR(STRING_ELT(sexp_data,i)),
             slen,MPI_CHAR,source,tag, comm[commn],&status[statusn]);

where the first argument to MPI_Recv is a buffer that MPI_Recv will
fill. sexp_data is a user-supplied character vector. A not-clever
solution creates a temporary buffer via R_alloc (for garbage-collected
memory) or R_Calloc (for user-managed memory, probably appropriate in
a loop where you'd like to reuse the buffer), passes the buffer to
MPI_Recv, and then SET_STRING_ELT with the now filled temporary buffer
converted to a CHARSXP with mkChar. I think this is backward
compatible. The user-supplied character vector has gone to waste, used
only to pass in the length of the expected string. mkChar will copy
the temporary buffer (unless an identical CHARSXP already exists), so
that there are potentially three memory allocations per string!  I
suspect most users rely on higher-level access (mpi.par*Apply,
mpi.*.Robj, etc) where this inefficiency is not important or can be
addressed without modifying the public interface.

Martin

Prof Brian Ripley <ripley at stats.ox.ac.uk> writes:

  
    
#
Thank all for your quick reply. I am wrong to say Rmpi does not modify
CHARSXP at C level. In fact as Martin points out, the receive buff must be
modified. Last night I started the modification of c codes.

For send buffer (no modification), I used
//copy from R 2.6.0 (not in previous versions)
char *acopy_string2(const char *in)
{
    char *out;
    int len = strlen(in);
    if (len > 0) {
        out = (char *) R_alloc(strlen(in), sizeof(char));
        strcpy(out, in);
    } else
        out = "";
    return out;
}

char *charsxp2char(SEXP x)
{
    return acopy_string2(CHAR(x));
}

// I may combine above two functions together

SEXP mpi_info_set(SEXP sexp_info, SEXP sexp_key, SEXP sexp_value){
        char *key, *value;
        key =  charsxp2char( STRING_ELT (sexp_key,0));
        value = charsxp2char (STRING_ELT (sexp_value,0));

        return
AsInt(erreturn(mpi_errhandler(MPI_Info_set(info[INTEGER(sexp_info)[0]],
key, value))));
}

//For modified buffer. Need to use R_alloc for better memory managment
SEXP mpi_info_get(SEXP sexp_info, SEXP sexp_key, SEXP sexp_valuelen){
        int flag;
        char *key, *value;
        SEXP sexp_value;

        key=charsxp2char( STRING_ELT (sexp_key,0));
        PROTECT (sexp_value  = allocVector (STRSXP, 1));
        value = (char *)Calloc(INTEGER(sexp_valuelen)[0], char);
        mpi_errhandler(MPI_Info_get(info[INTEGER(sexp_info)[0]], key,
INTEGER(sexp_valuelen)[0], value, &flag));
        SET_STRING_ELT(sexp_value, 0, mkChar(value));
        UNPROTECT(1);
        Free(value);

        return sexp_value;
}

This works well. However, for nonblock calls, there is no way to receive a
char vector.

I am going to tidy up the codes and remove some redundant codes.

To Prof. Ripley. I am rewriting configure.ac (from configure.in) and put
lib64 in the search path. I am working on Debian 4.0 64bit and the
original configure.ac works well. The new configure.ac can be used for
OpenMPI so Rmpi can be used under OpenMPI (many request it). In addition,
Rmpi can be compiled and run under Mac OS X. I do not know if r-project
will put lam into OS X and make Rmpi officially available to Mac. I need
to fully test Rmpi before submitting next version.

Thanks all and have nice weekend days.
Hao
Martin Morgan wrote: