Linux Audio

Check our new training course

Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/* map.c - test memory slab APIs */

/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief Test memory slab APIs
 *
 * This module tests the following map routines:
 *
 *     k_mem_slab_alloc
 *     task_mem_map_free
 *     task_mem_map_used_get
 *
 * @note
 * One should ensure that the block is released to the same map from which it
 * was allocated, and is only released once.  Using an invalid pointer will
 * have unpredictable side effects.
 */

#include <tc_util.h>
#include <stdbool.h>
#include <zephyr.h>

/* size of stack area used by each thread */
#define STACKSIZE 1024 + CONFIG_TEST_EXTRA_STACKSIZE

/* Number of memory blocks. The minimum number of blocks needed to run the
 * test is 2
 */
#define NUMBLOCKS   2

static int tcRC = TC_PASS;     /* test case return code */

int testSlabGetAllBlocks(void **P);
int testSlabFreeAllBlocks(void **P);


K_SEM_DEFINE(SEM_HELPERDONE, 0, 1);
K_SEM_DEFINE(SEM_REGRESSDONE, 0, 1);

K_MEM_SLAB_DEFINE(MAP_LgBlks, 1024, NUMBLOCKS, 4);


/**
 *
 * @brief Verify return value
 *
 * This routine verifies current value against expected value
 * and returns true if they are the same.
 *
 * @param expectRetValue     expect value
 * @param currentRetValue    current value
 *
 * @return  true, false
 */

bool verifyRetValue(int expectRetValue, int currentRetValue)
{
	return (expectRetValue == currentRetValue);

} /* verifyRetValue */

/**
 *
 * @brief Helper task
 *
 * This routine gets all blocks from the memory slab.  It uses semaphores
 * SEM_REGRESDONE and SEM_HELPERDONE to synchronize between different parts
 * of the test.
 *
 * @return  N/A
 */

void HelperTask(void)
{
	void *ptr[NUMBLOCKS];           /* Pointer to memory block */

	memset(ptr, 0, sizeof(ptr));    /* keep static checkers happy */
	/* Wait for part 1 to complete */
	k_sem_take(&SEM_REGRESSDONE, K_FOREVER);

	/* Part 2 of test */

	TC_PRINT("Starts %s\n", __func__);
	PRINT_LINE;
	TC_PRINT("(2) - Allocate %d blocks in <%s>\n", NUMBLOCKS, __func__);
	PRINT_LINE;

	/* Test k_mem_slab_alloc */
	tcRC = testSlabGetAllBlocks(ptr);
	if (tcRC == TC_FAIL) {
		TC_ERROR("Failed testSlabGetAllBlocks function\n");
		goto exitTest1;          /* terminate test */
	}

	k_sem_give(&SEM_HELPERDONE);  /* Indicate part 2 is complete */
	/* Wait for part 3 to complete */
	k_sem_take(&SEM_REGRESSDONE, K_FOREVER);

	/*
	 * Part 4 of test.
	 * Free the first memory block.  RegressionTask is currently blocked
	 * waiting (with a timeout) for a memory block.  Freeing the memory
	 * block will unblock RegressionTask.
	 */
	PRINT_LINE;
	TC_PRINT("(4) - Free a block in <%s> to unblock the other task "
		 "from alloc timeout\n", __func__);
	PRINT_LINE;

	TC_PRINT("%s: About to free a memory block\n", __func__);
	k_mem_slab_free(&MAP_LgBlks, &ptr[0]);
	k_sem_give(&SEM_HELPERDONE);

	/* Part 5 of test */
	k_sem_take(&SEM_REGRESSDONE, K_FOREVER);
	PRINT_LINE;
	TC_PRINT("(5) <%s> freeing the next block\n", __func__);
	PRINT_LINE;
	TC_PRINT("%s: About to free another memory block\n", __func__);
	k_mem_slab_free(&MAP_LgBlks, &ptr[1]);

	/*
	 * Free all the other blocks.  The first 2 blocks are freed by this task
	 */
	for (int i = 2; i < NUMBLOCKS; i++) {
		k_mem_slab_free(&MAP_LgBlks, &ptr[i]);
	}
	TC_PRINT("%s: freed all blocks allocated by this task\n", __func__);

exitTest1:

	TC_END_RESULT(tcRC);
	k_sem_give(&SEM_HELPERDONE);
}  /* HelperTask */


/**
 *
 * @brief Get all blocks from the memory slab
 *
 * Get all blocks from the memory slab.  It also tries to get one more block
 * from the map after the map is empty to verify the error return code.
 *
 * This routine tests the following:
 *
 *   k_mem_slab_alloc(), k_mem_slab_num_used_get()
 *
 * @param p    pointer to pointer of allocated blocks
 *
 * @return  TC_PASS, TC_FAIL
 */

