/* * This file is part of GAPK (GSM Audio Pocket Knife). * * (C) 2017 by Vadim Yanitskiy * * GAPK is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GAPK is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GAPK. If not, see . */ #include #include #include #include #include /** * This test is intended to validate the processing queue * management API. Moreover, the talloc debugging API is * used to ensure that there are no memory leaks. * * First, four processing queues are being allocated. One * of them is empty, while others have different count of * items. Then the human-readable description is being * generated for all of them. And finally, the processing * and exit callback are being tested. * * During the test execution, the talloc NULL-context * tracking feature is enabled, allowing to observe every * memory allocation within the libosmogapk, and to detect * memory leaks. */ static void talloc_ctx_walk_cb(const void *chunk, int depth, int max_depth, int is_ref, void *data) { const char *chunk_name = talloc_get_name(chunk); int spaces_cnt; /* Hierarchical spacing */ for (spaces_cnt = 0; spaces_cnt < depth; spaces_cnt++) printf(" "); /* Chunk info */ printf("chunk %s: depth=%d\n", chunk_name, depth); } static int q3_i0_proc(void *state, uint8_t *out, const uint8_t *in, unsigned int in_len) { int i; printf("Incoming data: "); for (i = 0; i < 10; i++) { printf("%d ", i); out[i] = i; } printf("\n"); return 0; } static int q3_i1_proc(void *state, uint8_t *out, const uint8_t *in, unsigned int in_len) { int i; for (i = 0; i < 10; i++) out[i] = in[i] % 2; return 0; } static int q3_i2_proc(void *state, uint8_t *out, const uint8_t *in, unsigned int in_len) { int i; printf("Outgoing data: "); for (i = 0; i < 10; i++) printf("%d ", in[i]); printf("\n"); return 0; } static void q3_exit(void *state) { struct osmo_gapk_pq_item *item; /* Make sure the item's state is passed correctly */ assert(state != NULL); item = (struct osmo_gapk_pq_item *) state; printf("Calling exit callback for '%s/%s'\n", item->cat_name, item->sub_name); } int main(int argc, char **argv) { /* Enable tracking the use of NULL memory contexts */ talloc_enable_null_tracking(); /** * 1. Processing queue allocation test */ struct osmo_gapk_pq *q0, *q1, *q2, *q3; printf("Processing queue allocation test:\n"); /* Allocate four queues */ q0 = osmo_gapk_pq_create(NULL); q1 = osmo_gapk_pq_create("q1"); q2 = osmo_gapk_pq_create("q2"); q3 = osmo_gapk_pq_create("q3"); /* Make sure all queues are allocated */ assert(q0 != NULL); assert(q1 != NULL); assert(q2 != NULL); assert(q3 != NULL); /* Print talloc memory hierarchy */ talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL); printf("\n"); /** * 2. Item allocation test */ struct osmo_gapk_pq_item *q3_i0, *q3_i1, *q3_i2; struct osmo_gapk_pq_item *q2_i0, *q2_i1; struct osmo_gapk_pq_item *q1_i0; printf("Item allocation test:\n"); /* Make sure there are no items */ assert(q0->n_items == 0); assert(q1->n_items == 0); assert(q2->n_items == 0); assert(q3->n_items == 0); /* Allocate items */ q3_i0 = osmo_gapk_pq_add_item(q3); q3_i1 = osmo_gapk_pq_add_item(q3); q3_i2 = osmo_gapk_pq_add_item(q3); q2_i0 = osmo_gapk_pq_add_item(q2); q2_i1 = osmo_gapk_pq_add_item(q2); q1_i0 = osmo_gapk_pq_add_item(q1); /* Make sure all items are allocated */ assert(q3_i0 != NULL); assert(q3_i1 != NULL); assert(q3_i2 != NULL); assert(q2_i0 != NULL); assert(q2_i1 != NULL); assert(q1_i0 != NULL); /* Check item count */ assert(q0->n_items == 0); assert(q1->n_items == 1); assert(q2->n_items == 2); assert(q3->n_items == 3); /* Print talloc memory hierarchy */ talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL); printf("\n"); /** * 3. Items persistence test */ struct osmo_gapk_pq_item *item; /* Make sure that q0 is empty, others are not */ assert(llist_empty(&q0->items) == 1); assert(llist_empty(&q1->items) == 0); assert(llist_empty(&q2->items) == 0); assert(llist_empty(&q3->items) == 0); /* A single item must be the first and the last in a queue */ item = llist_first_entry(&q1->items, struct osmo_gapk_pq_item, list); assert(item == q1_i0); item = llist_last_entry(&q1->items, struct osmo_gapk_pq_item, list); assert(item == q1_i0); /* Two items: one is the first, second is the last */ item = llist_first_entry(&q2->items, struct osmo_gapk_pq_item, list); assert(item == q2_i0); item = llist_last_entry(&q2->items, struct osmo_gapk_pq_item, list); assert(item == q2_i1); /* Three items: one is the first, third is the last */ item = llist_first_entry(&q3->items, struct osmo_gapk_pq_item, list); assert(item == q3_i0); assert(item != q3_i1); item = llist_last_entry(&q3->items, struct osmo_gapk_pq_item, list); assert(item == q3_i2); assert(item != q3_i1); /** * 4. Queue I/O data lengths check */ q3_i0->len_in = 10; q3_i0->len_out = 20; q3_i1->len_in = 20; q3_i1->len_out = 30; q3_i2->len_in = 30; q3_i2->len_out = 10; /* Normal case */ assert(osmo_gapk_pq_check(q3, 0) == 0); /* Abnormal case (I/O length mismatch) */ q3_i0->len_out = 10; assert(osmo_gapk_pq_check(q3, 0) != 0); q3_i0->len_out = 20; /* Check queue in strict mode (requires src -> ... -> sink) */ q3_i0->type = OSMO_GAPK_ITEM_TYPE_SOURCE; q3_i1->type = OSMO_GAPK_ITEM_TYPE_PROC; q3_i2->type = OSMO_GAPK_ITEM_TYPE_SINK; /* Normal case (src -> proc -> sink) */ assert(osmo_gapk_pq_check(q3, 1) == 0); /* Abnormal case (proc -> proc -> sink) */ q3_i0->type = OSMO_GAPK_ITEM_TYPE_PROC; assert(osmo_gapk_pq_check(q3, 1) != 0); q3_i0->type = OSMO_GAPK_ITEM_TYPE_SOURCE; /** * 5. Buffer allocation test */ printf("Queue preparation test:\n"); /* Prepare the queue */ assert(osmo_gapk_pq_prepare(q3) == 0); /* Make sure buffers were allocated */ assert(q3_i0->buf != NULL); assert(q3_i1->buf != NULL); /* Currently, we don't allocate buffers for sinks */ assert(q3_i2->buf == NULL); /* Compare required vs allocated buffer sizes */ assert(talloc_total_size(q3_i0->buf) == q3_i0->len_out); assert(talloc_total_size(q3_i1->buf) == q3_i1->len_out); /* Print talloc memory hierarchy */ talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL); printf("\n"); /** * 6. Queue description test */ char *queue_desc; printf("Queue description test:\n"); /* An empty queue doesn't have description */ queue_desc = osmo_gapk_pq_describe(q0); assert(queue_desc == NULL); /* Fill in some data */ q3_i0->cat_name = OSMO_GAPK_CAT_NAME_SOURCE; q3_i0->sub_name = "file"; q3_i1->cat_name = OSMO_GAPK_CAT_NAME_PROC; q3_i1->sub_name = "dummy"; q3_i2->cat_name = OSMO_GAPK_CAT_NAME_SINK; q3_i2->sub_name = "alsa"; q2_i0->cat_name = OSMO_GAPK_CAT_NAME_SOURCE; q2_i0->sub_name = "dummy"; q2_i1->cat_name = OSMO_GAPK_CAT_NAME_SINK; q2_i1->sub_name = "dummy"; q1_i0->cat_name = "dummy"; q1_i0->sub_name = "dummy"; queue_desc = osmo_gapk_pq_describe(q3); assert(queue_desc != NULL); printf("Queue q3 description: %s\n", queue_desc); talloc_free(queue_desc); queue_desc = osmo_gapk_pq_describe(q2); assert(queue_desc != NULL); printf("Queue q2 description: %s\n", queue_desc); talloc_free(queue_desc); queue_desc = osmo_gapk_pq_describe(q1); assert(queue_desc != NULL); printf("Queue q1 description: %s\n\n", queue_desc); talloc_free(queue_desc); /** * 7. Queue execution test */ printf("Processing queue execution test:\n"); /* Make sure there are no callbacks by default */ assert(q3_i0->proc == NULL); assert(q3_i0->wait == NULL); assert(q3_i0->exit == NULL); assert(q3_i1->proc == NULL); assert(q3_i1->wait == NULL); assert(q3_i1->exit == NULL); assert(q3_i2->proc == NULL); assert(q3_i2->wait == NULL); assert(q3_i2->exit == NULL); q3_i0->proc = &q3_i0_proc; q3_i1->proc = &q3_i1_proc; q3_i2->proc = &q3_i2_proc; assert(osmo_gapk_pq_execute(q3) == 0); printf("\n"); /** * 8. Exit callback & deallocation tests */ printf("Processing queue exit callback test:\n"); q3_i0->state = q3_i0; q3_i1->state = q3_i1; q3_i2->state = q3_i2; q3_i0->exit = &q3_exit; q3_i1->exit = &q3_exit; q3_i2->exit = &q3_exit; osmo_gapk_pq_destroy(q0); osmo_gapk_pq_destroy(q1); osmo_gapk_pq_destroy(q2); osmo_gapk_pq_destroy(q3); printf("\n"); /** * 9. Memory leak detection test */ printf("Processing queue deallocation test:\n"); talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL); return 0; }