From 30b2f06c57394e745cf92d193d3ff0b4c236d51f Mon Sep 17 00:00:00 2001 From: Alec Tutin Date: Fri, 22 Sep 2023 15:53:53 +1000 Subject: [PATCH 1/4] Integrating RCL global argument parsing. --- rcldotnet/RCLdotnet.cs | 6 ++++-- rcldotnet/rcldotnet.c | 7 ++----- rcldotnet/rcldotnet.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/rcldotnet/RCLdotnet.cs b/rcldotnet/RCLdotnet.cs index 3a1136a1..af6eb5e1 100644 --- a/rcldotnet/RCLdotnet.cs +++ b/rcldotnet/RCLdotnet.cs @@ -26,7 +26,8 @@ internal static class RCLdotnetDelegates internal static readonly DllLoadUtils _dllLoadUtils; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate RCLRet NativeRCLInitType(); + internal delegate RCLRet NativeRCLInitType( + int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] argv); internal static NativeRCLInitType native_rcl_init = null; @@ -1396,7 +1397,8 @@ public static void Init() { if (!initialized) { - RCLRet ret = RCLdotnetDelegates.native_rcl_init(); + string[] args = System.Environment.GetCommandLineArgs(); + RCLRet ret = RCLdotnetDelegates.native_rcl_init(args.Length, args); RCLExceptionHelper.CheckReturnValue(ret, $"{nameof(RCLdotnetDelegates.native_rcl_init)}() failed."); initialized = true; } diff --git a/rcldotnet/rcldotnet.c b/rcldotnet/rcldotnet.c index ffd268dd..fe85820b 100644 --- a/rcldotnet/rcldotnet.c +++ b/rcldotnet/rcldotnet.c @@ -28,9 +28,7 @@ static rcl_context_t context; static rcl_clock_t clock; -int32_t native_rcl_init() { - // TODO(esteve): parse args - int num_args = 0; +int32_t native_rcl_init(int argc, const char *argv[]) { context = rcl_get_zero_initialized_context(); rcl_allocator_t allocator = rcl_get_default_allocator(); rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); @@ -38,8 +36,7 @@ int32_t native_rcl_init() { if (RCL_RET_OK != ret) { return ret; } - const char ** arg_values = NULL; - ret = rcl_init(num_args, arg_values, &init_options, &context); + ret = rcl_init(argc, argv, &init_options, &context); if (ret != RCL_RET_OK) { return ret; } diff --git a/rcldotnet/rcldotnet.h b/rcldotnet/rcldotnet.h index 6c4252ff..e35114ea 100644 --- a/rcldotnet/rcldotnet.h +++ b/rcldotnet/rcldotnet.h @@ -18,7 +18,7 @@ #include "rcldotnet_macros.h" RCLDOTNET_EXPORT -int32_t RCLDOTNET_CDECL native_rcl_init(); +int32_t RCLDOTNET_CDECL native_rcl_init(int argc, const char *argv[]); rcl_clock_t *native_rcl_get_default_clock(); From d3122ca268b36d61ff933b846a34f47287ce1a8a Mon Sep 17 00:00:00 2001 From: Alec Tutin Date: Fri, 22 Sep 2023 15:54:50 +1000 Subject: [PATCH 2/4] Integrating retrieval of node name and namespace. --- rcldotnet/Node.cs | 24 ++++++++++++++++++++++++ rcldotnet/rcldotnet_node.c | 22 ++++++++++++++++++++++ rcldotnet/rcldotnet_node.h | 6 ++++++ 3 files changed, 52 insertions(+) diff --git a/rcldotnet/Node.cs b/rcldotnet/Node.cs index 1439d56b..c392e645 100644 --- a/rcldotnet/Node.cs +++ b/rcldotnet/Node.cs @@ -96,6 +96,14 @@ internal delegate RCLRet NativeRCLActionDestroyServerHandleType( internal static NativeRCLActionDestroyServerHandleType native_rcl_action_destroy_server_handle = null; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate string NativeRCLGetStringType( + SafeNodeHandle nodeHandle); + + internal static NativeRCLGetStringType native_rcl_get_name_handle = null; + + internal static NativeRCLGetStringType native_rcl_get_namespace_handle = null; + static NodeDelegates() { _dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils(); @@ -182,6 +190,18 @@ static NodeDelegates() NodeDelegates.native_rcl_action_destroy_server_handle = (NativeRCLActionDestroyServerHandleType)Marshal.GetDelegateForFunctionPointer( native_rcl_action_destroy_server_handle_ptr, typeof(NativeRCLActionDestroyServerHandleType)); + + IntPtr native_rcl_get_name_handle_ptr = _dllLoadUtils.GetProcAddress( + nativeLibrary, "native_rcl_get_name_handle"); + NodeDelegates.native_rcl_get_name_handle = + (NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( + native_rcl_get_name_handle_ptr, typeof(NativeRCLGetStringType)); + + IntPtr native_rcl_get_namespace_handle_ptr = _dllLoadUtils.GetProcAddress( + nativeLibrary, "native_rcl_get_namespace_handle"); + NodeDelegates.native_rcl_get_namespace_handle = + (NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( + native_rcl_get_namespace_handle_ptr, typeof(NativeRCLGetStringType)); } } @@ -440,5 +460,9 @@ private static CancelResponse DefaultCancelCallback(ActionServerGoalHandle goalH { return CancelResponse.Reject; } + + public string GetName() => NodeDelegates.native_rcl_get_name_handle(Handle); + + public string GetNamespace() => NodeDelegates.native_rcl_get_namespace_handle(Handle); } } diff --git a/rcldotnet/rcldotnet_node.c b/rcldotnet/rcldotnet_node.c index 3dfa900a..1e4903be 100644 --- a/rcldotnet/rcldotnet_node.c +++ b/rcldotnet/rcldotnet_node.c @@ -240,3 +240,25 @@ int32_t native_rcl_action_destroy_server_handle(void *action_server_handle, void return ret; } + +// Avoid problems caused by automatic free of the original string. +const char * get_str_cpy(const char * src) { + size_t size = strlen(src) + 1; + + char *copy = (char *)malloc(size); + memcpy(copy, src, size); + + return copy; +} + +const char * native_rcl_get_name_handle(void *node_handle) { + rcl_node_t *node = (rcl_node_t *)node_handle; + + return get_str_cpy(rcl_node_get_name(node)); +} + +const char * native_rcl_get_namespace_handle(void *node_handle) { + rcl_node_t *node = (rcl_node_t *)node_handle; + + return get_str_cpy(rcl_node_get_namespace(node)); +} \ No newline at end of file diff --git a/rcldotnet/rcldotnet_node.h b/rcldotnet/rcldotnet_node.h index f28da07e..3fd949ea 100644 --- a/rcldotnet/rcldotnet_node.h +++ b/rcldotnet/rcldotnet_node.h @@ -71,4 +71,10 @@ int32_t RCLDOTNET_CDECL native_rcl_action_create_server_handle(void **action_ser RCLDOTNET_EXPORT int32_t RCLDOTNET_CDECL native_rcl_action_destroy_server_handle(void *action_server_handle, void *node_handle); +RCLDOTNET_EXPORT +const char * RCLDOTNET_CDECL native_rcl_get_name_handle(void *node_handle); + +RCLDOTNET_EXPORT +const char * RCLDOTNET_CDECL native_rcl_get_namespace_handle(void *node_handle); + #endif // RCLDOTNET_NODE_H From 7d3c0a3f58ac08376d07de7019201139b3e1562b Mon Sep 17 00:00:00 2001 From: Alec Tutin Date: Thu, 12 Oct 2023 10:07:12 +1000 Subject: [PATCH 3/4] Implementing feedback from @hoffmann-stefan --- rcldotnet/Node.cs | 46 +++++++++++++++++++++----------------- rcldotnet/RCLdotnet.cs | 22 ++++++++++++++++++ rcldotnet/rcldotnet_node.c | 18 ++++++--------- rcldotnet/rcldotnet_node.h | 7 ++++-- 4 files changed, 60 insertions(+), 33 deletions(-) diff --git a/rcldotnet/Node.cs b/rcldotnet/Node.cs index c392e645..80dfad9b 100644 --- a/rcldotnet/Node.cs +++ b/rcldotnet/Node.cs @@ -96,13 +96,11 @@ internal delegate RCLRet NativeRCLActionDestroyServerHandleType( internal static NativeRCLActionDestroyServerHandleType native_rcl_action_destroy_server_handle = null; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate string NativeRCLGetStringType( - SafeNodeHandle nodeHandle); + internal static RCLdotnetDelegates.NativeRCLGetStringType native_rcl_node_get_name_handle = null; - internal static NativeRCLGetStringType native_rcl_get_name_handle = null; + internal static RCLdotnetDelegates.NativeRCLGetStringType native_rcl_node_get_namespace_handle = null; - internal static NativeRCLGetStringType native_rcl_get_namespace_handle = null; + internal static RCLdotnetDelegates.NativeRCLGetStringType native_rcl_node_get_fully_qualified_name_handle = null; static NodeDelegates() { @@ -191,17 +189,23 @@ static NodeDelegates() (NativeRCLActionDestroyServerHandleType)Marshal.GetDelegateForFunctionPointer( native_rcl_action_destroy_server_handle_ptr, typeof(NativeRCLActionDestroyServerHandleType)); - IntPtr native_rcl_get_name_handle_ptr = _dllLoadUtils.GetProcAddress( - nativeLibrary, "native_rcl_get_name_handle"); - NodeDelegates.native_rcl_get_name_handle = - (NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( - native_rcl_get_name_handle_ptr, typeof(NativeRCLGetStringType)); - - IntPtr native_rcl_get_namespace_handle_ptr = _dllLoadUtils.GetProcAddress( - nativeLibrary, "native_rcl_get_namespace_handle"); - NodeDelegates.native_rcl_get_namespace_handle = - (NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( - native_rcl_get_namespace_handle_ptr, typeof(NativeRCLGetStringType)); + IntPtr native_rcl_node_get_name_handle_ptr = _dllLoadUtils.GetProcAddress( + nativeLibrary, "native_rcl_node_get_name_handle"); + NodeDelegates.native_rcl_node_get_name_handle = + (RCLdotnetDelegates.NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( + native_rcl_node_get_name_handle_ptr, typeof(RCLdotnetDelegates.NativeRCLGetStringType)); + + IntPtr native_rcl_node_get_namespace_handle_ptr = _dllLoadUtils.GetProcAddress( + nativeLibrary, "native_rcl_node_get_namespace_handle"); + NodeDelegates.native_rcl_node_get_namespace_handle = + (RCLdotnetDelegates.NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( + native_rcl_node_get_namespace_handle_ptr, typeof(RCLdotnetDelegates.NativeRCLGetStringType)); + + IntPtr native_rcl_node_get_fully_qualified_name_handle_ptr = _dllLoadUtils.GetProcAddress( + nativeLibrary, "native_rcl_node_get_fully_qualified_name_handle"); + NodeDelegates.native_rcl_node_get_fully_qualified_name_handle = + (RCLdotnetDelegates.NativeRCLGetStringType)Marshal.GetDelegateForFunctionPointer( + native_rcl_node_get_fully_qualified_name_handle_ptr, typeof(RCLdotnetDelegates.NativeRCLGetStringType)); } } @@ -230,6 +234,12 @@ internal Node(SafeNodeHandle handle) _actionServers = new List(); } + public string Name => RCLdotnet.GetStringFromNativeDelegate(NodeDelegates.native_rcl_node_get_name_handle, Handle); + + public string Namespace => RCLdotnet.GetStringFromNativeDelegate(NodeDelegates.native_rcl_node_get_namespace_handle, Handle); + + public string FullyQualifiedName => RCLdotnet.GetStringFromNativeDelegate(NodeDelegates.native_rcl_node_get_fully_qualified_name_handle, Handle); + public IList Subscriptions => _subscriptions; // TODO: (sh) wrap in readonly collection @@ -460,9 +470,5 @@ private static CancelResponse DefaultCancelCallback(ActionServerGoalHandle goalH { return CancelResponse.Reject; } - - public string GetName() => NodeDelegates.native_rcl_get_name_handle(Handle); - - public string GetNamespace() => NodeDelegates.native_rcl_get_namespace_handle(Handle); } } diff --git a/rcldotnet/RCLdotnet.cs b/rcldotnet/RCLdotnet.cs index af6eb5e1..bb2016fe 100644 --- a/rcldotnet/RCLdotnet.cs +++ b/rcldotnet/RCLdotnet.cs @@ -352,6 +352,9 @@ internal delegate RCLRet NativeRCLWriteToQosProfileHandleType( internal static NativeRCLWriteToQosProfileHandleType native_rcl_write_to_qos_profile_handle = null; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate IntPtr NativeRCLGetStringType(SafeHandle handle); + static RCLdotnetDelegates() { _dllLoadUtils = DllLoadUtilsFactory.GetDllLoadUtils(); @@ -1459,5 +1462,24 @@ internal static void WriteToMessageHandle(IRosMessage message, SafeHandle messag } } } + + internal static string GetStringFromNativeDelegate(RCLdotnetDelegates.NativeRCLGetStringType nativeDelegate, T safeHandle) where T : SafeHandle + { + bool mustRelease = false; + try + { + // This avoids accessing a invalid/freed pointer if some other thread disposes the SafeNodeHandle. + safeHandle.DangerousAddRef(ref mustRelease); + IntPtr namePtr = nativeDelegate(safeHandle); + return Marshal.PtrToStringAnsi(namePtr); + } + finally + { + if (mustRelease) + { + safeHandle.DangerousRelease(); + } + } + } } } diff --git a/rcldotnet/rcldotnet_node.c b/rcldotnet/rcldotnet_node.c index 1e4903be..0d70f4be 100644 --- a/rcldotnet/rcldotnet_node.c +++ b/rcldotnet/rcldotnet_node.c @@ -241,24 +241,20 @@ int32_t native_rcl_action_destroy_server_handle(void *action_server_handle, void return ret; } -// Avoid problems caused by automatic free of the original string. -const char * get_str_cpy(const char * src) { - size_t size = strlen(src) + 1; - - char *copy = (char *)malloc(size); - memcpy(copy, src, size); +const char * native_rcl_node_get_name_handle(void *node_handle) { + rcl_node_t *node = (rcl_node_t *)node_handle; - return copy; + return rcl_node_get_name(node); } -const char * native_rcl_get_name_handle(void *node_handle) { +const char * native_rcl_node_get_namespace_handle(void *node_handle) { rcl_node_t *node = (rcl_node_t *)node_handle; - return get_str_cpy(rcl_node_get_name(node)); + return rcl_node_get_namespace(node); } -const char * native_rcl_get_namespace_handle(void *node_handle) { +const char * native_rcl_node_get_fully_qualified_name_handle(void *node_handle) { rcl_node_t *node = (rcl_node_t *)node_handle; - return get_str_cpy(rcl_node_get_namespace(node)); + return rcl_node_get_fully_qualified_name(node); } \ No newline at end of file diff --git a/rcldotnet/rcldotnet_node.h b/rcldotnet/rcldotnet_node.h index 3fd949ea..ae610d9f 100644 --- a/rcldotnet/rcldotnet_node.h +++ b/rcldotnet/rcldotnet_node.h @@ -72,9 +72,12 @@ RCLDOTNET_EXPORT int32_t RCLDOTNET_CDECL native_rcl_action_destroy_server_handle(void *action_server_handle, void *node_handle); RCLDOTNET_EXPORT -const char * RCLDOTNET_CDECL native_rcl_get_name_handle(void *node_handle); +const char * RCLDOTNET_CDECL native_rcl_node_get_name_handle(void *node_handle); RCLDOTNET_EXPORT -const char * RCLDOTNET_CDECL native_rcl_get_namespace_handle(void *node_handle); +const char * RCLDOTNET_CDECL native_rcl_node_get_namespace_handle(void *node_handle); + +RCLDOTNET_EXPORT +const char * RCLDOTNET_CDECL native_rcl_node_get_fully_qualified_name_handle(void *node_handle); #endif // RCLDOTNET_NODE_H From c51b096c93764780f94d78372258063dcc6516c8 Mon Sep 17 00:00:00 2001 From: Alec Tutin Date: Mon, 16 Oct 2023 10:46:15 +1000 Subject: [PATCH 4/4] Removing use of generic. --- rcldotnet/RCLdotnet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rcldotnet/RCLdotnet.cs b/rcldotnet/RCLdotnet.cs index bb2016fe..5b3d296a 100644 --- a/rcldotnet/RCLdotnet.cs +++ b/rcldotnet/RCLdotnet.cs @@ -1463,7 +1463,7 @@ internal static void WriteToMessageHandle(IRosMessage message, SafeHandle messag } } - internal static string GetStringFromNativeDelegate(RCLdotnetDelegates.NativeRCLGetStringType nativeDelegate, T safeHandle) where T : SafeHandle + internal static string GetStringFromNativeDelegate(RCLdotnetDelegates.NativeRCLGetStringType nativeDelegate, SafeHandle safeHandle) { bool mustRelease = false; try