refactor init to not be global (#336)

* refactor init to not be global

Signed-off-by: William Woodall <william@osrfoundation.org>

* style changes

Signed-off-by: William Woodall <william@osrfoundation.org>

* refactor to hide use of C11 atomics in implementation

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix new action tests

Signed-off-by: William Woodall <william@osrfoundation.org>

* use alternative atomic init for Windows support

* updates after rebase

Signed-off-by: William Woodall <william@osrfoundation.org>

* cleanup rmw_init_options before copying

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix two bugs in new init code

* relax validity checks in a few places to facilitate post shutdown cleanup

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixing tests for new API behavior

Signed-off-by: William Woodall <william@osrfoundation.org>

* to allocator -> to allocate

* acutally call rmw_shutdown() and address review comments

Signed-off-by: William Woodall <william@osrfoundation.org>
This commit is contained in:
William Woodall 2018-11-29 21:32:54 -08:00 committed by GitHub
parent dfaa412bbf
commit 97ad0013e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 1951 additions and 629 deletions

View file

@ -30,14 +30,16 @@ set(${PROJECT_NAME}_sources
src/rcl/arguments.c
src/rcl/client.c
src/rcl/common.c
src/rcl/context.c
src/rcl/expand_topic_name.c
src/rcl/graph.c
src/rcl/guard_condition.c
src/rcl/init.c
src/rcl/init_options.c
src/rcl/lexer.c
src/rcl/lexer_lookahead.c
src/rcl/node.c
src/rcl/publisher.c
src/rcl/rcl.c
src/rcl/remap.c
src/rcl/rmw_implementation_identifier_check.c
src/rcl/service.c

View file

@ -278,30 +278,6 @@ rcl_ret_t
rcl_arguments_fini(
rcl_arguments_t * args);
/// Get a global instance of command line arguments.
/**
* \sa rcl_init(int, char **, rcl_allocator_t)
* \sa rcl_shutdown()
* This returns parsed command line arguments that were passed to `rcl_init()`.
* The value returned by this function is undefined before `rcl_init()` is called and after
* `rcl_shutdown()` is called.
* The return value must not be finalized.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | No
* Lock-Free | Yes
*
* \return a global instance of parsed command line arguments.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_arguments_t *
rcl_get_global_arguments();
#ifdef __cplusplus
}
#endif

261
rcl/include/rcl/context.h Normal file
View file

@ -0,0 +1,261 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__CONTEXT_H_
#define RCL__CONTEXT_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "rmw/init.h"
#include "rcl/allocator.h"
#include "rcl/arguments.h"
#include "rcl/init_options.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
typedef uint64_t rcl_context_instance_id_t;
struct rcl_context_impl_t;
/// Encapsulates the non-global state of an init/shutdown cycle.
/**
* The context is used in the creation of top level entities like nodes and
* guard conditions, as well as to shutdown a specific instance of init.
*
* Here is a diagram of a typical context's lifecycle:
*
* ```
* +---------------+
* | |
* +--> uninitialized +---> rcl_get_zero_initialized_context() +
* | | | |
* | +---------------+ |
* | |
* | +-----------------------------------------------+
* | |
* | +--------v---------+ +-----------------------+
* | | | | |
* | | zero-initialized +-> rcl_init() +-> initialized and valid +-> rcl_shutdown() +
* | | | | | |
* | +------------------+ +-----------------------+ |
* | |
* | +-----------------------------------------------------------------+
* | |
* | +------------v------------+
* | | |
* | | initialized but invalid +---> finalize all entities, then rcl_context_fini() +
* | | | |
* | +-------------------------+ |
* | |
* +---------------------------------------------------------------------------------+
* ```
*
* A declared but not defined `rcl_context_t` instance is considered to be
* "uninitialized", and passing an uninitialized context to any functions will
* result in undefined behavior.
* Some functions, like `rcl_init()` require the context instance to be
* zero initialized (all members set to "zero" state) before use.
*
* Zero initialization of an `rcl_context_t` should be done with
* `rcl_get_zero_initialized_context()`, which ensures the context is in a safe
* state for initialization with `rcl_init()`.
*
* Initialization of an `rcl_context_t` should be done with `rcl_init()`, after
* which the context is considered both initialized and valid.
* After initialization it can be used in the creation of other entities like
* nodes and guard conditions.
*
* At any time the context can be invalidated by calling `rcl_shutdown()` on
* the `rcl_context_t`, after which the context is still initialized but now
* invalid.
*
* Invalidation indicates to other entities that the context was shutdown, but
* is still accessible for use during cleanup of themselves.
*
* After being invalidated, and after all of the entities which used it have
* been finalized, the context should be finalized with `rcl_context_fini()`.
*
* Finalizing the context while entities which have copies of it have not yet
* been finalized is undefined behavior.
* Therefore, the context's lifetime (between calls to `rcl_init()` and
* `rcl_context_fini()`) should exceed the lifetime of all entities which use
* it directly (e.g. nodes and guard conditions) or indirectly (e.g.
* subscriptions and topics).
*/
typedef struct rcl_context_t
{
/// Global arguments for all nodes which share this context.
/** Typically generated by the parsing of argc/argv in `rcl_init()`. */
rcl_arguments_t global_arguments;
/// Implementation specific pointer.
struct rcl_context_impl_t * impl;
// The assumption that this is big enough for an atomic_uint_least64_t is
// ensured with a static_assert in the context.c file.
// In most cases it should just be a plain uint64_t.
#if !defined(RCL_CONTEXT_ATOMIC_INSTANCE_ID_STORAGE_SIZE)
#define RCL_CONTEXT_ATOMIC_INSTANCE_ID_STORAGE_SIZE sizeof(uint_least64_t)
#endif
/// Private storage for instance ID atomic.
/**
* Accessing the instance id should be done using the function
* `rcl_context_get_instance_id()` because the instance id's type is an
* atomic and needs to be accessed properly to ensure safety.
*
* The instance id should not be changed manually - doing so is undefined
* behavior.
*
* The instance id cannot be protected within the `impl` pointer's type
* because it needs to be accessible even when the context is zero
* initialized and therefore `impl` is `NULL`.
* Specifically, storing the instance id in the `impl` would introduce a
* race condition between accessing it and finalizing the context.
* Additionally, C11 atomics (i.e. "stdatomic.h") cannot be used directly
* here in the case that this header is included into a C++ program.
* See this paper for an effort to make this possible in the future:
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0943r1.html
*/
uint8_t instance_id_storage[RCL_CONTEXT_ATOMIC_INSTANCE_ID_STORAGE_SIZE];
} rcl_context_t;
/// Return a zero initialization context object.
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_context_t
rcl_get_zero_initialized_context(void);
// See `rcl_init()` for initialization of the context.
/// Finalize a context.
/**
* The context to be finalized must have been previously initialized with
* `rcl_init()`, and then later invalidated with `rcl_shutdown()`.
* If context is `NULL`, then `RCL_RET_INVALID_ARGUMENT` is returned.
* If context is zero-initialized, then `RCL_RET_INVALID_ARGUMENT` is returned.
* If context is initialized and valid (`rcl_shutdown()` was not called on it),
* then `RCL_RET_INVALID_ARGUMENT` is returned.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \return `RCL_RET_OK` if the shutdown was completed successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_context_fini(rcl_context_t * context);
// See `rcl_shutdown()` for invalidation of the context.
/// Return the init options used during initialization for this context.
/**
* This function can fail and return `NULL` if:
* - context is NULL
* - context is zero-initialized, e.g. context->impl is `NULL`
*
* If context is uninitialized then that is undefined behavior.
*
* If `NULL` is returned an error message will have been set.
*
* The options are for reference only, and therefore the returned pointer is
* const.
* Changing the values in the options is undefined behavior but will likely
* have no effect.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes
*
* \param[in] context object from which the init options should be retrieved
* \return pointer to the the init options, or
* \return `NULL` if there was an error
*/
RCL_PUBLIC
RCL_WARN_UNUSED
const rcl_init_options_t *
rcl_context_get_init_options(rcl_context_t * context);
/// Returns an unsigned integer that is unique to the given context, or `0` if invalid.
/**
* The given context must be non-`NULL`, but does not need to be initialized or valid.
* If context is `NULL`, then `0` will be returned.
* If context is uninitialized, then it is undefined behavior.
*
* The instance ID may be `0` if the context is zero-initialized or if the
* context has been invalidated by `rcl_shutdown()`.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \param[in] context object from which the instance id should be retrieved
* \return a unique id specific to this context instance, or
* \return `0` if invalid, or
* \return `0` if context is `NULL`
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_context_instance_id_t
rcl_context_get_instance_id(rcl_context_t * context);
/// Return `true` if the given context is currently valid, otherwise `false`.
/**
* If context is `NULL`, then `false` is returned.
* If context is zero-initialized, then `false` is returned.
* If context is uninitialized, then it is undefined behavior.
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \param[in] context object which should be checked for validity
* \return `true` if valid, otherwise `false`
*/
RCL_PUBLIC
RCL_WARN_UNUSED
bool
rcl_context_is_valid(rcl_context_t * context);
#ifdef __cplusplus
}
#endif
#endif // RCL__CONTEXT_H_

View file

@ -21,6 +21,7 @@ extern "C"
#endif
#include "rcl/allocator.h"
#include "rcl/context.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
@ -31,6 +32,9 @@ struct rcl_guard_condition_impl_t;
/// Handle for a rcl guard condition.
typedef struct rcl_guard_condition_t
{
/// Context associated with this guard condition.
rcl_context_t * context;
struct rcl_guard_condition_impl_t * impl;
} rcl_guard_condition_t;
@ -61,7 +65,7 @@ rcl_get_zero_initialized_guard_condition(void);
* rcl_guard_condition_t guard_condition = rcl_get_zero_initialized_guard_condition();
* // ... customize guard condition options
* rcl_ret_t ret = rcl_guard_condition_init(
* &guard_condition, rcl_guard_condition_get_default_options());
* &guard_condition, context, rcl_guard_condition_get_default_options());
* // ... error handling, and on shutdown do deinitialization:
* ret = rcl_guard_condition_fini(&guard_condition);
* // ... error handling for rcl_guard_condition_fini()
@ -76,9 +80,12 @@ rcl_get_zero_initialized_guard_condition(void);
* Lock-Free | Yes
*
* \param[inout] guard_condition preallocated guard_condition structure
* \param[in] context the context instance with which the guard condition
* should be associated
* \param[in] options the guard_condition's options
* \return `RCL_RET_OK` if guard_condition was initialized successfully, or
* \return `RCL_RET_ALREADY_INIT` if the guard condition is already initialized, or
* \return `RCL_RET_NOT_INIT` if the given context is invalid, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
@ -88,6 +95,7 @@ RCL_WARN_UNUSED
rcl_ret_t
rcl_guard_condition_init(
rcl_guard_condition_t * guard_condition,
rcl_context_t * context,
const rcl_guard_condition_options_t options);
/// Same as rcl_guard_condition_init(), but reusing an existing rmw handle.
@ -114,6 +122,9 @@ rcl_guard_condition_init(
*
* \param[inout] guard_condition preallocated guard_condition structure
* \param[in] rmw_guard_condition existing rmw guard condition to reuse
* \param[in] context the context instance with which the rmw guard condition
* was initialized with, i.e. the rmw context inside rcl context needs to
* match rmw context in rmw guard condition
* \param[in] options the guard_condition's options
* \return `RCL_RET_OK` if guard_condition was initialized successfully, or
* \return `RCL_RET_ALREADY_INIT` if the guard condition is already initialized, or
@ -125,6 +136,7 @@ rcl_ret_t
rcl_guard_condition_init_from_rmw(
rcl_guard_condition_t * guard_condition,
const rmw_guard_condition_t * rmw_guard_condition,
rcl_context_t * context,
const rcl_guard_condition_options_t options);
/// Finalize a rcl_guard_condition_t.
@ -142,6 +154,7 @@ rcl_guard_condition_init_from_rmw(
* <i>[1] specifically not thread-safe with rcl_trigger_guard_condition()</i>
*
* \param[inout] guard_condition handle to the guard_condition to be finalized
* \param[in] context the context originally used to init the guard condition
* \return `RCL_RET_OK` if guard_condition was finalized successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.

117
rcl/include/rcl/init.h Normal file
View file

@ -0,0 +1,117 @@
// Copyright 2014 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__INIT_H_
#define RCL__INIT_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/allocator.h"
#include "rcl/context.h"
#include "rcl/init_options.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
/// Initialization of rcl.
/**
* This function can be run any number of times, so long as the given context
* has been properly prepared.
*
* The given `rcl_context_t` must be zero initialized with the function
* `rcl_get_zero_initialized_context()` and must not be already initialized
* by this function.
* If the context is already initialized this function will fail and return the
* `RCL_RET_ALREADY_INIT` error code.
* A context may be initialized again after it has been finalized with the
* `rcl_shutdown()` function and zero initialized again with
* `rcl_get_zero_initialized_context()`.
*
* The `argc` and `argv` parameters may contain command line arguments for the
* program.
* rcl specific arguments will be parsed, but not removed.
* If `argc` is `0` and `argv` is `NULL` no parameters will be parsed.
*
* The `options` argument must be non-`NULL` and must have been initialized
* with `rcl_init_options_init()`.
* It is unmodified by this function, and the ownership is not transfered to
* the context, but instead a copy is made into the context for later reference.
* Therefore, the given options need to be cleaned up with
* `rcl_init_options_fini()` after this function returns.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \param[in] argc number of strings in argv
* \param[in] argv command line arguments; rcl specific arguments are removed
* \param[in] options options used during initialization
* \param[out] context resulting context object that represents this init
* \return `RCL_RET_OK` if initialization is successful, or
* \return `RCL_RET_ALREADY_INIT` if rcl_init has already been called, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_init(
int argc,
char const * const * argv,
const rcl_init_options_t * options,
rcl_context_t * context);
/// Shutdown a given rcl context.
/**
* The given context must have been initialized with `rcl_init()`.
* If not, this function will fail with `RCL_RET_ALREADY_SHUTDOWN`.
*
* When this function is called:
* - Any rcl objects created using this context are invalidated.
* - Functions called on invalid objects may or may not fail.
* - Calls to `rcl_context_is_initialized()` will return `false`.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \return `RCL_RET_OK` if the shutdown was completed successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ALREADY_SHUTDOWN` if the context is not currently valid, or
* \return `RCL_RET_ERROR` if an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_shutdown(rcl_context_t * context);
#ifdef __cplusplus
}
#endif
#endif // RCL__INIT_H_

View file

@ -0,0 +1,159 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__INIT_OPTIONS_H_
#define RCL__INIT_OPTIONS_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "rmw/init.h"
#include "rcl/allocator.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
struct rcl_init_options_impl_t;
/// Encapsulation of init options and implementation defined init options.
typedef struct rcl_init_options_t
{
/// Implementation specific pointer.
struct rcl_init_options_impl_t * impl;
} rcl_init_options_t;
/// Return a zero initialized rcl_init_options_t struct.
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_init_options_t
rcl_get_zero_initialized_init_options(void);
/// Initialize given init_options with the default values and implementation specific values.
/**
* The given allocator is used, if required, during setup of the init options,
* but is also used during initialization.
*
* In either case the given allocator is stored in the returned init options.
*
* The `impl` pointer should not be changed manually.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes
*
* \param[inout] init_options object to be setup
* \param[in] allocator to be used during setup and during initialization
* \return `RCL_RET_OK` if setup is successful, or
* \return `RCL_RET_ALREADY_INIT` if init_options has already be initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_init_options_init(rcl_init_options_t * init_options, rcl_allocator_t allocator);
/// Copy the given source init_options to the destination init_options.
/**
* The allocator from the source is used for any allocations and stored in the
* destination.
*
* The destination should either be zero initialized with
* `rcl_get_zero_initialized_init_options()` or should have had
* `rcl_init_options_fini()` called on it.
* Giving an already initialized init options for the destination will result
* in a failure with return code `RCL_RET_ALREADY_INIT`.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes
*
* \param[in] src rcl_init_options_t object to be copied from
* \param[out] dst rcl_init_options_t object to be copied into
* \return `RCL_RET_OK` if the copy is successful, or
* \return `RCL_RET_ALREADY_INIT` if the dst has already be initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_init_options_copy(const rcl_init_options_t * src, rcl_init_options_t * dst);
/// Finalize the given init_options.
/**
* The given init_options must be non-`NULL` and valid, i.e. had
* `rcl_init_options_init()` called on it but not this function yet.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes
*
* \param[inout] init_options object to be setup
* \return `RCL_RET_OK` if setup is successful, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_init_options_fini(rcl_init_options_t * init_options);
/// Return the rmw init options which are stored internally.
/**
* This function can fail and return `NULL` if:
* - init_options is NULL
* - init_options is invalid, e.g. init_options->impl is NULL
*
* If NULL is returned an error message will have been set.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes
*
* \param[in] init_options object from which the rmw init options should be retrieved
* \return pointer to the the rmw init options, or
* \return `NULL` if there was an error
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rmw_init_options_t *
rcl_init_options_get_rmw_init_options(rcl_init_options_t * init_options);
#ifdef __cplusplus
}
#endif
#endif // RCL__INIT_OPTIONS_H_

View file

@ -24,6 +24,7 @@ extern "C"
#include "rcl/allocator.h"
#include "rcl/arguments.h"
#include "rcl/context.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
@ -37,6 +38,9 @@ struct rcl_node_impl_t;
/// Structure which encapsulates a ROS Node.
typedef struct rcl_node_t
{
/// Context associated with this node.
rcl_context_t * context;
/// Private implementation pointer.
struct rcl_node_impl_t * impl;
} rcl_node_t;
@ -74,6 +78,19 @@ typedef struct rcl_node_options_t
rcl_arguments_t arguments;
} rcl_node_options_t;
/// Return the default node options in a rcl_node_options_t.
/**
* The default values are:
*
* - domain_id = RCL_NODE_OPTIONS_DEFAULT_DOMAIN_ID
* - allocator = rcl_get_default_allocator()
* - use_global_arguments = true
* - arguments = rcl_get_zero_initialized_arguments()
*/
RCL_PUBLIC
rcl_node_options_t
rcl_node_get_default_options(void);
/// Return a rcl_node_t struct with members initialized to `NULL`.
RCL_PUBLIC
RCL_WARN_UNUSED
@ -152,9 +169,12 @@ rcl_get_zero_initialized_node(void);
* \param[inout] node a preallocated rcl_node_t
* \param[in] name the name of the node, must be a valid c-string
* \param[in] namespace_ the namespace of the node, must be a valid c-string
* \param[in] context the context instance with which the node should be
* associated
* \param[in] options the node options.
* The options are deep copied into the node.
* The caller is always responsible for freeing memory used options they pass in.
* The caller is always responsible for freeing memory used options they
* pass in.
* \return `RCL_RET_OK` if the node was initialized successfully, or
* \return `RCL_RET_ALREADY_INIT` if the node has already be initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
@ -170,6 +190,7 @@ rcl_node_init(
rcl_node_t * node,
const char * name,
const char * namespace_,
rcl_context_t * context,
const rcl_node_options_t * options);
/// Finalize a rcl_node_t.
@ -190,6 +211,7 @@ rcl_node_init(
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \param[in] node rcl_node_t to be finalized
* \param[in] context the context originally used to init the node
* \return `RCL_RET_OK` if node was finalized successfully, or
* \return `RCL_RET_NODE_INVALID` if the node pointer is null, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
@ -199,17 +221,6 @@ RCL_WARN_UNUSED
rcl_ret_t
rcl_node_fini(rcl_node_t * node);
/// Return the default node options in a rcl_node_options_t.
/**
* The default values are:
*
* - domain_id = RCL_NODE_OPTIONS_DEFAULT_DOMAIN_ID
* - allocator = rcl_get_default_allocator()
*/
RCL_PUBLIC
rcl_node_options_t
rcl_node_get_default_options(void);
/// Copy one options structure into another.
/**
* <hr>
@ -274,6 +285,19 @@ RCL_PUBLIC
bool
rcl_node_is_valid(const rcl_node_t * node);
/// Return true if node is valid, except for the context being valid.
/**
* This is used in clean up functions that need to access the node, but do not
* need use any functions with the context.
*
* It is identical to rcl_node_is_valid except it ignores the state of the
* context associated with the node.
* \sa rcl_node_is_valid()
*/
RCL_PUBLIC
bool
rcl_node_is_valid_except_context(const rcl_node_t * node);
/// Return the name of the node.
/**
* This function returns the node's internal name string.

View file

@ -375,7 +375,35 @@ RCL_WARN_UNUSED
rmw_publisher_t *
rcl_publisher_get_rmw_handle(const rcl_publisher_t * publisher);
/// Check that the publisher is valid
/// Return the context associated with this publisher.
/**
* This function can fail, and therefore return `NULL`, if the:
* - publisher is `NULL`
* - publisher is invalid (never called init, called fini, etc.)
*
* The returned context is made invalid if the publisher is finalized or if
* rcl_shutdown() is called.
* Therefore it is recommended to get the handle from the publisher using
* this function each time it is needed and avoid use of the handle
* concurrently with functions that might change it.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] publisher pointer to the rcl publisher
* \return context if successful, otherwise `NULL`
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_context_t *
rcl_publisher_get_context(const rcl_publisher_t * publisher);
/// Return true if the publisher is valid, otherwise false.
/**
* The bool returned is `false` if `publisher` is invalid.
* The bool returned is `true` otherwise.
@ -397,6 +425,19 @@ RCL_PUBLIC
bool
rcl_publisher_is_valid(const rcl_publisher_t * publisher);
/// Return true if the publisher is valid except the context, otherwise false.
/**
* This is used in clean up functions that need to access the publisher, but do
* not need use any functions with the context.
*
* It is identical to rcl_publisher_is_valid except it ignores the state of the
* context associated with the publisher.
* \sa rcl_publisher_is_valid()
*/
RCL_PUBLIC
bool
rcl_publisher_is_valid_except_context(const rcl_publisher_t * publisher);
/// Get the number of subscriptions matched to a publisher.
/**
* Used to get the internal count of subscriptions matched to a publisher.

View file

@ -40,8 +40,8 @@
*
* It also has some machinery that is necessary to wait on and act on these concepts:
*
* - Initialization and shutdown management (global for now)
* - rcl/rcl.h
* - Initialization and shutdown management
* - rcl/init.h
* - Wait sets for waiting on messages/service requests and responses/timers to be ready
* - rcl/wait.h
* - Guard conditions for waking up wait sets asynchronously
@ -73,125 +73,11 @@ extern "C"
{
#endif
#include "rcl/macros.h"
#include "rcl/init.h"
#include "rcl/node.h"
#include "rcl/publisher.h"
#include "rcl/subscription.h"
#include "rcl/types.h"
#include "rcl/wait.h"
#include "rcl/visibility_control.h"
/// Global initialization of rcl.
/**
* Unless otherwise noted, this must be called before using any rcl functions.
*
* This function can only be run once after starting the program, and once
* after each call to rcl_shutdown().
* Repeated calls will fail with `RCL_RET_ALREADY_INIT`.
*
* This function can be called any time after rcl_shutdown() is called, but it
* cannot be called from within a callback being executed by an rcl executor.
* For example, you can call rcl_shutdown() from within a timer callback, but
* you have to return from the callback, and therefore exit any in-progress
* call to a spin function, before calling rcl_init() again.
*
* The `argc` and `argv` parameters can contain command line arguments for the
* program.
* rcl specific arguments will be parsed and removed, but other arguments will
* be ignored.
* If `argc` is `0` and `argv` is `NULL` no parameters will be parsed.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \param[in] argc number of strings in argv
* \param[in] argv command line arguments; rcl specific arguments are removed
* \param[in] allocator rcl_allocator_t used in rcl_init() and rcl_shutdown()
* \return `RCL_RET_OK` if initialization is successful, or
* \return `RCL_RET_ALREADY_INIT` if rcl_init has already been called, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_init(int argc, char const * const * argv, rcl_allocator_t allocator);
/// Signal global shutdown of rcl.
/**
* This function does not have to be called on exit, but does have to be called
* making a repeat call to rcl_init().
*
* This function can only be called once after each call to rcl_init().
* Repeated calls will fail with RCL_RET_NOT_INIT.
* This function is not thread safe.
*
* When this function is called:
* - Any rcl objects created since the last call to rcl_init() are invalidated.
* - Calls to rcl_ok() will return `false`.
* - Any executors waiting for work (within a call to spin) are interrupted.
* - No new work (executing callbacks) will be done in executors.
* - Currently running work in executors will be finished.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | Yes [1]
* Uses Atomics | Yes
* Lock-Free | Yes [2]
* <i>[1] not thread-safe with rcl_init()</i>
* <i>[2] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \return `RCL_RET_OK` if the shutdown was completed successfully, or
* \return `RCL_RET_NOT_INIT` if rcl is not currently initialized, or
* \return `RCL_RET_ERROR` if an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_shutdown(void);
/// Returns an uint64_t number that is unique for the latest rcl_init call.
/**
* If called before rcl_init or after rcl_shutdown then 0 will be returned.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*
* \return a unique id specific to this rcl instance, or `0` if not initialized.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
uint64_t
rcl_get_instance_id(void);
/// Return `true` if rcl is currently initialized, otherwise `false`.
/**
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes
* Lock-Free | Yes [1]
* <i>[1] if `atomic_is_lock_free()` returns true for `atomic_uint_least64_t`</i>
*/
RCL_PUBLIC
RCL_WARN_UNUSED
bool
rcl_ok(void);
#ifdef __cplusplus
}

View file

@ -23,6 +23,7 @@ extern "C"
#include <stdbool.h>
#include "rcl/allocator.h"
#include "rcl/context.h"
#include "rcl/guard_condition.h"
#include "rcl/macros.h"
#include "rcl/time.h"
@ -107,6 +108,7 @@ rcl_get_zero_initialized_timer(void);
* // Optionally reconfigure, cancel, or reset the timer...
* }
*
* rcl_context_t * context; // initialized previously by rcl_init()...
* rcl_clock_t clock;
* rcl_allocator_t allocator = rcl_get_default_allocator();
* rcl_ret_t ret = rcl_clock_init(RCL_STEADY_TIME, &clock, &allocator);
@ -114,7 +116,7 @@ rcl_get_zero_initialized_timer(void);
*
* rcl_timer_t timer = rcl_get_zero_initialized_timer();
* ret = rcl_timer_init(
* &timer, &clock, RCL_MS_TO_NS(100), my_timer_callback, allocator);
* &timer, &clock, context, RCL_MS_TO_NS(100), my_timer_callback, allocator);
* // ... error handling, use the timer with a wait set, or poll it manually, then cleanup
* ret = rcl_timer_fini(&timer);
* // ... error handling
@ -135,6 +137,7 @@ rcl_get_zero_initialized_timer(void);
*
* \param[inout] timer the timer handle to be initialized
* \param[in] clock the clock providing the current time
* \param[in] context the context that this timer is to be associated with
* \param[in] period the duration between calls to the callback in nanoseconds
* \param[in] callback the user defined function to be called every period
* \param[in] allocator the allocator to use for allocations
@ -150,6 +153,7 @@ rcl_ret_t
rcl_timer_init(
rcl_timer_t * timer,
rcl_clock_t * clock,
rcl_context_t * context,
int64_t period,
const rcl_timer_callback_t callback,
rcl_allocator_t allocator);

