Skip to content

Commit 3cd2174

Browse files
committed
Add NNG thread module. Update error codes.
1 parent b361604 commit 3cd2174

File tree

13 files changed

+204
-23
lines changed

13 files changed

+204
-23
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ All notable changes to the project will be documented in this file.
1010
* `Added` module `dm_group` for observation groups
1111
* `Added` module `dm_ipc` for NNG socket access
1212
* `Added` module `dm_ipc_message` for NNG message handling
13+
* `Added` module `dm_ipc_mutex` for NNG mutex access
14+
* `Added` module `dm_ipc_thread` for NNG thread access
1315
* `Added` module `dm_job_list` (outsourced from `dm_job`)
1416
* `Added` interface bindings to NNG
1517
* `Added` error codes

Makefile

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ SRC = $(SRCDIR)/dm_ansi.f90 \
294294
$(SRCDIR)/dm_ipc.f90 \
295295
$(SRCDIR)/dm_ipc_message.f90 \
296296
$(SRCDIR)/dm_ipc_mutex.f90 \
297+
$(SRCDIR)/dm_ipc_thread.f90 \
297298
$(SRCDIR)/dm_job.f90 \
298299
$(SRCDIR)/dm_job_list.f90 \
299300
$(SRCDIR)/dm_js.f90 \
@@ -419,6 +420,7 @@ OBJ = dm_ansi.o \
419420
dm_ipc.o \
420421
dm_ipc_message.o \
421422
dm_ipc_mutex.o \
423+
dm_ipc_thread.o \
422424
dm_job.o \
423425
dm_job_list.o \
424426
dm_js.o \
@@ -570,23 +572,25 @@ test: dmtestapi \
570572
dmtesthtml \
571573
dmtestid \
572574
dmtestipc \
575+
dmtestipcthread \
576+
dmtestjob \
577+
dmtestjson \
573578
dmtestlinux \
574579
dmtestlog \
575580
dmtestlogger \
576581
dmtestlua \
577-
dmtestjob \
578-
dmtestjson \
579582
dmtestmail \
580583
dmtestmodbus \
581584
dmtestmqtt \
582-
dmtestposixmqueue \
583585
dmtestnet \
584586
dmtestnetstring \
585587
dmtestnml \
586588
dmtestobserv \
587589
dmtestpath \
588590
dmtestpipe \
589591
dmtestplot \
592+
dmtestposixmqueue \
593+
dmtestposixthread \
590594
dmtestregex \
591595
dmtestroff \
592596
dmtestrpc \
@@ -595,7 +599,6 @@ test: dmtestapi \
595599
dmteststatistics \
596600
dmteststring \
597601
dmtestsystem \
598-
dmtestposixthread \
599602
dmtesttime \
600603
dmtesttty \
601604
dmtestunit \
@@ -884,6 +887,9 @@ dm_ipc_message.o: $(SRCDIR)/dm_ipc_message.f90
884887
dm_ipc_mutex.o: $(SRCDIR)/dm_ipc_mutex.f90
885888
$(FC) $(FFLAGS) $(LIBFLAGS) $(MODFLAGS) -c $(SRCDIR)/dm_ipc_mutex.f90
886889

890+
dm_ipc_thread.o: $(SRCDIR)/dm_ipc_thread.f90
891+
$(FC) $(FFLAGS) $(LIBFLAGS) $(MODFLAGS) -c $(SRCDIR)/dm_ipc_thread.f90
892+
887893
dm_job.o: $(SRCDIR)/dm_job.f90
888894
$(FC) $(FFLAGS) $(LIBFLAGS) $(MODFLAGS) -c $(SRCDIR)/dm_job.f90
889895

@@ -1209,6 +1215,7 @@ $(TARGET): $(SRC)
12091215
@$(MAKE) dm_ipc.o
12101216
@$(MAKE) dm_ipc_message.o
12111217
@$(MAKE) dm_ipc_mutex.o
1218+
@$(MAKE) dm_ipc_thread.o
12121219
@$(MAKE) dmpack.o
12131220
$(AR) $(ARFLAGS) $(THIN) $(OBJ)
12141221
$(SH) $(MAKELIB) $(TARGET) $(LIBDIR)
@@ -1299,7 +1306,10 @@ dmtestid: test/dmtestid.f90 $(TARGET)
12991306
$(FC) $(FFLAGS) $(MODFLAGS) $(LDFLAGS) -o dmtestid test/dmtestid.f90 $(TARGET) $(LDLIBS)
13001307

