Free Web Hosting by Netfirms
Web Hosting by Netfirms | Free Domain Names by Netfirms

 

Java2Fortran
what for ?
more ? (links)

Contact
mail me !
 

 
 
 

Java To C To Fortran Interfacing

(used for Multithreading)


1. Introduction
2. Overview
3. Java Native Interfacing
3.1 Writing the Java code
3.2 Generating the Class file
3.3 Generating Function Prototypes
3.4 Building the C Stub File
3.5 Writing the C Source File
A. Function specification and mapping
B. Data type
C. Argument handling
3.6 Building Native Libraries
4. C to Fortran Interfacing
4.1 Argument Types
4.2 Subroutines and Functions
5. Fortran Compilation Allowing Multithreading
6. Summary

1. Introduction


You'll find here an extract of my my MS Thesis, giving enough information to build your own Java to C to Fortran interface. If you still need a hand just mail me ! . I made this documentation back in February 1999, by that time I used my CIS professor in KSU, and some other materials you may still fin on the web and on other deadtree books. 
 

2. Overview


Java includes features to import C code, features called Java Native Interface JNI. But as it is not possible to directly reference Fortran from Java, we established an interface between Fortran and C. It was then possible to indirectly call from Java, passing through C, the subroutines implemented in Fortran. We will cover in this section the detail of this interfacing.

Let us first have a look at the condensed version of the different steps involved in this Java to Fortran (through C) interfacing:

1. Write the Java source file, declaring the native method and specifying the libraries to be loaded.
2. Run Java source file through javac to produce the class file.
3. Run the Java class file through javah to produce the header file.
4. Run again the Java class file through javah to produce the C stub file.
5. Write the C source file according to the function prototypes generated by javah, importing the header files generated by javah, and according to Sun conventions and ANSI Standart function prototypes that allows cross language communication between C and Fortran.
6. Write the Fortran source files that the C file references.
7. Compile the C source and stubs files.
8. Compile the Fortran source files with the option that forces local variables to be allocated on the memory stack so that parallelization can be ensured.
9. Create the shared object (the dynamic library) referencing all the source files.
10. Run java on the Java class file ( it will then load once, at run Time, the dynamic library created at the previous step and the F77 and sunmath libraries thanks to System.LoadLibrary Java API).


Those words are turned into a picture in the figure1 below.
 
 

Figure 1: Steps to integrate the C and Fortran Native codes

 
 

3. Java Native Interfacing


We used the JDK 1.0 approach (the native method support), as it was still supported by the Java version we used. Some may say that the JDK 1.0 solution has a major shortcoming [CIS 4]. It makes indeed assumptions about how the JVM laid out Java objects in memory. Since native code may directly reference fields in a Java Object, any change to this layout on the part of the JVM would require that native method libraries be recompiled. Further, different implementations of the JVM for a single platform could arrange objects in memory differently. However, this is not relevant for us, as in the proposed implementation the native code does not refer directly to the Java objects.

We will cover here the different Java Native interfacing steps, corresponding to those listed in section 1 and depicted in Figure 1.
 
 

3.1 Writing the Java code

Listing 1. The native method declaration class, FortranCall.java
Declaring a native method within a Java class is as simple as the use of the native attribute keyword. A class can signify that any methods will be implemented with native code simply by preceding the method name with the native keyword and not supplying the body of the method. So we defined a class named FortranCall referencing the five Fortran subroutines the java application needs to call. Here is the source code.
 
 
Class FortranCall
{
 public native int initgrid();
 public native void work(int id, int nstep);
 public native void borderInfo(int id, int neighbor);
 public native void shadowInfo(int id, int neighbor);
 public native int updateInfo();
  static
 {
  System.loadLibrary(“fortran”);
  System.loadLibrary(“F77”);
  System.loadLibrary(“sunmath”),
 }
}
Listing 1.

