/*
 * File         : mpi_Comm.c
 * Headerfile   : mpi_Comm.h 
 * Author       : Sung-Hoon Ko, Xinying Li, Sang Lim, Bryan Carpenter
 * Created      : Thu Apr  9 12:22:15 1998
 * Revision     : $Revision: 1.8 $
 * Updated      : $Date: 1999/09/13 18:57:44 $
 * Copyright: Northeast Parallel Architectures Center
 *            at Syracuse University 1998
 */

#include <mpi.h>
#include <malloc.h>
#include "mpi_Comm.h"

#include "buffer.h"
#include "handle.h"
#include "ID.h"

DECLARE_CLASS("mpi/Comm", comm_class)
DECLARE_FIELD_ID(comm_class, "handle", "J", CommhandleID)

DECLARE_CLASS("mpi/Request", request_class)
DECLARE_FIELD_ID(request_class, "handle", "J", reqhandleID)
DECLARE_FIELD_ID(request_class, "CbufHandle", "J", reqbufhandleID)
DECLARE_FIELD_ID(request_class, "releaseCbufWhenDone", "I", reqrelbufID)
DECLARE_FIELD_ID(request_class, "commBuf", "Ljava/lang/Object;", reqbufID)
DECLARE_FIELD_ID(request_class, "commOffset", "I", reqoffsetID)
DECLARE_FIELD_ID(request_class, "commType", "Lmpi/Datatype;", reqtypeID)
DECLARE_FIELD_ID(request_class, "commCount", "I", reqcountID)

DECLARE_CLASS("mpi/Status", status_class)
DECLARE_FIELD_ID(status_class, "handle", "J", stathandleID)
DECLARE_FIELD_ID(status_class, "source", "I", sourceID)
DECLARE_FIELD_ID(status_class, "tag", "I", tagID)
DECLARE_FIELD_ID(status_class, "count", "I", countID)
DECLARE_FIELD_ID(status_class, "index", "I", indexID)

DECLARE_CLASS("mpi/Datatype", datatype_class)
DECLARE_FIELD_ID(datatype_class, "handle", "J", DatatypehandleID)
DECLARE_FIELD_ID(datatype_class, "baseType", "I", DatatypebaseTypeID)
DECLARE_FIELD_ID(datatype_class, "baseSize", "I", DatatypebaseSizeID)

DECLARE_CLASS("mpi/Errhandler", errhandler_class)
DECLARE_FIELD_ID(errhandler_class, "handle", "J", ErrhandleID)

void markNonblocking(JNIEnv *env, jobject req, int releaseLater,
		     jobject buf, jobject type, void *bufptr,
		     jint offset, jint count)
{
  (*env)->SetIntField(env, req, reqrelbufID, releaseLater);
  (*env)->SetLongField(env, req, reqbufhandleID, handle_to_jlong(bufptr));
  (*env)->SetObjectField(env, req, reqbufID, buf);
  (*env)->SetIntField(env, req, reqoffsetID, offset);
  (*env)->SetIntField(env, req, reqcountID, count);
  (*env)->SetObjectField(env, req, reqtypeID, type);
}

/*
 * Class:     mpi_Comm
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_init
  (JNIEnv *env, jclass thisClass)
{
  jfieldID nullHandleID =
              (*env)->GetStaticFieldID(env,thisClass,"nullHandle","J");
  (*env)->SetStaticLongField(env,thisClass,nullHandleID,MPI_COMM_NULL);
}

/*
 * Class:     mpi_Comm
 * Method:    GetComm
 * Signature: (I)J
 */
JNIEXPORT void JNICALL Java_mpi_Comm_GetComm
  (JNIEnv *env, jobject jthis, jint type)
{
  switch (type) {
    case 0:
	  (*env)->SetLongField(env,jthis, CommhandleID,(jlong)MPI_COMM_NULL);
      break;
    case 1:
	  (*env)->SetLongField(env,jthis, CommhandleID,(jlong)MPI_COMM_SELF); 
      break;
    case 2:
	  (*env)->SetLongField(env,jthis, CommhandleID,(jlong)MPI_COMM_WORLD);
      break;
  }
  /* printf("Comm_constructor ... \n"); */
}


