You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
578 lines
20 KiB
578 lines
20 KiB
/* Copyright (c) 2015, The Linux Foundation. All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are |
|
* met: |
|
* * Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* * Redistributions in binary form must reproduce the above |
|
* copyright notice, this list of conditions and the following |
|
* disclaimer in the documentation and/or other materials provided |
|
* with the distribution. |
|
* * Neither the name of The Linux Foundation nor the names of its |
|
* contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <pthread.h> |
|
|
|
#define LOG_TAG "WifiHAL" |
|
|
|
#include <utils/Log.h> |
|
|
|
typedef unsigned char u8; |
|
typedef uint16_t u16; |
|
typedef uint32_t u32; |
|
typedef uint64_t u64; |
|
|
|
#include "ring_buffer.h" |
|
|
|
enum rb_bool { |
|
RB_TRUE = 0, |
|
RB_FALSE = 1 |
|
}; |
|
|
|
typedef struct rb_entry_s { |
|
u8 *data; |
|
unsigned int last_wr_index; |
|
u8 full; |
|
} rb_entry_t; |
|
|
|
typedef struct ring_buf_cb { |
|
unsigned int rd_buf_no; // Current buffer number to be read from |
|
unsigned int wr_buf_no; // Current buffer number to be written into |
|
unsigned int cur_rd_buf_idx; // Read index within the current read buffer |
|
unsigned int cur_wr_buf_idx; // Write index within the current write buffer |
|
rb_entry_t *bufs; // Array of buffer pointers |
|
|
|
unsigned int max_num_bufs; // Maximum number of buffers that should be used |
|
size_t each_buf_size; // Size of each buffer in bytes |
|
|
|
pthread_mutex_t rb_rw_lock; |
|
|
|
/* Threshold vars */ |
|
unsigned int num_min_bytes; |
|
void (*threshold_cb)(void *); |
|
void *cb_ctx; |
|
|
|
u32 total_bytes_written; |
|
u32 total_bytes_read; |
|
u32 total_bytes_overwritten; |
|
u32 cur_valid_bytes; |
|
enum rb_bool threshold_reached; |
|
} rbc_t; |
|
|
|
|
|
#define RB_MIN(x, y) ((x) < (y)?(x):(y)) |
|
inline void rb_lock(pthread_mutex_t *lock) |
|
{ |
|
int error = pthread_mutex_lock(lock); |
|
|
|
if (error) |
|
ALOGE("Failed to acquire lock with err %d", error); |
|
// TODO Handle the lock failure |
|
} |
|
|
|
inline void rb_unlock(pthread_mutex_t *lock) |
|
{ |
|
int error = pthread_mutex_unlock(lock); |
|
|
|
if (error) |
|
ALOGE("Failed to release lock with err %d", error); |
|
// TODO Handle the unlock failure |
|
} |
|
|
|
void * ring_buffer_init(size_t size_of_buf, int num_bufs) |
|
{ |
|
struct ring_buf_cb *rbc; |
|
int status; |
|
|
|
rbc = (struct ring_buf_cb *)malloc(sizeof(struct ring_buf_cb)); |
|
if (rbc == NULL) { |
|
ALOGE("Failed to alloc rbc"); |
|
return NULL; |
|
} |
|
memset(rbc, 0, sizeof(struct ring_buf_cb)); |
|
|
|
rbc->bufs = (rb_entry_t *)malloc(num_bufs * sizeof(rb_entry_t)); |
|
if (rbc->bufs == NULL) { |
|
free(rbc); |
|
ALOGE("Failed to alloc rbc->bufs"); |
|
return NULL; |
|
} |
|
memset(rbc->bufs, 0, (num_bufs * sizeof(rb_entry_t))); |
|
|
|
rbc->each_buf_size = size_of_buf; |
|
rbc->max_num_bufs = num_bufs; |
|
|
|
status = pthread_mutex_init(&rbc->rb_rw_lock, NULL); |
|
if (status != 0) { |
|
ALOGE("Failed to initialize rb_rw_lock"); |
|
// TODO handle lock initialization failure |
|
} |
|
rbc->threshold_reached = RB_FALSE; |
|
return rbc; |
|
} |
|
|
|
void ring_buffer_deinit(void *ctx) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
int status; |
|
unsigned int buf_no; |
|
|
|
status = pthread_mutex_destroy(&rbc->rb_rw_lock); |
|
if (status != 0) { |
|
ALOGE("Failed to destroy rb_rw_lock"); |
|
// TODO handle the lock destroy failure |
|
} |
|
for (buf_no = 0; buf_no < rbc->max_num_bufs; buf_no++) { |
|
free(rbc->bufs[buf_no].data); |
|
} |
|
free(rbc->bufs); |
|
free(rbc); |
|
} |
|
|
|
/* |
|
* record_length : 0 - byte boundary |
|
* : >0 - Ensures to write record_length no.of bytes to the same buffer. |
|
*/ |
|
enum rb_status rb_write (void *ctx, u8 *buf, size_t length, int overwrite, |
|
size_t record_length) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
unsigned int bytes_written = 0; // bytes written into rb so far |
|
unsigned int push_in_rd_ptr = 0; // push required in read pointer because of |
|
// write in current buffer |
|
unsigned int total_push_in_rd_ptr = 0; // Total amount of push in read pointer in this write |
|
|
|
if (record_length > rbc->each_buf_size) { |
|
return RB_FAILURE; |
|
} |
|
|
|
if (overwrite == 0) { |
|
/* Check if the complete RB is full. If the current wr_buf is also |
|
* full, it indicates that the complete RB is full |
|
*/ |
|
if (rbc->bufs[rbc->wr_buf_no].full == 1) |
|
return RB_FULL; |
|
/* Check whether record fits in current buffer */ |
|
if (rbc->wr_buf_no == rbc->rd_buf_no) { |
|
if ((rbc->cur_wr_buf_idx == rbc->cur_rd_buf_idx) && |
|
rbc->cur_valid_bytes) { |
|
return RB_FULL; |
|
} else if (rbc->cur_wr_buf_idx < rbc->cur_rd_buf_idx) { |
|
if (record_length > |
|
(rbc->cur_rd_buf_idx - rbc->cur_wr_buf_idx)) { |
|
return RB_FULL; |
|
} |
|
} else { |
|
if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) { |
|
/* Check if the next buffer is not full to write this record into |
|
* next buffer |
|
*/ |
|
unsigned int next_buf_no = rbc->wr_buf_no + 1; |
|
|
|
if (next_buf_no >= rbc->max_num_bufs) { |
|
next_buf_no = 0; |
|
} |
|
if (rbc->bufs[next_buf_no].full == 1) { |
|
return RB_FULL; |
|
} |
|
} |
|
} |
|
} else if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) { |
|
/* Check if the next buffer is not full to write this record into |
|
* next buffer |
|
*/ |
|
unsigned int next_buf_no = rbc->wr_buf_no + 1; |
|
|
|
if (next_buf_no >= rbc->max_num_bufs) { |
|
next_buf_no = 0; |
|
} |
|
if (rbc->bufs[next_buf_no].full == 1) { |
|
return RB_FULL; |
|
} |
|
} |
|
} |
|
|
|
/* Go to next buffer if the current buffer is not enough to write the |
|
* complete record |
|
*/ |
|
if (record_length > (rbc->each_buf_size - rbc->cur_wr_buf_idx)) { |
|
rbc->bufs[rbc->wr_buf_no].full = 1; |
|
rbc->bufs[rbc->wr_buf_no].last_wr_index = rbc->cur_wr_buf_idx; |
|
rbc->wr_buf_no++; |
|
if (rbc->wr_buf_no == rbc->max_num_bufs) { |
|
rbc->wr_buf_no = 0; |
|
} |
|
rbc->cur_wr_buf_idx = 0; |
|
} |
|
|
|
|
|
/* In each iteration of below loop, the data that can be fit into |
|
* buffer @wr_buf_no will be copied from input buf */ |
|
while (bytes_written < length) { |
|
unsigned int cur_copy_len; |
|
|
|
/* Allocate a buffer if no buf available @ wr_buf_no */ |
|
if (rbc->bufs[rbc->wr_buf_no].data == NULL) { |
|
rbc->bufs[rbc->wr_buf_no].data = (u8 *)malloc(rbc->each_buf_size); |
|
if (rbc->bufs[rbc->wr_buf_no].data == NULL) { |
|
ALOGE("Failed to alloc write buffer"); |
|
return RB_RETRY; |
|
} |
|
} |
|
|
|
/* Take the minimum of the remaining length that needs to be written |
|
* from buf and the maximum length that can be written into current |
|
* buffer in ring buffer |
|
*/ |
|
cur_copy_len = RB_MIN((rbc->each_buf_size - rbc->cur_wr_buf_idx), |
|
(length - bytes_written)); |
|
|
|
rb_lock(&rbc->rb_rw_lock); |
|
|
|
/* Push the read pointer in case of overrun */ |
|
if (rbc->rd_buf_no == rbc->wr_buf_no) { |
|
if ((rbc->cur_rd_buf_idx > rbc->cur_wr_buf_idx) || |
|
((rbc->cur_rd_buf_idx == rbc->cur_wr_buf_idx) && |
|
rbc->cur_valid_bytes)) { |
|
/* If read ptr is ahead of write pointer and if the |
|
* gap is not enough to fit the cur_copy_len bytes then |
|
* push the read pointer so that points to the start of |
|
* old bytes after this write |
|
*/ |
|
if ((rbc->cur_rd_buf_idx - rbc->cur_wr_buf_idx) < |
|
cur_copy_len) { |
|
push_in_rd_ptr += cur_copy_len - |
|
(rbc->cur_rd_buf_idx - rbc->cur_wr_buf_idx); |
|
rbc->cur_rd_buf_idx = rbc->cur_wr_buf_idx + cur_copy_len; |
|
if (rbc->cur_rd_buf_idx >= |
|
rbc->bufs[rbc->rd_buf_no].last_wr_index) { |
|
rbc->cur_rd_buf_idx = 0; |
|
rbc->rd_buf_no++; |
|
if (rbc->rd_buf_no == rbc->max_num_bufs) { |
|
rbc->rd_buf_no = 0; |
|
ALOGV("Pushing read to the start of ring buffer"); |
|
} |
|
/* the previous buffer might have little more empty room |
|
* after overwriting the remaining bytes |
|
*/ |
|
rbc->bufs[rbc->wr_buf_no].full = 0; |
|
} |
|
} |
|
} |
|
} |
|
rb_unlock(&rbc->rb_rw_lock); |
|
|
|
/* don't use lock while doing memcpy, so that we don't block the read |
|
* context for too long. There is no harm while writing the memory if |
|
* locking is properly done while upgrading the pointers */ |
|
memcpy((rbc->bufs[rbc->wr_buf_no].data + rbc->cur_wr_buf_idx), |
|
(buf + bytes_written), |
|
cur_copy_len); |
|
|
|
rb_lock(&rbc->rb_rw_lock); |
|
/* Update the write idx by the amount of write done in this iteration */ |
|
rbc->cur_wr_buf_idx += cur_copy_len; |
|
if (rbc->cur_wr_buf_idx == rbc->each_buf_size) { |
|
/* Increment the wr_buf_no as the current buffer is full */ |
|
rbc->bufs[rbc->wr_buf_no].full = 1; |
|
rbc->bufs[rbc->wr_buf_no].last_wr_index = rbc->cur_wr_buf_idx; |
|
rbc->wr_buf_no++; |
|
if (rbc->wr_buf_no == rbc->max_num_bufs) { |
|
ALOGV("Write rolling over to the start of ring buffer"); |
|
rbc->wr_buf_no = 0; |
|
} |
|
/* Reset the write index to zero as this is a new buffer */ |
|
rbc->cur_wr_buf_idx = 0; |
|
} |
|
|
|
if ((rbc->cur_valid_bytes + (cur_copy_len - push_in_rd_ptr)) > |
|
(rbc->max_num_bufs * rbc->each_buf_size)) { |
|
/* The below is only a precautionary print and ideally should never |
|
* come */ |
|
ALOGE("Something going wrong in ring buffer"); |
|
} else { |
|
/* Increase the valid bytes count by number of bytes written without |
|
* overwriting the old bytes */ |
|
rbc->cur_valid_bytes += cur_copy_len - push_in_rd_ptr; |
|
} |
|
total_push_in_rd_ptr += push_in_rd_ptr; |
|
push_in_rd_ptr = 0; |
|
rb_unlock(&rbc->rb_rw_lock); |
|
bytes_written += cur_copy_len; |
|
} |
|
|
|
rb_lock(&rbc->rb_rw_lock); |
|
rbc->total_bytes_written += bytes_written - total_push_in_rd_ptr; |
|
rbc->total_bytes_overwritten += total_push_in_rd_ptr; |
|
|
|
/* check if valid bytes is going more than threshold */ |
|
if ((rbc->threshold_reached == RB_FALSE) && |
|
(rbc->cur_valid_bytes >= rbc->num_min_bytes) && |
|
((length == record_length) || !record_length) && |
|
rbc->threshold_cb) { |
|
/* Release the lock before calling threshold_cb as it might call rb_read |
|
* in this same context in order to avoid dead lock |
|
*/ |
|
rbc->threshold_reached = RB_TRUE; |
|
rb_unlock(&rbc->rb_rw_lock); |
|
rbc->threshold_cb(rbc->cb_ctx); |
|
} else { |
|
rb_unlock(&rbc->rb_rw_lock); |
|
} |
|
return RB_SUCCESS; |
|
} |
|
|
|
size_t rb_read (void *ctx, u8 *buf, size_t max_length) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
unsigned int bytes_read = 0; |
|
unsigned int no_more_bytes_available = 0; |
|
|
|
rb_lock(&rbc->rb_rw_lock); |
|
while (bytes_read < max_length) { |
|
unsigned int cur_cpy_len; |
|
|
|
if (rbc->bufs[rbc->rd_buf_no].data == NULL) { |
|
break; |
|
} |
|
|
|
/* if read and write are on same buffer, work with rd, wr indices */ |
|
if (rbc->rd_buf_no == rbc->wr_buf_no) { |
|
if (rbc->cur_rd_buf_idx < rbc->cur_wr_buf_idx) { |
|
/* Check if all the required bytes are available, if not |
|
* read only the available bytes in the current buffer and |
|
* break out after reading current buffer |
|
*/ |
|
if ((rbc->cur_wr_buf_idx - rbc->cur_rd_buf_idx) < |
|
(max_length - bytes_read)) { |
|
cur_cpy_len = rbc->cur_wr_buf_idx - rbc->cur_rd_buf_idx; |
|
no_more_bytes_available = 1; |
|
} else { |
|
cur_cpy_len = max_length - bytes_read; |
|
} |
|
} else { |
|
/* When there are no bytes available to read cur_rd_buf_idx |
|
* will be euqal to cur_wr_buf_idx. Handle this scenario using |
|
* cur_valid_bytes */ |
|
if (rbc->cur_valid_bytes <= bytes_read) { |
|
/* Suppress possible static analyzer's warning */ |
|
cur_cpy_len = 0; |
|
break; |
|
} |
|
cur_cpy_len = RB_MIN((rbc->each_buf_size - rbc->cur_rd_buf_idx), |
|
(max_length - bytes_read)); |
|
} |
|
} else { |
|
/* Check if all remaining_length bytes can be read from this |
|
* buffer, if not read only the available bytes in the current |
|
* buffer and go to next buffer using the while loop. |
|
*/ |
|
cur_cpy_len = RB_MIN((rbc->each_buf_size - rbc->cur_rd_buf_idx), |
|
(max_length - bytes_read)); |
|
} |
|
|
|
memcpy((buf + bytes_read), |
|
(rbc->bufs[rbc->rd_buf_no].data + rbc->cur_rd_buf_idx), |
|
cur_cpy_len); |
|
|
|
/* Update the read index */ |
|
rbc->cur_rd_buf_idx += cur_cpy_len; |
|
if (rbc->cur_rd_buf_idx == rbc->each_buf_size) { |
|
/* Increment rd_buf_no as the current buffer is completely read */ |
|
if (rbc->rd_buf_no != rbc->wr_buf_no) { |
|
free(rbc->bufs[rbc->rd_buf_no].data); |
|
rbc->bufs[rbc->rd_buf_no].data = NULL; |
|
} |
|
rbc->rd_buf_no++; |
|
if (rbc->rd_buf_no == rbc->max_num_bufs) { |
|
ALOGV("Read rolling over to the start of ring buffer"); |
|
rbc->rd_buf_no = 0; |
|
} |
|
/* Reset the read index as this is a new buffer */ |
|
rbc->cur_rd_buf_idx = 0; |
|
} |
|
|
|
bytes_read += cur_cpy_len; |
|
if (no_more_bytes_available) { |
|
break; |
|
} |
|
} |
|
|
|
rbc->total_bytes_read += bytes_read; |
|
if (rbc->cur_valid_bytes < bytes_read) { |
|
/* The below is only a precautionary print and ideally should never |
|
* come */ |
|
ALOGE("Something going wrong in ring buffer"); |
|
} else { |
|
rbc->cur_valid_bytes -= bytes_read; |
|
} |
|
|
|
/* check if valid bytes is going less than threshold */ |
|
if (rbc->threshold_reached == RB_TRUE) { |
|
if (rbc->cur_valid_bytes < rbc->num_min_bytes) { |
|
rbc->threshold_reached = RB_FALSE; |
|
} |
|
} |
|
rb_unlock(&rbc->rb_rw_lock); |
|
return bytes_read; |
|
} |
|
|
|
u8 *rb_get_read_buf(void *ctx, size_t *length) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
unsigned int cur_read_len = 0; |
|
u8 *buf; |
|
|
|
/* If no buffer is available for reading */ |
|
if (rbc->bufs[rbc->rd_buf_no].data == NULL) { |
|
*length = 0; |
|
return NULL; |
|
} |
|
|
|
rb_lock(&rbc->rb_rw_lock); |
|
if ((rbc->bufs[rbc->rd_buf_no].full == 1) && |
|
(rbc->cur_rd_buf_idx == rbc->bufs[rbc->rd_buf_no].last_wr_index)) { |
|
if (rbc->wr_buf_no != rbc->rd_buf_no) { |
|
free(rbc->bufs[rbc->rd_buf_no].data); |
|
rbc->bufs[rbc->rd_buf_no].data = NULL; |
|
} |
|
rbc->bufs[rbc->rd_buf_no].full = 0; |
|
rbc->rd_buf_no++; |
|
if (rbc->rd_buf_no == rbc->max_num_bufs) { |
|
rbc->rd_buf_no = 0; |
|
} |
|
rbc->cur_rd_buf_idx = 0; |
|
} |
|
|
|
if (rbc->wr_buf_no == rbc->rd_buf_no) { |
|
/* If read and write are happening on the same buffer currently, use |
|
* rd and wr indices within the buffer */ |
|
if ((rbc->cur_rd_buf_idx == rbc->cur_wr_buf_idx) && |
|
(rbc->cur_valid_bytes == 0)) { |
|
/* No bytes available for reading */ |
|
*length = 0; |
|
rb_unlock(&rbc->rb_rw_lock); |
|
return NULL; |
|
} else if (rbc->cur_rd_buf_idx < rbc->cur_wr_buf_idx) { |
|
/* write is just ahead of read in this buffer */ |
|
cur_read_len = rbc->cur_wr_buf_idx - rbc->cur_rd_buf_idx; |
|
} else { |
|
/* write is rolled over and just behind the read */ |
|
cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index - rbc->cur_rd_buf_idx; |
|
} |
|
} else { |
|
if (rbc->cur_rd_buf_idx == 0) { |
|
/* The complete buffer can be read out */ |
|
cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index; |
|
} else { |
|
/* Read the remaining bytes in this buffer */ |
|
cur_read_len = rbc->bufs[rbc->rd_buf_no].last_wr_index - rbc->cur_rd_buf_idx; |
|
} |
|
} |
|
|
|
if ((rbc->bufs[rbc->rd_buf_no].full == 1) && |
|
(rbc->cur_rd_buf_idx == 0)) { |
|
/* Pluck out the complete buffer and send it out */ |
|
buf = rbc->bufs[rbc->rd_buf_no].data; |
|
rbc->bufs[rbc->rd_buf_no].data = NULL; |
|
|
|
/* Move to the next buffer */ |
|
rbc->bufs[rbc->rd_buf_no].full = 0; |
|
rbc->rd_buf_no++; |
|
if (rbc->rd_buf_no == rbc->max_num_bufs) { |
|
ALOGV("Read rolling over to the start of ring buffer"); |
|
rbc->rd_buf_no = 0; |
|
} |
|
} else { |
|
/* We cannot give out the complete buffer, so allocate a new memory and |
|
* and copy the data into it. |
|
*/ |
|
buf = (u8 *)malloc(cur_read_len); |
|
if (buf == NULL) { |
|
ALOGE("Failed to alloc buffer for partial buf read"); |
|
*length = 0; |
|
rb_unlock(&rbc->rb_rw_lock); |
|
return NULL; |
|
} |
|
memcpy(buf, |
|
(rbc->bufs[rbc->rd_buf_no].data + rbc->cur_rd_buf_idx), |
|
cur_read_len); |
|
|
|
/* Update the read index */ |
|
if (rbc->bufs[rbc->rd_buf_no].full == 1) { |
|
if (rbc->wr_buf_no != rbc->rd_buf_no) { |
|
free(rbc->bufs[rbc->rd_buf_no].data); |
|
rbc->bufs[rbc->rd_buf_no].data = NULL; |
|
} |
|
rbc->bufs[rbc->rd_buf_no].full = 0; |
|
rbc->rd_buf_no++; |
|
if (rbc->rd_buf_no == rbc->max_num_bufs) { |
|
rbc->rd_buf_no = 0; |
|
} |
|
rbc->cur_rd_buf_idx = 0; |
|
} else { |
|
rbc->cur_rd_buf_idx += cur_read_len; |
|
} |
|
} |
|
|
|
rbc->total_bytes_read += cur_read_len; |
|
if (rbc->cur_valid_bytes < cur_read_len) { |
|
/* The below is only a precautionary print and ideally should never |
|
* come */ |
|
ALOGE("Something going wrong in ring buffer"); |
|
} else { |
|
rbc->cur_valid_bytes -= cur_read_len; |
|
} |
|
|
|
/* check if valid bytes is going less than threshold */ |
|
if (rbc->threshold_reached == RB_TRUE) { |
|
if (rbc->cur_valid_bytes < rbc->num_min_bytes) { |
|
rbc->threshold_reached = RB_FALSE; |
|
} |
|
} |
|
rb_unlock(&rbc->rb_rw_lock); |
|
|
|
*length = cur_read_len; |
|
return buf; |
|
} |
|
|
|
void rb_config_threshold(void *ctx, |
|
unsigned int num_min_bytes, |
|
threshold_call_back callback, |
|
void *cb_ctx) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
|
|
rbc->num_min_bytes = num_min_bytes; |
|
rbc->threshold_cb = callback; |
|
rbc->cb_ctx = cb_ctx; |
|
} |
|
|
|
void rb_get_stats(void *ctx, struct rb_stats *rbs) |
|
{ |
|
rbc_t *rbc = (rbc_t *)ctx; |
|
|
|
rbs->total_bytes_written = rbc->total_bytes_written; |
|
rbs->total_bytes_read = rbc->total_bytes_read; |
|
rbs->cur_valid_bytes = rbc->cur_valid_bytes; |
|
rbs->each_buf_size = rbc->each_buf_size; |
|
rbs->max_num_bufs = rbc->max_num_bufs; |
|
}
|
|
|