This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to wait on multiple objects in CMSIS-RTOS?

Hello.

I have a thread which must be waked-up from multiple sources - 3 different message box for example. How I can organize this in CMSIS-RTOS? Currently in revision 4.00 of CMSIS, there is a osWait() function. But in RTX 4.74 (which comes with latest CMSIS), this function is not implemented.

So what I can do like a workaround of this problem? Wake-up regularly via timer and check all message boxes? Working but not efficient.Currently the only multi-object wake-up source implemented in CMSIS-RTOS seems to be the signals. But it's not really cool to use message box and signals in parallel for waking up. Did I'm missing something?

Parents
  • Has anyone attempted to implement and add this feature in RTX?

    Looking at the CMSIS-RTOS API it seems the API is designed to support waiting on a signal and simultaneously on one (not multiple) message queues and getting unblocked by either one. Both the osSignalWait and the osMessageGet functions return the same structure an osEvent which contains osStatus that can be used to tell the caller what type of an unblock reason it was if they should interpret the structure as an osEventSignal or an osEventMessage.

    A pretty common use case in an RTOS world is to use one or more Signals as the best way to communicate from IRQs to a Task A and then use a message queue to communicate from other Tasks to Task A.

    If you looking the RTX 4.74 source code it really seems to me that this feature is quite simply not implemented, I guess ARM open sourced a legacy RTOS that only partially implements the CMSIS-RTOS API. Lets say that something is better than nothing...

    I'm considering an alternate implementation where each IRQ uses only a signal while other Tasks send a message and then a signal - the receiving Task A would then block only on signals using osSignalWait(waitforever) and then check either its message queue or do an action particular to the specific signal from the IRQ.

    Note to the OP - if you had a signal per message queue the receiving Task A could know which message queue to check and make sure to use osMessageGet with a timeout of 0.

    This isn't super elegant but would probably be similar but not quite as efficient as how the OS itself would implement it internally.  

    /// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
    /// \param[in]     signals       wait until all specified signal flags set or 0 for any single signal flag.
    /// \param[in]     millisec      timeout value or 0 in case of no time-out.
    /// \return event flag information or error code.
    /// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
    os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
    
    

    Beware even though the signal field is defined as int32_t the RTX source code it is only a U16.

    /// Get a Message or Wait for a Message from a Queue.
    /// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
    /// \param[in]     millisec      timeout value or 0 in case of no time-out.
    /// \return event information that includes status code.
    /// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
    os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
    
    
    typedef struct  {
      osStatus                 status;     ///< status code: event or error information
      union  {
        uint32_t                    v;     ///< message as 32-bit value
        void                       *p;     ///< message or mail as void pointer
        int32_t               signals;     ///< signal flags
      } value;                             ///< event value
      union  {
        osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate
        osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate
      } def;                               ///< event definition
    } osEvent;
    

    Should check status to know how to interpret the osEvent.

    typedef enum  {
      osOK                    =     0,       ///< function completed; no error or event occurred.
      osEventSignal           =  0x08,       ///< function completed; signal event occurred.
      osEventMessage          =  0x10,       ///< function completed; message event occurred.
      osEventMail             =  0x20,       ///< function completed; mail event occurred.
      osEventTimeout          =  0x40,       ///< function completed; timeout occurred.
    ....snip.....
    
      os_status_reserved      =  0x7FFFFFFF  ///< prevent from enum down-size compiler optimization.
    } osStatus;
    
Reply
  • Has anyone attempted to implement and add this feature in RTX?

    Looking at the CMSIS-RTOS API it seems the API is designed to support waiting on a signal and simultaneously on one (not multiple) message queues and getting unblocked by either one. Both the osSignalWait and the osMessageGet functions return the same structure an osEvent which contains osStatus that can be used to tell the caller what type of an unblock reason it was if they should interpret the structure as an osEventSignal or an osEventMessage.

    A pretty common use case in an RTOS world is to use one or more Signals as the best way to communicate from IRQs to a Task A and then use a message queue to communicate from other Tasks to Task A.

    If you looking the RTX 4.74 source code it really seems to me that this feature is quite simply not implemented, I guess ARM open sourced a legacy RTOS that only partially implements the CMSIS-RTOS API. Lets say that something is better than nothing...

    I'm considering an alternate implementation where each IRQ uses only a signal while other Tasks send a message and then a signal - the receiving Task A would then block only on signals using osSignalWait(waitforever) and then check either its message queue or do an action particular to the specific signal from the IRQ.

    Note to the OP - if you had a signal per message queue the receiving Task A could know which message queue to check and make sure to use osMessageGet with a timeout of 0.

    This isn't super elegant but would probably be similar but not quite as efficient as how the OS itself would implement it internally.  

    /// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
    /// \param[in]     signals       wait until all specified signal flags set or 0 for any single signal flag.
    /// \param[in]     millisec      timeout value or 0 in case of no time-out.
    /// \return event flag information or error code.
    /// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
    os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
    
    

    Beware even though the signal field is defined as int32_t the RTX source code it is only a U16.

    /// Get a Message or Wait for a Message from a Queue.
    /// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
    /// \param[in]     millisec      timeout value or 0 in case of no time-out.
    /// \return event information that includes status code.
    /// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
    os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
    
    
    typedef struct  {
      osStatus                 status;     ///< status code: event or error information
      union  {
        uint32_t                    v;     ///< message as 32-bit value
        void                       *p;     ///< message or mail as void pointer
        int32_t               signals;     ///< signal flags
      } value;                             ///< event value
      union  {
        osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate
        osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate
      } def;                               ///< event definition
    } osEvent;
    

    Should check status to know how to interpret the osEvent.

    typedef enum  {
      osOK                    =     0,       ///< function completed; no error or event occurred.
      osEventSignal           =  0x08,       ///< function completed; signal event occurred.
      osEventMessage          =  0x10,       ///< function completed; message event occurred.
      osEventMail             =  0x20,       ///< function completed; mail event occurred.
      osEventTimeout          =  0x40,       ///< function completed; timeout occurred.
    ....snip.....
    
      os_status_reserved      =  0x7FFFFFFF  ///< prevent from enum down-size compiler optimization.
    } osStatus;
    
Children