# HG changeset patch # User Edouard Tisserant # Date 1629146948 -7200 # Node ID e3db472b0dfb219b83685552998e470c97283045 # Parent d2b0c768755d7f486dc8588bdcbd3a701215b133 Runtime+SVGHMI: Added a generic way to wakeup non-real-time threads from real-time PLC thread. Replace SVGHMI specific calls in Linux and Xenomai implementations of plc_main.c. Fixed xenomai build, xeno-config making problems with --no-auto-init argument. diff -r d2b0c768755d -r e3db472b0dfb svghmi/svghmi.c --- a/svghmi/svghmi.c Thu Jul 29 11:59:28 2021 +0200 +++ b/svghmi/svghmi.c Mon Aug 16 22:49:08 2021 +0200 @@ -208,8 +208,17 @@ return 0; } -void SVGHMI_SuspendFromPythonThread(void); -void SVGHMI_WakeupFromRTThread(void); +static void *svghmi_handle; + +void SVGHMI_SuspendFromPythonThread(void) +{ + wait_RT_to_nRT_signal(svghmi_handle); +} + +void SVGHMI_WakeupFromRTThread(void) +{ + unblock_RT_to_nRT_signal(svghmi_handle); +} int svghmi_continue_collect; @@ -220,6 +229,12 @@ svghmi_continue_collect = 1; + /* create svghmi_pipe */ + svghmi_handle = create_RT_to_nRT_signal("SVGHMI_pipe"); + + if(!svghmi_handle) + return 1; + return 0; } @@ -227,6 +242,7 @@ { svghmi_continue_collect = 0; SVGHMI_WakeupFromRTThread(); + delete_RT_to_nRT_signal(svghmi_handle); } void __retrieve_svghmi() diff -r d2b0c768755d -r e3db472b0dfb targets/Linux/plc_Linux_main.c --- a/targets/Linux/plc_Linux_main.c Thu Jul 29 11:59:28 2021 +0200 +++ b/targets/Linux/plc_Linux_main.c Mon Aug 16 22:49:08 2021 +0200 @@ -239,14 +239,53 @@ static pthread_cond_t svghmi_send_WakeCond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t svghmi_send_WakeCondLock = PTHREAD_MUTEX_INITIALIZER; -void SVGHMI_SuspendFromPythonThread(void) -{ - pthread_mutex_lock(&svghmi_send_WakeCondLock); - pthread_cond_wait(&svghmi_send_WakeCond, &svghmi_send_WakeCondLock); - pthread_mutex_unlock(&svghmi_send_WakeCondLock); -} - -void SVGHMI_WakeupFromRTThread(void) -{ - pthread_cond_signal(&svghmi_send_WakeCond); -} +struct RT_to_nRT_signal_s { + pthread_cond_t WakeCond; + pthread_mutex_t WakeCondLock; +}; + +typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t; + +#define _LogAndReturnNull(text) \ + {\ + char mstr[256] = text " for ";\ + strncat(mstr, name, 255);\ + LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\ + return NULL;\ + } + +void *create_RT_to_nRT_signal(char* name){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)malloc(sizeof(RT_to_nRT_signal_t)); + + if(!sig) + _LogAndReturnNull("Failed allocating memory for RT_to_nRT signal"); + + pthread_cond_init(&sig->WakeCond, NULL); + pthread_mutex_init(&sig->WakeCondLock, NULL); + + return (void*)sig; +} + +void delete_RT_to_nRT_signal(void* handle){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + + pthread_cond_destroy(&sig->WakeCond); + pthread_mutex_destroy(&sig->WakeCondLock); + + free(sig); +} + +int wait_RT_to_nRT_signal(void* handle){ + int ret; + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + pthread_mutex_lock(&sig->WakeCondLock); + ret = pthread_cond_wait(&sig->WakeCond, &sig->WakeCondLock); + pthread_mutex_unlock(&sig->WakeCondLock); + return ret; +} + +int unblock_RT_to_nRT_signal(void* handle){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + return pthread_cond_signal(&sig->WakeCond); +} + diff -r d2b0c768755d -r e3db472b0dfb targets/Xenomai/__init__.py --- a/targets/Xenomai/__init__.py Thu Jul 29 11:59:28 2021 +0200 +++ b/targets/Xenomai/__init__.py Mon Aug 16 22:49:08 2021 +0200 @@ -37,7 +37,7 @@ if xeno_config: from util.ProcessLogger import ProcessLogger status, result, _err_result = ProcessLogger(self.CTRInstance.logger, - xeno_config + " --skin=posix --skin=alchemy --no-auto-init --"+flagsname, + xeno_config + " --skin=posix --skin=alchemy "+flagsname, no_stdout=True).spin() if status: self.CTRInstance.logger.write_error(_("Unable to get Xenomai's %s \n") % flagsname) @@ -45,9 +45,9 @@ return [] def getBuilderLDFLAGS(self): - xeno_ldflags = self.getXenoConfig("ldflags") + xeno_ldflags = self.getXenoConfig("--no-auto-init --ldflags") return toolchain_gcc.getBuilderLDFLAGS(self) + xeno_ldflags + ["-shared"] def getBuilderCFLAGS(self): - xeno_cflags = self.getXenoConfig("cflags") + xeno_cflags = self.getXenoConfig("--cflags") return toolchain_gcc.getBuilderCFLAGS(self) + xeno_cflags + ["-fPIC"] diff -r d2b0c768755d -r e3db472b0dfb targets/Xenomai/plc_Xenomai_main.c --- a/targets/Xenomai/plc_Xenomai_main.c Thu Jul 29 11:59:28 2021 +0200 +++ b/targets/Xenomai/plc_Xenomai_main.c Mon Aug 16 22:49:08 2021 +0200 @@ -18,27 +18,11 @@ unsigned int PLC_state = 0; #define PLC_STATE_TASK_CREATED 1 -#define PLC_STATE_DEBUG_FILE_OPENED 2 -#define PLC_STATE_DEBUG_PIPE_CREATED 4 -#define PLC_STATE_PYTHON_FILE_OPENED 8 -#define PLC_STATE_PYTHON_PIPE_CREATED 16 -#define PLC_STATE_WAITDEBUG_FILE_OPENED 32 -#define PLC_STATE_WAITDEBUG_PIPE_CREATED 64 -#define PLC_STATE_WAITPYTHON_FILE_OPENED 128 -#define PLC_STATE_WAITPYTHON_PIPE_CREATED 256 -#define PLC_STATE_SVGHMI_FILE_OPENED 512 -#define PLC_STATE_SVGHMI_PIPE_CREATED 1024 - -#define WAITDEBUG_PIPE_DEVICE "/dev/rtp0" -#define WAITDEBUG_PIPE_MINOR 0 -#define DEBUG_PIPE_DEVICE "/dev/rtp1" -#define DEBUG_PIPE_MINOR 1 -#define WAITPYTHON_PIPE_DEVICE "/dev/rtp2" -#define WAITPYTHON_PIPE_MINOR 2 -#define PYTHON_PIPE_DEVICE "/dev/rtp3" -#define PYTHON_PIPE_MINOR 3 -#define SVGHMI_PIPE_DEVICE "/dev/rtp4" -#define SVGHMI_PIPE_MINOR 4 +#define PLC_STATE_DEBUG_PIPE_CREATED 2 +#define PLC_STATE_PYTHON_PIPE_CREATED 8 +#define PLC_STATE_WAITDEBUG_PIPE_CREATED 16 +#define PLC_STATE_WAITPYTHON_PIPE_CREATED 32 + #define PIPE_SIZE 1 // rt-pipes commands @@ -68,16 +52,36 @@ } RT_TASK PLC_task; -RT_PIPE WaitDebug_pipe; -RT_PIPE WaitPython_pipe; -RT_PIPE Debug_pipe; -RT_PIPE Python_pipe; -RT_PIPE svghmi_pipe; -int WaitDebug_pipe_fd; -int WaitPython_pipe_fd; -int Debug_pipe_fd; -int Python_pipe_fd; -int svghmi_pipe_fd; +void *WaitDebug_handle; +void *WaitPython_handle; +void *Debug_handle; +void *Python_handle; +void *svghmi_handle; + +struct RT_to_nRT_signal_s { + int used; + RT_PIPE pipe; + int pipe_fd; + char *name; +}; +typedef struct RT_to_nRT_signal_s RT_to_nRT_signal_t; + +#define max_RT_to_nRT_signals 16 + +static RT_to_nRT_signal_t RT_to_nRT_signal_pool[max_RT_to_nRT_signals]; + +int recv_RT_to_nRT_signal(void* handle, char* payload){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + if(!sig->used) return -EINVAL; + return read(sig->pipe_fd, payload, 1); +} + +int send_RT_to_nRT_signal(void* handle, char payload){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + if(!sig->used) return -EINVAL; + return rt_pipe_write(&sig->pipe, &payload, 1, P_NORMAL); +} + int PLC_shutdown = 0; @@ -102,17 +106,85 @@ { /* explicitely finish python thread */ char msg = PYTHON_FINISH; - rt_pipe_write(&WaitPython_pipe, &msg, sizeof(msg), P_NORMAL); + send_RT_to_nRT_signal(WaitPython_handle, msg); } { /* explicitely finish debug thread */ char msg = DEBUG_FINISH; - rt_pipe_write(&WaitDebug_pipe, &msg, sizeof(msg), P_NORMAL); + send_RT_to_nRT_signal(WaitDebug_handle, msg); } } static unsigned long __debug_tick; +#define _LogAndReturnNull(text) \ + {\ + char mstr[256] = text " for ";\ + strncat(mstr, name, 255);\ + LogMessage(LOG_CRITICAL, mstr, strlen(mstr));\ + return NULL;\ + } + +void *create_RT_to_nRT_signal(char* name){ + int new_index = -1; + RT_to_nRT_signal_t *sig; + char pipe_dev[64]; + + /* find a free slot */ + for(int i=0; i < max_RT_to_nRT_signals; i++){ + sig = &RT_to_nRT_signal_pool[i]; + if(!sig->used){ + new_index = i; + break; + } + } + + /* fail if none found */ + if(new_index == -1) { + _LogAndReturnNull("Maximum count of RT-PIPE reached while creating pipe"); + } + + /* create rt pipe */ + if(rt_pipe_create(&sig->pipe, name, new_index, PIPE_SIZE) < 0){ + _LogAndReturnNull("Failed opening real-time end of RT-PIPE"); + } + + /* open pipe's userland */ + snprintf(pipe_dev, 64, "/dev/rtp%d", new_index); + if((sig->pipe_fd = open(pipe_dev, O_RDWR)) == -1){ + rt_pipe_delete(&sig->pipe); + _LogAndReturnNull("Failed opening non-real-time end of RT-PIPE"); + } + + sig->used = 1; + sig->name = name; + + return sig; +} + +void delete_RT_to_nRT_signal(void* handle){ + RT_to_nRT_signal_t *sig = (RT_to_nRT_signal_t*)handle; + + if(!sig->used) return; + + rt_pipe_delete(&sig->pipe); + + close(sig->pipe_fd); + + sig->used = 0; +} + +int wait_RT_to_nRT_signal(void* handle){ + char cmd; + int ret = recv_RT_to_nRT_signal(handle, &cmd); + return (ret == 1) ? 0 : ((ret == 0) ? ENODATA : -ret); +} + +int unblock_RT_to_nRT_signal(void* handle){ + int ret = send_RT_to_nRT_signal(handle, 0); + return (ret == 1) ? 0 : ((ret == 0) ? EINVAL : -ret); +} + void PLC_cleanup_all(void) { if (PLC_state & PLC_STATE_TASK_CREATED) { @@ -120,56 +192,25 @@ PLC_state &= ~PLC_STATE_TASK_CREATED; } - if (PLC_state & PLC_STATE_SVGHMI_PIPE_CREATED) { - rt_pipe_delete(&svghmi_pipe); - PLC_state &= ~PLC_STATE_SVGHMI_PIPE_CREATED; - } - - if (PLC_state & PLC_STATE_SVGHMI_FILE_OPENED) { - close(svghmi_pipe_fd); - PLC_state &= ~PLC_STATE_SVGHMI_FILE_OPENED; - } - if (PLC_state & PLC_STATE_WAITDEBUG_PIPE_CREATED) { - rt_pipe_delete(&WaitDebug_pipe); + delete_RT_to_nRT_signal(WaitDebug_handle); PLC_state &= ~PLC_STATE_WAITDEBUG_PIPE_CREATED; } - if (PLC_state & PLC_STATE_WAITDEBUG_FILE_OPENED) { - close(WaitDebug_pipe_fd); - PLC_state &= ~PLC_STATE_WAITDEBUG_FILE_OPENED; - } - if (PLC_state & PLC_STATE_WAITPYTHON_PIPE_CREATED) { - rt_pipe_delete(&WaitPython_pipe); + delete_RT_to_nRT_signal(WaitPython_handle); PLC_state &= ~PLC_STATE_WAITPYTHON_PIPE_CREATED; } - if (PLC_state & PLC_STATE_WAITPYTHON_FILE_OPENED) { - close(WaitPython_pipe_fd); - PLC_state &= ~PLC_STATE_WAITPYTHON_FILE_OPENED; - } - if (PLC_state & PLC_STATE_DEBUG_PIPE_CREATED) { - rt_pipe_delete(&Debug_pipe); + delete_RT_to_nRT_signal(Debug_handle); PLC_state &= ~PLC_STATE_DEBUG_PIPE_CREATED; } - if (PLC_state & PLC_STATE_DEBUG_FILE_OPENED) { - close(Debug_pipe_fd); - PLC_state &= ~PLC_STATE_DEBUG_FILE_OPENED; - } - if (PLC_state & PLC_STATE_PYTHON_PIPE_CREATED) { - rt_pipe_delete(&Python_pipe); + delete_RT_to_nRT_signal(Python_handle); PLC_state &= ~PLC_STATE_PYTHON_PIPE_CREATED; } - - if (PLC_state & PLC_STATE_PYTHON_FILE_OPENED) { - close(Python_pipe_fd); - PLC_state &= ~PLC_STATE_PYTHON_FILE_OPENED; - } - } int stopPLC() @@ -213,59 +254,28 @@ /* no memory swapping for that process */ mlockall(MCL_CURRENT | MCL_FUTURE); + + /* memory initialization */ PLC_shutdown = 0; - - /*** RT Pipes creation and opening ***/ + bzero(RT_to_nRT_signal_pool, sizeof(RT_to_nRT_signal_pool)); + + /*** RT Pipes ***/ /* create Debug_pipe */ - if(rt_pipe_create(&Debug_pipe, "Debug_pipe", DEBUG_PIPE_MINOR, PIPE_SIZE) < 0) - _startPLCLog(FO "Debug_pipe real-time end"); + if(Debug_handle = create_RT_to_nRT_signal("Debug_pipe")) goto error; PLC_state |= PLC_STATE_DEBUG_PIPE_CREATED; - - /* open Debug_pipe*/ - if((Debug_pipe_fd = open(DEBUG_PIPE_DEVICE, O_RDWR)) == -1) - _startPLCLog(FO DEBUG_PIPE_DEVICE); - PLC_state |= PLC_STATE_DEBUG_FILE_OPENED; - + /* create Python_pipe */ - if(rt_pipe_create(&Python_pipe, "Python_pipe", PYTHON_PIPE_MINOR, PIPE_SIZE) < 0) - _startPLCLog(FO "Python_pipe real-time end"); + if(Python_handle = create_RT_to_nRT_signal("Python_pipe")) goto error; PLC_state |= PLC_STATE_PYTHON_PIPE_CREATED; - /* open Python_pipe*/ - if((Python_pipe_fd = open(PYTHON_PIPE_DEVICE, O_RDWR)) == -1) - _startPLCLog(FO PYTHON_PIPE_DEVICE); - PLC_state |= PLC_STATE_PYTHON_FILE_OPENED; - /* create WaitDebug_pipe */ - if(rt_pipe_create(&WaitDebug_pipe, "WaitDebug_pipe", WAITDEBUG_PIPE_MINOR, PIPE_SIZE) < 0) - _startPLCLog(FO "WaitDebug_pipe real-time end"); + if(WaitDebug_handle = create_RT_to_nRT_signal("WaitDebug_pipe")) goto error; PLC_state |= PLC_STATE_WAITDEBUG_PIPE_CREATED; - /* open WaitDebug_pipe*/ - if((WaitDebug_pipe_fd = open(WAITDEBUG_PIPE_DEVICE, O_RDWR)) == -1) - _startPLCLog(FO WAITDEBUG_PIPE_DEVICE); - PLC_state |= PLC_STATE_WAITDEBUG_FILE_OPENED; - /* create WaitPython_pipe */ - if(rt_pipe_create(&WaitPython_pipe, "WaitPython_pipe", WAITPYTHON_PIPE_MINOR, PIPE_SIZE) < 0) - _startPLCLog(FO "WaitPython_pipe real-time end"); + if(WaitPython_handle = create_RT_to_nRT_signal("WaitPython_pipe")) goto error; PLC_state |= PLC_STATE_WAITPYTHON_PIPE_CREATED; - /* open WaitPython_pipe*/ - if((WaitPython_pipe_fd = open(WAITPYTHON_PIPE_DEVICE, O_RDWR)) == -1) - _startPLCLog(FO WAITPYTHON_PIPE_DEVICE); - PLC_state |= PLC_STATE_WAITPYTHON_FILE_OPENED; - - /* create svghmi_pipe */ - if(rt_pipe_create(&svghmi_pipe, "svghmi_pipe", SVGHMI_PIPE_MINOR, PIPE_SIZE) < 0) - _startPLCLog(FO "svghmi_pipe real-time end"); - PLC_state |= PLC_STATE_SVGHMI_PIPE_CREATED; - - /* open svghmi_pipe*/ - if((svghmi_pipe_fd = open(SVGHMI_PIPE_DEVICE, O_RDWR)) == -1) - _startPLCLog(FO SVGHMI_PIPE_DEVICE); - PLC_state |= PLC_STATE_SVGHMI_FILE_OPENED; - /*** create PLC task ***/ if(rt_task_create(&PLC_task, "PLC_task", 0, 50, T_JOINABLE)) _startPLCLog("Failed creating PLC task"); @@ -309,7 +319,7 @@ DEBUG_BUSY, DEBUG_FREE) == DEBUG_BUSY){ char msg = DEBUG_UNLOCK; /* signal to NRT for wakeup */ - rt_pipe_write(&Debug_pipe, &msg, sizeof(msg), P_NORMAL); + send_RT_to_nRT_signal(Debug_handle, msg); } } @@ -321,8 +331,8 @@ int res; if (PLC_shutdown) return -1; /* Wait signal from PLC thread */ - res = read(WaitDebug_pipe_fd, &cmd, sizeof(cmd)); - if (res == sizeof(cmd) && cmd == DEBUG_PENDING_DATA){ + recv_RT_to_nRT_signal(WaitDebug_handle, &cmd); + if (res == 1 && cmd == DEBUG_PENDING_DATA){ *tick = __debug_tick; return 0; } @@ -337,7 +347,7 @@ /* remember tick */ __debug_tick = __tick; /* signal debugger thread it can read data */ - rt_pipe_write(&WaitDebug_pipe, &msg, sizeof(msg), P_NORMAL); + send_RT_to_nRT_signal(WaitDebug_handle, msg); } int suspendDebug(int disable) @@ -349,7 +359,7 @@ DEBUG_FREE, DEBUG_BUSY) != DEBUG_FREE && cmd == DEBUG_UNLOCK){ - if(read(Debug_pipe_fd, &cmd, sizeof(cmd)) != sizeof(cmd)){ + if(recv_RT_to_nRT_signal(Debug_handle, &cmd) != 1){ return -1; } } @@ -373,7 +383,7 @@ char cmd; if (PLC_shutdown) return -1; /* Wait signal from PLC thread */ - if(read(WaitPython_pipe_fd, &cmd, sizeof(cmd))==sizeof(cmd) && cmd==PYTHON_PENDING_COMMAND){ + if(recv_RT_to_nRT_signal(WaitPython_handle, &cmd) == 1 && cmd==PYTHON_PENDING_COMMAND){ return 0; } return -1; @@ -383,7 +393,7 @@ void UnBlockPythonCommands(void) { char msg = PYTHON_PENDING_COMMAND; - rt_pipe_write(&WaitPython_pipe, &msg, sizeof(msg), P_NORMAL); + send_RT_to_nRT_signal(WaitPython_handle, msg); } int TryLockPython(void) @@ -404,7 +414,7 @@ PYTHON_FREE, PYTHON_BUSY) != PYTHON_FREE && cmd == UNLOCK_PYTHON){ - read(Python_pipe_fd, &cmd, sizeof(cmd)); + recv_RT_to_nRT_signal(Python_handle, &cmd); } } @@ -416,23 +426,11 @@ PYTHON_FREE) == PYTHON_BUSY){ if(rt_task_self()){/*is that the real time task ?*/ char cmd = UNLOCK_PYTHON; - rt_pipe_write(&Python_pipe, &cmd, sizeof(cmd), P_NORMAL); + send_RT_to_nRT_signal(Python_handle, cmd); }/* otherwise, no signaling from non real time */ } /* as plc does not wait for lock. */ } -void SVGHMI_SuspendFromPythonThread(void) -{ - char cmd = 1; /*whatever*/ - read(svghmi_pipe_fd, &cmd, sizeof(cmd)); -} - -void SVGHMI_WakeupFromRTThread(void) -{ - char cmd; - rt_pipe_write(&svghmi_pipe, &cmd, sizeof(cmd), P_NORMAL); -} - #ifndef HAVE_RETAIN int CheckRetainBuffer(void) { diff -r d2b0c768755d -r e3db472b0dfb targets/beremiz.h --- a/targets/beremiz.h Thu Jul 29 11:59:28 2021 +0200 +++ b/targets/beremiz.h Mon Aug 16 22:49:08 2021 +0200 @@ -26,5 +26,9 @@ #endif long AtomicCompareExchange(long* atomicvar,long compared, long exchange); +void *create_RT_to_nRT_signal(char* name); +void delete_RT_to_nRT_signal(void* handle); +int wait_RT_to_nRT_signal(void* handle); +int unblock_RT_to_nRT_signal(void* handle); #endif