Search code examples
linuxlistusbdrivers

list_empty returns 1 (non zero) if the list is not empty


I am working on Linux Device Driver code. I cant reveal what exactly this code is used for. I will try my best to explain my situation. Below code will be executed in interrupt context when we receive an USB interrupt stating that there is some data from USB. The data will arrive as URB's and we will convert them into chunks, add them to Linux Circular Doubly linked list for further processing.

     spin_lock(&demod->demod_lock);          
     /* Delete node from free list */ 
     list_del(&chunk->list_head);
     /* Add it to full list */
     list_add_tail(&chunk->list_head,&demod->ChunkRefList.full);
     /* Update chunk status */  
     chunk->status=CHUNKDESC_FULL_LIST;                         
     /* Increment the chunks assigned to application */ 
     demod->stats.assigned.c++;                         
     spin_unlock(&demod->demod_lock);          

     printk("Value returned by list_empty is %d ",list_empty(&demod->ChunkRefList.full));

I repeat, this code gets executed in interrupt context. I am using this code as a part of embedded system which displays Audio & Video(AV) forever.

After approx 12 hours, the AV is frozen and when I analyse, I see the value of list_empty(&demod->ChunkRefList.full) returned is always 0x1 forever. Usually in working case where AV is playing fine, its value will be 0x0 stating that the list is not empty.

As you can see, when above code gets executed, it first adds a node to the full list and checks if full list is empty. Ideally, the value should be always 0x0. Why its value is 0x1

I am monitoring the value of list_empty(&demod->ChunkRefList.full) using timedoctor applicaiton which doesn't introduce any overhead in interrupt context. I have used printk above to make you understand that I am printing its value.


Solution

  • Finally, I was able to figure out the issue.

    Since the code is implemented in interrupt context, using list_del followed by list_add_tail was causing issue.

    So, I removed these two macros and introduced list_move_tail macro which resolved the issue.

    By using list_move_tail, there is no need for us to remove the node and add it to the new list. The kernel will takecare of both operations.

    So, to conclude, its better to make Linux Linked list manipulations as minimal as possible in interrupt context.