Why would Mail.alloc() return false when Main.full() is false?

Hi,

I have the following code:

// Sender
Mail<RadioReceivedData, 32> mailBox;

if(!mailBox.full()) {
    // Question: allocation will always be successful since mailbox is not full ?
    RadioReceivedData * radioRdPtr = mailBox.alloc();
    if(radioRdPtr) {
        mailBox.put(radioRdPtr);
    } else {
        print_function("RdMail alloc failed\r\n");
    }
}

If mailBox is not freed

// Receiver
if(!mailBox.empty()) {
    osEvent evt = mailBox.get();
    if(evt.status == osEventMail) {
        RadioReceivedData *radioRdPtr = (RadioReceivedData *)evt.value.p;
        //mailBox.free(radioRdPtr);
    }
}

I soon started see a lot of the following message in console output.

RdMail alloc failed

My question is, why would I see this line of debug output? I assume mailBox.full() will be true if no memory block is available. What am I missing here? I compiled code in mbed-os-5.15

Thanks.

Hello Li,

I guess the mailBox is not full yet (hence the full function returns false) but for the alloc function it takes more time to succeed when there is less free memory available in the mailBox's memory pool (probably because of the algorithm used to find a free memory block). However, the alloc function must not wait (block the system) and that’s why it returns a nullptr. If the radio transmitter can allow for some small delay try to use the alloc_for(uint32_t millisec) function rather than the alloc() and see how it works.

I think there is no harm if you completely omit calling the full function because you have to check the pointer returned by the alloc function anyway.

Thanks for your reply. I guess what I missed is the following note in Mail.h

 * Memory considerations: The mail data store and control structures are part of this class - they do not (themselves)
 * allocate memory on the heap, both for the Mbed OS and underlying RTOS objects (static or dynamic RTOS memory
 * pools are not being used).

For the sake of discussion, is there a way to pre-allocate memory for the entire mailbox? Use alloc_for() can mitigate the problem to a large degree, but still not a deterministic way.

I have never tried such arrangement but maybe you can try to use a Queue rather than a Mail and allocate a global static array of messages for example as follows:

typedef struct {
...
} RadioMessage;

//MemoryPool<RadioMessage, 16> mpool;
RadioMessage radioMessage[16];  // allocate the static global memory
Queue<RadioMessage, 16> queue;  // create a queue

// Sender/Producer
int i = 0; // next index

while(true) {
    ...
    // Make it circular
    if (i == 16) {
       i = 0;
    }
    // fill in the 'radioMessage[i]' structure with data
    ...
    // Put the message on the queue by passing its address to the 'put' function
    queue.put(&radioMessage[i++]);
    ...
}

// Receiver/Consumer
...
while(true) {
    ...
    osEvent evt = queue.get();
    if (evt.status == osEventMessage) {
        RadioMessage *radioRdPtr = (RadioMessage *)evt.value.p;
        // Use the data received
        ...
        // Since the radioRdPtr is pointing to a cell in the static array there is nothing to free.
        //mpool.free(radioRdPtr);
    }
}

I eventually went with the MemoryPool + Queue similar to the official example, to avoid the hassle of managing index manually.

Update: it seems Mail = Queue + MemoryPool. Using an array + Queue seems to be the only deterministic way.