diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-04-03 13:11:05 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-04-04 16:32:27 -0700 |
commit | a3dcfd54ef29ac7cbd988ce94e96bcc6ba924ac6 (patch) | |
tree | 89787caadeae884edc7b7fe75810aba39c181f73 | |
parent | af4d0fb2976f5d5e9104366f4c525010cfc7489b (diff) | |
download | chrome-ec-a3dcfd54ef29ac7cbd988ce94e96bcc6ba924ac6.tar.gz |
Improve deferred function calls
1) Check vs. number of allowable deferred function calls is made at
link time.
2) Added a check for whether hook_call_deferred() has been made after
the start of calculating the time when the hook task should wake. If
it has, go back and recalculate the wake time. This works around a
race condition.
BUG=chrome-os-partner:18473
BRANCH=none
TEST=add a bunch of deferrable functions and recompile; generates a link error
Change-Id: Ie833e2a699c47b6702957ed67bf7d3925f2df099
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/47266
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/lm4/config.h | 3 | ||||
-rw-r--r-- | chip/stm32/config.h | 3 | ||||
-rw-r--r-- | common/hooks.c | 36 | ||||
-rw-r--r-- | core/cortex-m/ec.lds.S | 8 | ||||
-rw-r--r-- | core/cortex-m/link_defs.h | 5 |
5 files changed, 33 insertions, 22 deletions
diff --git a/chip/lm4/config.h b/chip/lm4/config.h index b82c74eae7..46a0b125cf 100644 --- a/chip/lm4/config.h +++ b/chip/lm4/config.h @@ -18,6 +18,9 @@ /* Interval between HOOK_TICK notifications */ #define HOOK_TICK_INTERVAL (250 * MSEC) +/* Maximum number of deferrable functions */ +#define DEFERRABLE_MAX_COUNT 8 + /****************************************************************************/ /* Memory mapping */ diff --git a/chip/stm32/config.h b/chip/stm32/config.h index 7a2d286e82..989cafa087 100644 --- a/chip/stm32/config.h +++ b/chip/stm32/config.h @@ -31,6 +31,9 @@ /* Interval between HOOK_TICK notifications */ #define HOOK_TICK_INTERVAL (500 * MSEC) +/* Maximum number of deferrable functions */ +#define DEFERRABLE_MAX_COUNT 8 + /* support programming on-chip flash */ #define CONFIG_FLASH diff --git a/common/hooks.c b/common/hooks.c index 6ccfaf56e5..3597a77ea8 100644 --- a/common/hooks.c +++ b/common/hooks.c @@ -20,10 +20,7 @@ #define CPRINTF(format, args...) #endif -/* Maximum number of deferrable functions */ -#ifndef DEFERRABLE_MAX_COUNT -#define DEFERRABLE_MAX_COUNT 8 -#endif +#define DEFERRED_FUNCS_COUNT (__deferred_funcs_end - __deferred_funcs) struct hook_ptrs { const struct hook_data *start; @@ -51,7 +48,7 @@ static const struct hook_ptrs hook_list[] = { /* Times for deferrable functions */ static uint64_t defer_until[DEFERRABLE_MAX_COUNT]; -static int defer_count; +static int defer_new_call; void hook_notify(enum hook_type type) { @@ -86,9 +83,6 @@ void hook_notify(enum hook_type type) void hook_init(void) { - defer_count = __deferred_funcs_end - __deferred_funcs; - ASSERT(defer_count <= DEFERRABLE_MAX_COUNT); - hook_notify(HOOK_INIT); } @@ -105,20 +99,21 @@ int hook_call_deferred(void (*routine)(void), int us) if (p >= __deferred_funcs_end) return EC_ERROR_INVAL; /* Routine not registered */ - /* Convert to index */ i = p - __deferred_funcs; - if (i >= DEFERRABLE_MAX_COUNT) - return EC_ERROR_UNKNOWN; /* No space to hold time */ if (us == -1) { /* Cancel */ defer_until[i] = 0; } else { + /* Set alarm */ + defer_until[i] = get_time().val + us; /* - * Set alarm, and wake task so it can re-sleep for the - * proper time. + * Flag that hook_call_deferred() has been called. If the hook + * task is already active, this will allow it to go through the + * loop one more time before sleeping. */ - defer_until[i] = get_time().val + us; + defer_new_call = 1; + /* Wake task so it can re-sleep for the proper time */ task_wake(TASK_ID_HOOKS); } @@ -137,7 +132,7 @@ void hook_task(void) int i; /* Handle deferred routines */ - for (i = 0; i < defer_count; i++) { + for (i = 0; i < DEFERRED_FUNCS_COUNT; i++) { if (defer_until[i] && defer_until[i] < t) { CPRINTF("[%T hook call deferred 0x%p]\n", __deferred_funcs[i].routine); @@ -166,7 +161,8 @@ void hook_task(void) next = last_tick + HOOK_TICK_INTERVAL - t; /* Wake earlier if needed by a deferred routine */ - for (i = 0; i < defer_count && next > 0; i++) { + defer_new_call = 0; + for (i = 0; i < DEFERRED_FUNCS_COUNT && next > 0; i++) { if (!defer_until[i]) continue; @@ -176,8 +172,12 @@ void hook_task(void) next = defer_until[i] - t; } - /* Sleep until the next event */ - if (next > 0) + /* + * If nothing is immediately pending, and hook_call_deferred() + * hasn't been called since we started calculating next, sleep + * until the next event. + */ + if (next > 0 && !defer_new_call) task_wait_event(next); } } diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S index cb0f38f35a..339ee4f435 100644 --- a/core/cortex-m/ec.lds.S +++ b/core/cortex-m/ec.lds.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* 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. */ @@ -122,6 +122,12 @@ SECTIONS } > FLASH #endif __ro_end = . ; + + __deferred_funcs_count = + (__deferred_funcs_end - __deferred_funcs) / 4; + ASSERT(__deferred_funcs_count <= DEFERRABLE_MAX_COUNT, + "Increase DEFERRABLE_MAX_COUNT") + .bss : { /* Stacks must be 64-bit aligned */ . = ALIGN(8); diff --git a/core/cortex-m/link_defs.h b/core/cortex-m/link_defs.h index dbf2757b21..f78a7c46c4 100644 --- a/core/cortex-m/link_defs.h +++ b/core/cortex-m/link_defs.h @@ -44,9 +44,8 @@ extern const struct hook_data __hooks_second[]; extern const struct hook_data __hooks_second_end[]; /* Deferrable functions */ -static const struct deferred_data __deferred_funcs[]; -static const struct deferred_data __deferred_funcs_end[]; - +extern const struct deferred_data __deferred_funcs[]; +extern const struct deferred_data __deferred_funcs_end[]; /* Host commands */ extern const struct host_command __hcmds[]; |