Lockless queue implementation ends up having a loop under stress - c

I have lockless queues written in C in form of a linked list that contains requests from several threads posted to and handled in a single thread. After a few hours of stress I end up having the last request's next pointer pointing to itself, which creates an endless loop and locks up the handling thread.
The application runs (and fails) on both Linux and Windows. I'm debugging on Windows, where my COMPARE_EXCHANGE_PTR maps to InterlockedCompareExchangePointer.
This is the code that pushes a request to the head of the list, and is called from several threads:
void push_request(struct request * volatile * root, struct request * request)
{
assert(request);
do {
request->next = *root;
} while(COMPARE_EXCHANGE_PTR(root, request, request->next) != request->next);
}
This is the code that gets a request from the end of the list, and is only called by a single thread that is handling them:
struct request * pop_request(struct request * volatile * root)
{
struct request * volatile * p;
struct request * request;
do {
p = root;
while(*p && (*p)->next) p = &(*p)->next; // <- loops here
request = *p;
} while(COMPARE_EXCHANGE_PTR(p, NULL, request) != request);
assert(request->next == NULL);
return request;
}
Note that I'm not using a tail pointer because I wanted to avoid the complication of having to deal with the tail pointer in push_request. However I suspect that the problem might be in the way I find the end of the list.
There are several places that push a request into the queue, but they all look generaly like this:
// device->requests is defined as struct request * volatile requests;
struct request * request = malloc(sizeof(struct request));
if(request) {
// fill out request fields
push_request(&device->requests, request);
sem_post(device->request_sem);
}
The code that handles the request is doing more than that, but in essence does this in a loop:
if(sem_wait_timeout(device->request_sem, timeout) == sem_success) {
struct request * request = pop_request(&device->requests);
// handle request
free(request);
}
I also just added a function that is checking the list for duplicates before and after each operation, but I'm afraid that this check will change the timing so that I will never encounter the point where it fails. (I'm waiting for it to break as I'm writing this.)
When I break the hanging program the handler thread loops in pop_request at the marked position. I have a valid list of one or more requests and the last one's next pointer points to itself. The request queues are usually short, I've never seen more then 10, and only 1 and 3 the two times I could take a look at this failure in the debugger.
I thought this through as much as I could and I came to the conclusion that I should never be able to end up with a loop in my list unless I push the same request twice. I'm quite sure that this never happens. I'm also fairly sure (although not completely) that it's not the ABA problem.
I know that I might pop more than one request at the same time, but I believe this is irrelevant here, and I've never seen it happening. (I'll fix this as well)
I thought long and hard about how I can break my function, but I don't see a way to end up with a loop.
So the question is: Can someone see a way how this can break? Can someone prove that this can not?
Eventually I will solve this (maybe by using a tail pointer or some other solution - locking would be a problem because the threads that post should not be locked, I do have a RW lock at hand though) but I would like to make sure that changing the list actually solves my problem (as opposed to makes it just less likely because of different timing).

It's subtle but you do have a race condition there.
Start with a list with one element in it, req1. So we have:
device->requests == req1;
req1->next == NULL;
Now, we push a new element req2, and simultaneously try to pop the queue. The push for req2 starts first. The while loop body runs, so we now have:
device->requests == req1;
req1->next == NULL;
req2->next == req1;
Then the COMPARE_EXCHANGE_PTR runs, so we have:
device->requests == req2;
req1->next == NULL;
req2->next == req1;
...and the COMPARE_EXCHANGE_PTR() returns req1. Now, at this point, before the comparison in the while condition, the push gets interrupted and the pop starts running.
The pop runs correctly to completion, popping off req1 - which means that we have:
device->requests == req2;
req2->next == NULL;
The push restarts. It now fetches request->next to do the comparison - and it fetches the new value of req2->next, which is NULL. It compares req1 with NULL, the comparison succeeds, the while loop runs again, and now we have:
device->requests == req2;
req2->next == req2;
This time the test fails, the while loop exits, and you have your loop.
This should fix it:
void push_request(struct request * volatile * root, struct request * request)
{
struct request *oldroot;
assert(request);
do {
request->next = oldroot = *root;
} while(COMPARE_EXCHANGE_PTR(root, request, oldroot) != oldroot);
}