View file

@ -42,6 +42,8 @@ typedef rmw_ret_t rcl_ret_t;
#define RCL_RET_SERVICE_NAME_INVALID 104
/// Topic name substitution is unknown.
#define RCL_RET_UNKNOWN_SUBSTITUTION 105
/// rcl_shutdown() already called return code.
#define RCL_RET_ALREADY_SHUTDOWN 106
// rcl node specific ret codes in 2XX
/// Invalid rcl_node_t given return code.

View file

@ -36,9 +36,6 @@ extern "C"
{
#endif
// Instance of global arguments.
static rcl_arguments_t __rcl_global_arguments;
/// Parse an argument that may or may not be a remap rule.
/**
* \param[in] arg the argument to parse
@ -510,14 +507,6 @@ rcl_arguments_fini(
return RCL_RET_ERROR;
}
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_arguments_t *
rcl_get_global_arguments()
{
return &__rcl_global_arguments;
}
/// Parses a fully qualified namespace for a namespace replacement rule (ex: `/foo/bar`)
/**
* \sa _rcl_parse_remap_begin_remap_rule()

View file

@ -131,7 +131,7 @@ rcl_client_init(
}
rcl_arguments_t * global_args = NULL;
if (node_options->use_global_arguments) {
global_args = rcl_get_global_arguments();
global_args = &(node->context->global_arguments);
}
ret = rcl_remap_service_name(
&(node_options->arguments), global_args, expanded_service_name,
@ -200,7 +200,7 @@ rcl_client_fini(rcl_client_t * client, rcl_node_t * node)
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing client");
rcl_ret_t result = RCL_RET_OK;
RCL_CHECK_ARGUMENT_FOR_NULL(client, RCL_RET_INVALID_ARGUMENT);
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
if (client->impl) {

147
rcl/src/rcl/context.c Normal file
View file

@ -0,0 +1,147 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/context.h"
#include <stdbool.h>
#include "./context_impl.h"
#include "rcutils/stdatomic_helper.h"
rcl_context_t
rcl_get_zero_initialized_context(void)
{
static rcl_context_t context = {
.impl = NULL,
.instance_id_storage = {0},
};
// this is not constexpr so it cannot be in the struct initialization
context.global_arguments = rcl_get_zero_initialized_arguments();
// ensure assumption about static storage
static_assert(
sizeof(context.instance_id_storage) >= sizeof(atomic_uint_least64_t),
"expected rcl_context_t's instance id storage to be >= size of atomic_uint_least64_t");
// initialize atomic
atomic_init((atomic_uint_least64_t *)(&context.instance_id_storage), 0);
return context;
}
// See `rcl_init()` for initialization of the context.
rcl_ret_t
rcl_context_fini(rcl_context_t * context)
{
RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_FOR_NULL_WITH_MSG(
context->impl, "context is zero-initialized", return RCL_RET_INVALID_ARGUMENT);
if (rcl_context_is_valid(context)) {
RCL_SET_ERROR_MSG("rcl_shutdown() not called on the given context");
return RCL_RET_INVALID_ARGUMENT;
}
RCL_CHECK_ALLOCATOR_WITH_MSG(
&(context->impl->allocator), "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
__cleanup_context(context);
return RCL_RET_OK;
}
// See `rcl_shutdown()` for invalidation of the context.
const rcl_init_options_t *
rcl_context_get_init_options(rcl_context_t * context)
{
RCL_CHECK_ARGUMENT_FOR_NULL(context, NULL);
RCL_CHECK_FOR_NULL_WITH_MSG(context->impl, "context is zero-initialized", return NULL);
return &(context->impl->init_options);
}
rcl_context_instance_id_t
rcl_context_get_instance_id(rcl_context_t * context)
{
RCL_CHECK_ARGUMENT_FOR_NULL(context, 0);
return rcutils_atomic_load_uint64_t((atomic_uint_least64_t *)(&context->instance_id_storage));
}
bool
rcl_context_is_valid(rcl_context_t * context)
{
RCL_CHECK_ARGUMENT_FOR_NULL(context, false);
return 0 != rcl_context_get_instance_id(context);
}
void
__cleanup_context(rcl_context_t * context)
{
// if null, nothing can be done
if (NULL == context) {
return;
}
// reset the instance id to 0 to indicate "invalid" (should already be 0, but this is defensive)
rcutils_atomic_store((atomic_uint_least64_t *)(&context->instance_id_storage), 0);
// clean up global_arguments if initialized
if (NULL != context->global_arguments.impl) {
rcl_ret_t ret = rcl_arguments_fini(&(context->global_arguments));
if (RCL_RET_OK != ret) {
RCUTILS_SAFE_FWRITE_TO_STDERR(
"[rcl|init.c:" RCUTILS_STRINGIFY(__LINE__)
"] failed to finalize global arguments while cleaning up context, memory may be leaked: ");
RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
rcl_reset_error();
}
}
// if impl is null, nothing else can be cleaned up
if (NULL != context->impl) {
// pull allocator out for use during deallocation
rcl_allocator_t allocator = context->impl->allocator;
// finalize init options if valid
if (NULL != context->impl->init_options.impl) {
rcl_ret_t ret = rcl_init_options_fini(&(context->impl->init_options));
if (RCL_RET_OK != ret) {
RCUTILS_SAFE_FWRITE_TO_STDERR(
"[rcl|init.c:" RCUTILS_STRINGIFY(__LINE__)
"] failed to finalize init options while cleaning up context, memory may be leaked: ");
RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
rcl_reset_error();
}
}
// clean up copy of argv if valid
if (NULL != context->impl->argv) {
int64_t i;
for (i = 0; i < context->impl->argc; ++i) {
if (NULL != context->impl->argv[i]) {
allocator.deallocate(context->impl->argv[i], allocator.state);
}
}
allocator.deallocate(context->impl->argv, allocator.state);
}
} // if (NULL != context->impl)
// zero-initialize the context
*context = rcl_get_zero_initialized_context();
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,51 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__CONTEXT_IMPL_H_
#define RCL__CONTEXT_IMPL_H_
#include "rcl/context.h"
#include "rcl/error_handling.h"
#include "./init_options_impl.h"
#ifdef __cplusplus
extern "C"
{
#endif
/// \internal
typedef struct rcl_context_impl_t
{
/// Allocator used during init and shutdown.
rcl_allocator_t allocator;
/// Copy of init options given during init.
rcl_init_options_t init_options;
/// Length of argv (may be `0`).
int64_t argc;
/// Copy of argv used during init (may be `NULL`).
char ** argv;
/// rmw context.
rmw_context_t rmw_context;
} rcl_context_impl_t;
RCL_LOCAL
void
__cleanup_context(rcl_context_t * context);
#ifdef __cplusplus
}
#endif
#endif // RCL__CONTEXT_IMPL_H_

View file

@ -130,6 +130,9 @@ rcl_count_publishers(
const char * topic_name,
size_t * count)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
const rcl_node_options_t * node_options = rcl_node_get_options(node);
if (!node_options) {
return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
@ -146,6 +149,9 @@ rcl_count_subscribers(
const char * topic_name,
size_t * count)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
const rcl_node_options_t * node_options = rcl_node_get_options(node);
if (!node_options) {
return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
@ -162,6 +168,9 @@ rcl_service_server_is_available(
const rcl_client_t * client,
bool * is_available)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
const rcl_node_options_t * node_options = rcl_node_get_options(node);
if (!node_options) {
return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so

View file

@ -24,6 +24,8 @@ extern "C"
#include "rmw/error_handling.h"
#include "rmw/rmw.h"
#include "./context_impl.h"
typedef struct rcl_guard_condition_impl_t
{
rmw_guard_condition_t * rmw_handle;
@ -42,6 +44,7 @@ rcl_ret_t
__rcl_guard_condition_init_from_rmw_impl(
rcl_guard_condition_t * guard_condition,
const rmw_guard_condition_t * rmw_guard_condition,
rcl_context_t * context,
const rcl_guard_condition_options_t options)
{
// This function will create an rmw_guard_condition if the parameter is null.
@ -56,8 +59,11 @@ __rcl_guard_condition_init_from_rmw_impl(
return RCL_RET_ALREADY_INIT;
}
// Make sure rcl has been initialized.
if (!rcl_ok()) {
RCL_SET_ERROR_MSG("rcl_init() has not been called");
RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
if (!rcl_context_is_valid(context)) {
RCL_SET_ERROR_MSG(
"the given context is not valid, "
"either rcl_init() was not called or rcl_shutdown() was called.");
return RCL_RET_NOT_INIT;
}
// Allocate space for the guard condition impl.
@ -74,7 +80,7 @@ __rcl_guard_condition_init_from_rmw_impl(
guard_condition->impl->allocated_rmw_guard_condition = false;
} else {
// Otherwise create one.
guard_condition->impl->rmw_handle = rmw_create_guard_condition();
guard_condition->impl->rmw_handle = rmw_create_guard_condition(&(context->impl->rmw_context));
if (!guard_condition->impl->rmw_handle) {
// Deallocate impl and exit.
allocator->deallocate(guard_condition->impl, allocator->state);
@ -91,19 +97,22 @@ __rcl_guard_condition_init_from_rmw_impl(
rcl_ret_t
rcl_guard_condition_init(
rcl_guard_condition_t * guard_condition,
rcl_context_t * context,
const rcl_guard_condition_options_t options)
{
// NULL indicates "create a new rmw guard condition".
return __rcl_guard_condition_init_from_rmw_impl(guard_condition, NULL, options);
return __rcl_guard_condition_init_from_rmw_impl(guard_condition, NULL, context, options);
}
rcl_ret_t
rcl_guard_condition_init_from_rmw(
rcl_guard_condition_t * guard_condition,
const rmw_guard_condition_t * rmw_guard_condition,
rcl_context_t * context,
const rcl_guard_condition_options_t options)
{
return __rcl_guard_condition_init_from_rmw_impl(guard_condition, rmw_guard_condition, options);
return __rcl_guard_condition_init_from_rmw_impl(
guard_condition, rmw_guard_condition, context, options);
}
rcl_ret_t

178
rcl/src/rcl/init.c Normal file
View file

@ -0,0 +1,178 @@
// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/init.h"
#include "./arguments_impl.h"
#include "./common.h"
#include "./context_impl.h"
#include "./init_options_impl.h"
#include "rcl/arguments.h"
#include "rcl/error_handling.h"
#include "rcutils/logging_macros.h"
#include "rcutils/stdatomic_helper.h"
#include "rmw/error_handling.h"
static atomic_uint_least64_t __rcl_next_unique_id = ATOMIC_VAR_INIT(1);
rcl_ret_t
rcl_init(
int argc,
char const * const * argv,
const rcl_init_options_t * options,
rcl_context_t * context)
{
rcl_ret_t fail_ret = RCL_RET_ERROR;
if (argc > 0) {
RCL_CHECK_ARGUMENT_FOR_NULL(argv, RCL_RET_INVALID_ARGUMENT);
} else {
if (NULL != argv) {
RCL_SET_ERROR_MSG("argc is <= 0, but argv is not NULL");
return RCL_RET_INVALID_ARGUMENT;
}
}
RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(options->impl, RCL_RET_INVALID_ARGUMENT);
rcl_allocator_t allocator = options->impl->allocator;
RCL_CHECK_ALLOCATOR(&allocator, return RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
RCUTILS_LOG_DEBUG_NAMED(
ROS_PACKAGE_NAME,
"Initializing ROS client library, for context at address: %p", context);
// test expectation that given context is zero initialized
if (NULL != context->impl) {
// note that this can also occur when the given context is used before initialization
// i.e. it is declared on the stack but never defined or zero initialized
RCL_SET_ERROR_MSG("rcl_init called on an already initialized context");
return RCL_RET_ALREADY_INIT;
}
// Zero initialize global arguments.
context->global_arguments = rcl_get_zero_initialized_arguments();
// Setup impl for context.
// use zero_allocate so the cleanup function will not try to clean up uninitialized parts later
context->impl = allocator.zero_allocate(1, sizeof(rcl_context_impl_t), allocator.state);
RCL_CHECK_FOR_NULL_WITH_MSG(
context->impl, "failed to allocate memory for context impl", return RCL_RET_BAD_ALLOC);
// Copy the options into the context for future reference.
rcl_ret_t ret = rcl_init_options_copy(options, &(context->impl->init_options));
if (RCL_RET_OK != ret) {
fail_ret = ret; // error message already set
goto fail;
}
// Copy the argc and argv into the context, if argc >= 0.
context->impl->argc = argc;
context->impl->argv = NULL;
if (0 != argc && argv != NULL) {
context->impl->argv = (char **)allocator.zero_allocate(argc, sizeof(char *), allocator.state);
RCL_CHECK_FOR_NULL_WITH_MSG(
context->impl->argv,
"failed to allocate memory for argv",
fail_ret = RCL_RET_BAD_ALLOC; goto fail);
int64_t i;
for (i = 0; i < argc; ++i) {
size_t argv_i_length = strlen(argv[i]);
context->impl->argv[i] = (char *)allocator.allocate(argv_i_length, allocator.state);
RCL_CHECK_FOR_NULL_WITH_MSG(
context->impl->argv[i],
"failed to allocate memory for string entry in argv",
fail_ret = RCL_RET_BAD_ALLOC; goto fail);
memcpy(context->impl->argv[i], argv[i], argv_i_length);
}
}
// Parse the ROS specific arguments.
ret = rcl_parse_arguments(argc, argv, allocator, &context->global_arguments);
if (RCL_RET_OK != ret) {
fail_ret = ret;
RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to parse global arguments");
goto fail;
}
// Update the default log level if specified in arguments.
if (context->global_arguments.impl->log_level >= 0) {
rcutils_logging_set_default_logger_level(context->global_arguments.impl->log_level);
}
// Set the instance id.
uint64_t next_instance_id = rcutils_atomic_fetch_add_uint64_t(&__rcl_next_unique_id, 1);
if (0 == next_instance_id) {
// Roll over occurred, this is an extremely unlikely occurrence.
RCL_SET_ERROR_MSG("unique rcl instance ids exhausted");
// Roll back to try to avoid the next call succeeding, but there's a data race here.
rcutils_atomic_store(&__rcl_next_unique_id, -1);
goto fail;
}
rcutils_atomic_store((atomic_uint_least64_t *)(&context->instance_id_storage), next_instance_id);
context->impl->init_options.impl->rmw_init_options.instance_id = next_instance_id;
// Initialize rmw_init.
context->impl->rmw_context = rmw_get_zero_initialized_context();
rmw_ret_t rmw_ret = rmw_init(
&(context->impl->init_options.impl->rmw_init_options),
&(context->impl->rmw_context));
if (RMW_RET_OK != rmw_ret) {
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
fail_ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
goto fail;
}
// Store the allocator.
context->impl->allocator = allocator;
return RCL_RET_OK;
fail:
__cleanup_context(context);
return fail_ret;
}
rcl_ret_t
rcl_shutdown(rcl_context_t * context)
{
RCUTILS_LOG_DEBUG_NAMED(
ROS_PACKAGE_NAME,
"Shutting down ROS client library, for context at address: %p", context);
RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_FOR_NULL_WITH_MSG(
context->impl, "context is zero-initialized", return RCL_RET_INVALID_ARGUMENT);
if (!rcl_context_is_valid(context)) {
RCL_SET_ERROR_MSG("rcl_shutdown already called on the given context");
return RCL_RET_ALREADY_SHUTDOWN;
}
// reset the instance id to 0 to indicate "invalid"
rcutils_atomic_store((atomic_uint_least64_t *)(&context->instance_id_storage), 0);
rmw_ret_t rmw_ret = rmw_shutdown(&(context->impl->rmw_context));
if (RMW_RET_OK != rmw_ret) {
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
return RCL_RET_OK;
}
#ifdef __cplusplus
}
#endif

144
rcl/src/rcl/init_options.c Normal file
View file

@ -0,0 +1,144 @@
// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/init_options.h"
#include "./common.h"
#include "./init_options_impl.h"
#include "rcl/error_handling.h"
#include "rmw/error_handling.h"
#include "rcutils/logging_macros.h"
rcl_init_options_t
rcl_get_zero_initialized_init_options(void)
{
return (const rcl_init_options_t) {
.impl = 0,
}; // NOLINT(readability/braces): false positive
}
rcl_ret_t
rcl_init_options_init(rcl_init_options_t * init_options, rcl_allocator_t allocator)
{
RCL_CHECK_ARGUMENT_FOR_NULL(init_options, RCL_RET_INVALID_ARGUMENT);
if (NULL != init_options->impl) {
RCL_SET_ERROR_MSG("given init_options (rcl_init_options_t) is already initialized");
return RCL_RET_ALREADY_INIT;
}
RCL_CHECK_ALLOCATOR(&allocator, return RCL_RET_INVALID_ARGUMENT);
init_options->impl = allocator.allocate(sizeof(rcl_init_options_impl_t), allocator.state);
RCL_CHECK_FOR_NULL_WITH_MSG(
init_options->impl,
"failed to allocate memory for init options impl",
return RCL_RET_BAD_ALLOC);
init_options->impl->allocator = allocator;
init_options->impl->rmw_init_options = rmw_get_zero_initialized_init_options();
rmw_ret_t rmw_ret = rmw_init_options_init(&(init_options->impl->rmw_init_options), allocator);
if (RMW_RET_OK != rmw_ret) {
allocator.deallocate(init_options->impl, allocator.state);
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
return RCL_RET_OK;
}
rcl_ret_t
rcl_init_options_copy(const rcl_init_options_t * src, rcl_init_options_t * dst)
{
RCL_CHECK_ARGUMENT_FOR_NULL(src, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(src->impl, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(dst, RCL_RET_INVALID_ARGUMENT);
if (NULL != dst->impl) {
RCL_SET_ERROR_MSG("given dst (rcl_init_options_t) is already initialized");
return RCL_RET_ALREADY_INIT;
}
// initialize dst (since we know it's in a zero initialized state)
rcl_ret_t ret = rcl_init_options_init(dst, src->impl->allocator);
if (RCL_RET_OK != ret) {
return ret; // error already set
}
// copy src information into dst
dst->impl->allocator = src->impl->allocator;
// first zero-initialize rmw init options
rmw_ret_t rmw_ret = rmw_init_options_fini(&(dst->impl->rmw_init_options));
if (RMW_RET_OK != rmw_ret) {
rmw_error_string_t error_string = rmw_get_error_string();
rmw_reset_error();
ret = rcl_init_options_fini(dst);
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
"rcl",
"failed to finalize dst rcl_init_options while handling failure to "
"finalize rmw_init_options, original ret '%d' and error: %s", rmw_ret, error_string.str);
return ret; // error already set
}
RCL_SET_ERROR_MSG(error_string.str);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
// then copy
dst->impl->rmw_init_options = rmw_get_zero_initialized_init_options();
rmw_ret =
rmw_init_options_copy(&(src->impl->rmw_init_options), &(dst->impl->rmw_init_options));
if (RMW_RET_OK != rmw_ret) {
rmw_error_string_t error_string = rmw_get_error_string();
rmw_reset_error();
ret = rcl_init_options_fini(dst);
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
"rcl",
"failed to finalize dst rcl_init_options while handling failure to "
"copy rmw_init_options, original ret '%d' and error: %s", rmw_ret, error_string.str);
return ret; // error already set
}
RCL_SET_ERROR_MSG(error_string.str);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
return RCL_RET_OK;
}
rcl_ret_t
rcl_init_options_fini(rcl_init_options_t * init_options)
{
RCL_CHECK_ARGUMENT_FOR_NULL(init_options, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(init_options->impl, RCL_RET_INVALID_ARGUMENT);
rcl_allocator_t allocator = init_options->impl->allocator;
RCL_CHECK_ALLOCATOR(&allocator, return RCL_RET_INVALID_ARGUMENT);
rmw_ret_t rmw_ret = rmw_init_options_fini(&(init_options->impl->rmw_init_options));
if (RMW_RET_OK != rmw_ret) {
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
allocator.deallocate(init_options->impl, allocator.state);
return RCL_RET_OK;
}
rmw_init_options_t *
rcl_init_options_get_rmw_init_options(rcl_init_options_t * init_options)
{
RCL_CHECK_ARGUMENT_FOR_NULL(init_options, NULL);
RCL_CHECK_ARGUMENT_FOR_NULL(init_options->impl, NULL);
return &(init_options->impl->rmw_init_options);
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,38 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__INIT_OPTIONS_IMPL_H_
#define RCL__INIT_OPTIONS_IMPL_H_
#include "rcl/init_options.h"
#include "rmw/init.h"
#ifdef __cplusplus
extern "C"
{
#endif
/// \internal
typedef struct rcl_init_options_impl_t
{
rcl_allocator_t allocator;
rmw_init_options_t rmw_init_options;
} rcl_init_options_impl_t;
#ifdef __cplusplus
}
#endif
#endif // RCL__INIT_OPTIONS_IMPL_H_

View file

@ -44,7 +44,7 @@ extern "C"
#include "rmw/validate_node_name.h"
#include "./common.h"
#include "./context_impl.h"
#define ROS_SECURITY_NODE_DIRECTORY_VAR_NAME "ROS_SECURITY_NODE_DIRECTORY"
#define ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "ROS_SECURITY_ROOT_DIRECTORY"
@ -56,7 +56,6 @@ typedef struct rcl_node_impl_t
rcl_node_options_t options;
size_t actual_domain_id;
rmw_node_t * rmw_node_handle;
uint64_t rcl_instance_id;
rcl_guard_condition_t * graph_guard_condition;
const char * logger_name;
} rcl_node_impl_t;
@ -192,6 +191,7 @@ rcl_node_init(
rcl_node_t * node,
const char * name,
const char * namespace_,
rcl_context_t * context,
const rcl_node_options_t * options)
{
size_t domain_id = 0;
@ -218,8 +218,12 @@ rcl_node_init(
return RCL_RET_ALREADY_INIT;
}
// Make sure rcl has been initialized.
if (!rcl_ok()) {
RCL_SET_ERROR_MSG("rcl_init() has not been called");
RCL_CHECK_FOR_NULL_WITH_MSG(
context, "given context in options is NULL", return RCL_RET_INVALID_ARGUMENT);
if (!rcl_context_is_valid(context)) {
RCL_SET_ERROR_MSG(
"the given context is not valid, "
"either rcl_init() was not called or rcl_shutdown() was called.");
return RCL_RET_NOT_INIT;
}
// Make sure the node name is valid before allocating memory.
@ -277,6 +281,7 @@ rcl_node_init(
node->impl->graph_guard_condition = NULL;
node->impl->logger_name = NULL;
node->impl->options = rcl_node_get_default_options();
node->context = context;
// Initialize node impl.
ret = rcl_node_options_copy(options, &(node->impl->options));
if (RCL_RET_OK != ret) {
@ -286,7 +291,7 @@ rcl_node_init(
// Remap the node name and namespace if remap rules are given
rcl_arguments_t * global_args = NULL;
if (node->impl->options.use_global_arguments) {
global_args = rcl_get_global_arguments();
global_args = &(node->context->global_arguments);
}
ret = rcl_remap_node_name(
&(node->impl->options.arguments), global_args, name, *allocator,
@ -386,12 +391,11 @@ rcl_node_init(
}
}
node->impl->rmw_node_handle = rmw_create_node(
&(node->context->impl->rmw_context),
name, local_namespace_, domain_id, &node_security_options);
RCL_CHECK_FOR_NULL_WITH_MSG(
node->impl->rmw_node_handle, rmw_get_error_string().str, goto fail);
// instance id
node->impl->rcl_instance_id = rcl_get_instance_id();
// graph guard condition
rmw_graph_guard_condition = rmw_node_get_graph_guard_condition(node->impl->rmw_node_handle);
RCL_CHECK_FOR_NULL_WITH_MSG(
@ -408,6 +412,7 @@ rcl_node_init(
ret = rcl_guard_condition_init_from_rmw(
node->impl->graph_guard_condition,
rmw_graph_guard_condition,
context,
graph_guard_condition_options);
if (ret != RCL_RET_OK) {
// error message already set
@ -503,19 +508,29 @@ rcl_node_fini(rcl_node_t * node)
}
bool
rcl_node_is_valid(const rcl_node_t * node)
rcl_node_is_valid_except_context(const rcl_node_t * node)
{
RCL_CHECK_FOR_NULL_WITH_MSG(node, "rcl node pointer is invalid", return false);
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "rcl node implementation is invalid", return false);
if (node->impl->rcl_instance_id != rcl_get_instance_id()) {
RCL_SET_ERROR_MSG("rcl node is invalid, rcl instance id does not match");
return false;
}
RCL_CHECK_FOR_NULL_WITH_MSG(
node->impl->rmw_node_handle, "rcl node's rmw handle is invalid", return false);
return true;
}
bool
rcl_node_is_valid(const rcl_node_t * node)
{
bool result = rcl_node_is_valid_except_context(node);
if (!result) {
return result;
}
if (!rcl_context_is_valid(node->context)) {
RCL_SET_ERROR_MSG("rcl node's context is invalid");
return false;
}
return true;
}
rcl_node_options_t
rcl_node_get_default_options()
{
@ -554,7 +569,7 @@ rcl_node_options_copy(
const char *
rcl_node_get_name(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return node->impl->rmw_node_handle->name;
@ -563,7 +578,7 @@ rcl_node_get_name(const rcl_node_t * node)
const char *
rcl_node_get_namespace(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return node->impl->rmw_node_handle->namespace_;
@ -572,7 +587,7 @@ rcl_node_get_namespace(const rcl_node_t * node)
const rcl_node_options_t *
rcl_node_get_options(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return &node->impl->options;
@ -593,7 +608,7 @@ rcl_node_get_domain_id(const rcl_node_t * node, size_t * domain_id)
rmw_node_t *
rcl_node_get_rmw_handle(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return node->impl->rmw_node_handle;
@ -602,17 +617,16 @@ rcl_node_get_rmw_handle(const rcl_node_t * node)
uint64_t
rcl_node_get_rcl_instance_id(const rcl_node_t * node)
{
// Not using rcl_node_is_valid() since we can still get the
// instance ID from an initialized node, even if it is invalid
RCL_CHECK_ARGUMENT_FOR_NULL(node, 0);
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return 0);
return node->impl->rcl_instance_id;
if (!rcl_node_is_valid_except_context(node)) {
return 0; // error already set
}
return rcl_context_get_instance_id(node->context);
}
const struct rcl_guard_condition_t *
rcl_node_get_graph_guard_condition(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return node->impl->graph_guard_condition;
@ -621,7 +635,7 @@ rcl_node_get_graph_guard_condition(const rcl_node_t * node)
const char *
rcl_node_get_logger_name(const rcl_node_t * node)
{
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return NULL; // error already set
}
return node->impl->logger_name;

View file

@ -35,6 +35,7 @@ extern "C"
typedef struct rcl_publisher_impl_t
{
rcl_publisher_options_t options;
rcl_context_t * context;
rmw_publisher_t * rmw_handle;
} rcl_publisher_impl_t;
@ -130,7 +131,7 @@ rcl_publisher_init(
}
rcl_arguments_t * global_args = NULL;
if (node_options->use_global_arguments) {
global_args = rcl_get_global_arguments();
global_args = &(node->context->global_arguments);
}
ret = rcl_remap_topic_name(
&(node_options->arguments), global_args, expanded_topic_name,
@ -173,6 +174,8 @@ rcl_publisher_init(
// options
publisher->impl->options = *options;
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher initialized");
// context
publisher->impl->context = node->context;
goto cleanup;
fail:
if (publisher->impl) {
@ -195,7 +198,7 @@ rcl_publisher_fini(rcl_publisher_t * publisher, rcl_node_t * node)
{
rcl_ret_t result = RCL_RET_OK;
RCL_CHECK_ARGUMENT_FOR_NULL(publisher, RCL_RET_PUBLISHER_INVALID);
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
@ -232,7 +235,6 @@ rcl_publisher_get_default_options()
rcl_ret_t
rcl_publish(const rcl_publisher_t * publisher, const void * ros_message)
{
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Publisher publishing message");
if (!rcl_publisher_is_valid(publisher)) {
return RCL_RET_PUBLISHER_INVALID; // error already set
}
@ -266,7 +268,7 @@ rcl_publish_serialized_message(
const char *
rcl_publisher_get_topic_name(const rcl_publisher_t * publisher)
{
if (!rcl_publisher_is_valid(publisher)) {
if (!rcl_publisher_is_valid_except_context(publisher)) {
return NULL; // error already set
}
return publisher->impl->rmw_handle->topic_name;
@ -277,7 +279,7 @@ rcl_publisher_get_topic_name(const rcl_publisher_t * publisher)
const rcl_publisher_options_t *
rcl_publisher_get_options(const rcl_publisher_t * publisher)
{
if (!rcl_publisher_is_valid(publisher)) {
if (!rcl_publisher_is_valid_except_context(publisher)) {
return NULL; // error already set
}
return _publisher_get_options(publisher);
@ -286,14 +288,38 @@ rcl_publisher_get_options(const rcl_publisher_t * publisher)
rmw_publisher_t *
rcl_publisher_get_rmw_handle(const rcl_publisher_t * publisher)
{
if (!rcl_publisher_is_valid(publisher)) {
if (!rcl_publisher_is_valid_except_context(publisher)) {
return NULL; // error already set
}
return publisher->impl->rmw_handle;
}
rcl_context_t *
rcl_publisher_get_context(const rcl_publisher_t * publisher)
{
if (!rcl_publisher_is_valid_except_context(publisher)) {
return NULL; // error already set
}
return publisher->impl->context;
}
bool
rcl_publisher_is_valid(const rcl_publisher_t * publisher)
{
if (!rcl_publisher_is_valid_except_context(publisher)) {
return false; // error already set
}
if (!rcl_context_is_valid(publisher->impl->context)) {
RCL_SET_ERROR_MSG("publisher's context is invalid");
return false;
}
RCL_CHECK_FOR_NULL_WITH_MSG(
publisher->impl->rmw_handle, "publisher's rmw handle is invalid", return false);
return true;
}
bool
rcl_publisher_is_valid_except_context(const rcl_publisher_t * publisher)
{
RCL_CHECK_FOR_NULL_WITH_MSG(publisher, "publisher pointer is invalid", return false);
RCL_CHECK_FOR_NULL_WITH_MSG(

View file

@ -1,166 +0,0 @@
// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/rcl.h"
#include <string.h>
#include "./arguments_impl.h"
#include "rcl/arguments.h"
#include "rcl/error_handling.h"
#include "rcutils/logging_macros.h"
#include "rcutils/stdatomic_helper.h"
#include "rmw/error_handling.h"
static atomic_bool __rcl_is_initialized = ATOMIC_VAR_INIT(false);
static rcl_allocator_t __rcl_allocator;
static int __rcl_argc = 0;
static char ** __rcl_argv = NULL;
static atomic_uint_least64_t __rcl_instance_id = ATOMIC_VAR_INIT(0);
static uint64_t __rcl_next_unique_id = 0;
static void
__clean_up_init()
{
if (__rcl_argv) {
int i;
for (i = 0; i < __rcl_argc; ++i) {
if (__rcl_argv[i]) {
// Use the old allocator.
__rcl_allocator.deallocate(__rcl_argv[i], __rcl_allocator.state);
}
}
// Use the old allocator.
__rcl_allocator.deallocate(__rcl_argv, __rcl_allocator.state);
}
__rcl_argc = 0;
__rcl_argv = NULL;
// This is the only place where it is OK to finalize the global arguments.
rcl_arguments_t * global_args = rcl_get_global_arguments();
if (NULL != global_args->impl && RCL_RET_OK != rcl_arguments_fini(global_args)) {
rcl_reset_error();
}
rcutils_atomic_store(&__rcl_instance_id, 0);
rcutils_atomic_store(&__rcl_is_initialized, false);
}
rcl_ret_t
rcl_init(int argc, char const * const * argv, rcl_allocator_t allocator)
{
rcl_ret_t fail_ret = RCL_RET_ERROR;
// Check allocator first, so it can be used in other errors.
RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
if (argc > 0) {
RCL_CHECK_ARGUMENT_FOR_NULL(argv, RCL_RET_INVALID_ARGUMENT);
}
if (rcutils_atomic_exchange_bool(&__rcl_is_initialized, true)) {
RCL_SET_ERROR_MSG("rcl_init called while already initialized");
return RCL_RET_ALREADY_INIT;
}
// Zero initialize global arguments before any chance of calling __clean_up_init()
rcl_arguments_t * global_args = rcl_get_global_arguments();
*global_args = rcl_get_zero_initialized_arguments();
// There is a race condition between the time __rcl_is_initialized is set true,
// and when the allocator is set, in which rcl_shutdown() could get rcl_ok() as
// true and try to use the allocator, but it isn't set yet...
// A very unlikely race condition, but it is possile I think.
// I've documented that rcl_init() and rcl_shutdown() are not thread-safe with each other.
__rcl_allocator = allocator; // Set the new allocator.
// Initialize rmw_init.
rmw_ret_t rmw_ret = rmw_init();
if (rmw_ret != RMW_RET_OK) {
RCL_SET_ERROR_MSG(rmw_get_error_string().str);
fail_ret = RCL_RET_ERROR;
goto fail;
}
// TODO(wjwwood): Remove rcl specific command line arguments.
// For now just copy the argc and argv.
__rcl_argc = argc;
__rcl_argv = (char **)__rcl_allocator.allocate(sizeof(char *) * argc, __rcl_allocator.state);
if (!__rcl_argv) {
RCL_SET_ERROR_MSG("allocation failed");
fail_ret = RCL_RET_BAD_ALLOC;
goto fail;
}
memset(__rcl_argv, 0, sizeof(char **) * argc);
int i;
for (i = 0; i < argc; ++i) {
__rcl_argv[i] = (char *)__rcl_allocator.allocate(strlen(argv[i]), __rcl_allocator.state);
if (!__rcl_argv[i]) {
RCL_SET_ERROR_MSG("allocation failed");
fail_ret = RCL_RET_BAD_ALLOC;
goto fail;
}
memcpy(__rcl_argv[i], argv[i], strlen(argv[i]));
}
if (RCL_RET_OK != rcl_parse_arguments(argc, (const char **)argv, allocator, global_args)) {
RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to parse global arguments");
goto fail;
}
// Update the default log level if specified in arguments.
if (global_args->impl->log_level >= 0) {
rcutils_logging_set_default_logger_level(global_args->impl->log_level);
}
rcutils_atomic_store(&__rcl_instance_id, ++__rcl_next_unique_id);
if (rcutils_atomic_load_uint64_t(&__rcl_instance_id) == 0) {
// Roll over occurred.
__rcl_next_unique_id--; // roll back to avoid the next call succeeding.
RCL_SET_ERROR_MSG("unique rcl instance ids exhausted");
goto fail;
}
return RCL_RET_OK;
fail:
__clean_up_init();
return fail_ret;
}
rcl_ret_t
rcl_shutdown()
{
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Shutting down");
if (!rcl_ok()) {
// must use default allocator here because __rcl_allocator may not be set yet
RCL_SET_ERROR_MSG("rcl_shutdown called before rcl_init");
return RCL_RET_NOT_INIT;
}
__clean_up_init();
return RCL_RET_OK;
}
uint64_t
rcl_get_instance_id()
{
return rcutils_atomic_load_uint64_t(&__rcl_instance_id);
}
bool
rcl_ok()
{
return rcutils_atomic_load_bool(&__rcl_is_initialized);
}
#ifdef __cplusplus
}
#endif

View file

@ -129,10 +129,12 @@ INITIALIZER(initialize) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME,
"Error getting RMW implementation identifier / RMW implementation not installed "
"(expected identifier of '%s'), exiting with %d.",
"(expected identifier of '%s'), with error message '%s', exiting with %d.",
expected_rmw_impl,
rcl_get_error_string().str,
RCL_RET_ERROR
);
rcl_reset_error();
exit(RCL_RET_ERROR);
}
if (strcmp(actual_rmw_impl_id, expected_rmw_impl) != 0) {

View file

@ -129,7 +129,7 @@ rcl_service_init(
}
rcl_arguments_t * global_args = NULL;
if (node_options->use_global_arguments) {
global_args = rcl_get_global_arguments();
global_args = &(node->context->global_arguments);
}
ret = rcl_remap_service_name(
&(node_options->arguments), global_args, expanded_service_name,
@ -204,7 +204,7 @@ rcl_service_fini(rcl_service_t * service, rcl_node_t * node)
{
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing service");
RCL_CHECK_ARGUMENT_FOR_NULL(service, RCL_RET_SERVICE_INVALID);
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return RCL_RET_NODE_INVALID; // error already set
}

View file

@ -127,7 +127,7 @@ rcl_subscription_init(
}
rcl_arguments_t * global_args = NULL;
if (node_options->use_global_arguments) {
global_args = rcl_get_global_arguments();
global_args = &(node->context->global_arguments);
}
ret = rcl_remap_topic_name(
&(node_options->arguments), global_args, expanded_topic_name,
@ -197,7 +197,7 @@ rcl_subscription_fini(rcl_subscription_t * subscription, rcl_node_t * node)
RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing subscription");
rcl_ret_t result = RCL_RET_OK;
RCL_CHECK_ARGUMENT_FOR_NULL(subscription, RCL_RET_SUBSCRIPTION_INVALID);
if (!rcl_node_is_valid(node)) {
if (!rcl_node_is_valid_except_context(node)) {
return RCL_RET_NODE_INVALID; // error already set
}
if (subscription->impl) {

View file

@ -30,6 +30,8 @@ typedef struct rcl_timer_impl_t
{
// The clock providing time.
rcl_clock_t * clock;
// The associated context.
rcl_context_t * context;
// A guard condition used to wake a wait set if using ROSTime, else zero initialized.
rcl_guard_condition_t guard_condition;
// The user supplied callback.
@ -123,6 +125,7 @@ rcl_ret_t
rcl_timer_init(
rcl_timer_t * timer,
rcl_clock_t * clock,
rcl_context_t * context,
int64_t period,
const rcl_timer_callback_t callback,
rcl_allocator_t allocator)
@ -147,10 +150,11 @@ rcl_timer_init(
}
rcl_timer_impl_t impl;
impl.clock = clock;
impl.context = context;
impl.guard_condition = rcl_get_zero_initialized_guard_condition();
if (RCL_ROS_TIME == impl.clock->type) {
rcl_guard_condition_options_t options = rcl_guard_condition_get_default_options();
rcl_ret_t ret = rcl_guard_condition_init(&(impl.guard_condition), options);
rcl_ret_t ret = rcl_guard_condition_init(&(impl.guard_condition), context, options);
if (RCL_RET_OK != ret) {
return ret;
}

View file

@ -61,6 +61,7 @@ function(test_target_function)
rcl_add_custom_gtest(test_get_node_names${target_suffix}
SRCS rcl/test_get_node_names.cpp
INCLUDE_DIRS ${osrf_testing_tools_cpp_INCLUDE_DIRS}
ENV ${rmw_implementation_env_var}
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
LIBRARIES ${PROJECT_NAME}
@ -111,8 +112,8 @@ function(test_target_function)
AMENT_DEPENDENCIES ${rmw_implementation} "test_msgs"
)
rcl_add_custom_gtest(test_rcl${target_suffix}
SRCS rcl/test_rcl.cpp
rcl_add_custom_gtest(test_init${target_suffix}
SRCS rcl/test_init.cpp
ENV ${rmw_implementation_env_var} ${memory_tools_ld_preload_env_var}
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
LIBRARIES ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools

View file

@ -15,12 +15,12 @@
#ifndef RCL__ARG_MACROS_HPP_
#define RCL__ARG_MACROS_HPP_
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/error_handling.h"
#include "rcl/rcl.h"
#include "rcutils/strdup.h"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
/// Helper to get around non-const args passed to rcl_init().
char **
copy_args(int argc, const char ** args)
@ -45,17 +45,22 @@ destroy_args(int argc, char ** args)
}
#define SCOPE_GLOBAL_ARGS(argc, argv, ...) \
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options(); \
ASSERT_EQ(RCL_RET_OK, rcl_init_options_init(&init_options, rcl_get_default_allocator())) \
<< rcl_get_error_string().str; \
rcl_context_t context = rcl_get_zero_initialized_context(); \
{ \
const char * const_argv[] = {__VA_ARGS__}; \
argc = (sizeof(const_argv) / sizeof(const char *)); \
argv = copy_args(argc, const_argv); \
rcl_ret_t ret = rcl_init(argc, argv, rcl_get_default_allocator()); \
rcl_ret_t ret = rcl_init(argc, argv, &init_options, &context); \
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; \
} \
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({ \
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str; \
destroy_args(argc, argv); \
rcl_ret_t ret = rcl_shutdown(); \
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str; \
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context)) << rcl_get_error_string().str; \
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context)) << rcl_get_error_string().str; \
})
#define SCOPE_ARGS(local_arguments, ...) \

View file

@ -108,15 +108,36 @@ int main(int argc, char ** argv)
{
int main_ret = 0;
{
if (rcl_init(argc, argv, rcl_get_default_allocator()) != RCL_RET_OK) {
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in rcl init options init: %s", rcl_get_error_string().str);
return -1;
}
rcl_context_t context = rcl_get_zero_initialized_context();
if (rcl_init(argc, argv, &init_options, &context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in rcl init: %s", rcl_get_error_string().str);
return -1;
}
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
if (rcl_shutdown(&context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error shutting down rcl: %s", rcl_get_error_string().str);
main_ret = -1;
}
if (rcl_context_fini(&context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error finalizing rcl context: %s", rcl_get_error_string().str);
main_ret = -1;
}
});
ret = rcl_init_options_fini(&init_options);
rcl_node_t node = rcl_get_zero_initialized_node();
const char * name = "client_fixture_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
if (rcl_node_init(&node, name, "", &node_options) != RCL_RET_OK) {
if (rcl_node_init(&node, name, "", &context, &node_options) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in node init: %s", rcl_get_error_string().str);
return -1;
@ -135,7 +156,7 @@ int main(int argc, char ** argv)
rcl_client_t client = rcl_get_zero_initialized_client();
rcl_client_options_t client_options = rcl_client_get_default_options();
rcl_ret_t ret = rcl_client_init(&client, &node, ts, service_name, &client_options);
ret = rcl_client_init(&client, &node, ts, service_name, &client_options);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in client init: %s", rcl_get_error_string().str);

View file

@ -81,15 +81,36 @@ int main(int argc, char ** argv)
{
int main_ret = 0;
{
if (rcl_init(argc, argv, rcl_get_default_allocator()) != RCL_RET_OK) {
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in rcl init options init: %s", rcl_get_error_string().str);
return -1;
}
rcl_context_t context = rcl_get_zero_initialized_context();
if (rcl_init(argc, argv, &init_options, &context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in rcl init: %s", rcl_get_error_string().str);
return -1;
}
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
if (rcl_shutdown(&context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error shutting down rcl: %s", rcl_get_error_string().str);
main_ret = -1;
}
if (rcl_context_fini(&context) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error finalizing rcl context: %s", rcl_get_error_string().str);
main_ret = -1;
}
});
ret = rcl_init_options_fini(&init_options);
rcl_node_t node = rcl_get_zero_initialized_node();
const char * name = "service_fixture_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
if (rcl_node_init(&node, name, "", &node_options) != RCL_RET_OK) {
if (rcl_node_init(&node, name, "", &context, &node_options) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in node init: %s", rcl_get_error_string().str);
return -1;
@ -108,7 +129,7 @@ int main(int argc, char ** argv)
rcl_service_t service = rcl_get_zero_initialized_service();
rcl_service_options_t service_options = rcl_service_get_default_options();
rcl_ret_t ret = rcl_service_init(&service, &node, ts, service_name, &service_options);
ret = rcl_service_init(&service, &node, ts, service_name, &service_options);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
ROS_PACKAGE_NAME, "Error in service init: %s", rcl_get_error_string().str);

View file

@ -28,17 +28,28 @@
class TestClientFixture : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_client_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -47,7 +58,8 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -99,18 +99,24 @@ class CLASSNAME (TestCountFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_node_t * node_ptr;
rcl_context_t * context_ptr;
rcl_wait_set_t * wait_set_ptr;
void SetUp()
{
rcl_ret_t ret;
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_count_node";
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->wait_set_ptr = new rcl_wait_set_t;
@ -130,7 +136,11 @@ public:
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -21,6 +21,7 @@
#include "rcutils/types.h"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/graph.h"
#include "rcl/rcl.h"
#include "rmw/rmw.h"
@ -47,14 +48,26 @@ public:
};
TEST_F(CLASSNAME(TestGetNodeNames, RMW_IMPLEMENTATION), test_rcl_get_node_names) {
auto ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_ret_t ret;
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_shutdown(&context)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(&context)) << rcl_get_error_string().str;
});
auto node1_ptr = new rcl_node_t;
*node1_ptr = rcl_get_zero_initialized_node();
const char * node1_name = "node1";
const char * node1_namespace = "/";
rcl_node_options_t node1_options = rcl_node_get_default_options();
ret = rcl_node_init(node1_ptr, node1_name, node1_namespace, &node1_options);
ret = rcl_node_init(node1_ptr, node1_name, node1_namespace, &context, &node1_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
auto node2_ptr = new rcl_node_t;
@ -62,7 +75,7 @@ TEST_F(CLASSNAME(TestGetNodeNames, RMW_IMPLEMENTATION), test_rcl_get_node_names)
const char * node2_name = "node2";
const char * node2_namespace = "/";
rcl_node_options_t node2_options = rcl_node_get_default_options();
ret = rcl_node_init(node2_ptr, node2_name, node2_namespace, &node2_options);
ret = rcl_node_init(node2_ptr, node2_name, node2_namespace, &context, &node2_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
auto node3_ptr = new rcl_node_t;
@ -70,7 +83,7 @@ TEST_F(CLASSNAME(TestGetNodeNames, RMW_IMPLEMENTATION), test_rcl_get_node_names)
const char * node3_name = "node3";
const char * node3_namespace = "/ns";
rcl_node_options_t node3_options = rcl_node_get_default_options();
ret = rcl_node_init(node3_ptr, node3_name, node3_namespace, &node3_options);
ret = rcl_node_init(node3_ptr, node3_name, node3_namespace, &context, &node3_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
auto node4_ptr = new rcl_node_t;
@ -78,7 +91,7 @@ TEST_F(CLASSNAME(TestGetNodeNames, RMW_IMPLEMENTATION), test_rcl_get_node_names)
const char * node4_name = "node2";
const char * node4_namespace = "/ns/ns";
rcl_node_options_t node4_options = rcl_node_get_default_options();
ret = rcl_node_init(node4_ptr, node4_name, node4_namespace, &node4_options);
ret = rcl_node_init(node4_ptr, node4_name, node4_namespace, &context, &node4_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
std::this_thread::sleep_for(1s);
@ -126,7 +139,4 @@ TEST_F(CLASSNAME(TestGetNodeNames, RMW_IMPLEMENTATION), test_rcl_get_node_names)
ret = rcl_node_fini(node4_ptr);
delete node4_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}

View file

@ -51,29 +51,42 @@ bool is_connext =
class CLASSNAME (TestGraphFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_context_t * old_context_ptr;
rcl_context_t * context_ptr;
rcl_node_t * old_node_ptr;
rcl_node_t * node_ptr;
rcl_wait_set_t * wait_set_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->old_context_ptr = new rcl_context_t;
*this->old_context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->old_context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->old_node_ptr = new rcl_node_t;
*this->old_node_ptr = rcl_get_zero_initialized_node();
const char * old_name = "old_node_name";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->old_node_ptr, old_name, "", &node_options);
ret = rcl_node_init(this->old_node_ptr, old_name, "", this->old_context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown(); // after this, the old_node_ptr should be invalid
ret = rcl_shutdown(this->old_context_ptr); // after this, the old_node_ptr should be invalid
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_graph_node";
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->wait_set_ptr = new rcl_wait_set_t;
@ -96,8 +109,14 @@ public:
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
delete this->context_ptr;
ret = rcl_context_fini(this->old_context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
delete this->old_context_ptr;
}
};

View file

@ -63,13 +63,21 @@ TEST_F(
rcl_ret_t ret;
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret);
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads();
ASSERT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options));
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
// Setup automatic rcl_shutdown()
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads();
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
// Create a zero initialized guard_condition (but not initialized).
@ -78,7 +86,7 @@ TEST_F(
// Create a normal guard_condition.
rcl_guard_condition_options_t default_options = rcl_guard_condition_get_default_options();
rcl_guard_condition_t guard_condition = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_condition, default_options);
ret = rcl_guard_condition_init(&guard_condition, &context, default_options);
ASSERT_EQ(RCL_RET_OK, ret);
// Setup automatic finalization of guard condition.
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
@ -121,22 +129,34 @@ TEST_F(
TEST_F(
CLASSNAME(TestGuardConditionFixture, RMW_IMPLEMENTATION), test_rcl_guard_condition_life_cycle) {
rcl_ret_t ret;
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_guard_condition_t guard_condition = rcl_get_zero_initialized_guard_condition();
rcl_guard_condition_options_t default_options = rcl_guard_condition_get_default_options();
// Trying to init before rcl_init() should fail.
ret = rcl_guard_condition_init(&guard_condition, default_options);
ret = rcl_guard_condition_init(&guard_condition, &context, default_options);
ASSERT_EQ(RCL_RET_NOT_INIT, ret) << "Expected RCL_RET_NOT_INIT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret);
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads();
ASSERT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options));
});
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
});
// Try invalid arguments.
ret = rcl_guard_condition_init(nullptr, default_options);
ret = rcl_guard_condition_init(nullptr, &context, default_options);
ASSERT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << "Expected RCL_RET_INVALID_ARGUMENT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
// Now with nullptr for context.
ret = rcl_guard_condition_init(&guard_condition, nullptr, default_options);
ASSERT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << "Expected RCL_RET_INVALID_ARGUMENT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -146,7 +166,7 @@ TEST_F(
options_with_invalid_allocator.allocator.allocate = nullptr;
options_with_invalid_allocator.allocator.deallocate = nullptr;
options_with_invalid_allocator.allocator.reallocate = nullptr;
ret = rcl_guard_condition_init(&guard_condition, options_with_invalid_allocator);
ret = rcl_guard_condition_init(&guard_condition, &context, options_with_invalid_allocator);
ASSERT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << "Expected RCL_RET_INVALID_ARGUMENT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -156,12 +176,10 @@ TEST_F(
options_with_failing_allocator.allocator.allocate = failing_malloc;
options_with_failing_allocator.allocator.reallocate = failing_realloc;
options_with_failing_allocator.allocator.zero_allocate = failing_calloc;
ret = rcl_guard_condition_init(&guard_condition, options_with_failing_allocator);
ret = rcl_guard_condition_init(&guard_condition, &context, options_with_failing_allocator);
ASSERT_EQ(RCL_RET_BAD_ALLOC, ret) << "Expected RCL_RET_BAD_ALLOC";
// The error will not be set because the allocator will not work.
// It should, however, print a message to the screen and get the bad alloc ret code.
// ASSERT_TRUE(rcl_error_is_set());
// rcl_reset_error();
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
// Try fini with invalid arguments.
ret = rcl_guard_condition_fini(nullptr);
@ -172,14 +190,14 @@ TEST_F(
ret = rcl_guard_condition_fini(&guard_condition);
EXPECT_EQ(RCL_RET_OK, ret);
// Try a normal init and fini.
ret = rcl_guard_condition_init(&guard_condition, default_options);
ret = rcl_guard_condition_init(&guard_condition, &context, default_options);
EXPECT_EQ(RCL_RET_OK, ret);
ret = rcl_guard_condition_fini(&guard_condition);
EXPECT_EQ(RCL_RET_OK, ret);
// Try repeated init and fini calls.
ret = rcl_guard_condition_init(&guard_condition, default_options);
ret = rcl_guard_condition_init(&guard_condition, &context, default_options);
EXPECT_EQ(RCL_RET_OK, ret);
ret = rcl_guard_condition_init(&guard_condition, default_options);
ret = rcl_guard_condition_init(&guard_condition, &context, default_options);
EXPECT_EQ(RCL_RET_ALREADY_INIT, ret) << "Expected RCL_RET_ALREADY_INIT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();

View file

@ -18,10 +18,13 @@
#include "./failing_allocator_functions.hpp"
#include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/error_handling.h"
#include "rcutils/format_string.h"
#include "rcutils/snprintf.h"
#include "../src/rcl/init_options_impl.h"
#ifdef RMW_IMPLEMENTATION
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
@ -99,29 +102,32 @@ private:
*/
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_and_ok_and_shutdown) {
rcl_ret_t ret;
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_context_t context = rcl_get_zero_initialized_context();
// A shutdown before any init has been called should fail.
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_NOT_INIT, ret);
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
// If argc is not 0, but argv is, it should be an invalid argument.
ret = rcl_init(42, nullptr, rcl_get_default_allocator());
ret = rcl_init(42, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
// If either the allocate or deallocate function pointers are not set, it should be invalid arg.
rcl_allocator_t invalid_allocator = rcl_get_default_allocator();
invalid_allocator.allocate = nullptr;
ret = rcl_init(0, nullptr, invalid_allocator);
init_options.impl->allocator.allocate = nullptr;
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
invalid_allocator.allocate = rcl_get_default_allocator().allocate;
invalid_allocator.deallocate = nullptr;
ret = rcl_init(0, nullptr, invalid_allocator);
ASSERT_FALSE(rcl_context_is_valid(&context));
init_options.impl->allocator.allocate = rcl_get_default_allocator().allocate;
init_options.impl->allocator.deallocate = nullptr;
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
// If the malloc call fails (with some valid arguments to copy), it should be a bad alloc.
{
FakeTestArgv test_args;
@ -129,97 +135,127 @@ TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_and_ok_and_s
failing_allocator.allocate = failing_malloc;
failing_allocator.reallocate = failing_realloc;
failing_allocator.zero_allocate = failing_calloc;
ret = rcl_init(test_args.argc, test_args.argv, failing_allocator);
init_options.impl->allocator = failing_allocator;
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
}
init_options.impl->allocator = rcl_get_default_allocator();
// If argc is 0 and argv is nullptr and the allocator is valid, it should succeed.
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_TRUE(rcl_ok());
ASSERT_TRUE(rcl_context_is_valid(&context));
// Then shutdown should work.
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK);
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
context = rcl_get_zero_initialized_context();
// Valid argc/argv values and a valid allocator should succeed.
{
FakeTestArgv test_args;
ret = rcl_init(test_args.argc, test_args.argv, rcl_get_default_allocator());
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_TRUE(rcl_ok());
ASSERT_TRUE(rcl_context_is_valid(&context));
}
// Then shutdown should work.
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_FALSE(rcl_ok());
// A repeat call to shutdown should not work.
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_NOT_INIT, ret);
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK);
ASSERT_FALSE(rcl_context_is_valid(&context));
// Then a repeated shutdown should fail.
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_ALREADY_SHUTDOWN);
ASSERT_FALSE(rcl_context_is_valid(&context));
rcl_reset_error();
ASSERT_FALSE(rcl_ok());
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
context = rcl_get_zero_initialized_context();
// A repeat call to shutdown should not work.
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// Repeat, but valid, calls to rcl_init() should fail.
{
FakeTestArgv test_args;
ret = rcl_init(test_args.argc, test_args.argv, rcl_get_default_allocator());
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_TRUE(rcl_ok());
ret = rcl_init(test_args.argc, test_args.argv, rcl_get_default_allocator());
ASSERT_TRUE(rcl_context_is_valid(&context));
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_ALREADY_INIT, ret);
rcl_reset_error();
ASSERT_TRUE(rcl_ok());
ASSERT_TRUE(rcl_context_is_valid(&context));
}
// But shutdown should still work.
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK);
ASSERT_FALSE(rcl_ok());
ASSERT_FALSE(rcl_context_is_valid(&context));
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
context = rcl_get_zero_initialized_context();
}
/* Tests the rcl_get_instance_id() and rcl_ok() functions.
*/
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_get_instance_id_and_ok) {
rcl_ret_t ret;
rcl_context_t context = rcl_get_zero_initialized_context();
// Instance id should be 0 before rcl_init().
EXPECT_EQ(0u, rcl_get_instance_id());
ASSERT_FALSE(rcl_ok());
EXPECT_EQ(0u, rcl_context_get_instance_id(&context));
ASSERT_FALSE(rcl_context_is_valid(&context));
// It should still return 0 after an invalid init.
ret = rcl_init(1, nullptr, rcl_get_default_allocator());
ret = rcl_init(1, nullptr, nullptr, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
EXPECT_EQ(0u, rcl_get_instance_id());
ASSERT_FALSE(rcl_ok());
EXPECT_EQ(0u, rcl_context_get_instance_id(&context));
ASSERT_FALSE(rcl_context_is_valid(&context));
rcl_reset_error();
// A non-zero instance id should be returned after a valid init.
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
{
FakeTestArgv test_args;
ret = rcl_init(test_args.argc, test_args.argv, rcl_get_default_allocator());
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_TRUE(rcl_ok());
ASSERT_TRUE(rcl_context_is_valid(&context));
}
// And it should be allocation free.
uint64_t first_instance_id;
EXPECT_NO_MEMORY_OPERATIONS({
first_instance_id = rcl_get_instance_id();
first_instance_id = rcl_context_get_instance_id(&context);
});
EXPECT_NE(0u, first_instance_id);
EXPECT_EQ(first_instance_id, rcl_get_instance_id()); // Repeat calls should return the same.
EXPECT_EQ(true, rcl_ok());
// Repeat calls should return the same.
EXPECT_EQ(first_instance_id, rcl_context_get_instance_id(&context));
EXPECT_EQ(true, rcl_context_is_valid(&context));
// Calling after a shutdown should return 0.
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK);
EXPECT_EQ(0u, rcl_get_instance_id());
ASSERT_FALSE(rcl_ok());
EXPECT_EQ(0u, rcl_context_get_instance_id(&context));
ASSERT_FALSE(rcl_context_is_valid(&context));
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
context = rcl_get_zero_initialized_context();
// It should return a different value after another valid init.
{
FakeTestArgv test_args;
ret = rcl_init(test_args.argc, test_args.argv, rcl_get_default_allocator());
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
ASSERT_TRUE(rcl_ok());
ASSERT_TRUE(rcl_context_is_valid(&context));
}
EXPECT_NE(0u, rcl_get_instance_id());
EXPECT_NE(first_instance_id, rcl_get_instance_id());
ASSERT_TRUE(rcl_ok());
EXPECT_NE(0u, rcl_context_get_instance_id(&context));
EXPECT_NE(first_instance_id, rcl_context_get_instance_id(&context));
ASSERT_TRUE(rcl_context_is_valid(&context));
// Shutting down a second time should result in 0 again.
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK);
EXPECT_EQ(0u, rcl_context_get_instance_id(&context));
ASSERT_FALSE(rcl_context_is_valid(&context));
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
EXPECT_EQ(0u, rcl_get_instance_id());
ASSERT_FALSE(rcl_ok());
}

