Subversion Repositories f9daq

Rev

Rev 197 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /********************************************************************\
  2.  
  3.   Name:         rb.c
  4.   Created by:   Stefan Ritt
  5.  
  6.   $Id: rb.cpp 21437 2014-07-30 14:13:29Z ritt $
  7.  
  8. \********************************************************************/
  9.  
  10. #include <stdio.h>
  11. #ifdef OS_DARWIN
  12. #include <sys/malloc.h>
  13. #else
  14. #include <malloc.h>
  15. #endif
  16. #include <string.h>
  17. #include <assert.h>
  18.  
  19. #include "rb.h"
  20.  
  21. /********************************************************************\
  22. *                                                                    *
  23. *                 Ring buffer functions                              *
  24. *                                                                    *
  25. * Provide an inter-thread buffer scheme for handling front-end       *
  26. * events. This code allows concurrent data acquisition, calibration  *
  27. * and network transfer on a multi-CPU machine. One thread reads      *
  28. * out the data, passes it vis the ring buffer functions              *
  29. * to another thread running on the other CPU, which can then         *
  30. * calibrate and/or send the data over the network.                   *
  31. *                                                                    *
  32. \********************************************************************/
  33.  
  34. typedef struct {
  35.    unsigned char *buffer;
  36.    unsigned int size;
  37.    unsigned int max_event_size;
  38.    unsigned char *rp;
  39.    unsigned char *wp;
  40.    unsigned char *ep;
  41. } RING_BUFFER;
  42.  
  43. #define MAX_RING_BUFFER 100
  44. RING_BUFFER rb[MAX_RING_BUFFER];
  45.  
  46. volatile int _rb_nonblocking = 0;
  47.  
  48. extern void ss_sleep(int ms);
  49.  
  50. int rb_set_nonblocking()
  51. /********************************************************************\
  52.  
  53.   Routine: rb_set_nonblocking
  54.  
  55.   Purpose: Set all rb_get_xx to nonblocking. Needed in multi-thread
  56.            environments for stopping all theads without deadlock
  57.  
  58.   Input:
  59.     NONE
  60.  
  61.   Output:
  62.     NONE
  63.  
  64.   Function value:
  65.     RB_SUCCESS       Successful completion
  66.  
  67. \********************************************************************/
  68. {
  69.    _rb_nonblocking = 1;
  70.  
  71.    return RB_SUCCESS;
  72. }
  73.  
  74. int rb_create(int size, int max_event_size, int *handle)
  75. /********************************************************************\
  76.  
  77.   Routine: rb_create
  78.  
  79.   Purpose: Create a ring buffer with a given size
  80.  
  81.   Input:
  82.     int size             Size of ring buffer, must be larger than
  83.                          2*max_event_size
  84.     int max_event_size   Maximum event size to be placed into
  85.                          ring buffer
  86.   Output:
  87.     int *handle          Handle to ring buffer
  88.  
  89.   Function value:
  90.     DB_SUCCESS           Successful completion
  91.     DB_NO_MEMORY         Maximum number of ring buffers exceeded
  92.     DB_INVALID_PARAM     Invalid event size specified
  93.  
  94. \********************************************************************/
  95. {
  96.    int i;
  97.  
  98.    for (i = 0; i < MAX_RING_BUFFER; i++)
  99.       if (rb[i].buffer == NULL)
  100.          break;
  101.  
  102.    if (i == MAX_RING_BUFFER)
  103.       return RB_NO_MEMORY;
  104.  
  105.    if (size < max_event_size * 2)
  106.       return RB_INVALID_PARAM;
  107.  
  108.    memset(&rb[i], 0, sizeof(RING_BUFFER));
  109.    rb[i].buffer = (unsigned char *) malloc(size);
  110.    assert(rb[i].buffer);
  111.    rb[i].size = size;
  112.    rb[i].max_event_size = max_event_size;
  113.    rb[i].rp = rb[i].buffer;
  114.    rb[i].wp = rb[i].buffer;
  115.    rb[i].ep = rb[i].buffer;
  116.  
  117.    *handle = i + 1;
  118.  
  119.    return RB_SUCCESS;
  120. }
  121.  
  122. int rb_delete(int handle)
  123. /********************************************************************\
  124.  
  125.   Routine: rb_delete
  126.  
  127.   Purpose: Delete a ring buffer
  128.  
  129.   Input:
  130.     none
  131.   Output:
  132.     int handle       Handle to ring buffer
  133.  
  134.   Function value:
  135.     DB_SUCCESS       Successful completion
  136.  
  137. \********************************************************************/
  138. {
  139.    if (handle < 0 || handle >= MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  140.       return RB_INVALID_HANDLE;
  141.  
  142.    free(rb[handle - 1].buffer);
  143.    memset(&rb[handle - 1], 0, sizeof(RING_BUFFER));
  144.  
  145.    return RB_SUCCESS;
  146. }
  147.  
  148. int rb_get_wp(int handle, void **p, int millisec)
  149. /********************************************************************\
  150.  
  151. Routine: rb_get_wp
  152.  
  153.   Purpose: Retrieve write pointer where new data can be written
  154.  
  155.   Input:
  156.      int handle               Ring buffer handle
  157.      int millisec             Optional timeout in milliseconds if
  158.                               buffer is full. Zero to not wait at
  159.                               all (non-blocking)
  160.  
  161.   Output:
  162.     char **p                  Write pointer
  163.  
  164.   Function value:
  165.     DB_SUCCESS       Successful completion
  166.  
  167. \********************************************************************/
  168. {
  169.    int h, i;
  170.    unsigned char *rp;
  171.  
  172.    if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  173.       return RB_INVALID_HANDLE;
  174.  
  175.    h = handle - 1;
  176.  
  177.    for (i = 0; i <= millisec / 10; i++) {
  178.  
  179.       rp = rb[h].rp;            // keep local copy, rb[h].rp might be changed by other thread
  180.  
  181.       /* check if enough size for wp >= rp without wrap-around */
  182.       if (rb[h].wp >= rp
  183.           && rb[h].wp + rb[h].max_event_size <= rb[h].buffer + rb[h].size - rb[h].max_event_size) {
  184.          *p = rb[h].wp;
  185.          return RB_SUCCESS;
  186.       }
  187.  
  188.       /* check if enough size for wp >= rp with wrap-around */
  189.       if (rb[h].wp >= rp && rb[h].wp + rb[h].max_event_size > rb[h].buffer + rb[h].size - rb[h].max_event_size && rb[h].rp > rb[h].buffer) {    // next increment of wp wraps around, so need space at beginning
  190.          *p = rb[h].wp;
  191.          return RB_SUCCESS;
  192.       }
  193.  
  194.       /* check if enough size for wp < rp */
  195.       if (rb[h].wp < rp && rb[h].wp + rb[h].max_event_size < rp) {
  196.          *p = rb[h].wp;
  197.          return RB_SUCCESS;
  198.       }
  199.  
  200.       if (millisec == 0)
  201.          return RB_TIMEOUT;
  202.  
  203.       if (_rb_nonblocking)
  204.          return RB_TIMEOUT;
  205.  
  206.       /* wait one time slice */
  207.       ss_sleep(10);
  208.    }
  209.  
  210.    return RB_TIMEOUT;
  211. }
  212.  
  213. int rb_increment_wp(int handle, int size)
  214. /********************************************************************\
  215.  
  216.   Routine: rb_increment_wp
  217.  
  218.   Purpose: Increment current write pointer, making the data at
  219.            the write pointer available to the receiving thread
  220.  
  221.   Input:
  222.      int handle               Ring buffer handle
  223.      int size                 Number of bytes placed at the WP
  224.  
  225.   Output:
  226.     NONE
  227.  
  228.   Function value:
  229.     RB_SUCCESS                Successful completion
  230.     RB_INVALID_PARAM          Event size too large or invalid handle
  231. \********************************************************************/
  232. {
  233.    int h;
  234.    unsigned char *new_wp;
  235.  
  236.    if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  237.       return RB_INVALID_HANDLE;
  238.  
  239.    h = handle - 1;
  240.  
  241.    if ((unsigned int) size > rb[h].max_event_size)
  242.       return RB_INVALID_PARAM;
  243.  
  244.    new_wp = rb[h].wp + size;
  245.  
  246.    /* wrap around wp if not enough space */
  247.    if (new_wp > rb[h].buffer + rb[h].size - rb[h].max_event_size) {
  248.       rb[h].ep = new_wp;
  249.       new_wp = rb[h].buffer;
  250.       assert(rb[h].rp != rb[h].buffer);
  251.    }
  252.  
  253.    rb[h].wp = new_wp;
  254.  
  255.    return RB_SUCCESS;
  256. }
  257.  
  258. int rb_get_rp(int handle, void **p, int millisec)
  259. /********************************************************************\
  260.  
  261.   Routine: rb_get_rp
  262.  
  263.   Purpose: Obtain the current read pointer at which new data is
  264.            available with optional timeout
  265.  
  266.   Input:
  267.     int handle               Ring buffer handle
  268.     int millisec             Optional timeout in milliseconds if
  269.                              buffer is full. Zero to not wait at
  270.                              all (non-blocking)
  271.  
  272.   Output:
  273.     char **p                 Address of pointer pointing to newly
  274.                              available data. If p == NULL, only
  275.                              return status.
  276.  
  277.   Function value:
  278.     RB_SUCCESS       Successful completion
  279.  
  280. \********************************************************************/
  281. {
  282.    int i, h;
  283.  
  284.    if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  285.       return RB_INVALID_HANDLE;
  286.  
  287.    h = handle - 1;
  288.  
  289.    for (i = 0; i <= millisec / 10; i++) {
  290.  
  291.       if (rb[h].wp != rb[h].rp) {
  292.          if (p != NULL)
  293.             *p = rb[handle - 1].rp;
  294.          return RB_SUCCESS;
  295.       }
  296.  
  297.       if (millisec == 0)
  298.          return RB_TIMEOUT;
  299.  
  300.       if (_rb_nonblocking)
  301.          return RB_TIMEOUT;
  302.  
  303.       /* wait one time slice */
  304.       ss_sleep(10);
  305.    }
  306.  
  307.    return RB_TIMEOUT;
  308. }
  309.  
  310. int rb_increment_rp(int handle, int size)
  311. /********************************************************************\
  312.  
  313.   Routine: rb_increment_rp
  314.  
  315.   Purpose: Increment current read pointer, freeing up space for
  316.            the writing thread.
  317.  
  318.   Input:
  319.      int handle               Ring buffer handle
  320.      int size                 Number of bytes to free up at current
  321.                               read pointer
  322.  
  323.   Output:
  324.     NONE
  325.  
  326.   Function value:
  327.     RB_SUCCESS                Successful completion
  328.     RB_INVALID_PARAM          Event size too large or invalid handle
  329.  
  330. \********************************************************************/
  331. {
  332.    int h;
  333.  
  334.    unsigned char *new_rp;
  335.  
  336.    if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  337.       return RB_INVALID_HANDLE;
  338.  
  339.    h = handle - 1;
  340.  
  341.    if ((unsigned int) size > rb[h].max_event_size)
  342.       return RB_INVALID_PARAM;
  343.  
  344.    new_rp = rb[h].rp + size;
  345.  
  346.    /* wrap around if not enough space left */
  347.    if (new_rp + rb[h].max_event_size > rb[h].buffer + rb[h].size)
  348.       new_rp = rb[h].buffer;
  349.  
  350.    rb[handle - 1].rp = new_rp;
  351.  
  352.    return RB_SUCCESS;
  353. }
  354.  
  355. int rb_get_buffer_level(int handle, int *n_bytes)
  356. /********************************************************************\
  357.  
  358.   Routine: rb_get_buffer_level
  359.  
  360.   Purpose: Return number of bytes in a ring buffer
  361.  
  362.   Input:
  363.     int handle              Handle of the buffer to get the info
  364.  
  365.   Output:
  366.     int *n_bytes            Number of bytes in buffer
  367.  
  368.   Function value:
  369.     RB_SUCCESS              Successful completion
  370.     RB_INVALID_HANDLE       Buffer handle is invalid
  371.  
  372. \********************************************************************/
  373. {
  374.    int h;
  375.  
  376.    if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL)
  377.       return RB_INVALID_HANDLE;
  378.  
  379.    h = handle - 1;
  380.  
  381.    if (rb[h].wp >= rb[h].rp)
  382.       *n_bytes = rb[h].wp - rb[h].rp;
  383.    else
  384.       *n_bytes = rb[h].ep - rb[h].rp + rb[h].wp - rb[h].buffer;
  385.  
  386.    return RB_SUCCESS;
  387. }
  388.