data race within ptr_ring code implementation

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












1















I am implementing single-producer,single-consumer ptr_ring buffers. Are there really data races within this linux driver code ?



I asked this because ThreadSanitizer gives me error and my system crashes after I started the ptr_ring code implementation.



I have added locks to push_circ_queue(), pop_circ_queue() and free_circ_queue(). Why does data race still occur ?



Edit:



I think I got why I still have data race



I have two different instances of ptr_ring, for sending (chnl_send) and receiving (chnl_recv) purposes respectively.



push_circ_queue() and pop_circ_queue() for the same ptr_ring should not be executed concurrently by interupt handler (push) and the corresponding thread (pop)



how would I code the mutex lock code in this case ?



a mutex that makes push_circ_queue(ptr_ring A) and pop_circ_queue(ptr_ring A) cannot be executed concurrently



same for push_circ_queue(ptr_ring B) and pop_circ_queue(ptr_ring B)



but the problem got worse when push_circ_queue() is inside a interrupt handler



Any help ?



/*
* Filename: circ_ring.c
* Version: 1.0
* Description: A circular buffer using API from
* https://github.com/torvalds/linux/blob/master/include/linux/ptr_ring.h
*/

#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ptr_ring.h>
#include "circ_ring.h"
//#include <assert.h>

#define DEBUG 1

#ifdef DEBUG
#define DEBUG_MSG(...) printk(__VA_ARGS__)
#else
#define DEBUG_MSG(...)
#endif

struct mutex lock_push;
struct mutex lock_pop;
struct mutex lock_cleanup;

struct ptr_ring * init_circ_queue(int len)

struct ptr_ring * q;

q = kzalloc(sizeof(struct ptr_ring), GFP_KERNEL);
if (q == NULL)
DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring");
return NULL;


// creates an array of length 'len' where each array location can store a struct * item
if(ptr_ring_init(q, len, GFP_KERNEL) != 0)
DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring array");
return NULL;


return q;


inline int push_circ_queue(struct ptr_ring * buffer, struct item * item_push)

mutex_lock(&lock_push);

/* insert one item into the buffer */
if(ptr_ring_produce_any(buffer, item_push) == 0) // operation is successful

DEBUG_MSG(KERN_INFO "Successfully pushed val1 = %u and val2 = %un", item_push->val1, item_push->val2);

mutex_unlock(&lock_push);

return 0;


else
DEBUG_MSG(KERN_INFO "full, not enough buffer spacen");

mutex_unlock(&lock_push);

return 1;



inline int pop_circ_queue(struct ptr_ring * buffer, struct item * item_pop)

mutex_lock(&lock_pop);

struct item * item_temp;

/* extract one item struct containing two unsigned integers from the buffer */
item_temp = (struct item *)ptr_ring_consume_any(buffer);

if(item_temp) // (!= NULL)

item_pop->val1 = item_temp->val1;
item_pop->val2 = item_temp->val2;

// val1 will never be zero since the event number starts from 1 (so, val1 in push_circ_queue() will not be zero,
// same case after pop_circ_queue()), and 0 is only possible during initialization, not during pop_circ_queue()
//assert(item_pop->val1 != 0);

