Skip to content

Commit c270822

Browse files
committed
Apply suggestions
1 parent 49784a0 commit c270822

File tree

3 files changed

+108
-87
lines changed

3 files changed

+108
-87
lines changed

.clang-format

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ ForEachMacros:
2424
- hlist_for_each_entry
2525
- rb_list_foreach
2626
- rb_list_foreach_safe
27+
StatementAttributeLikeMacros:
28+
- IIF

common.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,19 @@ static inline int ilog2(int x)
3434
#else /* unsupported compilers */
3535
#define PACKED(name)
3636
#endif
37+
38+
/* Pattern Matching for C macros.
39+
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
40+
*/
41+
42+
/* In Visual Studio, __VA_ARGS__ is treated as a separate parameter. */
43+
#define FIX_VC_BUG(x) x
44+
45+
/* catenate */
46+
#define PRIMITIVE_CAT(a, ...) FIX_VC_BUG(a##__VA_ARGS__)
47+
48+
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
49+
/* run the 2nd parameter */
50+
#define IIF_0(t, ...) __VA_ARGS__
51+
/* run the 1st parameter */
52+
#define IIF_1(t, ...) t

virtio-snd.c

Lines changed: 90 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -335,95 +335,98 @@ typedef struct {
335335
struct virtq_desc vq_desc;
336336
struct list_head q;
337337
} virtq_desc_queue_node_t;
338-
#define VSND_GEN_TX_QUEUE_HANDLER(NAME_SUFFIX, WRITE) \
339-
static int virtio_snd_tx_desc_##NAME_SUFFIX##_handler( \
340-
virtio_snd_state_t *vsnd, const virtio_snd_queue_t *queue, \
341-
uint32_t desc_idx, uint32_t *plen) \
342-
{ \
343-
/* A PCM I/O message uses at least 3 virtqueue descriptors to \
344-
* represent a PCM data of a period size. \
345-
* The first part contains one descriptor as follows: \
346-
* struct virtio_snd_pcm_xfer \
347-
* The second part contains one or more descriptors \
348-
* representing PCM frames. \
349-
* the last part contains one descriptor as follows: \
350-
* struct virtio_snd_pcm_status \
351-
*/ \
352-
virtq_desc_queue_node_t *node; \
353-
struct list_head q; \
354-
INIT_LIST_HEAD(&q); \
355-
\
356-
/* Collect the descriptors */ \
357-
int cnt = 0; \
358-
for (;;) { \
359-
/* The size of the `struct virtq_desc` is 4 words */ \
360-
const uint32_t *desc = \
361-
&vsnd->ram[queue->QueueDesc + desc_idx * 4]; \
362-
\
363-
/* Retrieve the fields of current descriptor */ \
364-
node = (virtq_desc_queue_node_t *) malloc(sizeof(*node)); \
365-
node->vq_desc.addr = desc[0]; \
366-
node->vq_desc.len = desc[2]; \
367-
node->vq_desc.flags = desc[3]; \
368-
list_push(&node->q, &q); \
369-
desc_idx = desc[3] >> 16; /* vq_desc[desc_cnt].next */ \
370-
\
371-
cnt++; \
372-
\
373-
/* Leave the loop if next-flag is not set */ \
374-
if (!(desc[3] & VIRTIO_DESC_F_NEXT)) \
375-
break; \
376-
} \
377-
\
378-
int idx = 0; \
379-
uint32_t stream_id = 0; /* Explicitly set the stream_id */ \
380-
uintptr_t base = (uintptr_t) vsnd->ram; \
381-
uint32_t ret_len = 0; \
382-
list_for_each_entry (node, &q, q) { \
383-
uint32_t addr = node->vq_desc.addr; \
384-
uint32_t len = node->vq_desc.len; \
385-
if (idx == 0) { /* the first descriptor */ \
386-
const virtio_snd_pcm_xfer_t *request = \
387-
(virtio_snd_pcm_xfer_t *) (base + addr); \
388-
stream_id = request->stream_id; \
389-
goto early_continue; \
390-
} else if (idx == cnt - 1) { /* the last descriptor */ \
391-
virtio_snd_pcm_status_t *response = \
392-
(virtio_snd_pcm_status_t *) (base + addr); \
393-
response->status = VIRTIO_SND_S_OK; \
394-
response->latency_bytes = ret_len; \
395-
*plen = sizeof(*response); \
396-
goto early_continue; \
397-
} \
398-
\
399-
if (WRITE) { \
400-
void *payload = (void *) (base + addr); \
401-
__virtio_snd_frame_enqueue(payload, len, stream_id); \
402-
} \
403-
ret_len += len; \
404-
\
405-
early_continue: \
406-
idx++; \
407-
} \
408-
\
409-
if (WRITE) { \
410-
virtio_snd_prop_t *props = &vsnd_props[stream_id]; \
411-
props->lock.buf_ev_notity++; \
412-
pthread_cond_signal(&props->lock.readable); \
413-
} \
414-
\
415-
/* Tear down the descriptor list and free space. */ \
416-
virtq_desc_queue_node_t *tmp = NULL; \
417-
list_for_each_entry_safe (node, tmp, &q, q) { \
418-
list_del(&node->q); \
419-
free(node); \
420-
} \
421-
\
422-
return 0; \
338+
#define VSND_GEN_TX_QUEUE_HANDLER(NAME_SUFFIX, WRITE) \
339+
static int virtio_snd_tx_desc_##NAME_SUFFIX##_handler( \
340+
virtio_snd_state_t *vsnd, const virtio_snd_queue_t *queue, \
341+
uint32_t desc_idx, uint32_t *plen) \
342+
{ \
343+
/* A PCM I/O message uses at least 3 virtqueue descriptors to \
344+
* represent a PCM data of a period size. \
345+
* The first part contains one descriptor as follows: \
346+
* struct virtio_snd_pcm_xfer \
347+
* The second part contains one or more descriptors \
348+
* representing PCM frames. \
349+
* the last part contains one descriptor as follows: \
350+
* struct virtio_snd_pcm_status \
351+
*/ \
352+
virtq_desc_queue_node_t *node; \
353+
struct list_head q; \
354+
INIT_LIST_HEAD(&q); \
355+
\
356+
/* Collect the descriptors */ \
357+
int cnt = 0; \
358+
for (;;) { \
359+
/* The size of the `struct virtq_desc` is 4 words */ \
360+
const uint32_t *desc = \
361+
&vsnd->ram[queue->QueueDesc + desc_idx * 4]; \
362+
\
363+
/* Retrieve the fields of current descriptor */ \
364+
node = (virtq_desc_queue_node_t *) malloc(sizeof(*node)); \
365+
node->vq_desc.addr = desc[0]; \
366+
node->vq_desc.len = desc[2]; \
367+
node->vq_desc.flags = desc[3]; \
368+
list_push(&node->q, &q); \
369+
desc_idx = desc[3] >> 16; /* vq_desc[desc_cnt].next */ \
370+
\
371+
cnt++; \
372+
\
373+
/* Leave the loop if next-flag is not set */ \
374+
if (!(desc[3] & VIRTIO_DESC_F_NEXT)) \
375+
break; \
376+
} \
377+
\
378+
int idx = 0; \
379+
uint32_t stream_id = 0; /* Explicitly set the stream_id */ \
380+
uintptr_t base = (uintptr_t) vsnd->ram; \
381+
uint32_t ret_len = 0; \
382+
list_for_each_entry (node, &q, q) { \
383+
uint32_t addr = node->vq_desc.addr; \
384+
uint32_t len = node->vq_desc.len; \
385+
if (idx == 0) { /* the first descriptor */ \
386+
const virtio_snd_pcm_xfer_t *request = \
387+
(virtio_snd_pcm_xfer_t *) (base + addr); \
388+
stream_id = request->stream_id; \
389+
goto early_continue; \
390+
} else if (idx == cnt - 1) { /* the last descriptor */ \
391+
virtio_snd_pcm_status_t *response = \
392+
(virtio_snd_pcm_status_t *) (base + addr); \
393+
response->status = VIRTIO_SND_S_OK; \
394+
response->latency_bytes = ret_len; \
395+
*plen = sizeof(*response); \
396+
goto early_continue; \
397+
} \
398+
\
399+
IIF(WRITE) \
400+
(/* enqueue frames */ \
401+
void *payload = (void *) (base + addr); \
402+
__virtio_snd_frame_enqueue(payload, len, stream_id); \
403+
, /* flush queue */ \
404+
(void) stream_id; \
405+
/* Suppress unused variable warning. */) ret_len += len; \
406+
\
407+
early_continue: \
408+
idx++; \
409+
} \
410+
\
411+
IIF(WRITE) \
412+
(/* enque frames */ \
413+
virtio_snd_prop_t *props = &vsnd_props[stream_id]; \
414+
props->lock.buf_ev_notity++; \
415+
pthread_cond_signal(&props->lock.readable);, /* flush queue */ \
416+
) \
417+
\
418+
/* Tear down the descriptor list and free space. */ \
419+
virtq_desc_queue_node_t *tmp = NULL; \
420+
list_for_each_entry_safe (node, tmp, &q, q) { \
421+
list_del(&node->q); \
422+
free(node); \
423+
} \
424+
\
425+
return 0; \
423426
}
424427

425-
VSND_GEN_TX_QUEUE_HANDLER(normal, true);
426-
VSND_GEN_TX_QUEUE_HANDLER(flush, false);
428+
VSND_GEN_TX_QUEUE_HANDLER(normal, 1);
429+
VSND_GEN_TX_QUEUE_HANDLER(flush, 0);
427430

428431
static void virtio_snd_set_fail(virtio_snd_state_t *vsnd)
429432
{

0 commit comments

Comments
 (0)