implement allocator, node, and rcl functions
This commit is contained in:
parent
bac3b210d7
commit
2f029b560e
5 changed files with 408 additions and 0 deletions
37
rcl/src/rcl/allocator.c
Normal file
37
rcl/src/rcl/allocator.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
// 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.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
|
||||
static void *
|
||||
__default_allocate(size_t size, void * state)
|
||||
{
|
||||
(void)state; // unused
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void
|
||||
__default_deallocate(void * pointer, void * state)
|
||||
{
|
||||
(void)state; // unused
|
||||
return free(pointer);
|
||||
}
|
||||
|
||||
rcl_allocator_t
|
||||
rcl_get_default_allocator()
|
||||
{
|
||||
return {__default_allocate, __default_deallocate, NULL};
|
||||
}
|
48
rcl/src/rcl/common.c
Normal file
48
rcl/src/rcl/common.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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.
|
||||
|
||||
#if __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "./common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
static char __env_buffer[1024];
|
||||
#endif
|
||||
|
||||
rcl_ret_t
|
||||
rcl_impl_getenv(const char * env_name, char ** env_value)
|
||||
{
|
||||
env_value = NULL;
|
||||
#if !defined(WIN32)
|
||||
*env_value = getenv(env_name);
|
||||
#else
|
||||
size_t required_size;
|
||||
error_t ret = getenv_s(&required_size, __env_buffer, sizeof(__env_buffer), env_name);
|
||||
if (ret != 0) {
|
||||
RCL_SET_ERROR_MSG("value in env variable too large to read in");
|
||||
return RCL_RET_ERROR;
|
||||
}
|
||||
env_value = __env_buffer;
|
||||
#endif
|
||||
return RCL_RET_OK;
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
42
rcl/src/rcl/common.h
Normal file
42
rcl/src/rcl/common.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// 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.
|
||||
|
||||
#ifndef RCL__COMMON_H_
|
||||
#define RCL__COMMON_H_
|
||||
|
||||
#if __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/types.h"
|
||||
|
||||
#define RCL_CHECK_PARAMETER_FOR_NULL(parameter, error_return_type) \
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(parameter, #parameter " parameter is null", return error_return_type)
|
||||
|
||||
#define RCL_CHECK_FOR_NULL_WITH_MSG(value, msg, error_statement) if (!value) { \
|
||||
RCL_SET_ERROR_MSG(msg); \
|
||||
error_statement; \
|
||||
}
|
||||
|
||||
// This value put in env_value is only valid until the next call to rcl_impl_getenv (on Windows).
|
||||
rcl_ret_t
|
||||
rcl_impl_getenv(const char * env_name, char ** env_value);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RCL__COMMON_H_
|
173
rcl/src/rcl/node.c
Normal file
173
rcl/src/rcl/node.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
// 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.
|
||||
|
||||
#if __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rcl/node.h"
|
||||
#include "rcl/rcl.h"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
#include "./common.h"
|
||||
|
||||
typedef struct rcl_node_impl_t {
|
||||
char * name;
|
||||
rcl_node_options_t options;
|
||||
rmw_node_t * rmw_node_handle;
|
||||
uint64_t rcl_instance_id;
|
||||
} rcl_node_impl_t;
|
||||
|
||||
rcl_node_t
|
||||
rcl_get_uninitialized_node()
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
|
||||
rcl_ret_t
|
||||
rcl_node_init(rcl_node_t * node, const char * name, const rcl_node_options_t * options)
|
||||
{
|
||||
size_t domain_id = 0;
|
||||
char * ros_domain_id;
|
||||
rcl_ret_t ret;
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(name, RCL_RET_ERROR);
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(options, RCL_RET_ERROR);
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, RCL_RET_ERROR);
|
||||
if (node->impl) {
|
||||
RCL_SET_ERROR_MSG(
|
||||
"either double call to rcl_node_init or rcl_get_uninitialized_node was not used");
|
||||
return RCL_RET_ERROR;
|
||||
}
|
||||
const rcl_allocator_t * allocator = &options->allocator;
|
||||
// Allocate space for the implementation struct.
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(allocator->allocate, "allocate not set", return RCL_RET_ERROR);
|
||||
node->impl = (rcl_node_impl_t *)allocator->allocate(sizeof(rcl_node_impl_t), allocator->state);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "allocating memory failed", return RCL_RET_ERROR);
|
||||
// Initialize node impl.
|
||||
// node name
|
||||
size_t name_len = strlen(name);
|
||||
if (name_len == 0) {
|
||||
RCL_SET_ERROR_MSG("node name cannot be empty string");
|
||||
goto fail;
|
||||
}
|
||||
node->impl->name = (char *)allocator->allocate(strlen(name), allocator->state);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl->name, "allocating memory failed", goto fail);
|
||||
strncpy(node->impl->name, name, strlen(name));
|
||||
// node options
|
||||
node->impl->options = *options;
|
||||
// node rmw_node_handle
|
||||
// First determine the ROS_DOMAIN_ID.
|
||||
// The result of rcl_impl_getenv on Windows is only valid until the next call to rcl_impl_getenv.
|
||||
ret = rcl_impl_getenv("ROS_DOMAIN_ID", &ros_domain_id);
|
||||
if (ret != RCL_RET_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (ros_domain_id) {
|
||||
auto number = strtoul(ros_domain_id, NULL, 0);
|
||||
if (number == ULONG_MAX) {
|
||||
RCL_SET_ERROR_MSG("failed to interpret ROS_DOMAIN_ID as integral number");
|
||||
goto fail;
|
||||
}
|
||||
domain_id = (size_t)number;
|
||||
}
|
||||
node->impl->rmw_node_handle = rmw_create_node(name, domain_id);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(
|
||||
node->impl->rmw_node_handle, rmw_get_error_string_safe(), goto fail);
|
||||
node->impl->rcl_instance_id = rcl_get_instance_id();
|
||||
return RCL_RET_OK;
|
||||
fail:
|
||||
if (node->impl->name) {
|
||||
allocator->deallocate(node->impl->name, allocator->state);
|
||||
}
|
||||
if (node->impl) {
|
||||
allocator->deallocate(node->impl, allocator->state);
|
||||
}
|
||||
return RCL_RET_ERROR;
|
||||
}
|
||||
|
||||
rcl_ret_t
|
||||
rcl_node_fini(rcl_node_t * node)
|
||||
{
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, RCL_RET_ERROR);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return RCL_RET_ERROR);
|
||||
rcl_ret_t result = RCL_RET_OK;
|
||||
rmw_ret_t node_ret = rmw_destroy_node(node->impl->rmw_node_handle);
|
||||
if (node_ret != RMW_RET_OK) {
|
||||
RCL_SET_ERROR_MSG(rmw_get_error_string_safe());
|
||||
result = RCL_RET_ERROR;
|
||||
}
|
||||
rcl_allocator_t allocator = node->impl->options.allocator;
|
||||
allocator.deallocate(node->impl->name, allocator.state);
|
||||
allocator.deallocate(node->impl, allocator.state);
|
||||
return result;
|
||||
}
|
||||
|
||||
rcl_node_options_t
|
||||
rcl_node_get_default_options()
|
||||
{
|
||||
return {false, rcl_get_default_allocator()};
|
||||
}
|
||||
|
||||
const char *
|
||||
rcl_node_get_name(const rcl_node_t * node)
|
||||
{
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, NULL);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return NULL);
|
||||
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 NULL;
|
||||
}
|
||||
return node->impl->name;
|
||||
}
|
||||
|
||||
const rcl_node_options_t *
|
||||
rcl_node_get_options(const rcl_node_t * node)
|
||||
{
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, NULL);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return NULL);
|
||||
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 NULL;
|
||||
}
|
||||
return &node->impl->options;
|
||||
}
|
||||
|
||||
rmw_node_t *
|
||||
rcl_node_get_rmw_node_handle(const rcl_node_t * node)
|
||||
{
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, NULL);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return NULL);
|
||||
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 NULL;
|
||||
}
|
||||
return node->impl->rmw_node_handle;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
rcl_node_get_rcl_instance_id(const rcl_node_t * node)
|
||||
{
|
||||
RCL_CHECK_PARAMETER_FOR_NULL(node, NULL);
|
||||
RCL_CHECK_FOR_NULL_WITH_MSG(node->impl, "node implementation is invalid", return NULL);
|
||||
return node->impl->rcl_instance_id;
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
108
rcl/src/rcl/rcl.c
Normal file
108
rcl/src/rcl/rcl.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
// 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.
|
||||
|
||||
#if __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "rcl/rcl.h"
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
static atomic_bool __rcl_is_initialized = false;
|
||||
static rcl_allocator_t __rcl_allocator = {0};
|
||||
static int __rcl_argc = 0;
|
||||
static char ** __rcl_argv = NULL;
|
||||
static atomic_uint_fast64_t __rcl_instance_id = 0;
|
||||
static uint64_t __rcl_next_unique_id = 0;
|
||||
|
||||
static inline void
|
||||
__clean_up_init()
|
||||
{
|
||||
if (__rcl_argv) {
|
||||
for (size_t i = 0; i < __rcl_argc; ++i) {
|
||||
if (__rcl_argv[i]) {
|
||||
__rcl_allocator.deallocate(__rcl_argv[i], __rcl_allocator.state);
|
||||
}
|
||||
}
|
||||
__rcl_allocator.deallocate(__rcl_argv, __rcl_allocator.state);
|
||||
}
|
||||
atomic_store(&__rcl_instance_id, 0);
|
||||
atomic_store(&__rcl_is_initialized, false);
|
||||
}
|
||||
|
||||
rcl_ret_t
|
||||
rcl_init(int argc, char ** argv, rcl_allocator_t allocator)
|
||||
{
|
||||
bool was_initialized = atomic_exchange(&__rcl_is_initialized, true);
|
||||
if (was_initialized) {
|
||||
RCL_SET_ERROR_MSG("rcl_init called while already initialized");
|
||||
return RCL_RET_ALREADY_INIT;
|
||||
}
|
||||
// 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");
|
||||
goto fail;
|
||||
}
|
||||
memset(__rcl_argv, 0, sizeof(char **) * argc);
|
||||
for (size_t i = 0; i < argc; ++i) {
|
||||
__rcl_argv[i] = (char *)__rcl_allocator.allocate(strlen(argv[i]), __rcl_allocator.state);
|
||||
strcpy(__rcl_argv[i], argv[i]);
|
||||
}
|
||||
atomic_store(&__rcl_instance_id, ++__rcl_next_unique_id);
|
||||
if (atomic_load(&__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 RCL_RET_ERROR;
|
||||
}
|
||||
|
||||
rcl_ret_t
|
||||
rcl_fini()
|
||||
{
|
||||
if (!atomic_load(&__rcl_is_initialized)) {
|
||||
RCL_SET_ERROR_MSG("rcl_fini called before rcl_init");
|
||||
return RCL_RET_NOT_INIT;
|
||||
}
|
||||
__clean_up_init();
|
||||
return RCL_RET_OK;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
rcl_get_instance_id()
|
||||
{
|
||||
return atomic_load(&__rcl_instance_id);
|
||||
}
|
||||
|
||||
bool
|
||||
rcl_ok()
|
||||
{
|
||||
return atomic_load(&__rcl_is_initialized);
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue