ZMQ 4.3.1
以前 ZMQ の f77 binding を利用して、Fortran で HTML サーバー文字表示を試してみました。
よくよく 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 を書いて見ました。型がうるさくて混乱します。
メモ帳として書いておきます。
コンソール出力
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$
メイン・ルーチン
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