The reader may recognize in the last lines of code the general construct static, which is a static class initializer. Any code between the brackets is executed only once, when the class is first loaded onto the system [9]. This is taking advantage of the fact to run something we want to run only once –the loading of the native library and the SUN Fortran libraries F77 and sunmath. This ties together the loading of the class itself with the loading of its native method code. If either fails for some reason, the other fails as well, guaranteeing that no “half set up” version of the class can ever be created.

Note that in order for System.loadLibrary to find your native library, the directory in which the shared object library file resides must appear in the LD_LIBRARY_PATH environment variable.
 
 

3.2 Generating the Class file

Once classes are defined in Java source files, you obviously need to run javac to generate class files.
 

3.3 Generating Function Prototypes

Using javah as follows:
% javah FortranCall


It generates an header file that defines the functions prototypes. The C native code will refer to it
 
 

3.4 Building the C Stub File


You create this stub files running javah again with the –stubs option. The stub file created consists of  wrappers around invocations of native functions.
 
 

3.5 Writing the C Source File


While writing the C source file, we have to follow a mapping between C Function and Java Native method types:
 

A. Function specification and mapping:
 the C Function names are following the Java Native Interface convention and the header file prototype functions definitions. For instance:
 
 public native void borderInfo(int id, int neighbor)


 is translated into:
 

 void FortranCall_work(struct HFortranCall *this, long id, long neighbor)


 The function name is built as following, first the Java_Class_Name, then underscore, then the 
 Java_Native_method_Name. 

 B. Data type:
 JNI also defines the Java Native Types which should be used by all native code. JNI defines types which map to Java primitives types and reference types. javah generates a struct typedef for each Java class referenced by the native code. Under this scheme Java objects are treated as C structures, and Java primitive types mapped to C scalar types. We mapped the Java int into a long C, but it depends on the platform.
C. Argument handling:
 A macro is needed to change a C struct into something that looks and feels like an object. Referring back to the FortranCall_work, the macro will be applied to the argument of type HfortranCall (which is the struct typedef generates by javah), before using it as an object

 3.6 Building Native Libraries


 Usually compilation of the native code and building native libraries are done in a single command :
 

 %cc –I$JDK_HOME/include–I$JDK_HOME/include/solaris –G –o libNative.so nativeImpl.c nativeStubs.c


 The cc command, with –G option, will generate a Shared Object Library. The lib prefix and so suffix are added to satisfy both a Solaris convention and a Java requirement. The –I searches the directories specified in order to point to the right places for inclusion of native interface .h files.

 We use a different method: 
 1. First we compile the C native implementation file, the stub file and the Fortran source files. When compiling the C code, we still need to point to all the right places for inclusion of StubPreamble.h, which provides information the C language code requires to interact with the Java runtime system.
 2. Then we used the link editor ld with the –G option to produce a shared object, which we name according to Java and Solaris specification and according to the name we specified in System.loadLibrary() in the Java source file. 
 

%cc –c –I$JDK_HOME/include–I$JDK_HOME/include/solaris –G –o FortranCallImp.c 
%cc –c –I$JDK_HOME/include–I$JDK_HOME/include/solaris –G –o Fortran.c
%f77 –O –stackvar –c *.f
%ld –G –o libfortran.so *.o –lF77 -lsunmath


Doing so allows us to create and link the dynamic library (libfortran.so) and the Fortran libraries F77 and sunmath used to make the C to Fortran interfacing covered in the next section.
 
 
 

4. C to Fortran Interfacing


The ANSI standard definition of C provides a powerful argument checking facility that, given the correct definitions of function prototypes, can facilitate cross language communication between C and not only Java but also Fortran. We will explain in this section how Fortran routines are called from the C functions and procedures which, remind, are themselves called from Java. The convention we applied are particular to Sun and other similar systems (different conventions are used for VAX/VMS and a NAG C header file can be used for C compilers that do not support the ANSI Standard function prototypes [6])
 

4.1 Argument Types


There exists a mapping between relevant Fortran and C argument and function types. We use long in C to map the Fortran INTEGER type. This is the only type we use to pass parameters back and forth from C to Fortran. Note also that all arguments are passed as pointers to a variable.
 