Related

FreeRTOS: xEventGroupWaitBits() crashes inside a loop with scheduler running

We have several tasks running on an STM32 MCU. In the main.c file we call all the init functions for the various threads. Currently there is one renewing xTimer to trigger a periodic callback (which, at present, does nothing except print a message that it was called). Declarations as follows, outside any function:
TimerHandle_t xMotorTimer;
StaticTimer_t xMotorTimerBuffer;
EventGroupHandle_t MotorEventGroupHandle;
In the init function for the thread:
xMotorTimer = xTimerCreateStatic("MotorTimer",
xTimerPeriod,
uxAutoReload,
( void * ) 0,
MotorTimerCallback,
&xMotorTimerBuffer);
xTimerStart(xMotorTimer, 100);
One thread starts an infinite loop that pauses on an xEventGroupWaitBits() to determine whether to enter an inner loop, which is then governed by its own state:
DeclareTask(MotorThread)
{
bool done = false;
EventBits_t event;
for (;;)
{
Packet * pkt = NULL;
event = xEventGroupWaitBits( MotorEventGroupHandle,
EVT_MOTOR_START | EVT_MOTOR_STOP, // EventBits_t uxBitsToWaitFor
pdTRUE, // BaseType_t xClearOnExit
pdFALSE, // BaseType_t xWaitForAllBits,
portMAX_DELAY //TickType_t xTicksToWait
);
if (event & EVT_MOTOR_STOP)
{
MotorStop(true);
}
if (event & EVT_MOTOR_START)
{
EnableMotor(MOTOR_ALL);
done = false;
while (!done && !abortTest)
{
xQueueReceive(motorQueue, &pkt, portMAX_DELAY);
if (pkt == NULL)
{
done = true;
} else {
done = MotorExecCmd(pkt);
done = ( uxQueueMessagesWaiting(motorQueue) == ( UBaseType_t ) 0);
FreePacket(pkt);
}
}
}
}
}
xEventGroupWaitBits() fires successfully once, the inner loop enters, then exits when the program state meets the expected conditions. The outer loop repeats as it should, but when it arrives again at the xEventGroupWaitBits() call, it crashes almost instantly. In fact, it crashes a few lines down into the wait function, at a call to uxTaskResetEventItemValue(). I can't even step the debugger into the function, as if calling a bad address. But if I check the disassembly, the memory address for the BL instruction hasn't changed since the previous loop, and that address is valid. The expected function is actually there.
I can prevent this chain of events happening altogether by not calling that xTimerStart() and leaving everything else as-is. Everything runs just fine, so it's definitely not xEventGroupWaitBits() (or at least not just that). We tried switching to xEventGroupGetBits() and adding a short osDelay to the loop just as an experiment. That also froze the whole system.
So, main question. Are we doing something FreeRTOS is not meant to do here, using xEventGroupWaitBits() with xTimers running? Or is there supposed to be something between xEventGroupWaitBits() calls, possibly some kind of state reset that we've overlooked? Reviewing the docs, I can't see it, but I could have missed a detail. The

Mutex Implementation in C

