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