diff --git a/qdf/inc/qdf_delayed_work.h b/qdf/inc/qdf_delayed_work.h new file mode 100644 index 000000000000..0aa781baa30b --- /dev/null +++ b/qdf/inc/qdf_delayed_work.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: qdf_delayed_work.h + * A simple, delayed work type for executing a callback after some delay. + */ + +#ifndef __QDF_DELAYED_WORK_H +#define __QDF_DELAYED_WORK_H + +#include "i_qdf_delayed_work.h" +#include "qdf_status.h" +#include "qdf_types.h" + +typedef void (*qdf_delayed_work_cb)(void *context); + +/** + * struct qdf_delayed_work - a defered work type which executes a callback after + * some delay + * @dwork: OS-specific delayed work + * @callback: the callback to be executed + * @context: the context to pass to the callback + */ +struct qdf_delayed_work { + struct __qdf_opaque_delayed_work dwork; + qdf_delayed_work_cb callback; + void *context; +}; + +/** + * qdf_delayed_work_create() - initialized a delayed work @dwork + * @dwork: the delayed work to initialize + * @callback: the callback to be executed + * @context: the context to pass to the callback + * + * Return: QDF_STATUS + */ +qdf_must_check QDF_STATUS +qdf_delayed_work_create(struct qdf_delayed_work *dwork, + qdf_delayed_work_cb callback, void *context); + +/** + * qdf_delayed_work_destroy() - deinitialize a delayed work @dwork + * @dwork: the delayed work to de-initialize + * + * Return: None + */ +void qdf_delayed_work_destroy(struct qdf_delayed_work *dwork); + +/** + * qdf_delayed_work_start() - schedule execution of @dwork callback + * @dwork: the delayed work to start + * @msec: the delay before execution in milliseconds + * + * Return: true if started successfully + */ +bool qdf_delayed_work_start(struct qdf_delayed_work *dwork, uint32_t msec); + +/** + * qdf_delayed_work_stop_sync() - Synchronously stop execution of @dwork + * @dwork: the delayed work to stop + * + * When this returns, @dwork is guaranteed to not be queued, and its callback + * not executing. + * + * Return: true if @dwork was queued or running + */ +bool qdf_delayed_work_stop_sync(struct qdf_delayed_work *dwork); + +#endif /* __QDF_DELAYED_WORK_H */ + diff --git a/qdf/linux/src/i_qdf_delayed_work.h b/qdf/linux/src/i_qdf_delayed_work.h new file mode 100644 index 000000000000..e72b8644b044 --- /dev/null +++ b/qdf/linux/src/i_qdf_delayed_work.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __I_QDF_DELAYED_WORK_H +#define __I_QDF_DELAYED_WORK_H + +#include "linux/workqueue.h" + +#define __qdf_opaque_delayed_work delayed_work + +#endif /* __I_QDF_DELAYED_WORK_H */ + diff --git a/qdf/linux/src/qdf_delayed_work.c b/qdf/linux/src/qdf_delayed_work.c new file mode 100644 index 000000000000..683d7b747158 --- /dev/null +++ b/qdf/linux/src/qdf_delayed_work.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_delayed_work.h" +#include "qdf_status.h" +#include "qdf_trace.h" +#include "qdf_types.h" + +static void __qdf_delayed_work_handler(struct work_struct *work) +{ + struct qdf_delayed_work *dwork = + container_of(work, struct qdf_delayed_work, dwork.work); + + dwork->callback(dwork->context); +} + +QDF_STATUS qdf_delayed_work_create(struct qdf_delayed_work *dwork, + qdf_delayed_work_cb callback, + void *context) +{ + QDF_BUG(dwork); + QDF_BUG(callback); + if (!dwork || !callback) + return QDF_STATUS_E_INVAL; + + INIT_DELAYED_WORK(&dwork->dwork, __qdf_delayed_work_handler); + dwork->callback = callback; + dwork->context = context; + + return QDF_STATUS_SUCCESS; +} + +void qdf_delayed_work_destroy(struct qdf_delayed_work *dwork) +{ + qdf_delayed_work_stop_sync(dwork); +} + +bool qdf_delayed_work_start(struct qdf_delayed_work *dwork, uint32_t msec) +{ + return schedule_delayed_work(&dwork->dwork, msecs_to_jiffies(msec)); +} + +bool qdf_delayed_work_stop_sync(struct qdf_delayed_work *dwork) +{ + return cancel_delayed_work_sync(&dwork->dwork); +} + diff --git a/qdf/test/qdf_delayed_work_test.c b/qdf/test/qdf_delayed_work_test.c new file mode 100644 index 000000000000..7b56827ecde2 --- /dev/null +++ b/qdf/test/qdf_delayed_work_test.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_delayed_work.h" +#include "qdf_delayed_work_test.h" +#include "qdf_trace.h" + +#define dwork_delay_ms 1 + +static void __qdf_dwork_cb(void *context) +{ + bool *flag = context; + + *flag = true; +} + +uint32_t qdf_delayed_work_unit_test(void) +{ + struct qdf_delayed_work dwork; + bool work_ran = false; + QDF_STATUS status; + + status = qdf_delayed_work_create(&dwork, __qdf_dwork_cb, &work_ran); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + + QDF_BUG(qdf_delayed_work_start(&dwork, dwork_delay_ms)); + + while (!work_ran) + schedule(); + + /* flush to avoid races with the next assert */ + qdf_delayed_work_stop_sync(&dwork); + QDF_BUG(!qdf_delayed_work_stop_sync(&dwork)); + + qdf_delayed_work_destroy(&dwork); + + return 0; +} + diff --git a/qdf/test/qdf_delayed_work_test.h b/qdf/test/qdf_delayed_work_test.h new file mode 100644 index 000000000000..9fa78a423806 --- /dev/null +++ b/qdf/test/qdf_delayed_work_test.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __QDF_DELAYED_WORK_TEST +#define __QDF_DELAYED_WORK_TEST + +#ifdef WLAN_DELAYED_WORK_TEST +/** + * qdf_delayed_work_unit_test() - run the qdf periodic work unit test suite + * + * Return: number of failed test cases + */ +uint32_t qdf_delayed_work_unit_test(void); +#else +static inline uint32_t qdf_delayed_work_unit_test(void) +{ + return 0; +} +#endif /* WLAN_DELAYED_WORK_TEST */ + +#endif /* __QDF_DELAYED_WORK_TEST */ +