b9eaf18722
This mechanically converts all remaining cases of ancient open-coded timer setup with the old setup_timer() API, which is the first step in timer conversions. This has no behavioral changes, since it ultimately just changes the order of assignment to fields of struct timer_list when finding variations of: init_timer(&t); f.function = timer_callback; t.data = timer_callback_arg; to be converted into: setup_timer(&t, timer_callback, timer_callback_arg); The conversion is done with the following Coccinelle script, which is an improved version of scripts/cocci/api/setup_timer.cocci, in the following ways: - assignments-before-init_timer() cases - limit the .data case removal to the specific struct timer_list instance - handling calls by dereference (timer->field vs timer.field) spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/setup_timer.cocci @fix_address_of@ expression e; @@ init_timer( -&(e) +&e , ...) // Match the common cases first to avoid Coccinelle parsing loops with // "... when" clauses. @match_immediate_function_data_after_init_timer@ expression e, func, da; @@ -init_timer +setup_timer ( \(&e\|e\) +, func, da ); ( -\(e.function\|e->function\) = func; -\(e.data\|e->data\) = da; | -\(e.data\|e->data\) = da; -\(e.function\|e->function\) = func; ) @match_immediate_function_data_before_init_timer@ expression e, func, da; @@ ( -\(e.function\|e->function\) = func; -\(e.data\|e->data\) = da; | -\(e.data\|e->data\) = da; -\(e.function\|e->function\) = func; ) -init_timer +setup_timer ( \(&e\|e\) +, func, da ); @match_function_and_data_after_init_timer@ expression e, e2, e3, e4, e5, func, da; @@ -init_timer +setup_timer ( \(&e\|e\) +, func, da ); ... when != func = e2 when != da = e3 ( -e.function = func; ... when != da = e4 -e.data = da; | -e->function = func; ... when != da = e4 -e->data = da; | -e.data = da; ... when != func = e5 -e.function = func; | -e->data = da; ... when != func = e5 -e->function = func; ) @match_function_and_data_before_init_timer@ expression e, e2, e3, e4, e5, func, da; @@ ( -e.function = func; ... when != da = e4 -e.data = da; | -e->function = func; ... when != da = e4 -e->data = da; | -e.data = da; ... when != func = e5 -e.function = func; | -e->data = da; ... when != func = e5 -e->function = func; ) ... when != func = e2 when != da = e3 -init_timer +setup_timer ( \(&e\|e\) +, func, da ); @r1 exists@ expression t; identifier f; position p; @@ f(...) { ... when any init_timer@p(\(&t\|t\)) ... when any } @r2 exists@ expression r1.t; identifier g != r1.f; expression e8; @@ g(...) { ... when any \(t.data\|t->data\) = e8 ... when any } // It is dangerous to use setup_timer if data field is initialized // in another function. @script:python depends on r2@ p << r1.p; @@ cocci.include_match(False) @r3@ expression r1.t, func, e7; position r1.p; @@ ( -init_timer@p(&t); +setup_timer(&t, func, 0UL); ... when != func = e7 -t.function = func; | -t.function = func; ... when != func = e7 -init_timer@p(&t); +setup_timer(&t, func, 0UL); | -init_timer@p(t); +setup_timer(t, func, 0UL); ... when != func = e7 -t->function = func; | -t->function = func; ... when != func = e7 -init_timer@p(t); +setup_timer(t, func, 0UL); ) Signed-off-by: Kees Cook <keescook@chromium.org>
209 lines
4.7 KiB
C
209 lines
4.7 KiB
C
/**
|
|
* A generic FSM based on fsm used in isdn4linux
|
|
*
|
|
*/
|
|
|
|
#include "fsm.h"
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/timer.h>
|
|
|
|
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
|
|
MODULE_DESCRIPTION("Finite state machine helper functions");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
fsm_instance *
|
|
init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
|
|
int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)
|
|
{
|
|
int i;
|
|
fsm_instance *this;
|
|
fsm_function_t *m;
|
|
fsm *f;
|
|
|
|
this = kzalloc(sizeof(fsm_instance), order);
|
|
if (this == NULL) {
|
|
printk(KERN_WARNING
|
|
"fsm(%s): init_fsm: Couldn't alloc instance\n", name);
|
|
return NULL;
|
|
}
|
|
strlcpy(this->name, name, sizeof(this->name));
|
|
init_waitqueue_head(&this->wait_q);
|
|
|
|
f = kzalloc(sizeof(fsm), order);
|
|
if (f == NULL) {
|
|
printk(KERN_WARNING
|
|
"fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
|
|
kfree_fsm(this);
|
|
return NULL;
|
|
}
|
|
f->nr_events = nr_events;
|
|
f->nr_states = nr_states;
|
|
f->event_names = event_names;
|
|
f->state_names = state_names;
|
|
this->f = f;
|
|
|
|
m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);
|
|
if (m == NULL) {
|
|
printk(KERN_WARNING
|
|
"fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
|
|
kfree_fsm(this);
|
|
return NULL;
|
|
}
|
|
f->jumpmatrix = m;
|
|
|
|
for (i = 0; i < tmpl_len; i++) {
|
|
if ((tmpl[i].cond_state >= nr_states) ||
|
|
(tmpl[i].cond_event >= nr_events) ) {
|
|
printk(KERN_ERR
|
|
"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
|
|
name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
|
|
(long)tmpl[i].cond_event, (long)f->nr_events);
|
|
kfree_fsm(this);
|
|
return NULL;
|
|
} else
|
|
m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
|
|
tmpl[i].function;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
void
|
|
kfree_fsm(fsm_instance *this)
|
|
{
|
|
if (this) {
|
|
if (this->f) {
|
|
kfree(this->f->jumpmatrix);
|
|
kfree(this->f);
|
|
}
|
|
kfree(this);
|
|
} else
|
|
printk(KERN_WARNING
|
|
"fsm: kfree_fsm called with NULL argument\n");
|
|
}
|
|
|
|
#if FSM_DEBUG_HISTORY
|
|
void
|
|
fsm_print_history(fsm_instance *fi)
|
|
{
|
|
int idx = 0;
|
|
int i;
|
|
|
|
if (fi->history_size >= FSM_HISTORY_SIZE)
|
|
idx = fi->history_index;
|
|
|
|
printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
|
|
for (i = 0; i < fi->history_size; i++) {
|
|
int e = fi->history[idx].event;
|
|
int s = fi->history[idx++].state;
|
|
idx %= FSM_HISTORY_SIZE;
|
|
if (e == -1)
|
|
printk(KERN_DEBUG " S=%s\n",
|
|
fi->f->state_names[s]);
|
|
else
|
|
printk(KERN_DEBUG " S=%s E=%s\n",
|
|
fi->f->state_names[s],
|
|
fi->f->event_names[e]);
|
|
}
|
|
fi->history_size = fi->history_index = 0;
|
|
}
|
|
|
|
void
|
|
fsm_record_history(fsm_instance *fi, int state, int event)
|
|
{
|
|
fi->history[fi->history_index].state = state;
|
|
fi->history[fi->history_index++].event = event;
|
|
fi->history_index %= FSM_HISTORY_SIZE;
|
|
if (fi->history_size < FSM_HISTORY_SIZE)
|
|
fi->history_size++;
|
|
}
|
|
#endif
|
|
|
|
const char *
|
|
fsm_getstate_str(fsm_instance *fi)
|
|
{
|
|
int st = atomic_read(&fi->state);
|
|
if (st >= fi->f->nr_states)
|
|
return "Invalid";
|
|
return fi->f->state_names[st];
|
|
}
|
|
|
|
static void
|
|
fsm_expire_timer(fsm_timer *this)
|
|
{
|
|
#if FSM_TIMER_DEBUG
|
|
printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
|
|
this->fi->name, this);
|
|
#endif
|
|
fsm_event(this->fi, this->expire_event, this->event_arg);
|
|
}
|
|
|
|
void
|
|
fsm_settimer(fsm_instance *fi, fsm_timer *this)
|
|
{
|
|
this->fi = fi;
|
|
#if FSM_TIMER_DEBUG
|
|
printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
|
|
this);
|
|
#endif
|
|
setup_timer(&this->tl, (void *)fsm_expire_timer, (long)this);
|
|
}
|
|
|
|
void
|
|
fsm_deltimer(fsm_timer *this)
|
|
{
|
|
#if FSM_TIMER_DEBUG
|
|
printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
|
|
this);
|
|
#endif
|
|
del_timer(&this->tl);
|
|
}
|
|
|
|
int
|
|
fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
|
|
{
|
|
|
|
#if FSM_TIMER_DEBUG
|
|
printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
|
|
this->fi->name, this, millisec);
|
|
#endif
|
|
|
|
setup_timer(&this->tl, (void *)fsm_expire_timer, (long)this);
|
|
this->expire_event = event;
|
|
this->event_arg = arg;
|
|
this->tl.expires = jiffies + (millisec * HZ) / 1000;
|
|
add_timer(&this->tl);
|
|
return 0;
|
|
}
|
|
|
|
/* FIXME: this function is never used, why */
|
|
void
|
|
fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
|
|
{
|
|
|
|
#if FSM_TIMER_DEBUG
|
|
printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
|
|
this->fi->name, this, millisec);
|
|
#endif
|
|
|
|
del_timer(&this->tl);
|
|
setup_timer(&this->tl, (void *)fsm_expire_timer, (long)this);
|
|
this->expire_event = event;
|
|
this->event_arg = arg;
|
|
this->tl.expires = jiffies + (millisec * HZ) / 1000;
|
|
add_timer(&this->tl);
|
|
}
|
|
|
|
EXPORT_SYMBOL(init_fsm);
|
|
EXPORT_SYMBOL(kfree_fsm);
|
|
EXPORT_SYMBOL(fsm_settimer);
|
|
EXPORT_SYMBOL(fsm_deltimer);
|
|
EXPORT_SYMBOL(fsm_addtimer);
|
|
EXPORT_SYMBOL(fsm_modtimer);
|
|
EXPORT_SYMBOL(fsm_getstate_str);
|
|
|
|
#if FSM_DEBUG_HISTORY
|
|
EXPORT_SYMBOL(fsm_print_history);
|
|
EXPORT_SYMBOL(fsm_record_history);
|
|
#endif
|