int testSlabGetAllBlocks(void **p)
{
	int retValue;   /* task_mem_map_xxx interface return value */
	void *errPtr;   /* Pointer to block */

	TC_PRINT("Function %s\n", __func__);

	for (int i = 0; i < NUMBLOCKS; i++) {
		/* Verify number of used blocks in the map */
		retValue = k_mem_slab_num_used_get(&MAP_LgBlks);
		if (verifyRetValue(i, retValue)) {
			TC_PRINT("MAP_LgBlks used %d blocks\n", retValue);
		} else {
			TC_ERROR("Failed task_mem_map_used_get for "
				 "MAP_LgBlks, i=%d, retValue=%d\n",
				 i, retValue);
			return TC_FAIL;
		}

		/* Get memory block */
		retValue = k_mem_slab_alloc(&MAP_LgBlks, &p[i], K_NO_WAIT);
		if (verifyRetValue(0, retValue)) {
			TC_PRINT("  k_mem_slab_alloc OK, p[%d] = %p\n",
				 i, p[i]);
		} else {
			TC_ERROR("Failed k_mem_slab_alloc, i=%d, "
				 "retValue %d\n", i, retValue);
			return TC_FAIL;
		}

	} /* for */

	/* Verify number of used blocks in the map - expect all blocks are
	 * used
	 */
	retValue = k_mem_slab_num_used_get(&MAP_LgBlks);
	if (verifyRetValue(NUMBLOCKS, retValue)) {
		TC_PRINT("MAP_LgBlks used %d blocks\n", retValue);
	} else {
		TC_ERROR("Failed task_mem_map_used_get for MAP_LgBlks, "
			 "retValue %d\n", retValue);
		return TC_FAIL;
	}

	/* Try to get one more block and it should fail */
	retValue = k_mem_slab_alloc(&MAP_LgBlks, &errPtr, K_NO_WAIT);
	if (verifyRetValue(-ENOMEM, retValue)) {
		TC_PRINT("  k_mem_slab_alloc RC_FAIL expected as all (%d) "
			 "blocks are used.\n", NUMBLOCKS);
	} else {
		TC_ERROR("Failed k_mem_slab_alloc, expect RC_FAIL, got %d\n",
			 retValue);
		return TC_FAIL;
	}

	PRINT_LINE;

	return TC_PASS;
}  /* testSlabGetAllBlocks */

/**
 *
 * @brief Free all memeory blocks
 *
 * This routine frees all memory blocks and also verifies that the number of
 * blocks used are correct.
 *
 * This routine tests the following:
 *
 *   k_mem_slab_free(&), k_mem_slab_num_used_get(&)
 *
 * @param p    pointer to pointer of allocated blocks
 *
 * @return  TC_PASS, TC_FAIL
 */

int testSlabFreeAllBlocks(void **p)
{
	int retValue;     /* task_mem_map_xxx interface return value */

	TC_PRINT("Function %s\n", __func__);

	for (int i = 0; i < NUMBLOCKS; i++) {
		/* Verify number of used blocks in the map */
		retValue = k_mem_slab_num_used_get(&MAP_LgBlks);
		if (verifyRetValue(NUMBLOCKS - i, retValue)) {
			TC_PRINT("MAP_LgBlks used %d blocks\n", retValue);
		} else {
			TC_ERROR("Failed task_mem_map_used_get for "
				 "MAP_LgBlks, expect %d, got %d\n",
				 NUMBLOCKS - i, retValue);
			return TC_FAIL;
		}

		TC_PRINT("  block ptr to free p[%d] = %p\n", i, p[i]);
		/* Free memory block */
		k_mem_slab_free(&MAP_LgBlks, &p[i]);

		TC_PRINT("MAP_LgBlks freed %d block\n", i + 1);

	} /* for */

	/*
	 * Verify number of used blocks in the map
	 *  - should be 0 as no blocks are used
	 */

	retValue = k_mem_slab_num_used_get(&MAP_LgBlks);
	if (verifyRetValue(0, retValue)) {
		TC_PRINT("MAP_LgBlks used %d blocks\n", retValue);
	} else {
		TC_ERROR("Failed task_mem_map_used_get for MAP_LgBlks, "
			 "retValue %d\n", retValue);
		return TC_FAIL;
	}

	PRINT_LINE;
	return TC_PASS;
}   /* testSlabFreeAllBlocks */

/**
 *
 * @brief Print the pointers
 *
 * This routine prints out the pointers.
 *
 * @param pointer    pointer to pointer of allocated blocks
 *
 * @return  N/A
 */
void printPointers(void **pointer)
{
	TC_PRINT("%s: ", __func__);
	for (int i = 0; i < NUMBLOCKS; i++) {
		TC_PRINT("p[%d] = %p, ", i, pointer[i]);
	}

	TC_PRINT("\n");
	PRINT_LINE;

}  /* printPointers */