/*
 * Class:     mpi_Comm
 * Method:    Size
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Size
  (JNIEnv *env, jobject jthis)
{
  int size;
  MPI_Comm_size((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), &size);
  return size;
}

/*
 * Class:     mpi_Comm
 * Method:    Rank
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Rank
  (JNIEnv *env, jobject jthis) {
  int rank;
  MPI_Comm_rank((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), &rank);
  return rank;
}

/*
 * Class:     mpi_Comm
 * Method:    Dup
 * Signature: ()Lmpi/Comm;
 */
JNIEXPORT jlong JNICALL Java_mpi_Comm_dup
  (JNIEnv *env, jobject jthis)
{
  MPI_Comm newcomm;
  MPI_Comm_dup((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), 
               &newcomm);
  return (jlong)newcomm;
}

/*
 * Class:     mpi_Comm
 * Method:    Compare
 * Signature: (Lmpi/Comm;Lmpi/Comm;)I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Compare
  (JNIEnv *env, jclass jthis, jobject comm1, jobject comm2)
{
    int result;
    MPI_Comm_compare(
        (MPI_Comm)((*env)->GetLongField(env,comm1,CommhandleID)),
        (MPI_Comm)((*env)->GetLongField(env,comm2,CommhandleID)),
        &result);
    return result;
}

/*
 * Class:     mpi_Comm
 * Method:    Free
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_Free
  (JNIEnv *env, jobject jthis)
{
  MPI_Comm comm=(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID));
  MPI_Comm_free(&comm);
  (*env)->SetLongField(env,jthis, CommhandleID, MPI_COMM_NULL);
}

/*
 * Class:     mpi_Comm
 * Method:    Is_null
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_mpi_Comm_Is_1null(JNIEnv *env, jobject jthis) {
  MPI_Comm comm;
  comm=(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID));
  if(comm==MPI_COMM_NULL)
    return JNI_TRUE;
  else
    return JNI_FALSE;
}

/*
 * Class:     mpi_Comm
 * Method:    group
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_mpi_Comm_group
  (JNIEnv *env, jobject jthis)
{
    MPI_Group group;
    MPI_Comm_group((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                   &group);
    return (jlong)group;
}

/*
 * Class:     mpi_Comm
 * Method:    Test_inter
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_mpi_Comm_Test_1inter
  (JNIEnv *env, jobject jthis)
{
    int flag;
    MPI_Comm_test_inter((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),&flag);
    if(flag==0)
        return JNI_FALSE;
    else
        return JNI_TRUE;
}

/*
 * Class:     mpi_Comm
 * Method:    GetIntercomm
 * Signature: (Lmpi/Comm;III)J
 */
JNIEXPORT jlong JNICALL Java_mpi_Comm_GetIntercomm
  (JNIEnv *env, jobject jthis, jobject local_comm, jint local_leader, jint remote_leader, jint tag)
{
  MPI_Comm newintercomm;

  MPI_Intercomm_create((MPI_Comm)((*env)->GetLongField(env,local_comm,CommhandleID)),
                       local_leader,
                       (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), 
                       remote_leader, 
                       tag, 
                       &newintercomm);
  return (jlong)newintercomm;
}

/* getBufPtr is used in 
   Send, Recv ...
   for getting pointer from 'jobject buf'
*/
void* getBufPtr(JNIEnv *env,jobject buf, jobject type, int offset,		int count, jboolean copy_in)
{
  void* bufptr;
  jint extent = Java_mpi_Datatype_extent(env, type);
  jint size = Java_mpi_Datatype_size(env, type);

  copy_in = copy_in || (extent != size); /* must copy-in if there's a hole */
  count *= (extent / (*env)->GetIntField(env, type, DatatypebaseSizeID));
  switch ((*env)->GetIntField(env,type,DatatypebaseTypeID)) {
    case 0:
      break;
    case 1:
      bufptr=calloc(count, sizeof(jbyte));
      if (copy_in)
	(*env)->GetByteArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 2:
      bufptr=calloc(count, sizeof(jchar));
      if (copy_in)
	(*env)->GetCharArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 3:
      bufptr=calloc(count, sizeof(jshort));
      if (copy_in)
	(*env)->GetShortArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 4:
      bufptr=calloc(count, sizeof(jboolean));
      if (copy_in)
	(*env)->GetBooleanArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 5:
      bufptr=calloc(count, sizeof(jint));
      if (copy_in)
	(*env)->GetIntArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 6:
      bufptr=calloc(count, sizeof(jlong));
      if (copy_in)
	(*env)->GetLongArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 7:
      bufptr=calloc(count, sizeof(jfloat));
      if (copy_in)
	(*env)->GetFloatArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 8:
      bufptr=calloc(count, sizeof(jdouble));
      if (copy_in)
	(*env)->GetDoubleArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 9:
      bufptr=calloc(count, sizeof(jbyte));
      if (copy_in)
	(*env)->GetByteArrayRegion(env,buf,offset,count,bufptr);
      break;
    case 10:
      break;
    case 11:
      break;
    case 12:
      bufptr=calloc(count, sizeof(jbyte));
      if (copy_in)
	(*env)->GetByteArrayRegion(env,buf,offset,count,bufptr);
      break;
    default:
      break;
  }
  return bufptr;
}

