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
__qdf_pwork_inside_cb(void * context)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
qdf_pwork_stop_inside_cb(void)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
__qdf_pwork_outside_cb(void * context)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
qdf_pwork_stop_outside_cb(void)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
qdf_periodic_work_unit_test(void)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