Receiving an ACK within time constraints for every message sent in a custom timer app in a non-blocking way

I have a timer app that fires off every expiry time, and are arranged in the order of their expiry time and priority (similar to how FreeRTOS implements I think apart from the priority part).

So if the following indicates the timers along with their expiry and priorities, the list would look like:
T2 -> T1 -> T3

Nodes Expiry Times Priorities
T1 5 1
T2 5 10
T3 10 1

In my app, once the node expires, a relevant message stored in the Node struct is sent over to the client, in response to which it shall receive an ACK within X seconds, and if it’s not received, the same node is added to the front of the list so it’s retransmitted next.

have the timer seems to be running fine but needed some design suggestions on integrating the ACK logic.

Sample pseudocode looks something like this:

static Queue *queue;  // gets populated in a different function in the same file

void callback(const char *timerMsg)
{
   // writes msg to a mqueue to be read by the client
   // in response to which an ACK should be sent...
}

void *TimerThread(void *arg)
{
  Queue *head = queue->head; 

  while(1)
  {
    long now = getCurrentTime();
    long timeElapsed = now - start;
    char *msg;

    if (timeElapsed >= head-> refExpiryTime) // if node expired
    { 
       msg = head->msg;  
       callback(msg); 
       PopAndPush(head);     // delete the current head from the list and append with an updated time
    }
  }
}

// thread that handles messages received from the client
void *ReadThread(void *arg)
{
   uint8_t buffer[100];

   while(1)
   {
     // block the thread to wait on a message queue to get populated from a client that may contain an ACK message...
     
     // have a state machine
     switch(buffer[0])
     {
       case ACK_MSG:
          // write to AckQueue?
          break;
     }
   }
}
  • Would it make sense to:
    • have two queues: SentQueue and AckQueue where the former stores the nodes that expired and the latter the ACK messages coming to ReadThread()
    • fire off a separate timer for every node that expired to keep track of whether an ACK was received within the X timeout. Once the timeout happens, scan through AckQueue and see whether an ACK for this particular node is there or not. If not, append to the front of the queue.

Something like this

Also I’m using Linux and not FreeRTOS :frowning: but i’d appreciate hearing some thoughts

If you are using Linux and have enough resources, you can use some dictionary like structure to avoid scanning the whole queue. Depending the maximum possible length of this queue, it might not be worth it though.

Thanks.

So you’re suggesting to not use queues and rather a hashmap so avoid doing a complete O(n) loop every time the timer expires?

Yes, for the ACKs only though.

right, but then you are still “waiting” till 5 seconds are over no? after futher looking into it, I think it may be better to read into the queue with a timer specified perhaps? mq_timedreceive which allows you to timeout if you haven’t received anything in the queue