* [PATCH 0/4] typesafe callbacks
@ 2008-07-25 2:13 Rusty Russell
2008-07-25 2:14 ` [PATCH 1/4] typesafe: cast_if_type: allow macros functions which take more than one type Rusty Russell
0 siblings, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-07-25 2:13 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, Al Viro
It's possible to portably make callbacks typesafe, as well as taking the
existing void * arg. This makes the callers more readable and more typesafe.
Done in a way that doesn't break non-gcc: they just don't get a warning.
Been in linux-next for about two full cycles now, and I really want to start
using this in my own code.
Thanks,
Rusty.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] typesafe: cast_if_type: allow macros functions which take more than one type.
2008-07-25 2:13 [PATCH 0/4] typesafe callbacks Rusty Russell
@ 2008-07-25 2:14 ` Rusty Russell
2008-07-25 2:16 ` [PATCH 2/4] typesafe: typesafe_cb: wrappers for typesafe callbacks Rusty Russell
0 siblings, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-07-25 2:14 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, Al Viro, Harvey Harrison
To create functions which can take two types, but still warn on any
other types, we need a way of casting one type and no others.
To make things more complex, it should correctly handle function args,
NULL, and be usable in initializers. __builtin_choose_expr was
introduced in gcc 3.1 (kernel needs >= 3.2 anyway).
(includes Harvey Harrison <harvey.harrison@gmail.com>'s sparse fix)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Cc: Harvey Harrison <harvey.harrison@gmail.com>
---
include/linux/compiler-gcc.h | 18 ++++++++++++++++++
include/linux/compiler-intel.h | 2 ++
2 files changed, 20 insertions(+)
diff -r ecbc022961d8 include/linux/compiler-gcc.h
--- a/include/linux/compiler-gcc.h Mon Jul 14 12:30:35 2008 +1000
+++ b/include/linux/compiler-gcc.h Mon Jul 14 20:46:23 2008 +1000
@@ -61,3 +61,21 @@
#define noinline __attribute__((noinline))
#define __attribute_const__ __attribute__((__const__))
#define __maybe_unused __attribute__((unused))
+
+/**
+ * cast_if_type - allow an alternate type
+ * @expr: the expression to optionally cast
+ * @oktype: the type to allow.
+ * @desttype: the type to cast to.
+ *
+ * This is used to accept a particular alternate type for an expression:
+ * because any other types will not be cast, they will cause a warning as
+ * normal.
+ *
+ * Note that the unnecessary trinary forces functions to devolve into
+ * function pointers as users expect, but means @expr must be a pointer or
+ * integer.
+ */
+#define cast_if_type(expr, oktype, desttype) __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(1?(expr):(expr)), oktype), \
+ (desttype)(expr), (expr))
diff -r ecbc022961d8 include/linux/compiler-intel.h
--- a/include/linux/compiler-intel.h Mon Jul 14 12:30:35 2008 +1000
+++ b/include/linux/compiler-intel.h Mon Jul 14 20:46:23 2008 +1000
@@ -29,3 +29,5 @@
#endif
#define uninitialized_var(x) x
+
+#define cast_if_type(expr, oktype, desttype) ((desttype)(expr))
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] typesafe: typesafe_cb: wrappers for typesafe callbacks.
2008-07-25 2:14 ` [PATCH 1/4] typesafe: cast_if_type: allow macros functions which take more than one type Rusty Russell
@ 2008-07-25 2:16 ` Rusty Russell
2008-07-25 2:17 ` [PATCH 3/4] typesafe: kthread_create and kthread_run Rusty Russell
0 siblings, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-07-25 2:16 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, Al Viro, Harvey Harrison
cast_if_type is clever but annoying to use, so we make some slightly
less annoying wrappers for callback registration.
These allow const pointer-taking functions as well as the normal
non-const ones (volatile variant omitted for simplicity). We also
have a typesafe_cb_preargs() for callbacks which don't just take one
argument.
Here's an example of use:
BEFORE:
void foo_set_callback(int (*callback)(void *), void *arg);
AFTER:
#define foo_set_callback(cb, arg) \
__foo_set_callback(typesafe_cb(int, (cb), (arg)), (arg))
void __foo_set_callback(int (*callback)(void *), void *arg);
o If cb is of form "int cb(typeof(arg))" or "int cb(const typeof(arg))" it
will be cast to form "int cb(void *)".
o Otherwise, if cb is not already of form "int cb(void *)" it will cause a
warning when passed to __foo_set_callback().
o If arg is not a pointer, then handing it to __foo_set_callback() will cause
a warning.
Note: there are at least two possible additions we don't yet need. We
don't cover callbacks which take a volatile pointer, even though that
would be fine, and we don't have a typesafe_cb_postargs().
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
include/linux/kernel.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff -r 907c55be656f include/linux/kernel.h
--- a/include/linux/kernel.h Mon Apr 21 06:58:00 2008 +1000
+++ b/include/linux/kernel.h Mon Apr 21 07:04:02 2008 +1000
@@ -436,4 +436,39 @@ struct sysinfo {
#define NUMA_BUILD 0
#endif
+/* If fn is of type ok1 or ok2, cast to desttype */
+#define __typesafe_cb(desttype, fn, ok1, ok2) \
+ cast_if_type(cast_if_type((fn), ok1, desttype), ok2, desttype)
+
+/**
+ * typesafe_cb - cast a callback function if it matches the arg
+ * @rettype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does
+ * appropriate casts to a function which takes a single void * argument if the
+ * callback provided matches the @arg (or a const or volatile version).
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ */
+#define typesafe_cb(rettype, fn, arg) \
+ __typesafe_cb(rettype (*)(void *), (fn), \
+ rettype (*)(const typeof(arg)), \
+ rettype (*)(typeof(arg)))
+
+/**
+ * typesafe_cb_preargs - cast a callback function if it matches the arg
+ * @rettype: the return type of the callback function
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * before the @arg.
+ */
+#define typesafe_cb_preargs(rettype, fn, arg, ...) \
+ __typesafe_cb(rettype (*)(__VA_ARGS__, void *), (fn), \
+ rettype (*)(__VA_ARGS__, const typeof(arg)), \
+ rettype (*)(__VA_ARGS__, typeof(arg)))
#endif
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] typesafe: kthread_create and kthread_run
2008-07-25 2:16 ` [PATCH 2/4] typesafe: typesafe_cb: wrappers for typesafe callbacks Rusty Russell
@ 2008-07-25 2:17 ` Rusty Russell
2008-07-25 2:19 ` [PATCH 4/4] typesafe: TIMER_INITIALIZER and setup_timer Rusty Russell
0 siblings, 1 reply; 5+ messages in thread
From: Rusty Russell @ 2008-07-25 2:17 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, Al Viro, Harvey Harrison
(Assumes patch to add printf attr to kthread_create is applied, but fixup trivial)
Straight-forward conversion to allow typesafe callbacks.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
include/linux/kthread.h | 28 +++++++++++++++++++++++++---
kernel/kthread.c | 29 +++++------------------------
2 files changed, 30 insertions(+), 27 deletions(-)
diff -r f5a7f7f9683c include/linux/kthread.h
--- a/include/linux/kthread.h Mon Apr 07 18:36:20 2008 +1000
+++ b/include/linux/kthread.h Mon Apr 07 19:12:04 2008 +1000
@@ -4,9 +4,31 @@
#include <linux/err.h>
#include <linux/sched.h>
-struct task_struct *kthread_create(int (*threadfn)(void *data),
- void *data,
- const char namefmt[], ...)
+/**
+ * kthread_create - create a kthread.
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: This helper function creates and names a kernel
+ * thread. The thread will be stopped: use wake_up_process() to start
+ * it. See also kthread_run(), kthread_create_on_cpu().
+ *
+ * When woken, the thread will run @threadfn() with @data as its
+ * argument. @threadfn() can either call do_exit() directly if it is a
+ * standalone thread for which noone will call kthread_stop(), or
+ * return when 'kthread_should_stop()' is true (which means
+ * kthread_stop() has been called). The return value should be zero
+ * or a negative error number; it will be passed to kthread_stop().
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM).
+ */
+#define kthread_create(threadfn, data, namefmt...) \
+ __kthread_create(typesafe_cb(int,(threadfn),(data)), (data), namefmt)
+
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data,
+ const char namefmt[], ...)
__attribute__((format(printf, 3, 4)));
/**
diff -r f5a7f7f9683c kernel/kthread.c
--- a/kernel/kthread.c Mon Apr 07 18:36:20 2008 +1000
+++ b/kernel/kthread.c Mon Apr 07 19:12:04 2008 +1000
@@ -112,29 +112,10 @@ static void create_kthread(struct kthrea
complete(&create->done);
}
-/**
- * kthread_create - create a kthread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
- *
- * Description: This helper function creates and names a kernel
- * thread. The thread will be stopped: use wake_up_process() to start
- * it. See also kthread_run(), kthread_create_on_cpu().
- *
- * When woken, the thread will run @threadfn() with @data as its
- * argument. @threadfn() can either call do_exit() directly if it is a
- * standalone thread for which noone will call kthread_stop(), or
- * return when 'kthread_should_stop()' is true (which means
- * kthread_stop() has been called). The return value should be zero
- * or a negative error number; it will be passed to kthread_stop().
- *
- * Returns a task_struct or ERR_PTR(-ENOMEM).
- */
-struct task_struct *kthread_create(int (*threadfn)(void *data),
- void *data,
- const char namefmt[],
- ...)
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data,
+ const char namefmt[],
+ ...)
{
struct kthread_create_info create;
@@ -159,7 +140,7 @@ struct task_struct *kthread_create(int (
}
return create.result;
}
-EXPORT_SYMBOL(kthread_create);
+EXPORT_SYMBOL(__kthread_create);
/**
* kthread_bind - bind a just-created kthread to a cpu.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] typesafe: TIMER_INITIALIZER and setup_timer
2008-07-25 2:17 ` [PATCH 3/4] typesafe: kthread_create and kthread_run Rusty Russell
@ 2008-07-25 2:19 ` Rusty Russell
0 siblings, 0 replies; 5+ messages in thread
From: Rusty Russell @ 2008-07-25 2:19 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, Al Viro, Harvey Harrison
This patch lets timer callback functions have their natural type
(ie. exactly match the data pointer type); it allows the old "unsigned
long data" type as well.
Downside: if you use the old "unsigned long" callback type, you won't
get a warning if your data is not an unsigned long, due to the cast.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
include/linux/timer.h | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff -r 138795de70da include/linux/timer.h
--- a/include/linux/timer.h Thu May 01 21:03:51 2008 +1000
+++ b/include/linux/timer.h Thu May 01 21:05:13 2008 +1000
@@ -25,12 +25,22 @@ struct timer_list {
extern struct tvec_base boot_tvec_bases;
-#define TIMER_INITIALIZER(_function, _expires, _data) { \
- .entry = { .prev = TIMER_ENTRY_STATIC }, \
- .function = (_function), \
- .expires = (_expires), \
- .data = (_data), \
- .base = &boot_tvec_bases, \
+/*
+ * For historic reasons the timer function takes an unsigned long, so
+ * we use this variant of typesafe_cb. data is converted to an unsigned long
+ * if it is another integer type, by adding 0UL.
+ */
+#define typesafe_timerfn(fn, data) \
+ __typesafe_cb(void (*)(unsigned long), (fn), \
+ void (*)(const typeof((data)+0UL)), \
+ void (*)(typeof((data)+0UL)))
+
+#define TIMER_INITIALIZER(_function, _expires, _data) { \
+ .entry = { .prev = TIMER_ENTRY_STATIC }, \
+ .function = typesafe_timerfn((_function), (_data)), \
+ .expires = (_expires), \
+ .data = (unsigned long)(_data), \
+ .base = &boot_tvec_bases, \
}
#define DEFINE_TIMER(_name, _function, _expires, _data) \
@@ -51,9 +61,13 @@ static inline void init_timer_on_stack(s
}
#endif
-static inline void setup_timer(struct timer_list * timer,
- void (*function)(unsigned long),
- unsigned long data)
+#define setup_timer(timer, function, data) \
+ __setup_timer((timer), typesafe_timerfn((function), (data)), \
+ (unsigned long)(data))
+
+static inline void __setup_timer(struct timer_list *timer,
+ void (*function)(unsigned long),
+ unsigned long data)
{
timer->function = function;
timer->data = data;
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-07-25 2:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-25 2:13 [PATCH 0/4] typesafe callbacks Rusty Russell
2008-07-25 2:14 ` [PATCH 1/4] typesafe: cast_if_type: allow macros functions which take more than one type Rusty Russell
2008-07-25 2:16 ` [PATCH 2/4] typesafe: typesafe_cb: wrappers for typesafe callbacks Rusty Russell
2008-07-25 2:17 ` [PATCH 3/4] typesafe: kthread_create and kthread_run Rusty Russell
2008-07-25 2:19 ` [PATCH 4/4] typesafe: TIMER_INITIALIZER and setup_timer Rusty Russell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox