From f9ea0910e081ca91ddb2a3555e4ed7f8d095f61a Mon Sep 17 00:00:00 2001 From: Bertho Stultiens Date: Fri, 31 Jul 2026 13:29:47 +0200 Subject: [PATCH] hal: Update functs and threads to use getter/setter and add threadbeat pin. --- src/hal/hal_lib.c | 67 +++++++++++++++++++++++++----------------- src/hal/hal_priv.h | 20 +++++++++---- src/hal/utils/halrmt.c | 2 +- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/hal/hal_lib.c b/src/hal/hal_lib.c index e24e6ed88b4..826bc7d46a7 100644 --- a/src/hal/hal_lib.c +++ b/src/hal/hal_lib.c @@ -2388,7 +2388,6 @@ int hal_export_funct(const char *name, void (*funct) (void *, long), int cmp; hal_funct_t *new, *fptr; hal_comp_t *comp; - char buf[HAL_NAME_LEN + 1]; if (hal_data == NULL) { rtapi_print_msg(RTAPI_MSG_ERR, @@ -2486,25 +2485,25 @@ int hal_export_funct(const char *name, void (*funct) (void *, long), halpr_mutex_release(); /* create a pin with the function's runtime in it */ - if (hal_pin_s32_newf(HAL_OUT, &(new->runtime), comp_id,"%s.time",name)) { - rtapi_print_msg(RTAPI_MSG_ERR, - "HAL: ERROR: fail to create pin '%s.time'\n", name); - return -EINVAL; + if (hal_pin_new_si32(comp_id, HAL_OUT, &(new->runtime), 0, "%s.time", name) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create pin '%s.time'\n", name); + return -EINVAL; } - *(new->runtime) = 0; /* note that failure to successfully create the following params does not cause the "export_funct()" call to fail - they are for debugging and testing use only */ /* create a parameter with the function's maximum runtime in it */ - rtapi_snprintf(buf, sizeof(buf), "%s.tmax", name); - new->maxtime = 0; - hal_param_s32_new(buf, HAL_RW, &(new->maxtime), comp_id); + if(hal_param_new_si32(comp_id, HAL_RW, &(new->maxtime), 0, "%s.tmax", name) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create param '%s.tmax'\n", name); + return -EINVAL; + } /* create a parameter with the function's maximum runtime in it */ - rtapi_snprintf(buf, sizeof(buf), "%s.tmax-increased", name); - new->maxtime_increased = 0; - hal_param_bit_new(buf, HAL_RO, &(new->maxtime_increased), comp_id); + if(hal_param_new_bool(comp_id, HAL_RO, &(new->maxtime_increased), 0, "%s.tmax-increased", name) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create param '%s.tmax-increased'\n", name); + return -EINVAL; + } return 0; } @@ -2652,6 +2651,13 @@ int hal_create_thread(const char *name, unsigned long period_nsec, int uses_fp) /* insert new structure at head of list */ new->next_ptr = hal_data->thread_list_ptr; hal_data->thread_list_ptr = SHMOFF(new); + + // The counter that increases monotonically once every thread loop cycle. + // This is a 'fast' counter with normal access semantics. Separated from + // the param 'threadbeat' so it only needs to write _once_ to volatile + // memory instead of a very expensive read-modify-write cycle. + new->beatcnt = 0; + /* done, release mutex */ halpr_mutex_release(); @@ -2663,20 +2669,26 @@ int hal_create_thread(const char *name, unsigned long period_nsec, int uses_fp) return new->comp_id; } - rtapi_snprintf(buf, sizeof(buf), "%s.tmax", new->name); - new->maxtime = 0; - if (hal_param_s32_new(buf, HAL_RW, &(new->maxtime), new->comp_id)) { + if ((retval = hal_param_new_si32(new->comp_id, HAL_RW, &(new->maxtime), 0, "%s.tmax", new->name)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create param '%s.tmax'\n", new->name); - return -EINVAL; + return retval; } - if (hal_pin_s32_newf(HAL_OUT, &(new->runtime), new->comp_id,"%s.time",new->name)) { + if ((retval = hal_pin_new_si32(new->comp_id, HAL_OUT, &(new->runtime), 0, "%s.time", new->name)) < 0) { rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create pin '%s.time'\n", new->name); - return -EINVAL; + return retval; } - *(new->runtime) = 0; + + // A pin that increases monotonically once every thread loop cycle. + // This way we can detect when a RT-cycle was completed from non-RT + // and prevent racy indeterministic sleep() constructs. + if((retval = hal_pin_new_sint(new->comp_id, HAL_OUT, &(new->threadbeat), 0, "%s.threadbeat", new->name)) < 0) { + rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: fail to create pin '%s.threadbeat'\n", new->name); + return retval; + } + hal_ready(new->comp_id); rtapi_print_msg(RTAPI_MSG_DBG, "HAL: thread created\n"); @@ -3647,12 +3659,12 @@ static void thread_task(void *arg) /* point to function structure */ funct = SHMPTR(funct_entry->funct_ptr); /* update execution time data */ - *(funct->runtime) = (hal_s32_t)(end_time - start_time); - if ( *(funct->runtime) > funct->maxtime) { - funct->maxtime = *(funct->runtime); - funct->maxtime_increased = 1; + rtapi_s32 runtime = hal_set_si32(funct->runtime, end_time - start_time); + if ( runtime > hal_get_si32(funct->maxtime)) { + hal_set_si32(funct->maxtime, runtime); + hal_set_bool(funct->maxtime_increased, 1); } else { - funct->maxtime_increased = 0; + hal_set_bool(funct->maxtime_increased, 0); } /* point to next next entry in list */ funct_entry = SHMPTR(funct_entry->links.next); @@ -3660,10 +3672,11 @@ static void thread_task(void *arg) start_time = end_time; } /* update thread execution time */ - *(thread->runtime) = (hal_s32_t)(end_time - thread_start_time); - if ( *(thread->runtime) > thread->maxtime) { - thread->maxtime = *(thread->runtime); + rtapi_s32 runtime = hal_set_si32(thread->runtime, end_time - thread_start_time); + if ( runtime > hal_get_si32(thread->maxtime)) { + hal_set_si32(thread->maxtime, runtime); } + hal_set_sint(thread->threadbeat, ++thread->beatcnt); } /* wait until next period */ rtapi_wait(); diff --git a/src/hal/hal_priv.h b/src/hal/hal_priv.h index 2ba6a0062d8..b34e9507d8d 100644 --- a/src/hal/hal_priv.h +++ b/src/hal/hal_priv.h @@ -118,7 +118,7 @@ */ #define HAL_KEY 0x48414C32 /* key used to open HAL shared memory */ -#define HAL_VER 0x00000013 /* version code */ +#define HAL_VER 0x00000014 /* version code */ #define HAL_SIZE (2*256*4096) /* These pointers are set by hal_init() to point to the shmem block @@ -396,9 +396,12 @@ struct hal_funct_t { int users; /* number of threads using function */ void *arg; /* argument for function */ void (*funct) (void *, long); /* ptr to function code */ - hal_s32_t* runtime; /* (pin) duration of last run, in CPU cycles */ - hal_s32_t maxtime; /* (param) duration of longest run, in CPU cycles */ - hal_bit_t maxtime_increased; /* (param) on last call, maxtime increased */ + // IMPORTANT: The pins and params are valid as seen from the context that + // created them. For uspace that is rtapi_app and in the kernel it is the + // kernel's module context. + hal_sint_t runtime; /* (pin) duration of last run, in CPU cycles */ + hal_sint_t maxtime; /* (param) duration of longest run, in CPU cycles */ + hal_bool_t maxtime_increased; /* (param) on last call, maxtime increased */ char name[HAL_NAME_LEN + 1]; /* function name */ }; @@ -417,8 +420,13 @@ struct hal_thread_t { long int period; /* period of the thread, in nsec */ int priority; /* priority of the thread */ int task_id; /* ID of the task that runs this thread */ - hal_s32_t* runtime; /* (pin) duration of last run, in ns */ - hal_s32_t maxtime; /* (param) duration of longest run, in ns */ + // IMPORTANT: The pins and params are valid as seen from the context that + // created them. For uspace that is rtapi_app and in the kernel it is the + // kernel's module context. + hal_sint_t runtime; /* (pin) duration of last run, in ns */ + hal_sint_t maxtime; /* (param) duration of longest run, in ns */ + hal_sint_t threadbeat; /* (pin) visible monotonic loop beat counter */ + rtapi_sint beatcnt; /* Thread monotonic increasing loop beat counter (so we don't need to read/write volatile) */ hal_list_t funct_list; /* list of functions to run */ hal_list_t init_funct_list; /* list of init functions, run once before first cyclic cycle */ int init_done; /* 0 = init pending, 1 = init cycle has executed */ diff --git a/src/hal/utils/halrmt.c b/src/hal/utils/halrmt.c index 6006ba3103e..6d9ad460dd8 100644 --- a/src/hal/utils/halrmt.c +++ b/src/hal/utils/halrmt.c @@ -1842,7 +1842,7 @@ static void getThreadInfo(char *pattern, connectionRecType *context) (unsigned int)tptr->period, (tptr->uses_fp ? "YES" : "NO "), runtime_pin_value, - (unsigned int)tptr->maxtime); + (unsigned int)hal_get_si32(tptr->maxtime)); sockWrite(context); list_root = &(tptr->funct_list); list_entry = list_next(list_root);