13011308
dmtestipc: test/dmtestipc.f90 $(TARGET)
1302-
$(FC) $(FFLAGS) $(MODFLAGS) $(LDFLAGS) -o dmtestipc test/dmtestipc.f90 $(TARGET) $(LDLIBS) $(LIBNNG)
1309+
$(FC) $(FFLAGS) $(MODFLAGS) $(LDFLAGS) -o dmtestipc test/dmtestipc.f90 $(TARGET) $(LIBNNG) $(LDLIBS)
1310+
1311+
dmtestipcthread: test/dmtestipcthread.f90 $(TARGET)
1312+
$(FC) $(FFLAGS) $(MODFLAGS) $(LDFLAGS) -o dmtestipcthread test/dmtestipcthread.f90 $(TARGET) $(LIBNNG) $(LDLIBS)
13031313

13041314
dmtestlinux: test/dmtestlinux.f90 $(TARGET)
13051315
$(FC) $(FFLAGS) $(MODFLAGS) $(LDFLAGS) -o dmtestlinux test/dmtestlinux.f90 $(TARGET) $(LDLIBS)

fpm.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ main = "dmtestid.f90"
286286
[[test]]
287287
name = "dmtestipc"
288288
main = "dmtestipc.f90"
289+
link = [ "nng" ]
290+
291+
[[test]]
292+
name = "dmtestipcthread"
293+
main = "dmtestipcthread.f90"
294+
link = [ "nng" ]
289295

290296
[[test]]
291297
name = "dmtestjob"

src/dm_error.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ module dm_error
110110
integer, parameter, public :: E_ZLIB = 133 !! zlib library error.
111111
integer, parameter, public :: E_ZSTD = 134 !! Zstandard library error.
112112
integer, parameter, public :: E_XMPP = 135 !! XMPP library error.
113+
integer, parameter, public :: E_NNG = 136 !! NNG library error.
113114
! Database errors.
114115
integer, parameter, public :: E_DB = 150 !! Generic database error.
115116
integer, parameter, public :: E_DB_ID = 151 !! Invalid database application id.
@@ -256,6 +257,7 @@ pure function dm_error_message(error) result(message)
256257
case (E_ZLIB); message = 'zlib error'
257258
case (E_ZSTD); message = 'zstd error'
258259
case (E_XMPP); message = 'XMPP error'
260+
case (E_NNG); message = 'NNG error'
259261
! Database.
260262
case (E_DB); message = 'database error'
261263
case (E_DB_ID); message = 'database application id invalid'

src/dm_ipc_thread.f90

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
! Author: Philipp Engel
2+
! Licence: ISC
3+
module dm_ipc_thread
4+
!! Abstraction layer over NNG threads.
5+
!!
6+
!! Thread routines must have the `bind(c)` attribute:
7+
!!
8+
!! ```fortran
9+
!! subroutine thread_callback(arg) bind(c)
10+
!! !! C-interoperable NNG thread routine.
11+
!! use, intrinsic :: iso_c_binding
12+
!! type(c_ptr), intent(in), value :: arg !! C pointer to client data.
13+
!! integer, pointer :: i !! Fortran pointer to client data.
14+
!!
15+
!! if (.not. c_associated(arg)) return
16+
!! call c_f_pointer(arg, i)
17+
!! print '("value: ", i0)', i
18+
!! end subroutine thread_callback
19+
!! ```
20+
!!
21+
!! The dummy argument `arg` can be of any type. The thread routine and the
22+
!! argument have to be passed to the create function:
23+
!!
24+
!! ```fortran
25+
!! integer, target :: arg
26+
!! integer :: rc
27+
!! type(ipc_thread_type) :: thread
28+
!!
29+
!! arg = 123
30+
!!
31+
!! rc = dm_ipc_thread_create(thread, thread_callback, arg)
32+
!! call dm_ipc_thread_join(thread)
33+
!! ```
34+
!!
35+
!! In contrast to the POSIX thread interface of module `dm_posix_thread`,
36+
!! the NNG routines are cross-platform.
37+
use :: dm_c
38+
use :: dm_error
39+
use :: dm_kind
40+
implicit none (type, external)
41+
private
42+
43+
abstract interface
44+
subroutine dm_ipc_thread_callback(ptr) bind(c)
45+
!! C-interoperable NNG thread routine.
46+
import :: c_ptr
47+
implicit none
48+
type(c_ptr), intent(in), value :: ptr !! Thread argument.
49+
end subroutine dm_ipc_thread_callback
50+
end interface
51+
52+
type, public :: ipc_thread_type
53+
!! Opaque NNG thread type.
54+
private
55+
type(c_ptr) :: ctx = c_null_ptr !! NNG thread context.
56+
end type ipc_thread_type
57+
58+
public :: dm_ipc_thread_create
59+
public :: dm_ipc_thread_join
60+
contains
61+
! **************************************************************************
62+
! PUBLIC PROCEDURES.
63+
! **************************************************************************
64+
integer function dm_ipc_thread_create(thread, callback, argument) result(rc)
65+
!! The function creates a single thread of execution, running func with
66+
!! the argument arg. The thread is started immediately. A pointer to
67+
!! the NNG thread object is returned in dummy argument `thread`.
68+
!!
69+
!! The intention of this module is to facilitate writing parallel
70+
!! programs. Threads created by this module will be based upon the
71+
!! underlying threading mechanism of the system that NNG is running on.
72+
!! This may include use of coroutines.
73+
!!
74+
!! Using threads created by this function can make it easy to write
75+
!! programs that use simple sequential execution, using functions in
76+
!! the NNG suite that would otherwise normally wait synchronously for
77+
!! completion.
78+
!!
79+
!! When the thread is no longer needed, the `dm_ipc_thread_join()`
80+
!! routine should be used to reap it. (This function will block waiting
81+
!! for `callback` to return.)
82+
use :: nng, only: nng_thread_create
83+
use :: dm_ipc, only: dm_ipc_error
84+
85+
type(ipc_thread_type), intent(out) :: thread !! IPC thread.
86+
procedure(dm_ipc_thread_callback) :: callback !! Thread routine.
87+
type(*), target, intent(inout) :: argument !! Client data to be passed to thread procedure.
88+
89+
integer :: stat
90+
91+
stat = nng_thread_create(thread%ctx, c_funloc(callback), c_loc(argument))
92+
rc = dm_ipc_error(stat)
93+
end function dm_ipc_thread_create
94+
95+
subroutine dm_ipc_thread_join(thread)
96+
!! Joins and destroys NNG thread. This routine is blocking.
97+
use :: nng, only: nng_thread_destroy
98+
99+
type(ipc_thread_type), intent(inout) :: thread !! IPC thread.
100+
101+
if (.not. c_associated(thread%ctx)) return
102+
call nng_thread_destroy(thread%ctx)
103+
end subroutine dm_ipc_thread_join
104+
end module dm_ipc_thread