/*
jbyte *getBufPtr(JNIEnv *env, jobject buf, jobject type)
{
  jbyte *bufptr;
  jboolean isCopy=JNI_TRUE;
  jfieldID baseTypeIndID;
  jclass typeClass=(*env)->FindClass(env,"mpi/Datatype");
  baseTypeIndID= (*env)->GetFieldID(env,typeClass,"baseType","I");
  switch ((*env)->GetIntField(env,type,baseTypeIndID)) {
    case 0:
      break;
    case 1:
      bufptr=(*env)->GetByteArrayElements(env,buf,&isCopy);
      break;
    case 2:
      bufptr=(jbyte*)((*env)->GetCharArrayElements(env,buf,&isCopy));
      break;
    case 3:
      bufptr=(jbyte*)(*env)->GetShortArrayElements(env,buf,&isCopy);
      break;
    case 4:
      bufptr=(jbyte*)(*env)->GetBooleanArrayElements(env,buf,&isCopy);
      break;
    case 5:
      bufptr=(jbyte*)(*env)->GetIntArrayElements(env,buf,&isCopy);
      break;
    case 6:
      bufptr=(jbyte*)(*env)->GetLongArrayElements(env,buf,&isCopy);
      break;
    case 7:
      bufptr=(jbyte*)(*env)->GetFloatArrayElements(env,buf,&isCopy);
      break;
    case 8:
      bufptr=(jbyte*)(*env)->GetDoubleArrayElements(env,buf,&isCopy);
      break;
    case 9:
      bufptr=(*env)->GetByteArrayElements(env,buf,&isCopy); 
      break;
    case 10:
      break;
    case 11:
      break;
    case 12:
      bufptr=(*env)->GetByteArrayElements(env,buf,&isCopy);
      break;
    default:
      break;
  }
  return bufptr;
}
*/

/* releaseBufPtr is used in 
   Send, Recv ...
   for release pointer corresponding to Get<...>ArrayElements
*/
void releaseBufPtr(JNIEnv *env,jobject buf, jobject type,
                   void* bufptr, int offset, int count, int release)
{
  if (release & BUF_WRITEBACK) {
    /* Copy back the changes into Java array. */
    count *= (Java_mpi_Datatype_extent(env, type) /
	      (*env)->GetIntField(env, type, DatatypebaseSizeID));
    switch ((*env)->GetIntField(env,type,DatatypebaseTypeID)) {
    case 0:
      break;
    case 1:
      (*env)->SetByteArrayRegion(env,buf,offset,count,(jbyte*)bufptr);
      break;
    case 2:
      (*env)->SetCharArrayRegion(env,buf,offset,count,(jchar*)bufptr);
      break;
    case 3:
      (*env)->SetShortArrayRegion(env,buf,offset,count,(jshort*)bufptr);
      break;
    case 4:
      (*env)->SetBooleanArrayRegion(env,buf,offset,count,(jboolean*)bufptr);
      break;
    case 5:
      (*env)->SetIntArrayRegion(env,buf,offset,count,(jint*)bufptr);
      break;
    case 6:
      (*env)->SetLongArrayRegion(env,buf,offset,count,(jlong*)bufptr);
      break;
    case 7:
      (*env)->SetFloatArrayRegion(env,buf,offset,count,(jfloat*)bufptr);
      break;
    case 8:
      (*env)->SetDoubleArrayRegion(env,buf,offset,count,(jdouble*)bufptr);
      break;
    case 9:
      (*env)->SetByteArrayRegion(env,buf,offset,count,(jbyte*)bufptr);
      break;
    case 10:
      break;
    case 11:
      break;
    case 12:
      (*env)->SetByteArrayRegion(env,buf,offset,count,(jbyte*)bufptr);
      break;
    default:
      break;
    }
  }
  if (release & BUF_RELEASE) {
    free(bufptr);
  }
}

