1 /* 2 * Copyright (c) 2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "qdf_periodic_work.h" 20 #include "qdf_periodic_work_test.h" 21 #include "qdf_trace.h" 22 23 #define pwork_iterations 2 24 #define pwork_delay_ms 1 25 26 struct qdf_pwork_ut_ctx { 27 struct qdf_periodic_work pwork; 28 uint32_t count; 29 }; 30 31 static void __qdf_pwork_inside_cb(void *context) 32 { 33 struct qdf_pwork_ut_ctx *ut_ctx = context; 34 35 /* stop before incrementing; the main thread is looking at @count */ 36 if (ut_ctx->count + 1 == pwork_iterations) 37 qdf_periodic_work_stop_async(&ut_ctx->pwork); 38 39 ut_ctx->count++; 40 } 41 42 static uint32_t qdf_pwork_stop_inside_cb(void) 43 { 44 struct qdf_pwork_ut_ctx ut_ctx = { .count = 0 }; 45 QDF_STATUS status; 46 47 status = qdf_periodic_work_create(&ut_ctx.pwork, 48 __qdf_pwork_inside_cb, &ut_ctx); 49 QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); 50 51 QDF_BUG(qdf_periodic_work_start(&ut_ctx.pwork, pwork_delay_ms)); 52 53 while (ut_ctx.count < pwork_iterations) 54 schedule(); 55 56 QDF_BUG(!qdf_periodic_work_stop_sync(&ut_ctx.pwork)); 57 QDF_BUG(ut_ctx.count == pwork_iterations); 58 59 qdf_periodic_work_destroy(&ut_ctx.pwork); 60 61 return 0; 62 } 63 64 static void __qdf_pwork_outside_cb(void *context) 65 { 66 struct qdf_pwork_ut_ctx *ut_ctx = context; 67 68 ut_ctx->count++; 69 } 70 71 static uint32_t qdf_pwork_stop_outside_cb(void) 72 { 73 struct qdf_pwork_ut_ctx ut_ctx = { .count = 0 }; 74 QDF_STATUS status; 75 76 status = qdf_periodic_work_create(&ut_ctx.pwork, 77 __qdf_pwork_outside_cb, &ut_ctx); 78 QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); 79 80 QDF_BUG(qdf_periodic_work_start(&ut_ctx.pwork, pwork_delay_ms)); 81 82 while (ut_ctx.count < pwork_iterations) 83 schedule(); 84 85 QDF_BUG(qdf_periodic_work_stop_sync(&ut_ctx.pwork)); 86 QDF_BUG(ut_ctx.count >= pwork_iterations); 87 88 qdf_periodic_work_destroy(&ut_ctx.pwork); 89 90 return 0; 91 } 92 93 uint32_t qdf_periodic_work_unit_test(void) 94 { 95 uint32_t errors = 0; 96 97 errors += qdf_pwork_stop_inside_cb(); 98 errors += qdf_pwork_stop_outside_cb(); 99 100 return errors; 101 } 102 103