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. svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Mon, 16 Aug 2021 22:49:08 +0200
branchsvghmi
changeset 3294 e3db472b0dfb
parent 3293 d2b0c768755d
child 3295 0375d801fff7
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.
svghmi/svghmi.c
targets/Linux/plc_Linux_main.c
targets/Xenomai/__init__.py
targets/Xenomai/plc_Xenomai_main.c
targets/beremiz.h
--- 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()
--- 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);
+}
+
--- 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"]
--- 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)
 {
--- 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