/*
void releaseBufPtr(JNIEnv *env,jobject buf,jobject type, jbyte* bufptr)
{
  jfieldID baseTypeIndID;
  jclass typeClass=(*env)->FindClass(env,"mpi/Datatype");
  baseTypeIndID= (*env)->GetFieldID(env,typeClass,"baseType","I");
  switch ((*env)->GetIntField(env,type,baseTypeIndID)) {
    case 0:
      break;
    case 1:
      (*env)->ReleaseByteArrayElements(env,buf,bufptr,0);
      break;
    case 2:
      (*env)->ReleaseCharArrayElements(env,buf,(jchar*)bufptr,0);
      break;
    case 3:
      (*env)->ReleaseShortArrayElements(env,buf,(jshort*)bufptr,0);
      break;
    case 4:
      (*env)->ReleaseBooleanArrayElements(env,buf,(jboolean*)bufptr,0);
      break;
    case 5:
      (*env)->ReleaseIntArrayElements(env,buf,(jint*)bufptr,0);
      break;
    case 6:
      (*env)->ReleaseLongArrayElements(env,buf,(jlong*)bufptr,0);
      break;
    case 7:
      (*env)->ReleaseFloatArrayElements(env,buf,(jfloat*)bufptr,0);
      break;
    case 8:
      (*env)->ReleaseDoubleArrayElements(env,buf,(jdouble*)bufptr,0);
      break;
    case 9:
      (*env)->ReleaseByteArrayElements(env,buf,bufptr,0);
      break;
    case 10:
      break;
    case 11:
      break;
    case 12:
     (*env)->ReleaseByteArrayElements(env,buf,bufptr,0);
      break;
    default:
      break;
  }
}
*/

/*
 * Class:     mpi_Comm
 * Method:    send
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;II)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_send
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint
count, jobject type, jint dest, jint tag)
{
  void* bufptr=getBufPtr(env,buf,type, offset, count, JNI_TRUE);

  MPI_Send(bufptr,
           count, 
           (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
           dest, 
           tag,
           (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));

  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE);
}

/*
 * Class:     mpi_Comm
 * Method:    Recv
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;IILmpi/Status;)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Recv
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint source, jint tag, jobject stat)
{
  MPI_Status *status =
    (MPI_Status*)jlong_to_handle((*env)->GetLongField(env,stat,stathandleID));
  int elementSize ;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Recv(bufptr,
	   count, 
	   (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	   source, tag,
	   (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
	   status);

  (*env)->SetIntField(env,stat, sourceID,status->MPI_SOURCE);
  (*env)->SetIntField(env,stat, tagID,status->MPI_TAG);

  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE|BUF_WRITEBACK);

  return stat;
}

/*
 * Class:     mpi_Comm
 * Method:    Sendrecv
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;IILjava/lang/Object;IILmpi/Da
tatype;IILmpi/Status;)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Sendrecv
  (JNIEnv *env, jobject jthis, jobject sbuf, jint soffset, jint scount, 
	jobject stype, jint dest, jint stag, 
	jobject rbuf, jint roffset, jint rcount, 
	jobject rtype, jint source, jint rtag, jobject stat)
{
  MPI_Status *status =
    (MPI_Status*)jlong_to_handle((*env)->GetLongField(env,stat,stathandleID));

  void* sbufptr=getBufPtr(env,sbuf,stype,soffset, scount, JNI_TRUE);
  void* rbufptr=getBufPtr(env,rbuf,rtype,roffset, rcount, JNI_FALSE);

  MPI_Sendrecv(sbufptr, scount, 
	(MPI_Datatype)((*env)->GetLongField(env,stype,DatatypehandleID)),
        dest, stag, 
        rbufptr, rcount,
	(MPI_Datatype)((*env)->GetLongField(env,rtype,DatatypehandleID)),
	source, rtag,
	(MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), 
	status);

  releaseBufPtr(env,rbuf,rtype,rbufptr,roffset,rcount, BUF_RELEASE|BUF_WRITEBACK);
  releaseBufPtr(env,sbuf,stype,sbufptr,soffset,scount, BUF_RELEASE);

  (*env)->SetIntField(env,stat, sourceID,status->MPI_SOURCE);
  (*env)->SetIntField(env,stat, tagID,status->MPI_TAG);

  return stat;
}

/*
 * Class:     mpi_Comm
 * Method:    Sendrecv_replace
 * Signature:
(Ljava/lang/Object;IILmpi/Datatype;IIILmpi/Datatype;IILmpi/Statu
s;)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Sendrecv_1replace
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count,
    jobject type, jint dest, jint stag,
    jint source, jint rtag, jobject stat)
{
  MPI_Status *status =
    (MPI_Status*)jlong_to_handle((*env)->GetLongField(env,stat,stathandleID));
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Sendrecv_replace(bufptr, count, 
    (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
    dest, stag, 
    source, rtag,
    (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
    status);
  
  
  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE|BUF_WRITEBACK);

  (*env)->SetIntField(env,stat, sourceID,status->MPI_SOURCE);
  (*env)->SetIntField(env,stat, tagID,status->MPI_TAG);

  return stat;
}

/* !! These Attr_put and Attr_get may be changed sometime later, because dbc
   suggest using NewGlobalRef.
   xli 1/23/98

   !! Attr_put and Attr_get are dealing with int attribute_val only now.
   xli 3/26/98
*/


