When do Fortran redistributables go out of scope when loaded as a shared library?
I am calling a fortran routine from R as part of a more complex optimization task. At present, the subroutine is autonomous - with the input of the current values โโof the parameters and the output of the evaluation functions and gradient terms. Now I want to initialize the allocated array as a shared module variable (before optimization) to be used (but not changed) by the subroutine during optimization.
In this context, when is a shared distributed array going out of scope or removed?
A naive reading of the memory management section in the Fortran wikibook suggests that module variables should be persisted (possibly even after the program has been executed).
Number of sources I read that the array being allocated will be automatically deallocated when it goes out of scope. This also happens for module variables, and when will it happen?
I found the number questions , but I was unable to place them in the context of both module variables and shared library loading.
Edit:
A minimal example of a fortran module. The selected array works as expected in the fortran program. In practice, both init()
and eval()
will be wrapped with R functions ( init_wrap()
and eval_wrap()
) and called from R. I want to confirm that the allocated variable is y
guaranteed not to be out of scope or deleted, but is test_module
loaded as a shared library.
module test_module
double precision, allocatable, dimension(:,:) :: y
contains
subroutine init() bind(C, name = "init_")
if (.not. allocated(y) ) then
allocate(y(1,1))
end if
y = 1
end subroutine init
subroutine eval(x, z) bind(C, name = "eval_")
double precision, intent(in) :: x
double precision, intent(out) :: z
z = x + y(1,1)
end subroutine eval
end module test_module
! Program added for testing purposes only,
! module is used as shared library
program test_program
use test_module
double precision :: x, z
! Initialize allocatable array
call init()
! Use allocatable array during optimization
x = 1
call eval(x, z)
x = 2
call eval(x, z)
print *, z
end program test_program
Edit 2:
I created a skeleton package on github that simulates how I use the fortran code: https://github.com/ssokolen/fortran.test
The following R code works as I need it to (the allocated array retains its value between calls eval_wrap()
), but I'm still hoping to get a definitive answer when the allocated module variable goes out of scope when loaded as a shared library (or the answer that says that there is no common behavior).
library(devtools)
install_github('ssokolen/fortran.test')
library(fortran.test)
init_wrap()
eval_wrap(1)
eval_wrap(2)
source to share
Dynamically loaded libraries are outside the Fortran standard. Which comes from the whole "processor", which is a complex of the Fortran compiler, operating system, linker, etc.
On Linux and other POSIX operating systems, if you unload a library from memory, it will go out of scope. This simple test case demonstrates that:
module test_module
double precision, allocatable, dimension(:,:) :: y
contains
subroutine init() bind(C, name = "init_")
print *, "init_"
if (.not. allocated(y) ) then
allocate(y(1,1))
end if
y = 1
end subroutine init
subroutine eval(x, z) bind(C, name = "eval_")
double precision, intent(in) :: x
double precision, intent(out) :: z
if (.not. allocated(y) ) error stop("not allocated!")
z = x + y(1,1)
print*, "success"
end subroutine eval
end module test_module
And C calls the library:
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
int main(){
void *handle = dlopen("/home/lada/f/testy/stackoverflow/dltest.so",RTLD_NOW);
void (*init_)() = (void (*)())dlsym(handle, "init_");
init_();
double x=0,y=0;
void (*eval_)(double x, double z) = (void (*)())dlsym(handle, "eval_");
eval_(x, y);
dlclose(handle);
handle = dlopen("./dltest.so",RTLD_NOW);
eval_ = (void (*)())dlsym(handle, "eval_");
eval_(x, y);
return 0;
}
And run:
> gfortran -shared -fPIC -o dltest.so dltest.f90
> gcc -ggdb dltest.c -ldl
> ./a.out
init_
success
ERROR STOP not allocated!
The array is no longer allocated after dlclose()
and dlopen()
. You must make sure that R does not unload the library from memory.
source to share