fortran66のブログ

fortran について書きます。

【メモ帳】ZMQ binding

ZMQ 4.3.1

以前 ZMQ の f77 binding を利用して、Fortran で HTML サーバー文字表示を試してみました。

fortran66.hatenablog.com

よくよく f77 ZMQ 文書を見てみると、自由書式用の include ファイルもあったようです。

interoperability with C

ここでは、Fortran2003 以降で強化されつつある、C 言語との相互運用について勉強するために、C で書かれた ZMQ ルーチンに、出来るだけインターフェースだけを使って、呼び出してみることを試してみました。

まだ数個のルーチンしかインターフェースを書いていませんが、早くも Fortran では無理っぽいルーチンがありました。

zmq_msg_init_data

ZMQ の初期化関数で、動的メモリー解放用ルーチンの関数ポインタを渡して、ZMQ のライブラリ内で Fortran で確保したメモリーを解放させるものです。うまくいきません。

関数ポインタを呼び出させて配列の内容を変えることは出来ましたが、解放は実行時のエラーになりました。ただ Fortran2018 での CFI 関数を使えば可能な気もします。

zmq_msg_init_data(3) - 0MQ Api

ZMQ インストールメモ

wget https://github.com/zeromq/libzmq/releases/download/v4.3.1/zeromq-4.3.1.tar.gz
tar zxvf zeromq-4.3.1.tar.gz
cd zeromq-4.3.1/
./configure
make -j 8
sudo make install

静的 Fortran HTTP サーバー

とりあえず、以前に書いた HTTP サーバーを試せるところまで interface を書いて見ました。型がうるさくて混乱します。

メモ帳として書いておきます。

f:id:fortran66:20190609211513p:plain
ZMQ

コンソール出力

hp8@HP8:~/f08_zmq$ ./a.out
 context                    0
 socketSuccess
 socket      139763505916576
 text:tcp://*:8080
 bind           0
 zmq_recv           5
 zmq_recv           5
 zmq_recv           5
 zmq_recv           5
 zmq_recv           5
^C
hp8@HP8:~/f08_zmq$

github.com

メイン・ルーチン

module m_test
    implicit none
    character(len = *), parameter :: CRLF = achar(13) // achar(10)
    character(len = *), parameter :: http_response_p =          &
          'HTTP/1.0 200 OK'                        // CRLF // &
          'Content-Type: text/html'                // CRLF // &
                                                      CRLF // &
          '<!DOCTYPE html>'                        // CRLF // &
          '<html>'                                 // CRLF // &
          '<head>'                                 // CRLF // &
          '<title>Fortran ZMQ http server</title>' // CRLF // &
          '</head>'                                // CRLF // &
          '<body>'                                 // CRLF // &
          '<h1>Fortran ZMQ http server </h1>'      // CRLF // &
          '<p>Reiwa 1-6-9 (2019.6.9)   </p>'       // CRLF // &
          '</body>'                                // CRLF // &
          '</html>'                                // achar(0)
end module m_test

program test
    use, intrinsic :: iso_c_binding
    use f08_zmq
    use m_test
    implicit none
    integer(c_int) :: ierr, id_size, iraw_size
    type(c_ptr) :: ctx, socket
    integer(8), pointer :: iadd1, iadd2
    integer(8), pointer :: inull => null()
    character(:), allocatable, target :: text, id, raw, http_response
    ctx = zmq_ctx_new()
    call c_f_pointer(ctx, iadd1)
    print *, 'context', iadd1

    socket = zmq_socket(ctx, ZMQ_STREAM)
    print *, 'socket', zmq_strerror(zmq_errno())
    call c_f_pointer(socket, iadd2)
    print *, 'socket', iadd2

    text = 'tcp://*:8080'//achar(0)
    print *, 'text:', text
    ierr = zmq_bind(socket, c_loc(text))
    print *, 'bind', ierr
    if (ierr /= 0) stop 'error'

    allocate(character(len = 256)::id, raw)
    http_response = http_response_p

    do
        id_size = zmq_recv(socket, c_loc(id), 256_c_size_t, 0)
        print *, 'zmq_recv', id_size
        if (id_size <= 0) stop 'id_size error!'
        do
            iraw_size = zmq_recv(socket, c_loc(raw), 256_c_size_t, 0)
            if (iraw_size < 0) stop 'raw_size error!'
            if (iraw_size == 256) cycle
            exit
        end do
        ierr = zmq_send(socket, c_loc(id), int(id_size, c_size_t), ZMQ_SNDMORE)
        ierr = zmq_send(socket, c_loc(http_response), int(len(http_response), c_size_t), 0)
        ierr = zmq_send(socket, c_loc(id), int(id_size, c_size_t), ZMQ_SNDMORE)
        ierr = zmq_send(socket, c_loc(inull), 0_c_size_t, 0)
     end do
     ierr = zmq_close(socket)
     print *, 'zmq_close socket', ierr, zmq_strerror(zmq_errno())
     ierr = zmq_ctx_term(ctx)
     print *, 'ierr=', ierr, zmq_strerror(zmq_errno())
end program test

メモ帳:動かない

type(c_ptr) で番地を渡しただけでは、サブルーチン等では割り付けを解放できない。gfortran は見かけ上解放するが、メインルーチンに戻ると解放されていない。intel fortran では実行時エラーで異常終了。

    module m_test
        use, intrinsic :: iso_c_binding
        implicit none
    contains
        subroutine sub(cptr)
            type(c_ptr) :: cptr
            real, pointer :: arr(:)
            call c_f_pointer(cptr, arr, [10])
            print *, associated(arr), arr
            arr = arr(10:1:-1)
            deallocate(arr)
            print *, associated(arr)

!            real, allocatable, target :: brr(:)
!            call c_f_pointer(cptr, brr, [10])
!            print *, 'brr', allocated(brr), brr
!            brr = brr(10:1:-1)
!            deallocate(brr)
!            print *, 'brr', allocated(brr)
        end subroutine sub
    end module m_test

    program Console4
        use, intrinsic :: iso_c_binding
        use m_test
        implicit none
        real, pointer :: crr(:)
        integer :: i
        allocate(crr(10))
        crr = [(i, i = 1, size(crr))]
        print *, 'crr', associated(crr) 
        call sub(c_loc(crr))
        print *, 'crr', associated(crr) 
    end program Console4