/* * Copyright (c) 2019, Google Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #define TEST_REQUEUE_CNT 10 struct dpc_test_ctx { struct dpc work; uint32_t count; uint32_t in_atomic_requeue_cnt; uint32_t in_thread_requeue_cnt; struct event evt; struct timer tmr; }; static enum handler_return dpc_test_timer_callback(struct timer* t, lk_time_ns_t now, void* arg) { struct dpc_test_ctx* ctx = arg; ctx->in_atomic_requeue_cnt++; dpc_enqueue_work(NULL, &ctx->work, false); return INT_RESCHEDULE; } static void dpc_test_callback(struct dpc* work) { struct dpc_test_ctx* ctx = containerof(work, struct dpc_test_ctx, work); if (ctx->count > TEST_REQUEUE_CNT / 2) { /* requeue work from irq context */ ctx->count--; timer_set_oneshot_ns(&ctx->tmr, 10 * 1000 * 1000, dpc_test_timer_callback, ctx); } else if (ctx->count) { /* requeue work from thread context */ ctx->count--; ctx->in_thread_requeue_cnt++; dpc_enqueue_work(NULL, &ctx->work, false); } else { /* we are done here */ event_signal(&ctx->evt, true); } } TEST(dpctest, test1) { status_t rc; struct dpc_test_ctx test_ctx; /* Init test context */ test_ctx.count = TEST_REQUEUE_CNT; test_ctx.in_atomic_requeue_cnt = 0; test_ctx.in_thread_requeue_cnt = 0; timer_initialize(&test_ctx.tmr); event_init(&test_ctx.evt, false, EVENT_FLAG_AUTOUNSIGNAL); dpc_work_init(&test_ctx.work, dpc_test_callback, 0); /* init dpc work and queue it on default queue */ dpc_enqueue_work(NULL, &test_ctx.work, false); /* wait for complete */ rc = event_wait_timeout(&test_ctx.evt, 1000); /* check results */ EXPECT_EQ(NO_ERROR, rc); EXPECT_EQ(0, test_ctx.count); EXPECT_EQ(TEST_REQUEUE_CNT / 2, test_ctx.in_atomic_requeue_cnt); EXPECT_EQ(TEST_REQUEUE_CNT / 2, test_ctx.in_thread_requeue_cnt); } PORT_TEST(dpctest, "com.android.kernel.dpc-unittest");