DEBUG_MSG(KERN_INFO "Before pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

DEBUG_MSG(KERN_INFO "val1 = %u , val2 = %un", item_pop->val1, item_pop->val2);

DEBUG_MSG(KERN_INFO "After pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

mutex_unlock(&lock_pop);

return 0;


else
//DEBUG_MSG(KERN_INFO "empty, nothing to pop from the ringn");
mutex_unlock(&lock_pop);

return 1;



void free_circ_queue(struct ptr_ring * q)

mutex_lock(&lock_cleanup);
ptr_ring_cleanup(q, NULL);
mutex_unlock(&lock_cleanup);










share|improve this question















migrated from unix.stackexchange.com yesterday


This question came from our site for users of Linux, FreeBSD and other Un*x-like operating systems.



















    1















    I am implementing single-producer,single-consumer ptr_ring buffers. Are there really data races within this linux driver code ?



    I asked this because ThreadSanitizer gives me error and my system crashes after I started the ptr_ring code implementation.



    I have added locks to push_circ_queue(), pop_circ_queue() and free_circ_queue(). Why does data race still occur ?



    Edit:



    I think I got why I still have data race



    I have two different instances of ptr_ring, for sending (chnl_send) and receiving (chnl_recv) purposes respectively.



    push_circ_queue() and pop_circ_queue() for the same ptr_ring should not be executed concurrently by interupt handler (push) and the corresponding thread (pop)



    how would I code the mutex lock code in this case ?



    a mutex that makes push_circ_queue(ptr_ring A) and pop_circ_queue(ptr_ring A) cannot be executed concurrently



    same for push_circ_queue(ptr_ring B) and pop_circ_queue(ptr_ring B)



    but the problem got worse when push_circ_queue() is inside a interrupt handler



    Any help ?



    /*
    * Filename: circ_ring.c
    * Version: 1.0
    * Description: A circular buffer using API from
    * https://github.com/torvalds/linux/blob/master/include/linux/ptr_ring.h
    */

    #include <linux/slab.h>
    #include <linux/mm.h>
    #include <linux/ptr_ring.h>
    #include "circ_ring.h"
    //#include <assert.h>

    #define DEBUG 1

    #ifdef DEBUG
    #define DEBUG_MSG(...) printk(__VA_ARGS__)
    #else
    #define DEBUG_MSG(...)
    #endif

    struct mutex lock_push;
    struct mutex lock_pop;
    struct mutex lock_cleanup;

    struct ptr_ring * init_circ_queue(int len)

    struct ptr_ring * q;

    q = kzalloc(sizeof(struct ptr_ring), GFP_KERNEL);
    if (q == NULL)
    DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring");
    return NULL;


    // creates an array of length 'len' where each array location can store a struct * item
    if(ptr_ring_init(q, len, GFP_KERNEL) != 0)
    DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring array");
    return NULL;


    return q;


    inline int push_circ_queue(struct ptr_ring * buffer, struct item * item_push)

    mutex_lock(&lock_push);

    /* insert one item into the buffer */
    if(ptr_ring_produce_any(buffer, item_push) == 0) // operation is successful

    DEBUG_MSG(KERN_INFO "Successfully pushed val1 = %u and val2 = %un", item_push->val1, item_push->val2);

    mutex_unlock(&lock_push);

    return 0;


    else
    DEBUG_MSG(KERN_INFO "full, not enough buffer spacen");

    mutex_unlock(&lock_push);

    return 1;



    inline int pop_circ_queue(struct ptr_ring * buffer, struct item * item_pop)

    mutex_lock(&lock_pop);

    struct item * item_temp;

    /* extract one item struct containing two unsigned integers from the buffer */
    item_temp = (struct item *)ptr_ring_consume_any(buffer);

    if(item_temp) // (!= NULL)

    item_pop->val1 = item_temp->val1;
    item_pop->val2 = item_temp->val2;

    // val1 will never be zero since the event number starts from 1 (so, val1 in push_circ_queue() will not be zero,
    // same case after pop_circ_queue()), and 0 is only possible during initialization, not during pop_circ_queue()
    //assert(item_pop->val1 != 0);

    DEBUG_MSG(KERN_INFO "Before pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

    DEBUG_MSG(KERN_INFO "val1 = %u , val2 = %un", item_pop->val1, item_pop->val2);

    DEBUG_MSG(KERN_INFO "After pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

    mutex_unlock(&lock_pop);

    return 0;


    else
    //DEBUG_MSG(KERN_INFO "empty, nothing to pop from the ringn");
    mutex_unlock(&lock_pop);

    return 1;



    void free_circ_queue(struct ptr_ring * q)

    mutex_lock(&lock_cleanup);
    ptr_ring_cleanup(q, NULL);
    mutex_unlock(&lock_cleanup);










    share|improve this question















    migrated from unix.stackexchange.com yesterday


    This question came from our site for users of Linux, FreeBSD and other Un*x-like operating systems.

















      1












      1








      1








      I am implementing single-producer,single-consumer ptr_ring buffers. Are there really data races within this linux driver code ?



      I asked this because ThreadSanitizer gives me error and my system crashes after I started the ptr_ring code implementation.



      I have added locks to push_circ_queue(), pop_circ_queue() and free_circ_queue(). Why does data race still occur ?



      Edit:



      I think I got why I still have data race



      I have two different instances of ptr_ring, for sending (chnl_send) and receiving (chnl_recv) purposes respectively.



      push_circ_queue() and pop_circ_queue() for the same ptr_ring should not be executed concurrently by interupt handler (push) and the corresponding thread (pop)



      how would I code the mutex lock code in this case ?



      a mutex that makes push_circ_queue(ptr_ring A) and pop_circ_queue(ptr_ring A) cannot be executed concurrently



      same for push_circ_queue(ptr_ring B) and pop_circ_queue(ptr_ring B)



      but the problem got worse when push_circ_queue() is inside a interrupt handler



      Any help ?



      /*
      * Filename: circ_ring.c
      * Version: 1.0
      * Description: A circular buffer using API from
      * https://github.com/torvalds/linux/blob/master/include/linux/ptr_ring.h
      */

      #include <linux/slab.h>
      #include <linux/mm.h>
      #include <linux/ptr_ring.h>
      #include "circ_ring.h"
      //#include <assert.h>

      #define DEBUG 1

      #ifdef DEBUG
      #define DEBUG_MSG(...) printk(__VA_ARGS__)
      #else
      #define DEBUG_MSG(...)
      #endif

      struct mutex lock_push;
      struct mutex lock_pop;
      struct mutex lock_cleanup;

      struct ptr_ring * init_circ_queue(int len)

      struct ptr_ring * q;

      q = kzalloc(sizeof(struct ptr_ring), GFP_KERNEL);
      if (q == NULL)
      DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring");
      return NULL;


      // creates an array of length 'len' where each array location can store a struct * item
      if(ptr_ring_init(q, len, GFP_KERNEL) != 0)
      DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring array");
      return NULL;


      return q;


      inline int push_circ_queue(struct ptr_ring * buffer, struct item * item_push)

      mutex_lock(&lock_push);

      /* insert one item into the buffer */
      if(ptr_ring_produce_any(buffer, item_push) == 0) // operation is successful

      DEBUG_MSG(KERN_INFO "Successfully pushed val1 = %u and val2 = %un", item_push->val1, item_push->val2);

      mutex_unlock(&lock_push);

      return 0;


      else
      DEBUG_MSG(KERN_INFO "full, not enough buffer spacen");

      mutex_unlock(&lock_push);

      return 1;



      inline int pop_circ_queue(struct ptr_ring * buffer, struct item * item_pop)

      mutex_lock(&lock_pop);

      struct item * item_temp;

      /* extract one item struct containing two unsigned integers from the buffer */
      item_temp = (struct item *)ptr_ring_consume_any(buffer);

      if(item_temp) // (!= NULL)

      item_pop->val1 = item_temp->val1;
      item_pop->val2 = item_temp->val2;

      // val1 will never be zero since the event number starts from 1 (so, val1 in push_circ_queue() will not be zero,
      // same case after pop_circ_queue()), and 0 is only possible during initialization, not during pop_circ_queue()
      //assert(item_pop->val1 != 0);

      DEBUG_MSG(KERN_INFO "Before pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

      DEBUG_MSG(KERN_INFO "val1 = %u , val2 = %un", item_pop->val1, item_pop->val2);

      DEBUG_MSG(KERN_INFO "After pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

      mutex_unlock(&lock_pop);

      return 0;


      else
      //DEBUG_MSG(KERN_INFO "empty, nothing to pop from the ringn");
      mutex_unlock(&lock_pop);

      return 1;



      void free_circ_queue(struct ptr_ring * q)

      mutex_lock(&lock_cleanup);
      ptr_ring_cleanup(q, NULL);
      mutex_unlock(&lock_cleanup);










      share|improve this question
















      I am implementing single-producer,single-consumer ptr_ring buffers. Are there really data races within this linux driver code ?



      I asked this because ThreadSanitizer gives me error and my system crashes after I started the ptr_ring code implementation.



      I have added locks to push_circ_queue(), pop_circ_queue() and free_circ_queue(). Why does data race still occur ?



      Edit:



      I think I got why I still have data race



      I have two different instances of ptr_ring, for sending (chnl_send) and receiving (chnl_recv) purposes respectively.



      push_circ_queue() and pop_circ_queue() for the same ptr_ring should not be executed concurrently by interupt handler (push) and the corresponding thread (pop)



      how would I code the mutex lock code in this case ?



      a mutex that makes push_circ_queue(ptr_ring A) and pop_circ_queue(ptr_ring A) cannot be executed concurrently



      same for push_circ_queue(ptr_ring B) and pop_circ_queue(ptr_ring B)



      but the problem got worse when push_circ_queue() is inside a interrupt handler



      Any help ?



      /*
      * Filename: circ_ring.c
      * Version: 1.0
      * Description: A circular buffer using API from
      * https://github.com/torvalds/linux/blob/master/include/linux/ptr_ring.h
      */

      #include <linux/slab.h>
      #include <linux/mm.h>
      #include <linux/ptr_ring.h>
      #include "circ_ring.h"
      //#include <assert.h>

      #define DEBUG 1

      #ifdef DEBUG
      #define DEBUG_MSG(...) printk(__VA_ARGS__)
      #else
      #define DEBUG_MSG(...)
      #endif

      struct mutex lock_push;
      struct mutex lock_pop;
      struct mutex lock_cleanup;

      struct ptr_ring * init_circ_queue(int len)

      struct ptr_ring * q;

      q = kzalloc(sizeof(struct ptr_ring), GFP_KERNEL);
      if (q == NULL)
      DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring");
      return NULL;


      // creates an array of length 'len' where each array location can store a struct * item
      if(ptr_ring_init(q, len, GFP_KERNEL) != 0)
      DEBUG_MSG(KERN_ERR "Not enough memory to allocate ptr_ring array");
      return NULL;


      return q;


      inline int push_circ_queue(struct ptr_ring * buffer, struct item * item_push)

      mutex_lock(&lock_push);

      /* insert one item into the buffer */
      if(ptr_ring_produce_any(buffer, item_push) == 0) // operation is successful

      DEBUG_MSG(KERN_INFO "Successfully pushed val1 = %u and val2 = %un", item_push->val1, item_push->val2);

      mutex_unlock(&lock_push);

      return 0;


      else
      DEBUG_MSG(KERN_INFO "full, not enough buffer spacen");

      mutex_unlock(&lock_push);

      return 1;



      inline int pop_circ_queue(struct ptr_ring * buffer, struct item * item_pop)

      mutex_lock(&lock_pop);

      struct item * item_temp;

      /* extract one item struct containing two unsigned integers from the buffer */
      item_temp = (struct item *)ptr_ring_consume_any(buffer);

      if(item_temp) // (!= NULL)

      item_pop->val1 = item_temp->val1;
      item_pop->val2 = item_temp->val2;

      // val1 will never be zero since the event number starts from 1 (so, val1 in push_circ_queue() will not be zero,
      // same case after pop_circ_queue()), and 0 is only possible during initialization, not during pop_circ_queue()
      //assert(item_pop->val1 != 0);

      DEBUG_MSG(KERN_INFO "Before pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

      DEBUG_MSG(KERN_INFO "val1 = %u , val2 = %un", item_pop->val1, item_pop->val2);

      DEBUG_MSG(KERN_INFO "After pop, head = %u , tail = %un", buffer->consumer_head, buffer->consumer_tail);

      mutex_unlock(&lock_pop);

      return 0;


      else
      //DEBUG_MSG(KERN_INFO "empty, nothing to pop from the ringn");
      mutex_unlock(&lock_pop);

      return 1;



      void free_circ_queue(struct ptr_ring * q)

      mutex_lock(&lock_cleanup);
      ptr_ring_cleanup(q, NULL);
      mutex_unlock(&lock_cleanup);







      multithreading kernel buffer driver address-sanitizer






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 21 hours ago









      kevin998x

      407




      407










      asked Jan 8 at 4:22









      kevinkevin

      339




      339




      migrated from unix.stackexchange.com yesterday


      This question came from our site for users of Linux, FreeBSD and other Un*x-like operating systems.






      migrated from unix.stackexchange.com yesterday


      This question came from our site for users of Linux, FreeBSD and other Un*x-like operating systems.
























          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54286731%2fdata-race-within-ptr-ring-code-implementation%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54286731%2fdata-race-within-ptr-ring-code-implementation%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown






          Popular posts from this blog

          How to check contact read email or not when send email to Individual?

          Bahrain

          Postfix configuration issue with fips on centos 7; mailgun relay