void sync_deinit(struct bladerf_sync *sync) { if (sync != NULL) { if (sync->stream_config.module == BLADERF_MODULE_TX) { async_submit_stream_buffer(sync->worker->stream, BLADERF_STREAM_SHUTDOWN, 0); } sync_worker_deinit(sync->worker, &sync->buf_mgmt.lock, &sync->buf_mgmt.buf_ready); /* De-allocate our buffer management resources */ free(sync->buf_mgmt.status); free(sync); } }
void sync_deinit(struct bladerf_sync *sync) { if (sync->initialized) { if ((sync->stream_config.layout & BLADERF_DIRECTION_MASK) == BLADERF_TX) { async_submit_stream_buffer(sync->worker->stream, BLADERF_STREAM_SHUTDOWN, 0, false); } sync_worker_deinit(sync->worker, &sync->buf_mgmt.lock, &sync->buf_mgmt.buf_ready); /* De-allocate our buffer management resources */ if (sync->buf_mgmt.status) { MUTEX_DESTROY(&sync->buf_mgmt.lock); free(sync->buf_mgmt.status); } MUTEX_DESTROY(&sync->lock); sync->initialized = false; } }
/* Assumes buffer lock is held */ static int advance_tx_buffer(struct bladerf_sync *s, struct buffer_mgmt *b) { int status; log_verbose("%s: Marking buf[%u] full\n", __FUNCTION__, b->prod_i); b->status[b->prod_i] = SYNC_BUFFER_IN_FLIGHT; /* This call may block and it results in a per-stream lock being held, so * the buffer lock must be dropped. * * A callback may occur in the meantime, but this will not touch the status * for this this buffer, or the producer index. */ MUTEX_UNLOCK(&b->lock); status = async_submit_stream_buffer(s->worker->stream, b->buffers[b->prod_i], s->stream_config.timeout_ms); MUTEX_LOCK(&b->lock); if (status == 0) { b->prod_i = (b->prod_i + 1) % b->num_buffers; /* Go handle the next buffer, if we have one available. Otherwise, * check up on the worker's state and restart it if needed. */ if (b->status[b->prod_i] == SYNC_BUFFER_EMPTY) { s->state = SYNC_STATE_BUFFER_READY; } else { s->state = SYNC_STATE_CHECK_WORKER; } } else { log_debug("%s: Failed to advance buffer: %s\n", __FUNCTION__, bladerf_strerror(status)); } return status; }
int bladerf_submit_stream_buffer(struct bladerf_stream *stream, void *buffer, unsigned int timeout_ms) { return async_submit_stream_buffer(stream, buffer, timeout_ms); }
/* Assumes buffer lock is held */ static int advance_tx_buffer(struct bladerf_sync *s, struct buffer_mgmt *b) { int status = 0; const unsigned int idx = b->prod_i; if (b->submitter == SYNC_TX_SUBMITTER_FN) { /* Mark buffer in flight because we're going to send it out. * This ensures that if the callback fires before this function * completes, its state will be correct. */ b->status[idx] = SYNC_BUFFER_IN_FLIGHT; /* This call may block and it results in a per-stream lock being held, * so the buffer lock must be dropped. * * A callback may occur in the meantime, but this will not touch the * status for this this buffer, or the producer index. */ MUTEX_UNLOCK(&b->lock); status = async_submit_stream_buffer(s->worker->stream, b->buffers[idx], s->stream_config.timeout_ms, true); MUTEX_LOCK(&b->lock); if (status == 0) { log_verbose("%s: buf[%u] submitted.\n", __FUNCTION__, idx); } else if (status == BLADERF_ERR_WOULD_BLOCK) { log_verbose("%s: Deferring buf[%u] submission to worker callback.\n", __FUNCTION__, idx); /* Mark this buffer as being full of data, but not in flight */ b->status[idx] = SYNC_BUFFER_FULL; /* Assign callback the duty of submitting deferred buffers, * and use buffer_mgmt.cons_i to denote which it should submit * (i.e., consume). */ b->submitter = SYNC_TX_SUBMITTER_CALLBACK; b->cons_i = idx; /* This is expected and we are handling it. Don't propagate this * status back up */ status = 0; } else { /* Unmark this as being in flight */ b->status[idx] = SYNC_BUFFER_FULL; log_debug("%s: Failed to submit buf[%u].\n", __FUNCTION__, idx); return status; } } else { /* We are not submitting this buffer; this is deffered to the worker * call back. Just update its state to being full of samples. */ b->status[idx] = SYNC_BUFFER_FULL; } /* Advance "producer" insertion index. */ b->prod_i = (idx + 1) % b->num_buffers; /* Determine our next state based upon the state of the next buffer we * want to use. */ if (b->status[b->prod_i] == SYNC_BUFFER_EMPTY) { /* Buffer is empty and ready for use */ s->state = SYNC_STATE_BUFFER_READY; } else { /* We'll have to wait on this buffer to become ready. First, we'll * verify that the worker is running. */ s->state = SYNC_STATE_CHECK_WORKER; } return status; }