I am trying to implement a mutex in c using the fetch and increment algorithm (sort of like the bakery algorithm). I have implemented the fetch and add part atomically. I have every thread obtain a ticket number and wait for their number to be "displayed". However, I have not found a way to tackle the issue of waiting for your ticket to be displayed. I have thought of using a queue to store your thread ID and descheudle/yield yourself until someone who has the lock, wakes you up. However, I would need a lock for the queue as well! :(
Are there any recommendations on what I could do to make the queue insertion safe or perhaps a different approach to using a queue?
Here is some code of my initial implementation:
void mutex_lock( mutex_t *mp ) {
while (compareAndSwap(&(mp->guard), 0, 1) == 1) {
// This will loop for a short period of time, Need to change this <--
}
if ( mp->lock == 1 ) {
queue_elem_t elem;
elem.data.tid = gettid();
enq( &(mp->queue), &(elem) );
mp->guard = 0;
deschedule();
}
else {
mp->lock = 1; // Lock the mutex
mp->guard = 0; // Allow others to enq themselves
}
}
Also, lets for now ignore the potential race condition where someone can call make_runnable before you call deschedule, I can write another system call that will say we are about to deschedule so queue make_runnable calls.

InternetReadFileEx gives 10035 and 1008 errors

I am trying to write an Asyncronous Wininet application. I read the data in my callback function in case of INTERNET_STATUS_REQUEST_COMPLETE and I handle the ERROR_IO_PENDING errors as well. But after some data read from internet, InternetReadFileEx function gives me 10035=WSAEWOULDBLOCK (A non-blocking socket operation could not be completed immediately) error. After that error I call InternetReadFileEx again and this time it gives me 1008=ERROR_NO_TOKEN (An attempt was made to reference a token that does not exist.) error. I think my design is not correct, and I receive these error because of that.
Here is a snippet of my code:
case INTERNET_STATUS_REQUEST_COMPLETE:
{
BOOL bAllDone= FALSE;
DWORD lastError;
do
{
//Create INTERNET_BUFFERS
char m_pbReadBuffer[4096];
INTERNET_BUFFERS BuffersIn;
ZeroMemory(&BuffersIn, sizeof(INTERNET_BUFFERS));
BuffersIn.dwStructSize = sizeof(INTERNET_BUFFERS);
BuffersIn.lpvBuffer = m_pbReadBuffer;
BuffersIn.dwBufferLength = 4096;
InternetReadFileEx(ReqContext->File, &BuffersIn, IRF_ASYNC, 1);
//HERE I GOT THOSE 10035 and 1008 ERRORS
lastError = GetLastError();
if(lastError == 997) // handling ERROR_IO_PENDING
break;//break the while loop
//append it to my ISTREAM
(ReqContext->savedStream)->Write(BuffersIn.lpvBuffer, BuffersIn.dwBufferLength, NULL);
if (BuffersIn.dwBufferLength == 0)
bAllDone = TRUE;
}while(bAllDone == FALSE);
//delete[] m_pbReadBuffer;
if(bAllDone == TRUE && lastError== 0)
{
//these are for passing the ISTREAM to the function which calls "InternetOpenUrl"
LARGE_INTEGER loc;
loc.HighPart = 0;
loc.LowPart = 0;
ReqContext->savedStream->Seek(loc, STREAM_SEEK_SET, NULL);
ReqContext->savedCallback->OnUrlDownloaded(S_OK, ReqContext->savedStream); //Tell silverlight ISTREAM is ready
ReqContext->savedStream->Release();
ReqContext->savedCallback->Release();
InternetCloseHandle(ReqContext->File);
InternetSetStatusCallback(ReqContext->Connection, NULL);
InternetCloseHandle(ReqContext->Connection);
delete[] ReqContext;
}
}
break;
Can anyone give me a hand to correct that?
Thanks everyone helping...
GetLastError() is only meaningful if InternetReadFileEx() (or any other API, for that matter) actually fails with an error. Otherwise, you will be processing an error from an earlier API call, giving your code a false illusion that an error happened when it really may not have. You MUST pay attention to API return values, but you are currently ignoring the return value of InternetReadFileEx().
Worse than that, though, you are using InternetReadFileEx() in async mode but you are using a receiving buffer that is local to the INTERNET_STATUS_REQUEST_COMPLETE callback handler. If InternetReadFileEx() fails with an ERROR_IO_PENDING error, the read is performed in the background and INTERNET_STATUS_REQUEST_COMPLETE will be triggered when the read is complete. However, when that error occurs, you are breaking your loop (even though the read is still in progress) and that buffer will go out of scope before the read is finished. While the reading is still in progress, the receiving buffer is still on the stack and InternetReadFileEx() is still writing to it, but it may get re-used for other things at the same time because your code moved on to do other things and did not wait for the read to finish.
You need to re-think your approach. Either:
remove the IRF_ASYNC flag, since that is how the rest of your callback code is expecting InternetReadFileEx() to behave.
re-write the code to operate in async mode correctly. Dynamically allocate the receive buffer (or at least store it somewhere else that remains in scope during the async reading), don't call IStream::Write() unless you actually have data to write (only when InternetReadFileEx() returned TRUE right away, or you get an INTERNET_STATUS_REQUEST_COMPLETE event with a success code from an earlier InternetReadFileEx()/ERROR_IO_PENDING call), etc.
There are plenty of online examples and tutorials that show how to use InternetReadFileEx() in async mode. Search around.

lock free queue enqueue if not empty

I have implemented a lock free queue in C using compare and swap based on http://www.boyet.com/articles/LockfreeQueue.html.
Its working great but I'm trying to integrate this queue into a lock free skip-list that i have implemented. I'm using the skip-list as a priority queue and would like to use the lock free queue inside each node to store multiple values when there is a priority collision. however due to the way nodes are managed in the skip list when i detect a priority collision i need to be able to add the item to the queue only if the queue is not empty.
due to the lock free nature of the queue im not sure how to actually perform this operation.
So basically how would i write an atomic enqueue_if_not_empty operation?
EDIT: As it was noticed, I wrote the function with quite the opposite semantics - enqueuing only into an empty queue. I fixed the name to reflect that, and decided to leave it as is just in case someone will be interested. So, this is not the right answer to the question, but do not downvote please, unless you find another reason :)
Below is an attempt to add EnqueueIfEmpty() to the queue implementation in the referenced paper. I did not verify that it works or even compiles.
The basic idea is that you insert a new node right after the head (and not the tail), provided that head's next is currently null (which is the necessary condition for an empty queue). I left additional checks for head being equal to tail, which possibly can be removed.
public bool EnqueueIfEmpty(T item) {
// Return immediately if the queue is not empty.
// Possibly the first condition is redundant.
if (head!=tail || head.Next!=null)
return false;
SingleLinkNode<T> oldHead = null;
// create and initialize the new node
SingleLinkNode<T> node = new SingleLinkNode<T>();
node.Item = item;
// loop until we have managed to update the tail's Next link
// to point to our new node
bool Succeeded = false;
while (head==tail && !Succeeded) {
// save the current value of the head
oldHead = head;
// providing that the tail still equals to head...
if (tail == oldHead) {
// ...and its Next field is null...
if (oldhead.Next == null) {
// ...try inserting new node right after the head.
// Do not insert at the tail, because that might succeed
// with a non-empty queue as well.
Succeeded = SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, null, node);
}
// if the head's Next field was non-null, another thread is
// in the middle of enqueuing a new node, so the queue becomes non-empty
else {
return false;
}
}
}
if (Succeeded) {
// try and update the tail field to point to our node; don't
// worry if we can't, another thread will update it for us on
// the next call to Enqueue()
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldHead, node);
}
return Succeeded;
}
Well, Enqueue-If-Not-Empty appears to be relatively straightforward, but with a limitation: other threads may concurrently remove all previous items from the queue, so that after insertion at the tail is done, the new item might happen to be the first in the queue. Since atomic compare-and-swap operations are done with different fields (enqueuing changes tail.Next while dequeuing advances head), stronger guarantees would require additional complexity not only in this function but at least in Dequeue() as well.
The following changes to the normal Enqueue() method are sufficient:
1) at the function start, check for head.Next being null, and if so, return immediately as the queue is empty.
2) add head.Next!=null into the loop condition in case enqueuing attempts should be stopped if the initially non-empty queue becomes empty before insertion succeeds. This does not prevent the situation I descibed above (because there is a time window between the check for emptiness and the node insertion), but reduces its chance to happen.
3) at the end of the function, only try advancing the tail if the new node was successfully enqueued (like I did in the Enqueue-If-Empty answer).

