Skip to content

Commit aeb3495

Browse files
committed
Decoupled the additional feature from rcl to rcutils, reflecting on the pointing out below.
ros2/rclcpp#2205 (comment) Signed-off-by: Shoji Morita <[email protected]>
1 parent 025f78f commit aeb3495

File tree

3 files changed

+302
-0
lines changed

3 files changed

+302
-0
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ set(rcutils_sources
7272
src/strerror.c
7373
src/string_array.c
7474
src/string_map.c
75+
src/thread_attr.c
7576
src/testing/fault_injection.c
7677
src/time.c
7778
${time_impl_c}

include/rcutils/thread_attr.h

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Copyright 2023 eSOL Co.,Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef RCUTILS__THREAD_ATTR_H_
16+
#define RCUTILS__THREAD_ATTR_H_
17+
18+
#include "rcutils/visibility_control.h"
19+
20+
#include "rcutils/allocator.h"
21+
#include "rcutils/macros.h"
22+
#include "rcutils/types/rcutils_ret.h"
23+
24+
#ifdef __cplusplus
25+
extern "C"
26+
{
27+
#endif
28+
29+
typedef enum rcutils_thread_scheduling_policy_e
30+
{
31+
RCUTILS_THREAD_SCHEDULING_POLICY_UNKNOWN = 0,
32+
RCUTILS_THREAD_SCHEDULING_POLICY_FIFO = 1,
33+
RCUTILS_THREAD_SCHEDULING_POLICY_RR = 2,
34+
RCUTILS_THREAD_SCHEDULING_POLICY_SPORADIC = 3,
35+
RCUTILS_THREAD_SCHEDULING_POLICY_OTHER = 4,
36+
RCUTILS_THREAD_SCHEDULING_POLICY_IDLE = 5,
37+
RCUTILS_THREAD_SCHEDULING_POLICY_BATCH = 6,
38+
RCUTILS_THREAD_SCHEDULING_POLICY_DEADLINE = 7
39+
} rcutils_thread_scheduling_policy_t;
40+
41+
typedef struct rcutils_thread_attr_s
42+
{
43+
/// Thread core affinity
44+
int core_affinity;
45+
/// Thread scheduling policy.
46+
rcutils_thread_scheduling_policy_t scheduling_policy;
47+
/// Thread priority.
48+
int priority;
49+
/// Thread name
50+
char const * name;
51+
} rcutils_thread_attr_t;
52+
53+
/// Hold thread attribute rules.
54+
typedef struct rcutils_thread_attrs_s
55+
{
56+
/// Private implementation array.
57+
rcutils_thread_attr_t * attributes;
58+
/// Number of threads attribute
59+
size_t num_attributes;
60+
/// Number of threads attribute capacity
61+
size_t capacity_attributes;
62+
/// Allocator used to allocate objects in this struct
63+
rcutils_allocator_t allocator;
64+
} rcutils_thread_attrs_t;
65+
66+
/**
67+
* \brief Return a rcutils_thread_attrs_t struct with members initialized to zero value.
68+
* \return a rcutils_thread_attrs_t struct with members initialized to zero value.
69+
*/
70+
RCUTILS_PUBLIC
71+
RCUTILS_WARN_UNUSED
72+
rcutils_thread_attrs_t
73+
rcutils_get_zero_initialized_thread_attrs(void);
74+
75+
/**
76+
* \brief Initialize list of thread attributes.
77+
* \param[out] thread_attrs list of thread attributes to be initialized
78+
* \param[in] allocator memory allocator to be used
79+
* \return #RCUTILS_RET_OK if the structure was initialized succeessfully, or
80+
* \return #RCUTILS_RET_INVALID_ARGUMENT if any function arguments are invalid, or
81+
* \return #RCUTILS_RET_BAD_ALLOC if allocating memory failed, or
82+
* \return #RCUTILS_RET_ERROR an unspecified error occur.
83+
*/
84+
RCUTILS_PUBLIC
85+
RCUTILS_WARN_UNUSED
86+
rcutils_ret_t
87+
rcutils_thread_attrs_init(
88+
rcutils_thread_attrs_t * thread_attrs,
89+
rcutils_allocator_t allocator);
90+
91+
/**
92+
* \brief Initialize list of thread attributes with a capacity.
93+
* \param[out] thread_attrs list of thread attributes to be initialized
94+
* \param[in] allocator memory allocator to be used
95+
* \return #RCUTILS_RET_OK if the structure was initialized succeessfully, or
96+
* \return #RCUTILS_RET_INVALID_ARGUMENT if any function arguments are invalid, or
97+
* \return #RCUTILS_RET_BAD_ALLOC if allocating memory failed, or
98+
* \return #RCUTILS_RET_ERROR an unspecified error occur.
99+
*/
100+
RCUTILS_PUBLIC
101+
RCUTILS_WARN_UNUSED
102+
rcutils_ret_t
103+
rcutils_thread_attrs_init_with_capacity(
104+
rcutils_thread_attrs_t * thread_attrs,
105+
rcutils_allocator_t allocator,
106+
size_t capacity);
107+
108+
/**
109+
* \brief Free list of thread attributes
110+
* \param[in] thread_attrs structure to be deallocated.
111+
* \return #RCUTILS_RET_OK if the memory was successfully freed, or
112+
* \return #RCUTILS_RET_INVALID_ARGUMENT if any function arguments are invalid
113+
*/
114+
RCUTILS_PUBLIC
115+
RCUTILS_WARN_UNUSED
116+
rcutils_ret_t
117+
rcutils_thread_attrs_fini(
118+
rcutils_thread_attrs_t * thread_attrs);
119+
120+
/**
121+
* \brief Add thread attribute to the list of thread attributes.
122+
* \param[inout] thread_attrs list of thread attributes to add a thread attribute to
123+
* \param[in] sched_policy thread scheduling policy of adding attribute
124+
* \param[in] core_affinity thread core affinity of adding attribute
125+
* \param[in] priority thread priority of adding attribute
126+
* \param[in] name thread name of adding attribute
127+
* \return #RCUTILS_RET_OK if the thread attribute was successfully added, or
128+
* \return #RCUTILS_RET_INVALID_ARGUMENT if any function arguments are invalid, or
129+
* \return #RCUTILS_RET_BAD_ALLOC if allocating memory failed, or
130+
* \return #RCUTILS_RET_ERROR an unspecified error occur.
131+
*/
132+
RCUTILS_PUBLIC
133+
RCUTILS_WARN_UNUSED
134+
rcutils_ret_t
135+
rcutils_thread_attrs_add_attr(
136+
rcutils_thread_attrs_t * thread_attrs,
137+
rcutils_thread_scheduling_policy_t sched_policy,
138+
int core_affinity,
139+
int priority,
140+
char const * name);
141+
142+
#ifdef __cplusplus
143+
}
144+
#endif
145+
146+
#endif // RCUTILS__THREAD_ATTR_H_

src/thread_attr.c

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright 2023 eSOL Co.,Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <limits.h>
16+
#include <stdio.h>
17+
#include <stdlib.h>
18+
#include <string.h>
19+
20+
#include <yaml.h>
21+
22+
#include "rcutils/allocator.h"
23+
#include "rcutils/error_handling.h"
24+
#include "rcutils/strdup.h"
25+
#include "rcutils/thread_attr.h"
26+
#include "rcutils/types/rcutils_ret.h"
27+
28+
#define INIT_NUM_THREAD_ATTRIBUTE 0U
29+
30+
rcutils_thread_attrs_t
31+
rcutils_get_zero_initialized_thread_attrs(void)
32+
{
33+
rcutils_thread_attrs_t ret = {
34+
NULL,
35+
};
36+
return ret;
37+
}
38+
39+
rcutils_ret_t
40+
rcutils_thread_attrs_init(
41+
rcutils_thread_attrs_t * thread_attrs,
42+
rcutils_allocator_t allocator)
43+
{
44+
return rcutils_thread_attrs_init_with_capacity(
45+
thread_attrs, allocator, INIT_NUM_THREAD_ATTRIBUTE);
46+
}
47+
48+
rcutils_ret_t
49+
rcutils_thread_attrs_init_with_capacity(
50+
rcutils_thread_attrs_t * thread_attrs,
51+
rcutils_allocator_t allocator,
52+
size_t capacity)
53+
{
54+
RCUTILS_CHECK_ARGUMENT_FOR_NULL(thread_attrs, RCUTILS_RET_INVALID_ARGUMENT);
55+
RCUTILS_CHECK_ALLOCATOR_WITH_MSG(
56+
&allocator, "invalid allocator", return RCUTILS_RET_INVALID_ARGUMENT);
57+
58+
thread_attrs->allocator = allocator;
59+
thread_attrs->num_attributes = 0U;
60+
thread_attrs->capacity_attributes = capacity;
61+
if (capacity > 0) {
62+
thread_attrs->attributes =
63+
allocator.zero_allocate(capacity, sizeof(rcutils_thread_attr_t), allocator.state);
64+
if (NULL == thread_attrs->attributes) {
65+
*thread_attrs = rcutils_get_zero_initialized_thread_attrs();
66+
RCUTILS_SET_ERROR_MSG("Failed to allocate memory for thread attributes");
67+
return RCUTILS_RET_BAD_ALLOC;
68+
}
69+
}
70+
return RCUTILS_RET_OK;
71+
}
72+
73+
rcutils_ret_t
74+
rcutils_thread_attrs_fini(rcutils_thread_attrs_t * thread_attrs)
75+
{
76+
RCUTILS_CHECK_ARGUMENT_FOR_NULL(thread_attrs, RCUTILS_RET_INVALID_ARGUMENT);
77+
rcutils_allocator_t * allocator = &thread_attrs->allocator;
78+
if (NULL == thread_attrs->attributes) {
79+
return RCUTILS_RET_OK;
80+
}
81+
// check the allocator only if attributes is available to avoid checking after zero-initialized
82+
RCUTILS_CHECK_ALLOCATOR(allocator, return RCUTILS_RET_INVALID_ARGUMENT);
83+
for (size_t i = 0; i < thread_attrs->num_attributes; ++i) {
84+
rcutils_thread_attr_t * attr = thread_attrs->attributes + i;
85+
if (NULL != attr->name) {
86+
allocator->deallocate((char *)attr->name, allocator->state);
87+
}
88+
}
89+
allocator->deallocate(thread_attrs->attributes, allocator->state);
90+
*thread_attrs = rcutils_get_zero_initialized_thread_attrs();
91+
92+
return RCUTILS_RET_OK;
93+
}
94+
95+
static inline rcutils_ret_t extend_thread_attrs_capacity(
96+
rcutils_thread_attrs_t * attrs,
97+
size_t new_cap)
98+
{
99+
size_t cap = attrs->capacity_attributes;
100+
size_t size = cap * sizeof(rcutils_thread_attr_t);
101+
size_t new_size = new_cap * sizeof(rcutils_thread_attr_t);
102+
rcutils_thread_attr_t * new_attrs = attrs->allocator.reallocate(
103+
attrs->attributes, new_size, attrs->allocator.state);
104+
105+
if (NULL == new_attrs) {
106+
RCUTILS_SET_ERROR_MSG("Failed to allocate memory for thread attributes");
107+
return RCUTILS_RET_BAD_ALLOC;
108+
}
109+
110+
memset(new_attrs + cap, 0, new_size - size);
111+
112+
attrs->capacity_attributes = new_cap;
113+
attrs->attributes = new_attrs;
114+
115+
return RCUTILS_RET_OK;
116+
}
117+
118+
rcutils_ret_t
119+
rcutils_thread_attrs_add_attr(
120+
rcutils_thread_attrs_t * thread_attrs,
121+
rcutils_thread_scheduling_policy_t sched_policy,
122+
int core_affinity,
123+
int priority,
124+
char const * name)
125+
{
126+
RCUTILS_CHECK_ARGUMENT_FOR_NULL(thread_attrs, RCUTILS_RET_INVALID_ARGUMENT);
127+
RCUTILS_CHECK_ARGUMENT_FOR_NULL(name, RCUTILS_RET_INVALID_ARGUMENT);
128+
129+
if (thread_attrs->num_attributes == thread_attrs->capacity_attributes) {
130+
size_t new_cap = 0;
131+
if (0 == thread_attrs->capacity_attributes) {
132+
new_cap = 1;
133+
} else {
134+
new_cap = thread_attrs->capacity_attributes * 2;
135+
}
136+
// Extend the capacity
137+
rcutils_ret_t ret = extend_thread_attrs_capacity(thread_attrs, new_cap);
138+
if (RCUTILS_RET_OK != ret) {
139+
return ret;
140+
}
141+
}
142+
143+
char const * dup_name = rcutils_strdup(name, thread_attrs->allocator);
144+
if (NULL == dup_name) {
145+
return RCUTILS_RET_BAD_ALLOC;
146+
}
147+
148+
rcutils_thread_attr_t * attr = thread_attrs->attributes + thread_attrs->num_attributes;
149+
attr->scheduling_policy = sched_policy;
150+
attr->core_affinity = core_affinity;
151+
attr->priority = priority;
152+
attr->name = dup_name;
153+
154+
return RCUTILS_RET_OK;
155+
}

0 commit comments

Comments
 (0)