- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have to port a windows fortran project to linux. The windows version uses CreateFileMapping,OpenFileMapping,MapViewOfFile and CopyMemory.
After some search I found, that linux has something similar with mmap and shm_open. Also I could use memcpy on both platforms.
My problem is that memcpy only works on windows and I always get undefined reference when I try to use shm_open for example. I guess I'm missing some compiler flags and/or using the wrong syntax for the external routines?
Here a little code example:
module test integer,parameter :: PROT_READ=1 integer,parameter :: PROT_WRITE=2 integer,parameter :: MAP_PRIVATE=2 integer,parameter :: MAP_SHARED=1 integer,parameter :: O_RDONLY=0 integer,parameter :: O_WRONLY=1 integer,parameter :: O_RDWR=2 integer,parameter :: O_ACCMODE=3 integer,parameter :: O_CREAT=512 integer,parameter :: O_EXCL=2048 integer,parameter :: O_TRUNC=1024 integer,parameter :: S_IRUSR=1024 integer,parameter :: S_IWUSR=512 integer,parameter :: S_IXUSR=256 integer,parameter :: S_IRGRP=64 integer,parameter :: S_IWGRP=32 integer,parameter :: S_IXGRP=16 integer,parameter :: S_IROTH=4 integer,parameter :: S_IWOTH=2 integer,parameter :: S_IXOTH=1 integer,parameter :: S_ISUID=16384 integer,parameter :: S_ISGID=8192 interface subroutine memcpy(dest, src, n) bind(C,name='memcpy') use iso_c_binding INTEGER(c_intptr_t), intent(in):: dest INTEGER(c_intptr_t), intent(in):: src integer(c_size_t), value :: n end subroutine memcpy end interface interface INTEGER(c_intptr_t) function mmap(addr,len,prot,flags,fildes,off) bind(c,name='mmap') use iso_c_binding integer(c_int), value :: addr integer(c_size_t), value :: len integer(c_int), value :: prot integer(c_int), value :: flags integer(c_int), value :: fildes integer(c_size_t), value :: off end function mmap end interface interface integer(c_int) function munmap(addr, len) bind(c,name='munmap') use iso_c_binding integer(c_int), value :: addr integer(c_size_t), value :: len end function munmap end interface interface integer(c_int) function shm_open(name,oflag,mode) \ bind(c,name='shm_open') use iso_c_binding character(kind=c_char) :: name(*) integer(c_int), value :: oflag integer(c_int16_t), value :: mode end function shm_open end interface interface integer(c_int) function shm_unlink(name) bind(c,name='shm_unlink') use iso_c_binding character(kind=c_char) :: name(*) end function shm_unlink end interface end module program FortranTest use iso_c_binding use test implicit none real*8, allocatable, dimension(:) :: testarr, testarr2 integer :: i, oflag, sflag oflag = ior(O_RDWR, O_CREAT) sflag = ior(S_IWUSR, S_IRUSR) i = shm_open('/home/lbb/FEAP/test/test123.blub', oflag, sflag) allocate(testarr(10)) allocate(testarr2(10)) do i=1,10 testarr(i) = 1 testarr2(i) = 2 end do print *, 'testarr' do i=1,10 print *, testarr(i) end do print *, 'testarr2' do i=1,10 print *, testarr2(i) end do print *, 'call memcpy' call memcpy(loc(testarr(1)), loc(testarr2(1)), 16) print *, 'testarr' do i=1,10 print *, testarr(i) end do read (*,*) end program FortranTest
The makefile looks like this:
# fortran compiler = intel fortran fcomp = ifort switch = -module obj -w -f77rtl -fpp -qopenmp -parallel -intconstant -zero -assume:byterecl -check:pointers -check:bounds -check:uninit baseList = test2.for baseObj = $(baseList:.for=.o) all: base test base: $(baseObj) %.o: %.for $(fcomp) $(switch) -c $< -o obj/$(notdir $@) test: base $(fcomp) $(switch) obj/*.o -o obj/test2 -mkl -shared-libgcc -threads -cxxlib clean: @echo "target clean: delete obj/*" rm -f obj/*
If I run this example (without shm_open) on windows I get the expected result:
testarr 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 testarr2 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 call memcpy testarr 2.00000000000000 2.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000
On linux I get :
lbb@dev-01:~/FEAP/test$ obj/test2 testarr 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 testarr2 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 call memcpy testarr 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000 1.00000000000000
So memcpy isn't working as expected (maybe the c function isn't called at all?)
So any hints for me?
Kind regards,
Stephan
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You need VALUE on the dest and src arguments in the interface to memcpy.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Steve.
In my last attempt I had "INTEGER(c_intptr_t), intent(in), value:: dest"
This worked on windows. After removing the "intent(in)" it works on both. Adding '-lrt' fixes the undefined reference error. I can now create a file with the correct size in /dev/shm. But it always contains zero. I guess I didn't understand how the different pointer types in fortran/c work. Any hints?
My current example:
module test ! O_CREAT | O_RDWR integer, parameter :: ocreate = 66 ! O_RDONLY integer, parameter :: oread = 0 ! PROT_READ | PROT_WRITE integer, parameter :: preadwrite = 6 ! MAP_SHARED integer, parameter :: mshare = 8 ! file permissions 0666 integer, parameter :: fperm = 438 interface subroutine memcpy(dest, src, n) bind(C,name='memcpy') use iso_c_binding INTEGER(c_intptr_t), value:: dest INTEGER(c_intptr_t), value:: src integer(c_size_t), value :: n end subroutine memcpy end interface interface INTEGER(c_intptr_t) function mmap(addr,len,prot, \ flags,fildes,off) bind(c,name='mmap') use iso_c_binding integer(c_int), value :: addr integer(c_size_t), value :: len integer(c_int), value :: prot integer(c_int), value :: flags integer(c_int), value :: fildes integer(c_size_t), value :: off end function mmap end interface interface integer(c_int) function munmap(addr, len) \ bind(c,name='munmap') use iso_c_binding integer(c_int), value :: addr integer(c_size_t), value :: len end function munmap end interface interface integer(c_int) function ftruncate(fd, len) \ bind(c,name='ftruncate') use iso_c_binding integer(c_int), value :: fd integer(c_size_t), value :: len end function ftruncate end interface interface integer(c_int) function close(fd) \ bind(c,name='close') use iso_c_binding integer(c_int), value :: fd end function close end interface interface integer(c_int) function shm_open(name,oflag,mode) \ bind(c,name='shm_open') use iso_c_binding character(kind=c_char) :: name(*) integer(c_int), value :: oflag integer(c_int16_t), value :: mode end function shm_open end interface interface integer(c_int) function shm_unlink(name) \ bind(c,name='shm_unlink') use iso_c_binding character(kind=c_char) :: name(*) end function shm_unlink end interface end module program FortranTest use iso_c_binding use test implicit none real*8, allocatable, dimension(:) :: testarr INTEGER(c_intptr_t) :: adr integer :: i, fd allocate(testarr(10)) do i=1,10 testarr(i) = i end do fd = shm_open('test123', ocreate, fperm) if(fd == -1) stop 'shm_open error' i = ftruncate(fd, 80) if(i == -1) stop 'ftruncate error' adr = mmap(0, 80, preadwrite, mshare, fd, 0) print *, 'call first memcpy' call memcpy(loc(adr), loc(testarr), 80) i = munmap(adr, 80) if(i == -1) stop 'munmap error' i = close(fd) if(i == -1) stop 'close error' ! i = shm_unlink('test123') ! if(i == -1) stop 'shm_unlink error' end program FortranTest
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can make only a general comment here. You declare the dest and src arguments to memcpy as address-sized integers, not pointers in the Fortran sense. memcpy wants to see the address of the dest and src by value in the argument list, so that's why you need VALUE as otherwise Fortran would pass the integer (that contains an address) itself by reference (address of an address). INTENT would have absolutely no effect on how it was passed.
I suggest stepping through the code in the debugger and make sure that all the arguments have the correct values as you go. However, I do see something that raises a red flag - you declare the "addr" argument to mmap and munmap as integer(c_int). This is absolutely wrong - use integer(c_intptr_t) instead. On Linux you are almost certainly on a 64-bit system and using an int for the address will result in errors.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you. I got it now. For anyone who might need the same here the working code:
module test ! O_CREAT | O_RDWR integer, parameter :: ocreate = 66 ! O_RDONLY integer, parameter :: oread = 0 ! PROT_READ | PROT_WRITE integer, parameter :: preadwrite = 3 ! PROT_READ integer, parameter :: pread = 1 ! MAP_SHARED integer, parameter :: mshare = 1 ! S_IRUSR | S_IWUSR integer, parameter :: fperm = 384 interface subroutine memcpy(dest, src, n) bind(C,name='memcpy') use iso_c_binding INTEGER(c_intptr_t), value:: dest INTEGER(c_intptr_t), value:: src integer(c_size_t), value :: n end subroutine memcpy end interface interface INTEGER(c_intptr_t) function mmap(addr,len,prot, \ flags,fildes,off) result(result) bind(c,name='mmap') use iso_c_binding INTEGER(c_intptr_t), value :: addr integer(c_size_t), value :: len integer(c_int), value :: prot integer(c_int), value :: flags integer(c_int), value :: fildes integer(c_size_t), value :: off end function mmap end interface interface integer(c_int) function munmap(addr, len) \ bind(c,name='munmap') use iso_c_binding INTEGER(c_intptr_t), value :: addr integer(c_size_t), value :: len end function munmap end interface interface integer(c_int) function ftruncate(fd, len) \ bind(c,name='ftruncate') use iso_c_binding integer(c_int), value :: fd integer(c_size_t), value :: len end function ftruncate end interface interface integer(c_int) function close(fd) \ bind(c,name='close') use iso_c_binding integer(c_int), value :: fd end function close end interface interface integer(c_int) function shm_open(name,oflag,mode) \ bind(c,name='shm_open') use iso_c_binding character(kind=c_char) :: name(*) integer(c_int), value :: oflag integer(c_int16_t), value :: mode end function shm_open end interface interface integer(c_int) function shm_unlink(name) \ bind(c,name='shm_unlink') use iso_c_binding character(kind=c_char) :: name(*) end function shm_unlink end interface end module program FortranTest use iso_c_binding use test use ifport implicit none real*8, allocatable, dimension(:) :: testarr, testarr2 INTEGER(c_intptr_t) :: adr integer :: i, fd, err allocate(testarr(10)) allocate(testarr2(10)) do i=1,10 testarr(i) = i end do fd = shm_open('test123', ocreate, fperm) if(fd == -1) stop 'shm_open error' i = ftruncate(fd, 80) if(i == -1) then err = GetLastError() print *, err stop 'ftruncate error' end if adr = mmap(loc(0), 80, preadwrite, mshare, fd, 0) if(adr == -1) then err = GetLastError() print *, err stop 'mmap error' endif print *,'adress:',loc(adr) print *,'adress:',adr print *, 'call first memcpy' call memcpy(adr, loc(testarr), 80) i = munmap(adr, 80) if(i == -1) stop 'munmap error' i = close(fd) if(i == -1) stop 'close error' fd = shm_open('test123', oread, fperm) if(fd == -1) stop 'shm_open error' adr = mmap(loc(0), 80, pread, mshare, fd, 0) if(adr == -1) then err = GetLastError() print *, err stop 'mmap error' endif print *, 'call second memcpy' call memcpy(loc(testarr2), adr, 80) i = munmap(adr, 80) if(i == -1) stop 'munmap error' i = close(fd) if(i == -1) stop 'close error' i = shm_unlink('test123') if(i == -1) stop 'shm_unlink error' do i=1,10 print *, testarr2(i) end do end program FortranTest
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page