/*
 * Class:     mpi_Comm
 * Method:    Attr_put
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_Attr_1put
  (JNIEnv *env, jobject jthis, jint keyval, jint attribute_val)
{
	MPI_Attr_put((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		     keyval, &attribute_val);
}

/*
 * Class:     mpi_Comm
 * Method:    Attr_get
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Attr_1get
  (JNIEnv *env, jobject jthis, jint keyval)
{
    int *attribute_val; 
    int flag;
    MPI_Attr_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		 keyval, &attribute_val, &flag);

  if(flag != 0)
    return *attribute_val;
  else
    return (int) NULL;

}

/*
 * Class:     mpi_Comm
 * Method:    Attr_put
 * Signature: (ILjava/lang/Object;)V
 */
/*
JNIEXPORT void JNICALL Java_mpi_Comm_Attr_1put
  (JNIEnv *env, jobject jthis, jint keyval, jobject attribute_val)
{
	MPI_Attr_put((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),keyval,
		attribute_val);
}
*/
/*
 * Class:     mpi_Comm
 * Method:    Attr_get
 * Signature: (I)Ljava/lang/Object;
 */
/*
JNIEXPORT jobject JNICALL Java_mpi_Comm_Attr_1get
  (JNIEnv *env, jobject jthis, jint keyval)
{
	jobject attribute_val;
	int flag;
    MPI_Attr_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),keyval,
        &attribute_val,&flag);
	return attribute_val;
}
*/