View file

@ -86,7 +86,14 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
osrf_testing_tools_cpp::memory_tools::enable_monitoring_in_all_threads();
rcl_ret_t ret;
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t invalid_context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &invalid_context);
ASSERT_EQ(RCL_RET_OK, ret); // Shutdown later after invalid node.
// Create an invalid node (rcl_shutdown).
rcl_node_t invalid_node = rcl_get_zero_initialized_node();
@ -94,13 +101,13 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
const char * namespace_ = "/ns";
rcl_node_options_t default_options = rcl_node_get_default_options();
default_options.domain_id = 42; // Set the domain id to something explicit.
ret = rcl_node_init(&invalid_node, name, namespace_, &default_options);
ret = rcl_node_init(&invalid_node, name, namespace_, &invalid_context, &default_options);
if (is_windows && is_opensplice) {
// On Windows with OpenSplice, setting the domain id is not expected to work.
ASSERT_NE(RCL_RET_OK, ret);
// So retry with the default domain id setting (uses the environment as is).
default_options.domain_id = rcl_node_get_default_options().domain_id;
ret = rcl_node_init(&invalid_node, name, namespace_, &default_options);
ret = rcl_node_init(&invalid_node, name, namespace_, &invalid_context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
} else {
// This is the normal check (not windows and windows if not opensplice)
@ -111,20 +118,24 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
rcl_ret_t ret = rcl_node_fini(&invalid_node);
EXPECT_EQ(RCL_RET_OK, ret);
});
ret = rcl_shutdown(); // Shutdown to invalidate the node.
ret = rcl_shutdown(&invalid_context); // Shutdown to invalidate the node.
ASSERT_EQ(RCL_RET_OK, ret);
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(&invalid_context)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads();
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
// Create a zero init node.
rcl_node_t zero_node = rcl_get_zero_initialized_node();
// Create a normal node.
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, namespace_, &default_options);
ret = rcl_node_init(&node, name, namespace_, &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
osrf_testing_tools_cpp::memory_tools::disable_monitoring_in_all_threads();
@ -139,9 +150,15 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
is_valid = rcl_node_is_valid(&zero_node);
EXPECT_FALSE(is_valid);
rcl_reset_error();
// invalid node will be true for rcl_node_is_valid_except_context, but false for valid only
is_valid = rcl_node_is_valid_except_context(&invalid_node);
EXPECT_TRUE(is_valid);
rcl_reset_error();
is_valid = rcl_node_is_valid(&invalid_node);
EXPECT_FALSE(is_valid);
rcl_reset_error();
is_valid = rcl_node_is_valid(&node);
EXPECT_TRUE(is_valid);
rcl_reset_error();
@ -154,14 +171,17 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, actual_node_name);
rcl_reset_error();
actual_node_name = rcl_node_get_name(&invalid_node);
EXPECT_EQ(nullptr, actual_node_name);
EXPECT_TRUE(actual_node_name ? true : false);
if (actual_node_name) {
EXPECT_STREQ(name, actual_node_name);
}
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
actual_node_name = rcl_node_get_name(&node);
});
EXPECT_TRUE(actual_node_name ? true : false);
if (actual_node_name) {
EXPECT_EQ(std::string(name), std::string(actual_node_name));
EXPECT_STREQ(name, actual_node_name);
}
// Test rcl_node_get_namespace().
const char * actual_node_namespace;
@ -172,7 +192,10 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, actual_node_namespace);
rcl_reset_error();
actual_node_namespace = rcl_node_get_namespace(&invalid_node);
EXPECT_EQ(nullptr, actual_node_namespace);
EXPECT_TRUE(actual_node_namespace ? true : false);
if (actual_node_namespace) {
EXPECT_STREQ(namespace_, actual_node_namespace);
}
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
actual_node_namespace = rcl_node_get_namespace(&node);
@ -190,7 +213,10 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, actual_node_logger_name);
rcl_reset_error();
actual_node_logger_name = rcl_node_get_logger_name(&invalid_node);
EXPECT_EQ(nullptr, actual_node_logger_name);
EXPECT_TRUE(actual_node_logger_name ? true : false);
if (actual_node_logger_name) {
EXPECT_EQ("ns." + std::string(name), std::string(actual_node_logger_name));
}
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
actual_node_logger_name = rcl_node_get_logger_name(&node);
@ -208,7 +234,11 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, actual_options);
rcl_reset_error();
actual_options = rcl_node_get_options(&invalid_node);
EXPECT_EQ(nullptr, actual_options);
EXPECT_NE(nullptr, actual_options);
if (actual_options) {
EXPECT_EQ(default_options.allocator.allocate, actual_options->allocator.allocate);
EXPECT_EQ(default_options.domain_id, actual_options->domain_id);
}
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
actual_options = rcl_node_get_options(&node);
@ -229,8 +259,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
ret = rcl_node_get_domain_id(&invalid_node, &actual_domain_id);
EXPECT_EQ(RCL_RET_NODE_INVALID, ret);
ASSERT_TRUE(rcl_error_is_set());
EXPECT_EQ(RCL_RET_OK, ret);
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
ret = rcl_node_get_domain_id(&node, &actual_domain_id);
@ -249,7 +278,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, node_handle);
rcl_reset_error();
node_handle = rcl_node_get_rmw_handle(&invalid_node);
EXPECT_EQ(nullptr, node_handle);
EXPECT_NE(nullptr, node_handle);
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
node_handle = rcl_node_get_rmw_handle(&node);
@ -264,15 +293,14 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(0u, instance_id);
rcl_reset_error();
instance_id = rcl_node_get_rcl_instance_id(&invalid_node);
EXPECT_NE(0u, instance_id);
EXPECT_NE(42u, instance_id);
EXPECT_EQ(0u, instance_id);
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
instance_id = rcl_node_get_rcl_instance_id(&node);
});
EXPECT_NE(0u, instance_id);
// Test rcl_node_get_graph_guard_condition
const rcl_guard_condition_t * graph_guard_condition = nullptr;
const rcl_guard_condition_t * graph_guard_condition;
graph_guard_condition = rcl_node_get_graph_guard_condition(nullptr);
EXPECT_EQ(nullptr, graph_guard_condition);
rcl_reset_error();
@ -280,7 +308,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
EXPECT_EQ(nullptr, graph_guard_condition);
rcl_reset_error();
graph_guard_condition = rcl_node_get_graph_guard_condition(&invalid_node);
EXPECT_EQ(nullptr, graph_guard_condition);
EXPECT_NE(nullptr, graph_guard_condition);
rcl_reset_error();
EXPECT_NO_MEMORY_OPERATIONS({
graph_guard_condition = rcl_node_get_graph_guard_condition(&node);
@ -292,36 +320,47 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_accessors)
*/
TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_life_cycle) {
rcl_ret_t ret;
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_node_t node = rcl_get_zero_initialized_node();
const char * name = "test_rcl_node_life_cycle_node";
const char * namespace_ = "/ns";
rcl_node_options_t default_options = rcl_node_get_default_options();
// Trying to init before rcl_init() should fail.
ret = rcl_node_init(&node, name, "", &default_options);
ret = rcl_node_init(&node, name, "", &context, &default_options);
ASSERT_EQ(RCL_RET_NOT_INIT, ret) << "Expected RCL_RET_NOT_INIT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
// Try invalid arguments.
ret = rcl_node_init(nullptr, name, namespace_, &default_options);
ret = rcl_node_init(nullptr, name, namespace_, &context, &default_options);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
ret = rcl_node_init(&node, nullptr, namespace_, &default_options);
ret = rcl_node_init(&node, nullptr, namespace_, &context, &default_options);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
ret = rcl_node_init(&node, name, nullptr, &default_options);
ret = rcl_node_init(&node, name, nullptr, &context, &default_options);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
ret = rcl_node_init(&node, name, namespace_, nullptr);
ret = rcl_node_init(&node, name, namespace_, nullptr, &default_options);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
ret = rcl_node_init(&node, name, namespace_, &context, nullptr);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -330,7 +369,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_life_cycle)
options_with_invalid_allocator.allocator.allocate = nullptr;
options_with_invalid_allocator.allocator.deallocate = nullptr;
options_with_invalid_allocator.allocator.reallocate = nullptr;
ret = rcl_node_init(&node, name, namespace_, &options_with_invalid_allocator);
ret = rcl_node_init(&node, name, namespace_, &context, &options_with_invalid_allocator);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret) << "Expected RCL_RET_INVALID_ARGUMENT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -338,12 +377,10 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_life_cycle)
rcl_node_options_t options_with_failing_allocator = rcl_node_get_default_options();
options_with_failing_allocator.allocator.allocate = failing_malloc;
options_with_failing_allocator.allocator.reallocate = failing_realloc;
ret = rcl_node_init(&node, name, namespace_, &options_with_failing_allocator);
ret = rcl_node_init(&node, name, namespace_, &context, &options_with_failing_allocator);
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret) << "Expected RCL_RET_BAD_ALLOC";
// The error will not be set because the allocator will not work.
// It should, however, print a message to the screen and get the bad alloc ret code.
// ASSERT_TRUE(rcl_error_is_set());
// rcl_reset_error();
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
// Try fini with invalid arguments.
ret = rcl_node_fini(nullptr);
@ -354,14 +391,14 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_life_cycle)
ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
// Try a normal init and fini.
ret = rcl_node_init(&node, name, namespace_, &default_options);
ret = rcl_node_init(&node, name, namespace_, &context, &default_options);
EXPECT_EQ(RCL_RET_OK, ret);
ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
// Try repeated init and fini calls.
ret = rcl_node_init(&node, name, namespace_, &default_options);
ret = rcl_node_init(&node, name, namespace_, &context, &default_options);
EXPECT_EQ(RCL_RET_OK, ret);
ret = rcl_node_init(&node, name, namespace_, &default_options);
ret = rcl_node_init(&node, name, namespace_, &context, &default_options);
EXPECT_EQ(RCL_RET_ALREADY_INIT, ret) << "Expected RCL_RET_ALREADY_INIT";
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -372,7 +409,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_life_cycle)
// Try with a specific domain id.
rcl_node_options_t options_with_custom_domain_id = rcl_node_get_default_options();
options_with_custom_domain_id.domain_id = 42;
ret = rcl_node_init(&node, name, namespace_, &options_with_custom_domain_id);
ret = rcl_node_init(&node, name, namespace_, &context, &options_with_custom_domain_id);
if (is_windows && is_opensplice) {
// A custom domain id is not expected to work on Windows with Opensplice.
EXPECT_NE(RCL_RET_OK, ret);
@ -390,11 +427,18 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_name_restri
rcl_ret_t ret;
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
const char * namespace_ = "/ns";
@ -403,7 +447,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_name_restri
// First do a normal node name.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, "my_node_42", namespace_, &default_options);
ret = rcl_node_init(&node, "my_node_42", namespace_, &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
@ -412,7 +456,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_name_restri
// Node name with invalid characters.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, "my_node_42$", namespace_, &default_options);
ret = rcl_node_init(&node, "my_node_42$", namespace_, &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAME, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -423,7 +467,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_name_restri
// Node name with /, which is valid in a topic, but not a node name.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, "my/node_42", namespace_, &default_options);
ret = rcl_node_init(&node, "my/node_42", namespace_, &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAME, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -434,7 +478,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_name_restri
// Node name with {}, which is valid in a topic, but not a node name.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, "my_{node}_42", namespace_, &default_options);
ret = rcl_node_init(&node, "my_{node}_42", namespace_, &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAME, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -449,11 +493,18 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
rcl_ret_t ret;
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
const char * name = "node";
@ -462,7 +513,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// First do a normal node namespace.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns", &default_options);
ret = rcl_node_init(&node, name, "/ns", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
@ -471,7 +522,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Node namespace which is an empty string, which is also valid.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "", &default_options);
ret = rcl_node_init(&node, name, "", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_STREQ("/", rcl_node_get_namespace(&node));
rcl_ret_t ret = rcl_node_fini(&node);
@ -481,7 +532,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Node namespace which is just a forward slash, which is valid.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/", &default_options);
ret = rcl_node_init(&node, name, "/", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
rcl_ret_t ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret);
@ -490,7 +541,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Node namespaces with invalid characters.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns/{name}", &default_options);
ret = rcl_node_init(&node, name, "/ns/{name}", &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAMESPACE, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -499,7 +550,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
}
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/~/", &default_options);
ret = rcl_node_init(&node, name, "/~/", &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAMESPACE, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -510,7 +561,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Node namespace with a trailing / which is not allowed.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns/foo/", &default_options);
ret = rcl_node_init(&node, name, "/ns/foo/", &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAMESPACE, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -521,7 +572,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Node namespace which is not absolute, it should get / added automatically.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "ns", &default_options);
ret = rcl_node_init(&node, name, "ns", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_STREQ("/ns", rcl_node_get_namespace(&node));
rcl_ret_t ret = rcl_node_fini(&node);
@ -531,7 +582,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_namespace_r
// Other reasons for being invalid, which are related to being part of a topic.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/starts/with/42number", &default_options);
ret = rcl_node_init(&node, name, "/starts/with/42number", &context, &default_options);
ASSERT_EQ(RCL_RET_NODE_INVALID_NAMESPACE, ret);
ASSERT_TRUE(rcl_error_is_set());
rcl_reset_error();
@ -546,11 +597,18 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
rcl_ret_t ret;
// Initialize rcl with rcl_init().
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
rcl_ret_t ret = rcl_shutdown();
ASSERT_EQ(RCL_RET_OK, ret);
ASSERT_EQ(RCL_RET_OK, rcl_shutdown(&context));
ASSERT_EQ(RCL_RET_OK, rcl_context_fini(&context));
});
const char * name = "node";
@ -560,7 +618,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
// First do a normal node namespace.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns", &default_options);
ret = rcl_node_init(&node, name, "/ns", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
@ -574,7 +632,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
// Node namespace that is an empty string.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "", &default_options);
ret = rcl_node_init(&node, name, "", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
@ -588,7 +646,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
// Node namespace that is just a forward slash.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/", &default_options);
ret = rcl_node_init(&node, name, "/", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
@ -602,7 +660,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
// Node namespace that is not absolute.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "ns", &default_options);
ret = rcl_node_init(&node, name, "ns", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);
@ -616,7 +674,7 @@ TEST_F(CLASSNAME(TestNodeFixture, RMW_IMPLEMENTATION), test_rcl_node_logger_name
// Nested namespace.
{
rcl_node_t node = rcl_get_zero_initialized_node();
ret = rcl_node_init(&node, name, "/ns/sub_1/sub_2", &default_options);
ret = rcl_node_init(&node, name, "/ns/sub_1/sub_2", &context, &default_options);
ASSERT_EQ(RCL_RET_OK, ret);
actual_node_logger_name = rcl_node_get_logger_name(&node);
EXPECT_TRUE(actual_node_logger_name ? true : false);

View file

@ -34,17 +34,28 @@
class CLASSNAME (TestPublisherFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_publisher_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -53,7 +64,10 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -50,7 +50,9 @@ TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), remap_using_g
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_node_options_t default_options = rcl_node_get_default_options();
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &default_options));
ASSERT_EQ(
RCL_RET_OK,
rcl_node_init(&node, "original_name", "/original_ns", &context, &default_options));
{ // Node name gets remapped
EXPECT_STREQ("new_name", rcl_node_get_name(&node));
@ -118,7 +120,7 @@ TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), ignore_global
rcl_node_options_t options = rcl_node_get_default_options();
options.use_global_arguments = false;
options.arguments = local_arguments;
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &options));
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &context, &options));
{ // Node name does not get remapped
EXPECT_STREQ("original_name", rcl_node_get_name(&node));
@ -187,7 +189,7 @@ TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), local_rules_b
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_node_options_t options = rcl_node_get_default_options();
options.arguments = local_arguments;
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &options));
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/original_ns", &context, &options));
{ // Node name
EXPECT_STREQ("local_name", rcl_node_get_name(&node));
@ -250,7 +252,7 @@ TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), remap_relativ
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_node_options_t default_options = rcl_node_get_default_options();
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/foo", &default_options));
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "/foo", &context, &default_options));
{ // Publisher topic
const rosidl_message_type_support_t * ts =
@ -305,7 +307,7 @@ TEST_F(CLASSNAME(TestRemapIntegrationFixture, RMW_IMPLEMENTATION), remap_using_n
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_node_options_t default_options = rcl_node_get_default_options();
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "", &default_options));
ASSERT_EQ(RCL_RET_OK, rcl_node_init(&node, "original_name", "", &context, &default_options));
{ // Node namespace gets remapped
EXPECT_STREQ("/new_ns", rcl_node_get_namespace(&node));

View file

@ -16,7 +16,22 @@
int main(int, char **)
{
rcl_ret_t ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
if (ret != RCL_RET_OK) {
return ret;
}
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
if (ret != RCL_RET_OK) {
return ret;
}
ret = rcl_init_options_fini(&init_options);
ret = rcl_shutdown(&context);
if (ret != RCL_RET_OK) {
return ret;
}
ret = rcl_context_fini(&context);
if (ret != RCL_RET_OK) {
return ret;
}

View file

@ -37,17 +37,28 @@
class CLASSNAME (TestServiceFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_service_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -56,7 +67,10 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -37,17 +37,28 @@
class CLASSNAME (TestSubscriptionFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_subscription_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -56,7 +67,10 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -26,17 +26,28 @@
class TestTimerFixture : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_publisher_node";
const char * name = "test_timer_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -45,7 +56,10 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};
@ -61,10 +75,12 @@ TEST_F(TestTimerFixture, test_two_timers) {
rcl_timer_t timer = rcl_get_zero_initialized_timer();
rcl_timer_t timer2 = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_timer_init(&timer2, &clock, RCL_MS_TO_NS(20), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer2, &clock, this->context_ptr, RCL_MS_TO_NS(20), nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
@ -115,10 +131,12 @@ TEST_F(TestTimerFixture, test_two_timers_ready_before_timeout) {
rcl_timer_t timer = rcl_get_zero_initialized_timer();
rcl_timer_t timer2 = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_timer_init(&timer2, &clock, RCL_MS_TO_NS(10), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer2, &clock, this->context_ptr, RCL_MS_TO_NS(10), nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
@ -168,7 +186,8 @@ TEST_F(TestTimerFixture, test_timer_not_ready) {
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, RCL_MS_TO_NS(5), nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
@ -212,7 +231,8 @@ TEST_F(TestTimerFixture, test_canceled_timer) {
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, 500, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, 500, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_timer_cancel(&timer);
@ -264,7 +284,8 @@ TEST_F(TestTimerFixture, test_rostime_time_until_next_call) {
ASSERT_EQ(RCL_RET_OK, rcl_enable_ros_time_override(&clock)) << rcl_get_error_string().str;
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, sec_5, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, sec_5, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(&timer)) << rcl_get_error_string().str;
@ -300,7 +321,8 @@ TEST_F(TestTimerFixture, test_system_time_to_ros_time) {
});
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, sec_5, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, sec_5, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(&timer)) << rcl_get_error_string().str;
@ -340,7 +362,8 @@ TEST_F(TestTimerFixture, test_ros_time_to_system_time) {
ASSERT_EQ(RCL_RET_OK, rcl_enable_ros_time_override(&clock)) << rcl_get_error_string().str;
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, sec_5, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, sec_5, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(&timer)) << rcl_get_error_string().str;
@ -383,7 +406,8 @@ TEST_F(TestTimerFixture, test_ros_time_backwards_jump) {
ASSERT_EQ(RCL_RET_OK, rcl_enable_ros_time_override(&clock)) << rcl_get_error_string().str;
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, sec_5, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, sec_5, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(&timer)) << rcl_get_error_string().str;
@ -424,7 +448,8 @@ TEST_F(TestTimerFixture, test_ros_time_wakes_wait) {
ASSERT_EQ(RCL_RET_OK, rcl_enable_ros_time_override(&clock)) << rcl_get_error_string().str;
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, sec_1, nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, sec_1, nullptr, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(&timer)) << rcl_get_error_string().str;

View file

@ -41,18 +41,27 @@
class CLASSNAME (WaitSetTestFixture, RMW_IMPLEMENTATION) : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
void TearDown()
{
rcl_ret_t ret;
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_shutdown(this->context_ptr)) << rcl_get_error_string().str;
EXPECT_EQ(RCL_RET_OK, rcl_context_fini(this->context_ptr)) << rcl_get_error_string().str;
delete this->context_ptr;
}
};
@ -102,7 +111,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), negative_timeout) {
// Add a dummy guard condition to avoid an error
rcl_guard_condition_t guard_cond = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_cond, rcl_guard_condition_get_default_options());
ret = rcl_guard_condition_init(
&guard_cond, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(&wait_set, &guard_cond, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -113,7 +123,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), negative_timeout) {
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_timer_t timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(&timer, &clock, RCL_MS_TO_NS(10), nullptr, rcl_get_default_allocator());
ret = rcl_timer_init(
&timer, &clock, this->context_ptr, RCL_MS_TO_NS(10), nullptr, rcl_get_default_allocator());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_timer(&wait_set, &timer, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -146,7 +157,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), zero_timeout) {
// Add a dummy guard condition to avoid an error
rcl_guard_condition_t guard_cond = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_cond, rcl_guard_condition_get_default_options());
ret = rcl_guard_condition_init(
&guard_cond, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(&wait_set, &guard_cond, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -176,7 +188,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), zero_timeout_triggered
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_guard_condition_t guard_cond = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_cond, rcl_guard_condition_get_default_options());
ret = rcl_guard_condition_init(
&guard_cond, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(&wait_set, &guard_cond, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -209,7 +222,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), canceled_timer) {
// Add a dummy guard condition to avoid an error
rcl_guard_condition_t guard_cond = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_cond, rcl_guard_condition_get_default_options());
ret = rcl_guard_condition_init(
&guard_cond, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(&wait_set, &guard_cond, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -221,7 +235,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), canceled_timer) {
rcl_timer_t canceled_timer = rcl_get_zero_initialized_timer();
ret = rcl_timer_init(
&canceled_timer, &clock, RCL_MS_TO_NS(1), nullptr, rcl_get_default_allocator());
&canceled_timer, &clock, this->context_ptr,
RCL_MS_TO_NS(1), nullptr, rcl_get_default_allocator());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_timer_cancel(&canceled_timer);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -334,7 +349,7 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), multi_wait_set_threade
// setup the guard condition
test_set.guard_condition = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(
&test_set.guard_condition, rcl_guard_condition_get_default_options());
&test_set.guard_condition, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
// setup the wait set
test_set.wait_set = rcl_get_zero_initialized_wait_set();
@ -398,7 +413,8 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), guard_condition) {
rcl_ret_t ret = rcl_wait_set_init(&wait_set, 0, 1, 0, 0, 0, rcl_get_default_allocator());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_guard_condition_t guard_cond = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(&guard_cond, rcl_guard_condition_get_default_options());
ret = rcl_guard_condition_init(
&guard_cond, this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(&wait_set, &guard_cond, NULL);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -452,7 +468,7 @@ TEST_F(CLASSNAME(WaitSetTestFixture, RMW_IMPLEMENTATION), add_with_index) {
for (size_t i = 0u; i < kNumEntities; ++i) {
guard_conditions[i] = rcl_get_zero_initialized_guard_condition();
ret = rcl_guard_condition_init(
&guard_conditions[i], rcl_guard_condition_get_default_options());
&guard_conditions[i], this->context_ptr, rcl_guard_condition_get_default_options());
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_add_guard_condition(
&wait_set, &guard_conditions[i], &guard_condition_index);

View file

@ -33,17 +33,28 @@ using namespace std::chrono_literals;
class TestNamespaceFixture : public ::testing::Test
{
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "rcl_test_namespace_node";
const char * name = "test_namespace_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -52,7 +63,10 @@ public:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -77,6 +77,7 @@ install(TARGETS ${PROJECT_NAME}
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_lint_auto REQUIRED)
find_package(osrf_testing_tools_cpp REQUIRED)
find_package(test_msgs REQUIRED)
ament_lint_auto_find_test_dependencies()
ament_find_gtest()
@ -87,6 +88,7 @@ if(BUILD_TESTING)
if(TARGET test_action_client)
target_include_directories(test_action_client PUBLIC
include
${osrf_testing_tools_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_action_client
${PROJECT_NAME}

View file

@ -24,6 +24,7 @@
<test_depend>ament_cmake_gtest</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>osrf_testing_tools_cpp</test_depend>
<test_depend>test_msgs</test_depend>
<export>

View file

@ -19,6 +19,7 @@
#include "rcl/error_handling.h"
#include "rcl/rcl.h"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "test_msgs/action/fibonacci.h"
class TestActionClientBaseFixture : public ::testing::Test
@ -26,12 +27,22 @@ class TestActionClientBaseFixture : public ::testing::Test
protected:
void SetUp() override
{
rcl_ret_t ret = rcl_init(0, nullptr, rcl_get_default_allocator());
rcl_ret_t ret;
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &this->context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node = rcl_get_zero_initialized_node();
rcl_node_options_t node_options = rcl_node_get_default_options();
const char * node_name = "test_action_client_node";
ret = rcl_node_init(&this->node, node_name, "", &node_options);
ret = rcl_node_init(&this->node, node_name, "", &this->context, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -39,10 +50,11 @@ protected:
{
rcl_ret_t ret = rcl_node_fini(&this->node);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(&this->context);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
rcl_context_t context;
rcl_node_t node;
};

View file

@ -37,11 +37,16 @@ protected:
void SetUp() override
{
rcl_allocator_t allocator = rcl_get_default_allocator();
rcl_ret_t ret = rcl_init(0, nullptr, allocator);
rcl_ret_t ret;
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, allocator);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->node = rcl_get_zero_initialized_node();
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(&this->node, "test_action_communication_node", "", &node_options);
ret = rcl_node_init(&this->node, "test_action_communication_node", "", &context, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_clock_init(RCL_STEADY_TIME, &this->clock, &allocator);
const rosidl_action_type_support_t * ts = ROSIDL_GET_ACTION_TYPE_SUPPORT(
@ -107,11 +112,11 @@ protected:
ret = rcl_action_client_fini(&this->action_client, &this->node);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
ret = rcl_node_fini(&this->node);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
ret = rcl_shutdown();
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_wait_set_fini(&this->wait_set);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
ret = rcl_shutdown(&context);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
rcl_reset_error();
}
@ -131,6 +136,7 @@ protected:
rcl_action_client_t action_client;
rcl_action_server_t action_server;
rcl_context_t context;
rcl_node_t node;
rcl_clock_t clock;

View file

@ -26,12 +26,17 @@
TEST(TestActionServerInitFini, test_action_server_init_fini)
{
rcl_allocator_t allocator = rcl_get_default_allocator();
rcl_ret_t ret = rcl_init(0, nullptr, allocator);
rcl_ret_t ret;
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, allocator);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_node_t node = rcl_get_zero_initialized_node();
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(&node, "test_action_server_node", "", &node_options);
ret = rcl_node_init(&node, "test_action_server_node", "", &context, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_clock_t clock;
ret = rcl_clock_init(RCL_STEADY_TIME, &clock, &allocator);
@ -133,7 +138,7 @@ TEST(TestActionServerInitFini, test_action_server_init_fini)
ret = rcl_node_fini(&node);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -143,11 +148,16 @@ protected:
void SetUp() override
{
rcl_allocator_t allocator = rcl_get_default_allocator();
rcl_ret_t ret = rcl_init(0, nullptr, allocator);
rcl_ret_t ret;
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, allocator);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
this->node = rcl_get_zero_initialized_node();
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(&this->node, "test_action_server_node", "", &node_options);
ret = rcl_node_init(&this->node, "test_action_server_node", "", &context, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_clock_init(RCL_ROS_TIME, &this->clock, &allocator);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
@ -170,7 +180,7 @@ protected:
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
ret = rcl_node_fini(&this->node);
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
@ -189,6 +199,7 @@ protected:
}
rcl_action_server_t action_server;
rcl_context_t context;
rcl_node_t node;
rcl_clock_t clock;
}; // class TestActionServer

View file

@ -61,6 +61,7 @@ if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_lint_auto REQUIRED)
find_package(rcl REQUIRED)
find_package(osrf_testing_tools_cpp REQUIRED)
ament_lint_auto_find_test_dependencies()
# Gtests
@ -70,6 +71,7 @@ if(BUILD_TESTING)
if(TARGET test_default_state_machine)
target_include_directories(test_default_state_machine PUBLIC
${rcl_INCLUDE_DIRS}
${osrf_testing_tools_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_default_state_machine ${PROJECT_NAME})
endif()
@ -79,6 +81,7 @@ if(BUILD_TESTING)
if(TARGET test_multiple_instances)
target_include_directories(test_multiple_instances PUBLIC
${rcl_INCLUDE_DIRS}
${osrf_testing_tools_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_multiple_instances ${PROJECT_NAME})
endif()

View file

@ -24,6 +24,7 @@
<test_depend>ament_cmake_gtest</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>osrf_testing_tools_cpp</test_depend>
<export>
<build_type>ament_cmake</build_type>

View file

@ -19,6 +19,8 @@
#include <gtest/gtest.h>
#include <vector>
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "lifecycle_msgs/msg/state.h"
#include "lifecycle_msgs/msg/transition.h"
@ -32,20 +34,30 @@
class TestDefaultStateMachine : public ::testing::Test
{
protected:
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
const rcl_allocator_t * allocator;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_state_machine_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
const rcl_node_options_t * node_ops = rcl_node_get_options(this->node_ptr);
this->allocator = &node_ops->allocator;
@ -56,7 +68,10 @@ protected:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};

View file

@ -19,6 +19,8 @@
#include <gtest/gtest.h>
#include <vector>
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "lifecycle_msgs/msg/state.h"
#include "lifecycle_msgs/msg/transition.h"
@ -30,19 +32,30 @@
class TestMultipleInstances : public ::testing::Test
{
protected:
public:
rcl_context_t * context_ptr;
rcl_node_t * node_ptr;
const rcl_allocator_t * allocator;
void SetUp()
{
rcl_ret_t ret;
ret = rcl_init(0, nullptr, rcl_get_default_allocator());
{
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT({
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
this->context_ptr = new rcl_context_t;
*this->context_ptr = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, this->context_ptr);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
this->node_ptr = new rcl_node_t;
*this->node_ptr = rcl_get_zero_initialized_node();
const char * name = "test_multiple_instances_node";
const char * name = "test_state_machine_node";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(this->node_ptr, name, "", &node_options);
ret = rcl_node_init(this->node_ptr, name, "", this->context_ptr, &node_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
const rcl_node_options_t * node_ops = rcl_node_get_options(this->node_ptr);
this->allocator = &node_ops->allocator;
@ -53,7 +66,10 @@ protected:
rcl_ret_t ret = rcl_node_fini(this->node_ptr);
delete this->node_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_shutdown();
ret = rcl_shutdown(this->context_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
ret = rcl_context_fini(this->context_ptr);
delete this->context_ptr;
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
}
};