Files
OpenCellular/core/host/task.c
Vic Yang e71f008388 Put test utility macros in header
Several test utility macros have been duplicated across tests. Let's put
them in a single place.

BUG=chrome-os-partner:19236
TEST='make runtests', 'BOARD=spring make tests'
BRANCH=None

Change-Id: Ib0c9f829715425cc23e33b8ef456b17dfadab13c
Signed-off-by: Vic Yang <victoryang@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/50513
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
2013-05-08 18:11:01 -07:00

207 lines
3.6 KiB
C

/* Copyright (c) 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 <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include "atomic.h"
#include "common.h"
#include "task.h"
#include "task_id.h"
#include "test_util.h"
#include "timer.h"
struct emu_task_t {
pthread_t thread;
pthread_cond_t resume;
uint32_t event;
timestamp_t wake_time;
};
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 __thread task_id_t my_task_id; /* thread local task id */
#define TASK(n, r, d, s) void r(void *);
CONFIG_TASK_LIST
CONFIG_TEST_TASK_LIST
#undef TASK
/* Idle task */
void __idle(void *d)
{
while (1)
task_wait_event(-1);
}
void _run_test(void *d)
{
run_test();
}
#define TASK(n, r, d, s) {r, d},
struct task_args task_info[TASK_ID_COUNT] = {
{__idle, NULL},
CONFIG_TASK_LIST
CONFIG_TEST_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
"<< test runner >>",
};
#undef TASK
void task_pre_init(void)
{
/* Nothing */
}
int in_interrupt_context(void)
{
return 0; /* No interrupt support yet */
}
void interrupt_disable(void)
{
/* Not supported yet */
}
void interrupt_enable(void)
{
/* Not supported yet */
}
uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait)
{
tasks[tskid].event = event;
if (wait)
return task_wait_event(-1);
return 0;
}
uint32_t task_wait_event(int timeout_us)
{
int tid = task_get_current();
int ret;
if (timeout_us > 0)
tasks[tid].wake_time.val = get_time().val + timeout_us;
pthread_cond_signal(&scheduler_cond);
pthread_cond_wait(&tasks[tid].resume, &run_lock);
ret = tasks[tid].event;
tasks[tid].event = 0;
return ret;
}
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(-1);
} 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, 0);
break;
}
}
task_id_t task_get_current(void)
{
return my_task_id;
}
void task_scheduler(void)
{
int i;
timestamp_t now;
while (1) {
now = get_time();
i = TASK_ID_COUNT - 1;
while (i >= 0) {
if (tasks[i].event || now.val >= tasks[i].wake_time.val)
break;
--i;
}
if (i < 0)
i = TASK_ID_IDLE;
tasks[i].wake_time.val = ~0ull;
pthread_cond_signal(&tasks[i].resume);
pthread_cond_wait(&scheduler_cond, &run_lock);
}
}
void *_task_start_impl(void *a)
{
long tid = (long)a;
struct task_args *arg = task_info + tid;
my_task_id = tid;
pthread_mutex_lock(&run_lock);
tasks[tid].event = 0;
(arg->routine)(arg->d);
while (1)
task_wait_event(-1);
}
int task_start(void)
{
int i;
pthread_mutex_init(&run_lock, NULL);
pthread_cond_init(&scheduler_cond, NULL);
pthread_mutex_lock(&run_lock);
for (i = 0; i < TASK_ID_COUNT; ++i) {
tasks[i].event = TASK_EVENT_WAKE;
tasks[i].wake_time.val = ~0ull;
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);
}
task_scheduler();
return 0;
}