diff --git a/include/nuttx/tls.h b/include/nuttx/tls.h index 1dc2a72b3e9..87794cc564f 100644 --- a/include/nuttx/tls.h +++ b/include/nuttx/tls.h @@ -83,6 +83,20 @@ typedef CODE void (*tls_dtor_t)(FAR void *); #endif +#if CONFIG_TLS_TASK_NELEM > 0 +# if CONFIG_TLS_TASK_NELEM > 64 +# error Too many TLS elements +# elif CONFIG_TLS_TASK_NELEM > 32 + typedef uint64_t tls_task_ndxset_t; +# elif CONFIG_TLS_TASK_NELEM > 16 + typedef uint32_t tls_task_ndxset_t; +# elif CONFIG_TLS_TASK_NELEM > 8 + typedef uint16_t tls_task_ndxset_t; +# else + typedef uint8_t tls_task_ndxset_t; +# endif +#endif + /* This structure encapsulates all variables associated with getopt(). */ struct getopt_s @@ -104,6 +118,9 @@ struct task_info_s { sem_t ta_sem; FAR char **argv; /* Name+start-up parameters */ +#if CONFIG_TLS_TASK_NELEM > 0 + uintptr_t ta_telem[CONFIG_TLS_TASK_NELEM]; /* Task local storage elements */ +#endif #if CONFIG_TLS_NELEM > 0 tls_ndxset_t ta_tlsset; /* Set of TLS indexes allocated */ tls_dtor_t ta_tlsdtor[CONFIG_TLS_NELEM]; /* List of TLS destructors */ @@ -269,6 +286,81 @@ uintptr_t tls_get_value(int tlsindex); int tls_set_value(int tlsindex, uintptr_t tlsvalue); #endif +#if CONFIG_TLS_TASK_NELEM > 0 + +/**************************************************************************** + * Name: task_tls_allocs + * + * Description: + * Allocate a global-unique task local storage data index + * + * Input Parameters: + * dtor - The destructor of task local storage data element + * + * Returned Value: + * A TLS index that is unique. + * + ****************************************************************************/ + +int task_tls_alloc(tls_dtor_t dtor); + +/**************************************************************************** + * Name: task_tls_destruct + * + * Description: + * Destruct all TLS data element associated with allocated key + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void task_tls_destruct(void); + +/**************************************************************************** + * Name: task_tls_set_value + * + * Description: + * Set the task local storage element associated with the 'tlsindex' to + * 'tlsvalue' + * + * Input Parameters: + * tlsindex - Index of task local storage data element to set + * tlsvalue - The new value of the task local storage data element + * + * Returned Value: + * Zero is returned on success, a negated errno value is return on + * failure: + * + * EINVAL - tlsindex is not in range. + * + ****************************************************************************/ + +int task_tls_set_value(int tlsindex, uintptr_t tlsvalue); + +/**************************************************************************** + * Name: task_tls_get_value + * + * Description: + * Return an the task local storage data value associated with 'tlsindx' + * + * Input Parameters: + * tlsindex - Index of task local storage data element to return + * + * Returned Value: + * The value of TLS element associated with 'tlsindex'. Errors are not + * reported. Zero is returned in the event of an error, but zero may also + * be valid value and returned when there is no error. The only possible + * error would be if tlsindex < 0 or tlsindex >=CONFIG_TLS_TASK_NELEM. + * + ****************************************************************************/ + +uintptr_t task_tls_get_value(int tlsindex); +#endif + /**************************************************************************** * Name: tls_get_info * @@ -300,7 +392,7 @@ FAR struct tls_info_s *tls_get_info(void); * None * * Returned Value: - * A set of allocated TLS index + * None * ****************************************************************************/ diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index 5316efbdf11..abc0b7137e2 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -105,6 +105,10 @@ SYSCALL_LOOKUP(up_assert, 2) SYSCALL_LOOKUP(task_testcancel, 0) #endif +#if CONFIG_TLS_TASK_NELEM > 0 + SYSCALL_LOOKUP(task_tls_alloc, 1) +#endif + /* The following can be individually enabled */ #if defined(CONFIG_SCHED_WAITPID) && defined(CONFIG_ARCH_HAVE_VFORK) diff --git a/libs/libc/tls/Kconfig b/libs/libc/tls/Kconfig index 5bc41f97e1e..171605d022b 100644 --- a/libs/libc/tls/Kconfig +++ b/libs/libc/tls/Kconfig @@ -55,4 +55,15 @@ config TLS_NELEM NOTE that the special value of CONFIG_TLS_NELEM disables these TLS interfaces. +config TLS_TASK_NELEM + int "Number of Task Local Storage elements" + default 0 + range 0 64 + ---help--- + The number of unique Task Local Storage elements similar with + Thread Local Storage. + These can be accessed with task_tls_alloc/task_tls_get_value/task_tls_set_value. + NOTE that the 0 value of CONFIG_SCHED_TLS_NELEM disables these + TLS interfaces. + endmenu # Thread Local Storage (TLS) diff --git a/libs/libc/tls/tls_getvalue.c b/libs/libc/tls/tls_getvalue.c index 68c262f02be..d6204ebd89f 100644 --- a/libs/libc/tls/tls_getvalue.c +++ b/libs/libc/tls/tls_getvalue.c @@ -75,3 +75,36 @@ uintptr_t tls_get_value(int tlsindex) } #endif /* CONFIG_TLS_NELEM > 0 */ + +#if CONFIG_TLS_TASK_NELEM > 0 + +/**************************************************************************** + * Name: task_tls_get_value + * + * Description: + * Return an the task local storage data value associated with 'tlsindx' + * + * Input Parameters: + * tlsindex - Index of task local storage data element to return + * + * Returned Value: + * The value of TLS element associated with 'tlsindex'. Errors are not + * reported. Zero is returned in the event of an error, but zero may also + * be valid value and returned when there is no error. The only possible + * error would be if tlsindex < 0 or tlsindex >=CONFIG_TLS_TASK_NELEM. + * + ****************************************************************************/ + +uintptr_t task_tls_get_value(int tlsindex) +{ + FAR struct task_info_s *info = task_get_info(); + + if (tlsindex >= 0 && tlsindex < CONFIG_TLS_TASK_NELEM) + { + return info->ta_telem[tlsindex]; + } + + return 0; +} + +#endif diff --git a/libs/libc/tls/tls_setvalue.c b/libs/libc/tls/tls_setvalue.c index a9f181aceca..6cf775df158 100644 --- a/libs/libc/tls/tls_setvalue.c +++ b/libs/libc/tls/tls_setvalue.c @@ -76,3 +76,42 @@ int tls_set_value(int tlsindex, uintptr_t tlsvalue) } #endif /* CONFIG_TLS_NELEM > 0 */ + +#if CONFIG_TLS_TASK_NELEM > 0 + +/**************************************************************************** + * Name: task_tls_set_value + * + * Description: + * Set the task local storage element associated with the 'tlsindex' to + * 'tlsvalue' + * + * Input Parameters: + * tlsindex - Index of task local storage data element to set + * tlsvalue - The new value of the task local storage data element + * + * Returned Value: + * Zero is returned on success, a negated errno value is return on + * failure: + * + * EINVAL - tlsindex is not in range. + * + ****************************************************************************/ + +int task_tls_set_value(int tlsindex, uintptr_t tlsvalue) +{ + FAR struct task_info_s *info = task_get_info(); + + if (tlsindex >= 0 && tlsindex < CONFIG_TLS_TASK_NELEM) + { + info->ta_telem[tlsindex] = tlsvalue; + } + else + { + return -ERANGE; + } + + return OK; +} + +#endif diff --git a/sched/group/group_leave.c b/sched/group/group_leave.c index d2d0c2e50c2..455a534a865 100644 --- a/sched/group/group_leave.c +++ b/sched/group/group_leave.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_BINFMT_LOADABLE # include @@ -127,6 +128,10 @@ static void group_remove(FAR struct task_group_s *group) static inline void group_release(FAR struct task_group_s *group) { +#if CONFIG_TLS_TASK_NELEM > 0 + task_tls_destruct(); +#endif + #if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS) /* Free all un-reaped child exit status */ diff --git a/sched/task/Make.defs b/sched/task/Make.defs index 86122bcda1d..85b893e642d 100644 --- a/sched/task/Make.defs +++ b/sched/task/Make.defs @@ -23,6 +23,7 @@ CSRCS += task_start.c task_delete.c task_exit.c task_exithook.c CSRCS += task_getgroup.c task_getpid.c task_prctl.c task_recover.c CSRCS += task_restart.c task_spawnparms.c task_setcancelstate.c CSRCS += task_cancelpt.c task_terminate.c task_gettid.c exit.c +CSRCS += task_tls_alloc.c ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) CSRCS += task_getppid.c diff --git a/sched/task/task_tls_alloc.c b/sched/task/task_tls_alloc.c new file mode 100644 index 00000000000..864135305dd --- /dev/null +++ b/sched/task/task_tls_alloc.c @@ -0,0 +1,127 @@ +/**************************************************************************** + * sched/task/task_tls_alloc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if CONFIG_TLS_TASK_NELEM > 0 + +static tls_task_ndxset_t g_tlsset; +static sem_t g_tlssem = SEM_INITIALIZER(1); +static tls_dtor_t g_tlsdtor[CONFIG_TLS_TASK_NELEM]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_tls_allocs + * + * Description: + * Allocate a global-unique task local storage data index + * + * Input Parameters: + * dtor - The destructor of task local storage data element + * + * Returned Value: + * A TLS index that is unique. + * + ****************************************************************************/ + +int task_tls_alloc(tls_dtor_t dtor) +{ + int ret; + int candidate; + + ret = nxsem_wait(&g_tlssem); + + if (ret < 0) + { + return ret; + } + + ret = -EUSERS; + + for (candidate = 0; candidate < CONFIG_TLS_TASK_NELEM; candidate++) + { + tls_task_ndxset_t mask = (tls_task_ndxset_t)1 << candidate; + if ((g_tlsset & mask) == 0) + { + g_tlsset |= mask; + g_tlsdtor[candidate] = dtor; + ret = candidate; + break; + } + } + + nxsem_post(&g_tlssem); + return ret; +} + +/**************************************************************************** + * Name: task_tls_destruct + * + * Description: + * Destruct all TLS data element associated with allocated key + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void task_tls_destruct(void) +{ + int candidate; + uintptr_t elem; + tls_dtor_t dtor; + FAR struct task_info_s *info = task_get_info(); + + for (candidate = 0; candidate < CONFIG_TLS_TASK_NELEM; candidate++) + { + tls_task_ndxset_t mask = (tls_task_ndxset_t)1 << candidate; + if ((g_tlsset & mask) != 0) + { + elem = info->ta_telem[candidate]; + dtor = g_tlsdtor[candidate]; + if (dtor != NULL && elem != 0) + { + dtor((void *)elem); + } + } + } +} + +#endif diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 12785b7e0b3..3c3b14a7f27 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -177,6 +177,7 @@ "task_setcanceltype","sched.h","defined(CONFIG_CANCELLATION_POINTS)","int","int","FAR int *" "task_spawn","nuttx/spawn.h","!defined(CONFIG_BUILD_KERNEL)","int","FAR const char *","main_t","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char * const []|FAR char * const *","FAR char * const []|FAR char * const *" "task_testcancel","pthread.h","defined(CONFIG_CANCELLATION_POINTS)","void" +"task_tls_alloc","nuttx/tls.h","CONFIG_TLS_TASK_NELEM > 0","int","uintptr_t" "telldir","dirent.h","","off_t","FAR DIR *" "timer_create","time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","clockid_t","FAR struct sigevent *","FAR timer_t *" "timer_delete","time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","timer_t"