ud3tn/components/platform/posix/hal_task.c
Felix Walter 1237eaa2db Remove heap-allocated Task_t
`hal_task_create` returned a reference to the new task allocated on the
heap via `malloc`. We commonly used the pattern to `free` this reference
from the new thread which, however, could result in race conditions and
other synchronization issues. We added a fix using a semaphore in the
application agent, but this would have been needed in other places (CLA,
...) as well. As we do not make use of the task reference anywhere
besides in the CLA for error handling, we can remove the heap-allocated
value altogether and replace it with an `enum ud3tn_result` to simplify
things and circumvent the named synchronization issues.

In the case of the CLA function `cla_link_init`, logic is introduced to
request the RX task to exit immediately in case the TX task cannot be
launched.

Signed-off-by: Felix Walter <felix.walter@d3tn.com>
2023-05-10 17:23:55 +02:00

150 lines
3.4 KiB
C

// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
/*
* hal_task.c
*
* Description: contains the POSIX implementation of the hardware
* abstraction layer interface for thread-related functionality
*
*/
/* enable linux features when linux OS */
#if linux
#define _GNU_SOURCE
#endif
#include "ud3tn/common.h"
#include "platform/hal_config.h"
#include "platform/hal_io.h"
#include "platform/hal_task.h"
#include "platform/hal_time.h"
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
struct task_description {
void (*task_function)(void *param);
void *task_parameter;
};
static void *execute_pthread_compat(void *task_description)
{
struct task_description *desc =
(struct task_description *)task_description;
void (*task_function)(void *param) = desc->task_function;
void *task_parameter = desc->task_parameter;
free(task_description);
task_function(task_parameter);
return NULL;
}
enum ud3tn_result hal_task_create(
void (*task_function)(void *), const char *task_name,
int task_priority, void *task_parameters,
size_t task_stack_size)
{
pthread_t thread;
struct sched_param param;
pthread_attr_t tattr;
int error_code;
struct task_description *desc = malloc(sizeof(*desc));
if (desc == NULL) {
LOG("Allocating the task attribute structure failed!");
goto fail;
}
/* initialize an attribute to the default value */
if (pthread_attr_init(&tattr)) {
/* abort if error occurs */
LOG("Initializing the task's attributes failed!");
goto fail;
}
/* set the scheduling policy */
if (pthread_attr_setschedpolicy(&tattr, SCHED_RR)) {
/* abort if error occurs */
LOG("Setting the scheduling policy failed!");
goto fail_attr;
}
/* Create thread in detached state, so that no cleanup is necessary */
if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED)) {
LOG("Setting detached state failed!");
goto fail_attr;
}
/* set the scheduling priority (just use the absolute minimum and add */
/* the given priority */
param.sched_priority = sched_get_priority_min(SCHED_RR) +
task_priority;
if (pthread_attr_setschedparam(&tattr, &param)) {
/* abort if error occurs */
LOG("Setting the scheduling priority failed!");
goto fail_attr;
}
/* update the stack size of the thread (only if greater than 0, */
/* otherwise set stack size to the default value */
if (task_stack_size != 0 &&
pthread_attr_setstacksize(&tattr, task_stack_size)) {
/* abort if error occurs */
LOG("Setting the tasks stack size failed! Wrong value!");
goto fail_attr;
}
desc->task_function = task_function;
desc->task_parameter = task_parameters;
error_code = pthread_create(&thread, &tattr,
execute_pthread_compat, desc);
if (error_code) {
LOG("Thread Creation failed!");
goto fail_attr;
}
#if LINUX_SPECIFIC_API
if (task_name) {
if (pthread_setname_np(thread, task_name)) {
LOG("Could not set thread name!");
goto fail_attr;
}
}
#endif
/* destroy the attr-object */
pthread_attr_destroy(&tattr);
return UD3TN_OK;
fail_attr:
/* destroy the attr-object */
pthread_attr_destroy(&tattr);
fail:
free(desc);
return UD3TN_FAIL;
}
__attribute__((noreturn))
void hal_task_start_scheduler(void)
{
/* Put the calling thread (in this case the main thread) to */
/* sleep indefinitely */
for (;;)
pause();
}
void hal_task_delay(int delay)
{
usleep(delay*1000);
}