e4466b00fc
This will cause XDS to segfault on exit, since the plugin (and hence HDF5 library) will likely have been unloaded. Calling "H5dont_atexit" before any other H5 calls will prevent the hook being installed, and we call "H5Close" ourselves as part of the plugin_close function.
454 lines
19 KiB
Fortran
454 lines
19 KiB
Fortran
!
|
|
! This is free and unencumbered software released into the public domain.!
|
|
! Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software,
|
|
! either in source code form or as a compiled binary, for any purpose, commercial or non-commercial,
|
|
! and by any means.
|
|
!
|
|
! In jurisdictions that recognize copyright laws, the author or authors of this software dedicate
|
|
! any and all copyright interest in the software to the public domain. We make this dedication for
|
|
! the benefit of the public at large and to the detriment of our heirs and successors. We intend
|
|
! this dedication to be an overt act of relinquishment in perpetuity of all present and future
|
|
! rights to this software under copyright law.
|
|
!
|
|
! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
! NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
! IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
! ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
! THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
!
|
|
! For more information, please refer to <http://unlicense.org/>
|
|
!
|
|
!
|
|
! vittorio.boccone@dectris.com
|
|
! Dectris Ltd., Taefernweg 1, 5405 Baden-Daettwil, Switzerland.
|
|
!
|
|
! (proof_of_concept)
|
|
!
|
|
! Interoperability with C in Fortran 2003
|
|
!
|
|
! Wrap up module to abstract the interface from
|
|
! http://cims.nyu.edu/~donev/Fortran/DLL/DLL.Forum.txt
|
|
!
|
|
module iso_c_utilities
|
|
use iso_c_binding ! intrinsic module
|
|
|
|
character(c_char), dimension(1), save, target, private :: dummy_string="?"
|
|
|
|
contains
|
|
|
|
function c_f_string(cptr) result(fptr)
|
|
! convert a null-terminated c string into a fortran character array pointer
|
|
type(c_ptr), intent(in) :: cptr ! the c address
|
|
character(kind=c_char), dimension(:), pointer :: fptr
|
|
|
|
interface ! strlen is a standard C function from <string.h>
|
|
function strlen(string) result(len) bind(C,name="strlen")
|
|
use iso_c_binding
|
|
type(c_ptr), value :: string ! a C pointer
|
|
end function
|
|
end interface
|
|
|
|
if(c_associated(cptr)) then
|
|
call c_f_pointer(fptr=fptr, cptr=cptr, shape=[strlen(cptr)])
|
|
else
|
|
! to avoid segfaults, associate fptr with a dummy target:
|
|
fptr=>dummy_string
|
|
end if
|
|
|
|
end function
|
|
|
|
end module iso_c_utilities
|
|
|
|
!
|
|
! Interoperability with C in Fortran 2003
|
|
!
|
|
! Wrap up module to abstract the interface from
|
|
! http://cims.nyu.edu/~donev/Fortran/DLL/DLL.Forum.txt
|
|
!
|
|
module dlfcn
|
|
use iso_c_binding
|
|
use iso_c_utilities
|
|
implicit none
|
|
private
|
|
|
|
public :: dlopen, dlsym, dlclose, dlerror ! dl api
|
|
|
|
! valid modes for mode in dlopen:
|
|
integer(c_int), parameter, public :: rtld_lazy=1, rtld_now=2, rtld_global=256, rtld_local=0
|
|
! obtained from the output of the previously listed c program
|
|
|
|
interface ! all we need is interfaces for the prototypes in <dlfcn.h>
|
|
function dlopen(file,mode) result(handle) bind(C,name="dlopen")
|
|
! void *dlopen(const char *file, int mode);
|
|
use iso_c_binding
|
|
character(c_char), dimension(*), intent(in) :: file
|
|
! c strings should be declared as character arrays
|
|
integer(c_int), value :: mode
|
|
type(c_ptr) :: handle
|
|
end function
|
|
function dlsym(handle,name) result(funptr) bind(C,name="dlsym")
|
|
! void *dlsym(void *handle, const char *name);
|
|
use iso_c_binding
|
|
type(c_ptr), value :: handle
|
|
character(c_char), dimension(*), intent(in) :: name
|
|
type(c_funptr) :: funptr ! a function pointer
|
|
end function
|
|
function dlclose(handle) result(status) bind(C,name="dlclose")
|
|
! int dlclose(void *handle);
|
|
use iso_c_binding
|
|
type(c_ptr), value :: handle
|
|
integer(c_int) :: status
|
|
end function
|
|
function dlerror() result(error) bind(C,name="dlerror")
|
|
! char *dlerror(void);
|
|
use iso_c_binding
|
|
type(c_ptr) :: error
|
|
end function
|
|
end interface
|
|
|
|
end module dlfcn
|
|
|
|
!
|
|
! Generic handle for share-object like structures
|
|
!
|
|
! Wrap up module to abstract the interface from
|
|
! http://cims.nyu.edu/~donev/Fortran/DLL/DLL.Forum.txt
|
|
!
|
|
module generic_data_plugin
|
|
use iso_c_binding
|
|
implicit none
|
|
|
|
character(kind=c_char,len=1024) :: dll_filename
|
|
character(kind=c_char,len=1024) :: image_data_filename
|
|
integer(c_int) :: status
|
|
type(c_ptr) :: handle=c_null_ptr
|
|
INTEGER :: nx,ny,firstqm=0,lastqm=0 ! global variables that do not change
|
|
! firstqm, lastq mark ? characters in NAME_TEMPLATE that get replaced by an image number
|
|
CHARACTER(len=:), allocatable :: library ! global variable that does not change
|
|
LOGICAL :: is_open=.FALSE. ! set .TRUE. if library successfully opened
|
|
|
|
!public :: generic_open !, generic_header, generic_data, generic_clone
|
|
|
|
!
|
|
! Abstract interfaces for C mapped functions
|
|
!
|
|
!
|
|
! get_header -> dll_get_header
|
|
abstract interface
|
|
|
|
subroutine plugin_open(filename, info_array, error_flag) bind(C)
|
|
use iso_c_binding
|
|
integer(c_int) :: error_flag
|
|
character(kind=c_char) :: filename(*)
|
|
integer(c_int), dimension(1024) :: info_array
|
|
|
|
|
|
end subroutine plugin_open
|
|
|
|
subroutine plugin_close(error_flag) bind(C)
|
|
use iso_c_binding
|
|
integer (c_int) :: error_flag
|
|
|
|
end subroutine plugin_close
|
|
|
|
subroutine plugin_get_header(nx, ny, nbyte, qx, qy, number_of_frames, info_array, error_flag) bind(C)
|
|
use iso_c_binding
|
|
integer(c_int) :: nx, ny, nbyte, number_of_frames
|
|
real(c_float) :: qx, qy
|
|
integer(c_int) :: error_flag
|
|
integer(c_int), dimension(1024) :: info_array
|
|
end subroutine plugin_get_header
|
|
|
|
subroutine plugin_get_data(frame_number, nx, ny, data_array, info_array, error_flag) bind(C)
|
|
use iso_c_binding
|
|
integer(c_int) :: nx, ny, frame_number
|
|
integer(c_int) :: error_flag
|
|
integer(c_int), dimension(nx:ny) :: data_array
|
|
integer(c_int), dimension(1024) :: info_array
|
|
end subroutine plugin_get_data
|
|
end interface
|
|
|
|
! dynamically-linked procedures
|
|
procedure(plugin_open), pointer :: dll_plugin_open
|
|
procedure(plugin_get_header), pointer :: dll_plugin_get_header
|
|
procedure(plugin_get_data), pointer :: dll_plugin_get_data
|
|
procedure(plugin_close), pointer :: dll_plugin_close
|
|
|
|
|
|
|
|
|
|
contains
|
|
|
|
|
|
!
|
|
! Open the shared-object
|
|
subroutine generic_open(library, template_name, info_array, error_flag) ! Requirements:
|
|
! 'LIBRARY' input (including path, otherwise using LD_LIBRARY_PATH)
|
|
! 'TEMPLATE_NAME' input (the resource in image data masterfile)
|
|
! 'INFO' (integer array) input Array of (1024) integers:
|
|
! INFO(1) = Consumer ID (1:XDS)
|
|
! INFO(2) = Version Number of the Consumer software
|
|
! INFO(3:8) = Unused
|
|
! INFO(9:40) = 1024bit signature of the consumer software
|
|
! INFO(>41) = Unused
|
|
! 'INFO' (integer array) output Array of (1024) integers:
|
|
! INFO(1) = Vendor ID (1:Dectris)
|
|
! INFO(2) = Major Version number of the library
|
|
! INFO(3) = Minor Version number of the library
|
|
! INFO(4) = Parch Version number of the library
|
|
! INFO(5) = Linux timestamp of library creation
|
|
! INFO(6:8) = Unused
|
|
! INFO(9:40) = 1024bit signature of the library
|
|
! INFO(>41) = Unused
|
|
! 'ERROR_FLAG' output Return values
|
|
! 0 Success
|
|
! -1 Handle already exists
|
|
! -2 Cannot open Library
|
|
! -3 Function not found in library
|
|
! -4 Master file cannot be opened (coming from C function)
|
|
! -10 Consumer identity not supported (coming from C function)
|
|
! -11 Consumer identity could not be verified (coming from C function)
|
|
! -12 Consumer software version not supported (coming from C function)
|
|
|
|
use iso_c_binding
|
|
use iso_c_utilities
|
|
use dlfcn
|
|
implicit none
|
|
|
|
character(len=:), allocatable :: library, template_name
|
|
integer(c_int) :: error_flag
|
|
integer(c_int), dimension(1024) :: info_array
|
|
type(c_funptr) :: fun_plugin_open_ptr = c_null_funptr
|
|
type(c_funptr) :: fun_plugin_close_ptr = c_null_funptr
|
|
type(c_funptr) :: fun_plugin_get_header_ptr = c_null_funptr
|
|
type(c_funptr) :: fun_plugin_get_data_ptr = c_null_funptr
|
|
integer(c_int) :: external_error_flag
|
|
logical :: loading_error_flag = .false.
|
|
|
|
error_flag=0
|
|
|
|
write(6,*) "[generic_data_plugin] - INFO - generic_open"
|
|
write(6,*) " + library = <", library, ">"
|
|
write(6,*) " + template_name = <", template_name, ">"
|
|
|
|
if ( c_associated(handle) ) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - 'handle' not null"
|
|
error_flag = -1
|
|
return
|
|
endif
|
|
|
|
dll_filename=library
|
|
error_flag = 0
|
|
write(6,*) " + dll_filename = <", trim(dll_filename)//C_NULL_CHAR, ">"
|
|
|
|
image_data_filename=trim(template_name)//C_NULL_CHAR
|
|
error_flag = 0
|
|
write(6,*) " + image_data_filename = <", trim(image_data_filename)//C_NULL_CHAR, ">"
|
|
|
|
!
|
|
! Open the DL:
|
|
! The use of IOR is not really proper...wait till Fortran 2008
|
|
handle=dlopen(trim(dll_filename)//C_NULL_CHAR, IOR(RTLD_NOW, RTLD_GLOBAL))
|
|
|
|
!
|
|
! Check if can use handle
|
|
if(.not.c_associated(handle)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - Cannot open Handle: ", c_f_string(dlerror())
|
|
error_flag = -2
|
|
return
|
|
end if
|
|
|
|
|
|
!
|
|
! Find the subroutines in the DL:
|
|
fun_plugin_get_data_ptr = DLSym(handle,"plugin_get_data")
|
|
if(.not.c_associated(fun_plugin_get_data_ptr)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR in DLSym(handle,'plugin_get_data'): ", c_f_string(dlerror())
|
|
loading_error_flag = .true.
|
|
else
|
|
call c_f_procpointer(cptr=fun_plugin_get_data_ptr, fptr=dll_plugin_get_data)
|
|
endif
|
|
!
|
|
fun_plugin_get_header_ptr = DLSym(handle,"plugin_get_header")
|
|
if(.not.c_associated(fun_plugin_get_header_ptr)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR in DLSym(handle,'plugin_get_header'): ",c_f_string(dlerror())
|
|
loading_error_flag = .true.
|
|
else
|
|
call c_f_procpointer(cptr=fun_plugin_get_header_ptr, fptr=dll_plugin_get_header)
|
|
endif
|
|
!
|
|
fun_plugin_open_ptr = DLSym(handle,"plugin_open")
|
|
if(.not.c_associated(fun_plugin_open_ptr)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR in DLSym(handle,'plugin_open'): ", c_f_string(dlerror())
|
|
loading_error_flag = .true.
|
|
else
|
|
call c_f_procpointer(cptr=fun_plugin_open_ptr, fptr=dll_plugin_open)
|
|
endif
|
|
|
|
fun_plugin_close_ptr = DLSym(handle,"plugin_close")
|
|
if(.not.c_associated(fun_plugin_close_ptr)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR in DLSym(handle,'plugin_close'): ", c_f_string(dlerror())
|
|
loading_error_flag = .true.
|
|
else
|
|
call c_f_procpointer(cptr=fun_plugin_close_ptr, fptr=dll_plugin_close)
|
|
endif
|
|
|
|
|
|
if (loading_error_flag) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - Cannot map function(s) from the dll"
|
|
error_flag = -3
|
|
else
|
|
call dll_plugin_open(image_data_filename, info_array, external_error_flag)
|
|
error_flag = external_error_flag
|
|
endif
|
|
IF (error_flag == 0) is_open=.TRUE.
|
|
return
|
|
|
|
end subroutine generic_open
|
|
|
|
!
|
|
! Get the header
|
|
subroutine generic_get_header(nx, ny, nbyte, qx, qy, number_of_frames, info_array, error_flag)
|
|
! Requirements:
|
|
! 'NX' (integer) output Number of pixels along X
|
|
! 'NY' (integer) output Number of pixels along Y
|
|
! 'NBYTE' (integer) output Number of bytes in the image... X*Y*DEPTH
|
|
! 'QX' (4*REAL) output Pixel size
|
|
! 'QY' (4*REAL) output Pixel size
|
|
! 'NUMBER_OF_FRAMES' (integer) output Number of frames for the full datase. So far unused
|
|
! 'INFO' (integer array) input Array of (1024) integers:
|
|
! INFO(>1) = Unused
|
|
! 'INFO' (integer array) output Array of (1024) integers:
|
|
! INFO(1) = Vendor ID (1:Dectris)
|
|
! INFO(2) = Major Version number of the library
|
|
! INFO(3) = Minor Version number of the library
|
|
! INFO(4) = Patch Version number of the library
|
|
! INFO(5) = Linux timestamp of library creation
|
|
! INFO(6:64) = Reserved
|
|
! INFO(65:1024) = Dataset parameters
|
|
! 'ERROR_FLAG' output Return values
|
|
! 0 Success
|
|
! -1 Cannot open library
|
|
! -2 Cannot read header (will come from C function)
|
|
! -4 Cannot read dataset informations (will come from C function)
|
|
! -10 Error in the determination of the Dataset parameters (will come from C function)
|
|
!
|
|
use iso_c_binding
|
|
use iso_c_utilities
|
|
use dlfcn
|
|
implicit none
|
|
|
|
integer(c_int) :: nx, ny, nbyte, number_of_frames
|
|
real(c_float) :: qx, qy
|
|
integer(c_int) :: error_flag
|
|
integer(c_int) :: external_error_flag
|
|
integer(c_int), dimension(1024) :: info_array
|
|
error_flag=0
|
|
|
|
write(6,*) "[generic_data_plugin] - INFO - generic_get_header"
|
|
|
|
! Check if can use handle
|
|
if(.not.c_associated(handle)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - Cannot open Handle"
|
|
write(6,*) " ", c_f_string(dlerror())
|
|
error_flag = -1
|
|
return
|
|
end if
|
|
|
|
! finally, invoke the dynamically-linked subroutine:
|
|
call dll_plugin_get_header(nx, ny, nbyte, qx, qy, number_of_frames, info_array, external_error_flag)
|
|
return
|
|
end subroutine generic_get_header
|
|
|
|
|
|
!
|
|
! Dynamically map function and execute it
|
|
subroutine generic_get_data(frame_number, nx, ny, data_array, info_array, error_flag)
|
|
! Requirements:
|
|
! 'FRAME_NUMBER' (integer) input Number of frames for the full datase. So far unused
|
|
! 'NX' (integer) input Number of pixels along X
|
|
! 'NY' (integer) input Number of pixels along Y
|
|
! 'DATA_ARRAY' (integer array) output 1D array containing pixel data with lenght = NX*NY
|
|
! 'INFO' (integer array) output Array of (1024) integers:
|
|
! INFO(1) = Vendor ID (1:Dectris)
|
|
! INFO(2) = Major Version number of the library
|
|
! INFO(3) = Minor Version number of the library
|
|
! INFO(4) = Parch Version number of the library
|
|
! INFO(5) = Linux timestamp of library creation
|
|
! INFO(6:8) = Unused
|
|
! INFO(9:40) = 1024bit verification key
|
|
! INFO(41:44) = Image MD5 Checksum
|
|
! INFO() = Unused
|
|
! 'ERROR_FLAG' (integer) output Provides error state condition
|
|
! 0 Success
|
|
! -1 Cannot open library
|
|
! -2 Cannot open frame (will come from C function)
|
|
! -3 Datatype not supported (will come from C function)
|
|
! -4 Cannot read dataset informations (will come from C function)
|
|
! -10 MD5 Checksum Error
|
|
! -11 Verification key error
|
|
!
|
|
use iso_c_binding
|
|
use iso_c_utilities
|
|
use dlfcn
|
|
implicit none
|
|
|
|
integer(c_int) :: nx, ny, frame_number
|
|
integer(c_int) :: error_flag
|
|
integer(c_int), dimension(1024) :: info_array
|
|
integer(c_int), dimension (nx*ny) :: data_array
|
|
|
|
|
|
error_flag=0
|
|
call dll_plugin_get_data(frame_number, nx, ny, data_array, info_array, error_flag)
|
|
|
|
end subroutine generic_get_data
|
|
|
|
! Close the shared-object
|
|
!
|
|
subroutine generic_close(error_flag)
|
|
! Requirements:
|
|
! 'ERROR_FLAG' (integer) output Return values:
|
|
! 0 Success
|
|
! -1 Error closing Masterfile
|
|
! -2 Error closing Shared-object
|
|
|
|
use iso_c_binding
|
|
use iso_c_utilities
|
|
use dlfcn
|
|
implicit none
|
|
|
|
integer(c_int) :: error_flag
|
|
integer(c_int) :: external_error_flag
|
|
|
|
IF (.NOT.is_open) RETURN
|
|
! Check if can use handle
|
|
if(.not.c_associated(handle)) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - Cannot open Handle"
|
|
write(6,*) " ", c_f_string(dlerror())
|
|
error_flag = -1
|
|
return
|
|
end if
|
|
|
|
write(6,*) "[generic_data_plugin] - INFO - 'call generic_close()'"
|
|
external_error_flag=0
|
|
call dll_plugin_close(external_error_flag)
|
|
error_flag = external_error_flag
|
|
|
|
write(6,*) "[generic_data_plugin] - INFO - 'plugin close flag:", error_flag, "'"
|
|
|
|
! now close the dl:
|
|
status=dlclose(handle)
|
|
if(status/=0) then
|
|
write(6,*) "[generic_data_plugin] - ERROR - Cannot open Handle"
|
|
write(6,*) " ", c_f_string(dlerror())
|
|
error_flag = -2
|
|
else
|
|
error_flag = 0
|
|
end if
|
|
|
|
return
|
|
end subroutine generic_close
|
|
|
|
end module generic_data_plugin
|