/* * Copyright 2024 Google LLC * * Licensed 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. */ #pragma once #include "services/common/system_task.h" #include "fake_pebble_tasks.h" #include "util/list.h" #include "clar_asserts.h" #include #include typedef struct { ListNode node; SystemTaskEventCallback callback; void *data; } SystemTaskCallbackNode; static ListNode *s_system_task_callback_head = NULL; static bool s_invoke_as_current = false; static uint32_t system_task_available_space = ~(uint32_t)0; bool system_task_add_callback(SystemTaskEventCallback cb, void *data) { SystemTaskCallbackNode *node = (SystemTaskCallbackNode *) malloc(sizeof(SystemTaskCallbackNode)); cl_assert(node != NULL); list_init(&node->node); cl_assert(cb); node->callback = cb; node->data = data; s_system_task_callback_head = list_prepend(s_system_task_callback_head, &node->node); cl_assert(s_system_task_callback_head); system_task_available_space--; return true; } bool system_task_add_callback_from_isr(SystemTaskEventCallback cb, void *data, bool *should_context_switch) { *should_context_switch = false; return system_task_add_callback(cb, data); } uint32_t system_task_get_available_space(void) { return system_task_available_space; } void system_task_set_available_space(uint32_t space) { system_task_available_space = space; } //////////////////////////////////// // Stub: // void stub_invoke_system_task_as_current(void) { s_invoke_as_current = !s_invoke_as_current; } //////////////////////////////////// // Fake manipulation: // void *s_fake_system_task_current_cb; void fake_system_task_callbacks_invoke(int num_to_invoke) { PebbleTask current_task = pebble_task_get_current(); if (!s_invoke_as_current) { stub_pebble_tasks_set_current(PebbleTask_KernelBackground); } // Start at tail ("oldest" callback): SystemTaskCallbackNode *node = (SystemTaskCallbackNode *) list_get_tail(s_system_task_callback_head); while (node && num_to_invoke) { // do callback first, in case callback enqueues more callbacks if (node->callback) { s_fake_system_task_current_cb = node->callback; node->callback(node->data); s_fake_system_task_current_cb = NULL; } SystemTaskCallbackNode *prev = (SystemTaskCallbackNode *) list_get_prev(&node->node); list_remove(&node->node, &s_system_task_callback_head, NULL); free(node); node = prev; system_task_available_space++; num_to_invoke--; } stub_pebble_tasks_set_current(current_task); } void fake_system_task_callbacks_invoke_pending(void) { // sometimes the cb's may add new jobs so we need to keep looping until no // more are left while (s_system_task_callback_head) { fake_system_task_callbacks_invoke(list_count(s_system_task_callback_head)); } } void fake_system_task_callbacks_cleanup(void) { SystemTaskCallbackNode *node = (SystemTaskCallbackNode *) s_system_task_callback_head; while (node) { SystemTaskCallbackNode *next = (SystemTaskCallbackNode *) list_get_next(&node->node); list_remove(&node->node, &s_system_task_callback_head, NULL); free(node); node = next; } cl_assert(s_system_task_callback_head == NULL); } void system_task_watchdog_feed(void) { } uint32_t fake_system_task_count_callbacks(void) { return list_count(s_system_task_callback_head); } void system_task_enable_raised_priority(bool is_raised) { } bool system_task_is_ready_to_run(void) { return true; } void* system_task_get_current_callback(void) { return s_fake_system_task_current_cb; }