Problem with Array of Queues in FreeRTOS

I am building a FreeRTOS application. I created a module which registers a freeRTOS queue handle from another module and when an interrupt in this module module occurs, it sends a message to all the registered queues. But it seems I am able to send the message from the queue but not able to receive it at the other module.
Here is my code.
remote module:-
CanRxMsg RxMessage;
can_rx0_queue = xQueueCreate( 10, sizeof(CanRxMsg) ); // can_rx0_queue is globally defined
// Register my queue with can module
if (registerRxQueueWithCAN(can_rx0_queue) == -1)
{
TurnLedRed();
}
while(1)
{
if(can_rx0_queue){
while( xQueueReceive( can_rx0_queue, ( void * ) &RxMessage, portMAX_DELAY))
{
}
.....
Here is the registration module
#define MAX_NUMBER_OF_RX_QUEUES 2
//xQueueHandle rxQueueStore[MAX_NUMBER_OF_RX_QUEUES];
typedef struct QUEUE_REGISTRY_ITEM
{
// signed char *pcQueueName;
xQueueHandle xHandle;
} xQueueRegistryItem;
xQueueRegistryItem rxQueueStore[MAX_NUMBER_OF_RX_QUEUES];
int numberOfQueuesRegistered;
#define cError -1
#define cSuccess 0
void processInterrupt()
{
for(int i=0; i < numberOfQueuesRegistered; i++)
{
if(xQueueSendFromISR(rxQueueStore[i].xHandle,(void *) &RxMessage,&tmp) != pdTRUE)
TurnLedRed();
if(tmp)resched_needed = pdTRUE;
}
portEND_SWITCHING_ISR(resched_needed);
}
int registerRxQueueWithCAN(xQueueHandle myQueue)
{
if(numberOfQueuesRegistered == MAX_NUMBER_OF_RX_QUEUES)
{
// Over Flow of registerations
TurnLedRed();
return cError;
}else
{
rxQueueStore[numberOfQueuesRegistered].xHandle = myQueue;
numberOfQueuesRegistered++;
}
return cSuccess;
}
Few points:-
xQuehandle is typdefed to "void *"
The code works if remove the registration thing and just do with directly pointer of queue in xQueueSendFromISR if I take the pointer by extern.
Any advice or information required?
At first glance I cannot see anything obviously wrong. The problem might be outside of the code you have shown, like how is can_rx0_queue declared, how is the interrupt entered, which port are you using, etc.
There is a FreeRTOS support forum, linked to from the FreeRTOS home page http://www.FreeRTOS.org
Regards.
I think Richard is right. The problem could be issues that are not within your code that you have posted here.
Are you calling any form of suspension on the receiving Task that is waiting on the Queue? When you invoke a vTaskSuspend() on a Task that is blocked waiting on a Queue, the Task that is suspended will be moved to the pxSuspendedTaskList and it will "forget" that it is waiting on an Event Queue because the pvContainer of xEventListItem in that Task will be set to NULL.
You might want to check if your receiving Task is ever suspended while waiting on a Queue. Hope that helped. Cheers!
Your shared memory should at least be declared volatile:
volatile xQueueRegistryItem rxQueueStore[MAX_NUMBER_OF_RX_QUEUES] ;
volatile int numberOfQueuesRegistered ;
otherwise the compiler may optimise out read or writes to these because it has no concept of different threads of execution (between the ISR and the main thread).
Also I recall that some PIC C runtime start-up options do not apply zero-initialisation of static data in order to minimise start-up time, if you are using such a start-up, you should explicitly initialise numberOfQueuesRegistered. I would suggest that to do so would be a good idea in any case.
It is not clear from your code that RxMessage in the ISR is not the same as RxMessage in the 'remote module'; they should not be shared, since that would allow the ISR to potentially modify the data while the receiving thread was processing it. If they could be shared, there would ne no reason to have a queue in the first place, since shared memory and a semaphore would suffice.
As a side-note, there is never any need to cast a pointer to void*, and you should generally avoid doing so, since it will prevent the compiler from issuing an error if you were to pass something other than a pointer. The whole point of a void* is rather that it can accept any pointer type.

Resources