4.2 Subroutines and Functions


Fortran routines are declared as void functions in C. Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner. Most Unix systems as the one we used, requires the addition of an underscore to the name of Fortran routines called from C. e.g. in the above Listing (Listing 2) do_work becomes do_work_. [WEB 6, 7, 8]
 
 

#include <StubPreamble>
#include “FortranCall.h”
#include <stdio.h>
extern void initialization_(long *);
extern void do_work_(long *, long *);
extern void get_border_(long *, long*);
extern void update_shadow_(long *, long *);
extern void pdf_output_(long *);
long FortranCall_initgrid(struct HFortranCall *this)
{
long numstep;
initialization_(&numstep);
return(numstep);
}
void FortranCall_work(struct HFortranCall *this,
   long id, long neighbor)
{
get_border_(&id,&neighbor);
return;
}
void FortranCall_borderInfo(struct HFortranCall *this,
    long id, long neighbor)
{
update_shadow_(&id,&neighbor);
return;
}
void FortranCall_shadowInfo(struct HFortranCall *this,
    long id, long neighbor)
{
update_shadow_(&id,&neighbor);
return;
}
long FortranCall_updateInfo(struct HFortranCall *this)
{
long iover;
pdf_output_(&iover);
return(iover);
}
Listing 2.

 
 
 
 

5. Fortran Compilation Allowing Multithreading


The Fortran compilers allocate by default local variable and arrays as STATIC (not on the stack). However, the -stackvar option allows us to force allocation of all local variables and arrays on the stack (as if they were AUTOMATIC variables).

Variables are then local, unless they are:

Arguments in a SUBROUTINE or FUNCTION statement (already on the stack)
Global items in a COMMON or SAVE, or STATIC statement
Items initialized in a type statement or DATA statement. Note that initializing a local variable in a DATA, statement after an executable reference to that variable is flagged as an error when -stackvar is used.


Each thread of the multithreaded program has its own thread stack. This stack mimics the main program stack but it is unique to the thread. The thread’s PRIVATE arrays and variables (local to the thread) are located on the thread stack. The default stack size in Fortran is about 256 kilobytes for each thread stack and about 8 Megabytes for the main stack.. Setting the thread stack size value larger than the default was necessary for most of the implementation test cases. However, it is not possible to know just how large to set it, except by trial and error, especially as large private/local arrays are often involved. If the stack size is too small for a thread to run, the program will abort by a segmentation fault and a very large core dump. Thus the user of the proposed implementation should know how to set the stacksize and how to limit the size of the core dumped. 

For example, the limit command with no parameters shows the current main stacksize:
 

%limit
cputime unlimited
filesize unlimited
datasize 523256 kbytes
coredumpsize unlimited
descriptor 64
memorysize unlimited


The following commands set the main stacksize unlimited, and set each thread stack size to 8 Megabytes:
 

%limit stacksize unlimited
%setenv STACKSIZE 8192
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

6. Summary


We have presented in this section the Java to Fortran (through C) interfacing. Listing 5.2-3 shows the script file we used to achieve the different compilations and interfacing presented in this section.
 

#!/bin/bash
javac SparseGrid.java
javah FortranCall
javah -stubs FortranCall
cc -c -I /apps2/JDK1.1.new/include -I /apps2/JDK1.1.new/include/solaris FortranCallImp.c
cc -c -I /apps2/JDK1.1.new/include -I /apps2/JDK1.1.new/include/solaris FortranCall.c
f77 -O -stackvar -c *.f
ld -G -o libfortran.so *.o -lF77 -lsunmath
Listing 3. The compilation script file

Note that we also used the Fortran compiler -c option to optimize the compilation
 

This technique has been successfully applied for my MS implementation. It is a significant achievement in the sense that it provides the developer with a means to exploit Java parallelism features (but also Java GUI features) while still using their long running and well-validated Fortran legacy code. However such interfacing is highly platform dependent and great attention has to be paid and sensible modification could be required if one intended to port this implementation onto another  platform.