This is an automated email from the ASF dual-hosted git repository. kasjer pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit c49b8541b785b08fc6c06c85e4bd2e5fcbd45f59 Author: Jerzy Kasenberg <[email protected]> AuthorDate: Thu Oct 22 12:26:26 2026 +0200 util/static_task: Add statically defined tasks Packages that own a task repeat the same code: task structure, stack, event queue, os_eventq_init() and os_task_init() from sysinit, and a handler that only loops on os_eventq_run(). Add util/static_task package with STATIC_TASK_DEFINE() and STATIC_EVENTQ_TASK_DEFINE() that define the task with its stack (and statically initialized event queue) and put a descriptor in the static_task_defs link table. static_task_init(), called by sysinit at STATIC_TASK_SYSINIT_STAGE (9000, after all other packages), creates all of them. The link table holds pointers to descriptors so element size does not depend on section alignment. Add static initializer for event queue OS_EVENTQ_INITIALIZER(), equivalent of os_eventq_init(). A statically initialized queue is valid from the start, so events can be put on it before the task that processes them is created, e.g. from earlier sysinit stages. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Jerzy Kasenberg <[email protected]> --- docs/os/core_os/event_queue/event_queue.rst | 18 +++ docs/os/core_os/task/task.rst | 52 ++++++++ kernel/os/include/os/os_eventq.h | 12 ++ util/static_task/include/static_task/static_task.h | 137 +++++++++++++++++++++ util/static_task/pkg.yml | 34 +++++ util/static_task/src/static_task.c | 35 ++++++ util/static_task/syscfg.yml | 26 ++++ 7 files changed, 314 insertions(+) diff --git a/docs/os/core_os/event_queue/event_queue.rst b/docs/os/core_os/event_queue/event_queue.rst index 8c2aabcf7..fa0fc025b 100644 --- a/docs/os/core_os/event_queue/event_queue.rst +++ b/docs/os/core_os/event_queue/event_queue.rst @@ -49,6 +49,24 @@ waiting for an event on the queue and puts the task into the A task can use the :c:func:`os_eventq_run()` wrapper function that calls the :c:func:`os_eventq_get()` function to dequeue an event from the queue and then calls the event callback function to process the event. +A task that does nothing else can call :c:func:`os_eventq_loop()`, which +calls :c:func:`os_eventq_run()` forever and never returns. +:c:func:`os_eventq_task_handler()` does the same with the event queue +passed as the task argument, so it can be given directly to +:c:func:`os_task_init()`. + +An event queue can be initialized statically with +``OS_EVENTQ_INITIALIZER``, so events can be put on it before the task +that processes them is created: + +.. code:: c + + struct os_eventq my_evq = OS_EVENTQ_INITIALIZER(my_evq); + +``STATIC_EVENTQ_TASK_DEFINE`` from ``util/static_task`` defines a task +together with its stack and statically initialized event queue; see +:doc:`../task/task`. + Note: - Only one task should consume or block waiting for events from an diff --git a/docs/os/core_os/task/task.rst b/docs/os/core_os/task/task.rst index 01cf85a06..8d88a222e 100644 --- a/docs/os/core_os/task/task.rst +++ b/docs/os/core_os/task/task.rst @@ -108,6 +108,58 @@ task. This task simply toggles an LED at a one second interval. /* main never returns */ } +Statically defined tasks +------------------------ + +Many packages need a task that only processes events from its own event +queue. Package ``util/static_task`` provides +``STATIC_EVENTQ_TASK_DEFINE(name, prio, stack_size)`` that defines such +a task ``name_task``, its stack ``name_stack`` and a statically +initialized event queue ``name_evq``. No task handler or initialization +code is needed: all tasks defined this way are created by +:c:func:`static_task_init()`, which sysinit calls at stage +``STATIC_TASK_SYSINIT_STAGE`` (by default after all other packages are +initialized). Events can be put on ``name_evq`` at any time, also from +earlier sysinit stages; they are processed once the task starts. +Tasks are started in alphabetical order of their names. A package using +the macros adds ``@apache-mynewt-core/util/static_task`` to its +``pkg.deps`` and includes ``static_task/static_task.h``. + +``STATIC_TASK_DEFINE(name, prio, stack_size, func, arg)`` does the same for +a task with its own handler and no event queue. +``STATIC_EVENTQ_TASK_DECLARE(name)`` declares the symbols for use in other +files. + +.. code-block:: c + + /* foo.h */ + STATIC_EVENTQ_TASK_DECLARE(foo); + + /* foo.c */ + STATIC_EVENTQ_TASK_DEFINE(foo, MYNEWT_VAL(FOO_TASK_PRIO), + MYNEWT_VAL(FOO_TASK_STACK_SIZE)); + + static void + foo_event_cb(struct os_event *ev) + { + /* Executed in foo_task context */ + } + + static struct os_event foo_event = { + .ev_cb = foo_event_cb, + }; + + void + foo_irq_handler(void) + { + os_eventq_put(&foo_evq, &foo_event); + } + +The definition is placed in a link table, so it is only linked in when +its object file is pulled from the package library; this is the case +when other code in the same file is referenced. Otherwise set +``pkg.whole_archive: true`` in the package's ``pkg.yml``. + API ---- diff --git a/kernel/os/include/os/os_eventq.h b/kernel/os/include/os/os_eventq.h index 046410700..4f798b3db 100644 --- a/kernel/os/include/os/os_eventq.h +++ b/kernel/os/include/os/os_eventq.h @@ -104,6 +104,18 @@ struct os_eventq { #endif }; +/** + * Static initializer for event queue, equivalent of os_eventq_init(). + * + * struct os_eventq my_evq = OS_EVENTQ_INITIALIZER(my_evq); + * + * @param evq The event queue variable being initialized + */ +#define OS_EVENTQ_INITIALIZER(evq) \ + { \ + .evq_list = STAILQ_HEAD_INITIALIZER((evq).evq_list), \ + } + /** * Initialize the event queue * diff --git a/util/static_task/include/static_task/static_task.h b/util/static_task/include/static_task/static_task.h new file mode 100644 index 000000000..89d036c5a --- /dev/null +++ b/util/static_task/include/static_task/static_task.h @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_STATIC_TASK_ +#define H_STATIC_TASK_ + +#include "os/os.h" +#include "os/link_tables.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Tasks defined with STATIC_TASK_DEFINE() or STATIC_EVENTQ_TASK_DEFINE() + * are collected in the static_task_defs link table and started by + * static_task_init() at sysinit stage STATIC_TASK_SYSINIT_STAGE, after + * all packages are initialized. + * + * - Task name is the stringified name argument; symbols defined are + * global so duplicate names fail to link. + * - Tasks are started in alphabetical order of their names. + * - Stack size is in os_stack_t units, as for OS_TASK_STACK_DEFINE(). + * - Definition is only linked if its object file is pulled in from the + * package archive. This is normally the case since the file also has + * code referenced from elsewhere (e.g. users of <name>_evq or the + * package init function); otherwise set pkg.whole_archive: true. + * + * Example: + * + * STATIC_EVENTQ_TASK_DEFINE(foo, MYNEWT_VAL(FOO_TASK_PRIO), + * MYNEWT_VAL(FOO_TASK_STACK_SIZE)); + * + * os_eventq_put(&foo_evq, &foo_event); + */ + +/** Static definition of task, created by static_task_init(). */ +struct static_task_def { + /** Task to initialize */ + struct os_task *task; + /** Task name */ + const char *name; + /** Task handler */ + os_task_func_t func; + /** Argument passed to task handler */ + void *arg; + /** Bottom of task stack */ + os_stack_t *stack; + /** Task stack size in os_stack_t units */ + uint16_t stack_size; + /** Task priority */ + uint8_t prio; +}; + +/* + * Table holds pointers rather than structures so element size does not + * depend on how the compiler aligns structures placed in sections. + */ +LINK_TABLE(const struct static_task_def *, static_task_defs) + +/** + * Defines task <name>_task with stack <name>_stack and adds it to the + * list of tasks started by static_task_init(). + * + * @param _name Task name, also prefix of defined symbols + * @param _prio Task priority + * @param _stack_size Stack size in os_stack_t units + * @param _func Task handler + * @param _arg Argument passed to task handler + */ +#define STATIC_TASK_DEFINE(_name, _prio, _stack_size, _func, _arg) \ + struct os_task _name##_task; \ + OS_TASK_STACK_DEFINE(_name##_stack, _stack_size) \ + static const struct static_task_def _name##_task_def = { \ + .task = &_name##_task, \ + .name = #_name, \ + .func = (_func), \ + .arg = (_arg), \ + .stack = _name##_stack, \ + .stack_size = OS_STACK_ALIGN(_stack_size), \ + .prio = (_prio), \ + }; \ + LINK_TABLE_ELEMENT(static_task_defs, _name##_task_def_ptr) = \ + &_name##_task_def + +/** + * Defines task <name>_task with stack <name>_stack and event queue + * <name>_evq. The task processes events from <name>_evq forever. + * The event queue is statically initialized, events can be put on it + * before the task is started. + * + * @param _name Task name, also prefix of defined symbols + * @param _prio Task priority + * @param _stack_size Stack size in os_stack_t units + */ +#define STATIC_EVENTQ_TASK_DEFINE(_name, _prio, _stack_size) \ + struct os_eventq _name##_evq = OS_EVENTQ_INITIALIZER(_name##_evq); \ + STATIC_TASK_DEFINE(_name, _prio, _stack_size, os_eventq_task_handler, \ + &_name##_evq) + +/** + * Declares symbols defined by STATIC_EVENTQ_TASK_DEFINE() for use in + * other files. + * + * @param _name Name used in STATIC_EVENTQ_TASK_DEFINE() + */ +#define STATIC_EVENTQ_TASK_DECLARE(_name) \ + extern struct os_task _name##_task; \ + extern struct os_eventq _name##_evq + +/** + * Starts all tasks defined with STATIC_TASK_DEFINE() and + * STATIC_EVENTQ_TASK_DEFINE(). Called by sysinit. + */ +void static_task_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_STATIC_TASK_ */ diff --git a/util/static_task/pkg.yml b/util/static_task/pkg.yml new file mode 100644 index 000000000..9a165f03e --- /dev/null +++ b/util/static_task/pkg.yml @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: util/static_task +pkg.description: > + Statically defined tasks, created by sysinit. +pkg.author: "Apache Mynewt <[email protected]>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/kernel/os" + +pkg.link_tables: + - static_task_defs + +pkg.init: + static_task_init: 'MYNEWT_VAL(STATIC_TASK_SYSINIT_STAGE)' diff --git a/util/static_task/src/static_task.c b/util/static_task/src/static_task.c new file mode 100644 index 000000000..49051196f --- /dev/null +++ b/util/static_task/src/static_task.c @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "static_task/static_task.h" + +void +static_task_init(void) +{ + const struct static_task_def *td; + int rc; + + LINK_TABLE_FOREACH(e, static_task_defs) { + td = *e; + rc = os_task_init(td->task, td->name, td->func, td->arg, td->prio, + OS_WAIT_FOREVER, td->stack, td->stack_size); + SYSINIT_PANIC_ASSERT(rc == 0); + } +} diff --git a/util/static_task/syscfg.yml b/util/static_task/syscfg.yml new file mode 100644 index 000000000..f56e69d50 --- /dev/null +++ b/util/static_task/syscfg.yml @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + STATIC_TASK_SYSINIT_STAGE: + description: > + Sysinit stage at which tasks defined with STATIC_TASK_DEFINE() + and STATIC_EVENTQ_TASK_DEFINE() are started. Should be later + than initialization of packages that define such tasks. + value: 9000