/**
 *
 * @brief Main task to test task_mem_map_xxx interfaces
 *
 * This routine calls testSlabGetAllBlocks() to get all memory blocks from the
 * map and calls testSlabFreeAllBlocks() to free all memory blocks.  It also
 * tries to wait (with and without timeout) for a memory block.
 *
 * This routine tests the following:
 *
 *   k_mem_slab_alloc
 *
 * @return  N/A
 */

void RegressionTask(void)
{
	int retValue;                   /* task_mem_map_xxx interface return value */
	void *b;                        /* Pointer to memory block */
	void *ptr[NUMBLOCKS];           /* Pointer to memory block */

	/* not strictly necessary, but keeps coverity checks happy */
	memset(ptr, 0, sizeof(ptr));

	/* Part 1 of test */

	TC_START("Test Kernel memory slabs");
	TC_PRINT("Starts %s\n", __func__);
	PRINT_LINE;
	TC_PRINT("(1) - Allocate and free %d blocks "
		 "in <%s>\n", NUMBLOCKS, __func__);
	PRINT_LINE;

	/* Test k_mem_slab_alloc */
	tcRC = testSlabGetAllBlocks(ptr);
	if (tcRC == TC_FAIL) {
		TC_ERROR("Failed testSlabGetAllBlocks function\n");
		goto exitTest;           /* terminate test */
	}

	printPointers(ptr);
	/* Test task_mem_map_free */
	tcRC = testSlabFreeAllBlocks(ptr);
	if (tcRC == TC_FAIL) {
		TC_ERROR("Failed testSlabFreeAllBlocks function\n");
		goto exitTest;           /* terminate test */
	}

	k_sem_give(&SEM_REGRESSDONE);   /* Allow HelperTask to run */
	/* Wait for HelperTask to finish */
	k_sem_take(&SEM_HELPERDONE, K_FOREVER);

	/*
	 * Part 3 of test.
	 *
	 * HelperTask got all memory blocks.  There is no free block left.
	 * The call will timeout.  Note that control does not switch back to
	 * HelperTask as it is waiting for SEM_REGRESSDONE.
	 */

	PRINT_LINE;
	TC_PRINT("(3) - Further allocation results in  timeout "
		 "in <%s>\n", __func__);
	PRINT_LINE;

	retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, 20);
	if (verifyRetValue(-EAGAIN, retValue)) {
		TC_PRINT("%s: k_mem_slab_alloc times out which is "
			 "expected\n", __func__);
	} else {
		TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue);
		tcRC = TC_FAIL;
		goto exitTest;           /* terminate test */
	}

	TC_PRINT("%s: start to wait for block\n", __func__);
	k_sem_give(&SEM_REGRESSDONE);    /* Allow HelperTask to run part 4 */
	retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, 50);
	if (verifyRetValue(0, retValue)) {
		TC_PRINT("%s: k_mem_slab_alloc OK, block allocated at %p\n",
			 __func__, b);
	} else {
		TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue);
		tcRC = TC_FAIL;
		goto exitTest;           /* terminate test */
	}

	/* Wait for HelperTask to complete */
	k_sem_take(&SEM_HELPERDONE, K_FOREVER);

	TC_PRINT("%s: start to wait for block\n", __func__);
	k_sem_give(&SEM_REGRESSDONE);    /* Allow HelperTask to run part 5 */
	retValue = k_mem_slab_alloc(&MAP_LgBlks, &b, K_FOREVER);
	if (verifyRetValue(0, retValue)) {
		TC_PRINT("%s: k_mem_slab_alloc OK, block allocated at %p\n",
			 __func__, b);
	} else {
		TC_ERROR("Failed k_mem_slab_alloc, retValue %d\n", retValue);
		tcRC = TC_FAIL;
		goto exitTest;           /* terminate test */
	}

	/* Wait for HelperTask to complete */
	k_sem_take(&SEM_HELPERDONE, K_FOREVER);


	/* Free memory block */
	TC_PRINT("%s: Used %d block\n", __func__,
		 k_mem_slab_num_used_get(&MAP_LgBlks));
	k_mem_slab_free(&MAP_LgBlks, &b);
	TC_PRINT("%s: 1 block freed, used %d block\n",
		 __func__,  k_mem_slab_num_used_get(&MAP_LgBlks));

exitTest:

	TC_END_RESULT(tcRC);
	TC_END_REPORT(tcRC);
}  /* RegressionTask */

K_THREAD_DEFINE(HELPERTASK, STACKSIZE, HelperTask, NULL, NULL, NULL,
		7, 0, K_NO_WAIT);

K_THREAD_DEFINE(REGRESSTASK, STACKSIZE, RegressionTask, NULL, NULL, NULL,
		5, 0, K_NO_WAIT);