/*
 * Class:     mpi_Comm
 * Method:    Attr_delete
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_Attr_1delete
  (JNIEnv *env, jobject jthis, jint keyval)
{
	MPI_Attr_delete((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),keyval);
}

/*
 * Class:     mpi_Comm
 * Method:    Abort
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_Abort
  (JNIEnv *env, jobject jthis, jint errorcode)
{
  MPI_Abort((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)), errorcode);
}

/*
 * Class:     mpi_Comm
 * Method:    bsend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;II)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_bsend
   (JNIEnv *env, jobject jthis, jobject buf, jint offset, 
	  jint count, jobject type, jint dest, jint tag)
{
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);
  MPI_Bsend(bufptr,
            count,
            (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
            dest,
            tag,
            (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE);
}

/*
 * Class:     mpi_Comm
 * Method:    ssend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;II)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_ssend
   (JNIEnv *env, jobject jthis, jobject buf, jint offset, 
	  jint count, jobject type, jint dest, jint tag)
{
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);
  MPI_Ssend(bufptr, count,
            (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
            dest, tag,
            (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE);
}

/*
 * Class:     mpi_Comm
 * Method:    rsend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;II)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_rsend
   (JNIEnv *env, jobject jthis, jobject buf, jint offset, 
	  jint count, jobject type, jint dest, jint tag)
{
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Rsend(bufptr,
       count,
       (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)), 
       dest, tag,
       (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)) );

  releaseBufPtr(env,buf,type,bufptr,offset,count, BUF_RELEASE);
}

/*
 * Class:     mpi_Comm
 * Method:    Isend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Request;)Lmpi/Request;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Isend
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Isend(bufptr, count,
      (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
      dest, tag,
      (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
      &request );

  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_RELEASE, buf, type, bufptr, offset, count);

  /*
  if(request==MPI_REQUEST_NULL)
        return NULL;
  */
  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Ibsend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Request;)Lmpi/Request;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Ibsend
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Ibsend(bufptr,
       count,
       (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
       dest, tag,
       (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
       &request );

  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_RELEASE, buf, type, bufptr, offset, count);
  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Issend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Request;)Lmpi/Request;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Issend
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Issend(bufptr,
       count, 
       (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
       dest, tag,
       (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
       &request );

  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_RELEASE, buf, type, bufptr, offset, count);
  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Irsend
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Request;)Lmpi/Request;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Irsend
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_TRUE);

  MPI_Irsend(bufptr,
       count, 
       (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
       dest, tag,
       (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
       &request );

  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_RELEASE, buf, type, bufptr, offset, count);
  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Irecv
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Status;)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Irecv
   (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
    type, jint source, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Irecv(bufptr,
            count, 
	    (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	    source, tag,
	    (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
	    &request);

  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_RELEASE|BUF_WRITEBACK, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Send_init
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Prequest;)Lmpi/Prequest;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Send_1init
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Send_init(bufptr,
                count,
                (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	        dest, tag,
                (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                &request);
  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));
  
  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, 0, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Bsend_init
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Prequest;)Lmpi/Prequest;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Bsend_1init
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Bsend_init(bufptr,
                 count,
                 (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	         dest,
                 tag,
                 (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                 &request);
  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));

  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, 0, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Ssend_init
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Prequest;)Lmpi/Prequest;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Ssend_1init
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Ssend_init(bufptr,
                 count,
                 (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	         dest, tag,
                 (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                 &request);
  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));

  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, 0, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Rsend_init
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Prequest;)Lmpi/Prequest;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Rsend_1init
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint dest, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Rsend_init(bufptr,
                 count,
                 (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	         dest, tag,
                 (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                 &request);
  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));

  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, 0, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    Recv_init
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;IILmpi/Prequest;)Lmpi/Prequest;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Recv_1init
  (JNIEnv *env, jobject jthis, jobject buf, jint offset, jint count, jobject
type, jint source, jint tag, jobject req)
{
  MPI_Request request;
  void* bufptr=getBufPtr(env,buf,type,offset, count, JNI_FALSE);

  MPI_Recv_init(bufptr,
                count,
                (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	        source, tag,
                (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                &request);
  (*env)->SetLongField(env,req,reqhandleID,handle_to_jlong(request));

  /*
  releaseBufPtr(env,buf,type,bufptr,offset);
  */
  markNonblocking(env, req, BUF_WRITEBACK, buf, type, bufptr, offset, count);

  return req;
}

/*
 * Class:     mpi_Comm
 * Method:    pack
 * Signature: (Ljava/lang/Object;IILmpi/Datatype;[BI)I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_pack
  (JNIEnv *env, jobject jthis, jobject inbuf, jint offset, jint incount, jobject type, 
  jbyteArray outbuf, jint position)
{
  void* ibufptr=getBufPtr(env,inbuf,type,offset, incount, JNI_TRUE);
  int outsize=(*env)->GetArrayLength(env,outbuf) - position;
  jbyte* obufptr=malloc(outsize);
  jint bytes = 0;

  MPI_Pack(ibufptr,
           incount,
           (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	   obufptr, outsize, (int*)&bytes,
           (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));

  releaseBufPtr(env,inbuf,type,ibufptr,offset,incount, BUF_RELEASE);
  (*env)->SetByteArrayRegion(env,outbuf,position,bytes, obufptr);
  free(obufptr);
  return position + bytes;
}

/*
 * Class:     mpi_Comm
 * Method:    unpack
 * Signature: ([BILjava/lang/Object;IILmpi/Datatype;)I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_unpack
  (JNIEnv *env, jobject jthis, jbyteArray inbuf, jint position, jobject outbuf, jint offset,
  jint outcount, jobject type)
{
  jbyte* obufptr=getBufPtr(env,outbuf,type,offset, outcount, JNI_FALSE);
  void* ibufptr=(*env)->GetByteArrayElements(env,inbuf,NULL);
  int insize=(*env)->GetArrayLength(env,inbuf);
  MPI_Unpack(ibufptr,
             insize, (int*)&position,
	     obufptr, outcount,
             (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
	     (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)));
  releaseBufPtr(env,outbuf,type,obufptr,offset,outcount, BUF_RELEASE|BUF_WRITEBACK);
  (*env)->ReleaseByteArrayElements(env,inbuf,ibufptr,JNI_ABORT);
  return position;
}

/*
 * Class:     mpi_Comm
 * Method:    Pack_size
 * Signature: (ILmpi/Datatype;)I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Pack_1size
  (JNIEnv *env, jobject jthis, jint incount, jobject type)
{
   int size;

   MPI_Pack_size(incount, 
                 (MPI_Datatype)((*env)->GetLongField(env,type,DatatypehandleID)),
                 (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
                 &size);

   return size;
}

/*
 * Class:     mpi_Comm
 * Method:    Iprobe
 * Signature: (II)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Iprobe
  (JNIEnv *env, jobject jthis, jint source, jint tag, jobject stat)
{
  int flag;
  MPI_Status *status =
    (MPI_Status*)jlong_to_handle((*env)->GetLongField(env,stat,stathandleID));

  MPI_Iprobe(source, tag,
	     (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
	     &flag, status);

  (*env)->SetIntField(env,stat, sourceID,status->MPI_SOURCE);
  (*env)->SetIntField(env,stat, tagID,status->MPI_TAG);

  if(flag != 0)
    return stat;
  else
    return NULL;

}
/*
 * Class:     mpi_Comm
 * Method:    Probe
 * Signature: (II)Lmpi/Status;
 */
JNIEXPORT jobject JNICALL Java_mpi_Comm_Probe
  (JNIEnv *env, jobject jthis, jint source, jint tag,jobject stat)
{
  MPI_Status *status =
    (MPI_Status*)jlong_to_handle((*env)->GetLongField(env,stat,stathandleID));

  MPI_Probe(source, tag,
	    (MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
	    status);

  (*env)->SetIntField(env,stat, sourceID,status->MPI_SOURCE);
  (*env)->SetIntField(env,stat, tagID,status->MPI_TAG);

  return stat;
}

/*
 * Class:     mpi_Comm
 * Method:    Errhandler_set
 * Signature: (Lmpi/Errhandler;)V
 */
JNIEXPORT void JNICALL Java_mpi_Comm_Errhandler_1set
  (JNIEnv *env, jobject jthis, jobject errhandler)
{
  MPI_Errhandler_set((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
	  (MPI_Errhandler)((*env)->GetLongField(env,errhandler,ErrhandleID)));
}


/*
 * Class:     mpi_Comm
 * Method:    errorhandler_get
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_mpi_Comm_errorhandler_1get
  (JNIEnv *env, jobject jthis)
{
  MPI_Errhandler errhandler;
  MPI_Errhandler_get((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		     &errhandler);
  return (jlong)errhandler;
}


/*
 * Class:     mpi_Comm
 * Method:    Topo_test
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_mpi_Comm_Topo_1test
  (JNIEnv *env, jobject jthis)
{
  int status;
  MPI_Topo_test((MPI_Comm)((*env)->GetLongField(env,jthis,CommhandleID)),
		&status);
  return status;
}

/*
 * Things to do:
 *
 *    Initialize `sourceID', `tagID' in consistent way with `stathandleId'.
 *
 *    `getBufPtr', `releaseBufPtr' should take `baseType' arguments rather
 *    than full `type'.
 */