src/dm_lua_api.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ integer function dm_lua_api_register(lua, errors, log_levels, procedures, respon
177177
rc = dm_lua_set(lua, 'E_ZLIB', E_ZLIB); if (dm_is_error(rc)) return
178178
rc = dm_lua_set(lua, 'E_ZSTD', E_ZSTD); if (dm_is_error(rc)) return
179179
rc = dm_lua_set(lua, 'E_XMPP', E_XMPP); if (dm_is_error(rc)) return
180+
rc = dm_lua_set(lua, 'E_NNG', E_NNG); if (dm_is_error(rc)) return
180181

181182
rc = dm_lua_set(lua, 'E_DB', E_DB); if (dm_is_error(rc)) return
182183
rc = dm_lua_set(lua, 'E_DB_ID', E_DB_ID); if (dm_is_error(rc)) return

src/dm_mail.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,12 @@ integer function dm_mail_send(mail, server, error_message, error_curl, debug) re
287287
!! The function returns the following error codes:
288288
!!
289289
!! * `E_COMPILER` if C pointers could not be nullified (compiler bug).
290-
!! * `E_CORRUPT` if mail or server type is not initialised properly.
291290
!! * `E_INVALID` if mail or server data is invalid.
292291
!! * `E_MAIL` if libcurl initialisation failed.
293292
!! * `E_MAIL_AUTH` if SMTP authentication failed.
294293
!! * `E_MAIL_CONNECT` if connection to server could not be established.
295294
!! * `E_MAIL_SSL` if SSL/TLS error occured.
295+
!! * `E_NULL` if mail or server type is not initialised properly.
296296
!!
297297
type(mail_type), intent(inout) :: mail !! Mail.
298298
type(mail_server_type), intent(inout) :: server !! Mail server.
@@ -310,7 +310,7 @@ integer function dm_mail_send(mail, server, error_message, error_curl, debug) re
310310

311311
mail_block: block
312312
! Mail and server must be initialised.
313-
rc = E_CORRUPT
313+
rc = E_NULL
314314
if (.not. mail%allocated .or. .not. server%allocated) exit mail_block
315315

316316
! Prepare payload.

src/dm_posix_thread.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,16 @@ end subroutine dm_posix_thread_callback
5959
public :: dm_posix_thread_create
6060
public :: dm_posix_thread_join
6161
contains
62-
integer function dm_posix_thread_create(thread, callback, arg) result(rc)
62+
integer function dm_posix_thread_create(thread, callback, argument) result(rc)
6363
!! Creates POSIX thread. The function returns `E_SYSTEM` on error.
6464
type(posix_thread_type), intent(out) :: thread !! Thread type.
6565
procedure(dm_posix_thread_callback) :: callback !! Callback procedure of POSIX thread.
66-
type(*), target, intent(inout) :: arg !! Client data to be passed to thread procedure.
66+
type(*), target, intent(inout) :: argument !! Client data to be passed to thread procedure.
6767

6868
integer :: stat
6969

7070
rc = E_SYSTEM
71-
stat = c_pthread_create(thread%ctx, c_null_ptr, c_funloc(callback), c_loc(arg))
71+
stat = c_pthread_create(thread%ctx, c_null_ptr, c_funloc(callback), c_loc(argument))
7272
if (stat /= 0) return
7373
rc = E_NONE
7474
end function dm_posix_thread_create

src/dm_rpc.f90

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,7 @@ integer function dm_rpc_post_types(requests, responses, types, url, username, pa
460460
!! `target_type`. The function returns `E_TYPE` on any other type.
461461
!!
462462
!! If `sequential` is `.true.`, the transfer will be sequentially
463-
!! instead of concurrently. The number of requests must match the
464-
!! number of types, or `E_CORRUPT` is returned.
463+
!! instead of concurrently.
465464
!!
466465
!! The function returns the following error codes:
467466
!!
@@ -866,14 +865,14 @@ integer function rpc_header_add_request(request, name, value) result(rc)
866865
!! The function returns the following error codes:
867866
!!
868867
!! * `E_BOUNDS` if headers array is full.
869-
!! * `E_CORRUPT` if headers array is not allocated.
870868
!! * `E_INVALID` if name is empty.
869+
!! * `E_NULL` if headers array is not allocated.
871870
!!
872871
type(rpc_request_type), intent(inout) :: request !! RPC request.
873872
character(*), intent(in) :: name !! Header name.
874873
character(*), intent(in), optional :: value !! Header value.
875874

876-
rc = E_CORRUPT
875+
rc = E_NULL
877876
if (.not. allocated(request%headers)) return
878877

879878
rc = rpc_header_add(request%headers, name, value)
@@ -885,14 +884,14 @@ integer function rpc_header_add_response(response, name, value) result(rc)
885884
!! The function returns the following error codes:
886885
!!
887886
!! * `E_BOUNDS` if headers array is full.
888-
!! * `E_CORRUPT` if headers array is not allocated.
889887
!! * `E_INVALID` if name is empty.
888+
!! * `E_NULL` if headers array is not allocated.
890889
!!
891890
type(rpc_response_type), intent(inout) :: response !! RPC response.
892891
character(*), intent(in) :: name !! Header name.
893892
character(*), intent(in), optional :: value !! Header value.
894893

895-
rc = E_CORRUPT
894+
rc = E_NULL
896895
if (.not. allocated(response%headers)) return
897896

898897
rc = rpc_header_add(response%headers, name, value)
@@ -982,14 +981,14 @@ integer function rpc_header_get_request(request, name, value) result(rc)
982981
!! The function returns the following error codes:
983982
!!
984983
!! * `E_EMPTY` if headers array is empty.
985-
!! * `E_CORRUPT` if headers array is not allocated.
986984
!! * `E_NOT_FOUND` if header has not been found.
985+
!! * `E_NULL` if headers array is not allocated.
987986
!!
988987
type(rpc_request_type), intent(inout) :: request !! RPC request.
989988
character(*), intent(in) :: name !! Header name.
990989
character(:), allocatable, intent(out) :: value !! Header value.
991990

992-
rc = E_CORRUPT
991+
rc = E_NULL
993992
if (.not. allocated(request%headers)) then
994993
value = ''
995994
return
@@ -1004,14 +1003,14 @@ integer function rpc_header_get_response(response, name, value) result(rc)
10041003
!! The function returns the following error codes:
10051004
!!
10061005
!! * `E_EMPTY` if headers array is empty.
1007-
!! * `E_CORRUPT` if headers array is not allocated.
10081006
!! * `E_NOT_FOUND` if header has not been found.
1007+
!! * `E_NULL` if headers array is not allocated.
10091008
!!
10101009
type(rpc_response_type), intent(inout) :: response !! RPC response.
10111010
character(*), intent(in) :: name !! Header name.
10121011
character(:), allocatable, intent(out) :: value !! Header value.
10131012

1014-
rc = E_CORRUPT
1013+
rc = E_NULL
10151014
if (.not. allocated(response%headers)) then
10161015
value = ''
10171016
return

src/dmpack.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ module dmpack
8282
use :: dm_ipc
8383
use :: dm_ipc_message
8484
use :: dm_ipc_mutex
85+
use :: dm_ipc_thread
8586
use :: dm_job
8687
use :: dm_job_list
8788
use :: dm_js

0 commit comments

Comments
 (0)