summaryrefslogtreecommitdiff
path: root/core/host/task.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /core/host/task.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-firmware-brya-14505.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'core/host/task.c')
-rw-r--r--core/host/task.c564
1 files changed, 0 insertions, 564 deletions
diff --git a/core/host/task.c b/core/host/task.c
deleted file mode 100644
index be7ed3c579..0000000000
--- a/core/host/task.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/* Copyright 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* Task scheduling / events module for Chrome EC operating system */
-
-#include <malloc.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "atomic.h"
-#include "common.h"
-#include "console.h"
-#include "host_task.h"
-#include "task.h"
-#include "task_id.h"
-#include "test_util.h"
-#include "timer.h"
-
-#define SIGNAL_INTERRUPT SIGUSR1
-
-struct emu_task_t {
- pthread_t thread;
- pthread_cond_t resume;
- uint32_t event;
- timestamp_t wake_time;
- uint8_t started;
-};
-
-struct task_args {
- void (*routine)(void *);
- void *d;
-};
-
-static struct emu_task_t tasks[TASK_ID_COUNT];
-static pthread_cond_t scheduler_cond;
-static pthread_mutex_t run_lock;
-static task_id_t running_task_id;
-static int task_started;
-
-static sem_t interrupt_sem;
-static pthread_mutex_t interrupt_lock;
-static pthread_t interrupt_thread;
-static int in_interrupt;
-static int interrupt_disabled;
-static void (*pending_isr)(void);
-static int generator_sleeping;
-static timestamp_t generator_sleep_deadline;
-static int has_interrupt_generator = 1;
-
-/* thread local task id */
-static __thread task_id_t my_task_id = TASK_ID_INVALID;
-
-static void task_enable_all_tasks_callback(void);
-
-#define TASK(n, r, d, s) void r(void *);
-CONFIG_TASK_LIST
-CONFIG_TEST_TASK_LIST
-CONFIG_CTS_TASK_LIST
-#undef TASK
-
-/* usleep that uses OS functions, instead of emulated timer. */
-void _usleep(int usec)
-{
- struct timespec req;
-
- req.tv_sec = usec / 1000000;
- req.tv_nsec = (usec % 1000000) * 1000;
-
- nanosleep(&req, NULL);
-}
-
-/* msleep that uses OS functions, instead of emulated timer. */
-void _msleep(int msec)
-{
- _usleep(1000 * msec);
-}
-
-/* Idle task */
-void __idle(void *d)
-{
- while (1)
- task_wait_event(-1);
-}
-
-void _run_test(void *d)
-{
- run_test(0, NULL);
-}
-
-#define TASK(n, r, d, s) {r, d},
-const struct task_args task_info[TASK_ID_COUNT] = {
- {__idle, NULL},
- CONFIG_TASK_LIST
- CONFIG_TEST_TASK_LIST
- CONFIG_CTS_TASK_LIST
- {_run_test, NULL},
-};
-#undef TASK
-
-#define TASK(n, r, d, s) #n,
-static const char * const task_names[] = {
- "<< idle >>",
- CONFIG_TASK_LIST
- CONFIG_TEST_TASK_LIST
- CONFIG_CTS_TASK_LIST
- "<< test runner >>",
-};
-#undef TASK
-
-void task_pre_init(void)
-{
- /* Nothing */
-}
-
-int in_interrupt_context(void)
-{
- return !!in_interrupt;
-}
-
-test_mockable void interrupt_disable(void)
-{
- pthread_mutex_lock(&interrupt_lock);
- interrupt_disabled = 1;
- pthread_mutex_unlock(&interrupt_lock);
-}
-
-test_mockable void interrupt_enable(void)
-{
- pthread_mutex_lock(&interrupt_lock);
- interrupt_disabled = 0;
- pthread_mutex_unlock(&interrupt_lock);
-}
-
-inline int is_interrupt_enabled(void)
-{
- return !interrupt_disabled;
-}
-
-static void _task_execute_isr(int sig)
-{
- in_interrupt = 1;
- pending_isr();
- sem_post(&interrupt_sem);
- in_interrupt = 0;
-}
-
-void task_register_interrupt(void)
-{
- sem_init(&interrupt_sem, 0, 0);
- signal(SIGNAL_INTERRUPT, _task_execute_isr);
-}
-
-void task_trigger_test_interrupt(void (*isr)(void))
-{
- pid_t main_pid;
- pthread_mutex_lock(&interrupt_lock);
- if (interrupt_disabled) {
- pthread_mutex_unlock(&interrupt_lock);
- return;
- }
-
- /* Suspend current task and excute ISR */
- pending_isr = isr;
- if (task_started) {
- pthread_kill(tasks[running_task_id].thread, SIGNAL_INTERRUPT);
- } else {
- main_pid = getpid();
- kill(main_pid, SIGNAL_INTERRUPT);
- }
-
- /* Wait for ISR to complete */
- sem_wait(&interrupt_sem);
- while (in_interrupt)
- _usleep(10);
- pending_isr = NULL;
-
- pthread_mutex_unlock(&interrupt_lock);
-}
-
-void interrupt_generator_udelay(unsigned us)
-{
- generator_sleep_deadline.val = get_time().val + us;
- generator_sleeping = 1;
- while (get_time().val < generator_sleep_deadline.val)
- ;
- generator_sleeping = 0;
-}
-
-const char *task_get_name(task_id_t tskid)
-{
- return task_names[tskid];
-}
-
-pthread_t task_get_thread(task_id_t tskid)
-{
- return tasks[tskid].thread;
-}
-
-uint32_t task_set_event(task_id_t tskid, uint32_t event)
-{
- atomic_or(&tasks[tskid].event, event);
- return 0;
-}
-
-uint32_t *task_get_event_bitmap(task_id_t tskid)
-{
- return &tasks[tskid].event;
-}
-
-uint32_t task_wait_event(int timeout_us)
-{
- int tid = task_get_current();
- int ret;
- pthread_mutex_lock(&interrupt_lock);
- if (timeout_us > 0)
- tasks[tid].wake_time.val = get_time().val + timeout_us;
-
- /* Transfer control to scheduler */
- pthread_cond_signal(&scheduler_cond);
- pthread_cond_wait(&tasks[tid].resume, &run_lock);
-
- /* Resume */
- ret = atomic_clear(&tasks[tid].event);
- pthread_mutex_unlock(&interrupt_lock);
- return ret;
-}
-
-uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us)
-{
- uint64_t deadline = get_time().val + timeout_us;
- uint32_t events = 0;
- int time_remaining_us = timeout_us;
-
- /* Add the timer event to the mask so we can indicate a timeout */
- event_mask |= TASK_EVENT_TIMER;
-
- while (!(events & event_mask)) {
- /* Collect events to re-post later */
- events |= task_wait_event(time_remaining_us);
-
- time_remaining_us = deadline - get_time().val;
- if (timeout_us > 0 && time_remaining_us <= 0) {
- /* Ensure we return a TIMER event if we timeout */
- events |= TASK_EVENT_TIMER;
- break;
- }
- }
-
- /* Re-post any other events collected */
- if (events & ~event_mask)
- atomic_or(&tasks[task_get_current()].event,
- events & ~event_mask);
-
- return events & event_mask;
-}
-
-void mutex_lock(struct mutex *mtx)
-{
- int value = 0;
- int id = 1 << task_get_current();
-
- mtx->waiters |= id;
-
- do {
- if (mtx->lock == 0) {
- mtx->lock = 1;
- value = 1;
- }
-
- if (!value)
- task_wait_event_mask(TASK_EVENT_MUTEX, 0);
- } while (!value);
-
- mtx->waiters &= ~id;
-}
-
-void mutex_unlock(struct mutex *mtx)
-{
- int v;
- mtx->lock = 0;
-
- for (v = 31; v >= 0; --v)
- if ((1ul << v) & mtx->waiters) {
- mtx->waiters &= ~(1ul << v);
- task_set_event(v, TASK_EVENT_MUTEX);
- break;
- }
-}
-
-task_id_t task_get_current(void)
-{
- return my_task_id;
-}
-
-task_id_t task_get_running(void)
-{
- return running_task_id;
-}
-
-void task_print_list(void)
-{
- int i;
-
- ccputs("Name Events\n");
-
- for (i = 0; i < TASK_ID_COUNT; i++) {
- ccprintf("%4d %-16s %08x\n", i, task_names[i], tasks[i].event);
- cflush();
- }
-}
-
-int command_task_info(int argc, char **argv)
-{
- task_print_list();
-
- return EC_SUCCESS;
-}
-DECLARE_SAFE_CONSOLE_COMMAND(taskinfo, command_task_info,
- NULL,
- "Print task info");
-
-static void _wait_for_task_started(int can_sleep)
-{
- int i, ok;
-
- while (1) {
- ok = 1;
- for (i = 0; i < TASK_ID_COUNT - 1; ++i) {
- if (!tasks[i].started) {
- if (can_sleep)
- msleep(10);
- else
- _msleep(10);
- ok = 0;
- break;
- }
- }
- if (ok)
- return;
- }
-}
-
-void wait_for_task_started(void)
-{
- _wait_for_task_started(1);
-}
-
-void wait_for_task_started_nosleep(void)
-{
- _wait_for_task_started(0);
-}
-
-static task_id_t task_get_next_wake(void)
-{
- int i;
- timestamp_t min_time;
- int which_task = TASK_ID_INVALID;
-
- min_time.val = ~0ull;
-
- for (i = TASK_ID_COUNT - 1; i >= 0; --i)
- if (min_time.val >= tasks[i].wake_time.val) {
- min_time.val = tasks[i].wake_time.val;
- which_task = i;
- }
-
- return which_task;
-}
-
-static int fast_forward(void)
-{
- /*
- * No task has event pending, and thus the next time we have an
- * event to process must be either of:
- * 1. Interrupt generator triggers an interrupt
- * 2. The next wake alarm is reached
- * So we should check whether an interrupt may happen, and fast
- * forward to the nearest among:
- * 1. When interrupt generator wakes up
- * 2. When the next task wakes up
- */
- int task_id = task_get_next_wake();
-
- if (!has_interrupt_generator) {
- if (task_id == TASK_ID_INVALID) {
- return TASK_ID_IDLE;
- } else {
- force_time(tasks[task_id].wake_time);
- return task_id;
- }
- }
-
- if (!generator_sleeping)
- return TASK_ID_IDLE;
-
- if (task_id != TASK_ID_INVALID &&
- tasks[task_id].thread != (pthread_t)NULL &&
- tasks[task_id].wake_time.val < generator_sleep_deadline.val) {
- force_time(tasks[task_id].wake_time);
- return task_id;
- } else {
- force_time(generator_sleep_deadline);
- return TASK_ID_IDLE;
- }
-}
-
-int task_start_called(void)
-{
- return task_started;
-}
-
-void task_scheduler(void)
-{
- int i;
- timestamp_t now;
-
- task_started = 1;
-
- while (1) {
- now = get_time();
- i = TASK_ID_COUNT - 1;
- while (i >= 0) {
- /*
- * Only tasks with spawned threads are valid to be
- * resumed.
- */
- if (tasks[i].thread) {
- if (tasks[i].event ||
- now.val >= tasks[i].wake_time.val)
- break;
- }
- --i;
- }
- if (i < 0)
- i = fast_forward();
-
- now = get_time();
- if (now.val >= tasks[i].wake_time.val)
- tasks[i].event |= TASK_EVENT_TIMER;
- tasks[i].wake_time.val = ~0ull;
- running_task_id = i;
- tasks[i].started = 1;
- pthread_cond_signal(&tasks[i].resume);
- pthread_cond_wait(&scheduler_cond, &run_lock);
- }
-}
-
-void *_task_start_impl(void *a)
-{
- long tid = (long)a;
- const struct task_args *arg = task_info + tid;
- my_task_id = tid;
- pthread_mutex_lock(&run_lock);
-
- /* Wait for scheduler */
- task_wait_event(1);
- tasks[tid].event = 0;
-
- /* Start the task routine */
- (arg->routine)(arg->d);
-
- /* Catch exited routine */
- while (1)
- task_wait_event(-1);
-}
-
-test_mockable void interrupt_generator(void)
-{
- has_interrupt_generator = 0;
-}
-
-void *_task_int_generator_start(void *d)
-{
- my_task_id = TASK_ID_INT_GEN;
- interrupt_generator();
- return NULL;
-}
-
-int task_start(void)
-{
- int i = TASK_ID_HOOKS;
-
- pthread_mutex_init(&run_lock, NULL);
- pthread_mutex_init(&interrupt_lock, NULL);
- pthread_cond_init(&scheduler_cond, NULL);
-
- pthread_mutex_lock(&run_lock);
-
- /*
- * Initialize the hooks task first. After its init, it will callback to
- * enable the remaining tasks.
- */
- tasks[i].event = TASK_EVENT_WAKE;
- tasks[i].wake_time.val = ~0ull;
- tasks[i].started = 0;
- pthread_cond_init(&tasks[i].resume, NULL);
- pthread_create(&tasks[i].thread, NULL, _task_start_impl,
- (void *)(uintptr_t)i);
- pthread_cond_wait(&scheduler_cond, &run_lock);
- /*
- * Interrupt lock is grabbed by the task which just started.
- * Let's unlock it so the next task can be started.
- */
- pthread_mutex_unlock(&interrupt_lock);
-
- /*
- * The hooks task is waiting in task_wait_event(). Lock interrupt_lock
- * here so the first task chosen sees it locked.
- */
- pthread_mutex_lock(&interrupt_lock);
-
- pthread_create(&interrupt_thread, NULL,
- _task_int_generator_start, NULL);
-
- /*
- * Tell the hooks task to continue so that it can call back to enable
- * the other tasks.
- */
- pthread_cond_signal(&tasks[i].resume);
- pthread_cond_wait(&scheduler_cond, &run_lock);
- task_enable_all_tasks_callback();
-
- task_scheduler();
-
- return 0;
-}
-
-static void task_enable_all_tasks_callback(void)
-{
- int i;
-
- /* Initialize the remaning tasks. */
- for (i = 0; i < TASK_ID_COUNT; ++i) {
- if (tasks[i].thread != (pthread_t)NULL)
- continue;
-
- tasks[i].event = TASK_EVENT_WAKE;
- tasks[i].wake_time.val = ~0ull;
- tasks[i].started = 0;
- pthread_cond_init(&tasks[i].resume, NULL);
- pthread_create(&tasks[i].thread, NULL, _task_start_impl,
- (void *)(uintptr_t)i);
- /*
- * Interrupt lock is grabbed by the task which just started.
- * Let's unlock it so the next task can be started.
- */
- pthread_mutex_unlock(&interrupt_lock);
- pthread_cond_wait(&scheduler_cond, &run_lock);
- }
-
-}
-
-void task_enable_all_tasks(void)
-{
- /* Signal to the scheduler to enable the remaining tasks. */
- pthread_cond_signal(&scheduler_cond);
-}