All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty@rustcorp.com.au>
To: Tejun Heo <htejun@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	linux-kernel@vger.kernel.org, Jeff Garzik <jeff@garzik.org>
Subject: Re: [PATCH 0/6] RFC: Typesafe callbacks
Date: Tue, 22 Jan 2008 10:27:14 +1100	[thread overview]
Message-ID: <200801221027.15002.rusty@rustcorp.com.au> (raw)
In-Reply-To: <47949257.1000102@gmail.com>

On Monday 21 January 2008 23:38:47 Tejun Heo wrote:
> Rusty Russell wrote:
> > On Monday 21 January 2008 09:17:30 Rusty Russell wrote:
> >> But it would be cool to allow functions which take an unsigned long.
> >> I'll test this out and see what I can make...
> >
> > I think this comes under "too ugly", but here's an attempt.
>
> Maybe we should be content with pointer type checking.  It seems like
> it's going too far and after all the clutter it's not possible to use
> int as argument.  :-(

It is possible, but the function has to take an unsigned long.

But I share your dislike of this.  Here's my final version, but it's still
ugly.

Rusty.

===
Attempt to create callbacks which take unsigned long as well as
correct pointer types.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 include/linux/compiler-gcc.h   |   61 +++++++++++++++++++++++++++++++++++++++++
 include/linux/compiler-intel.h |    3 ++
 include/linux/kernel.h         |   21 ++++++++++++++
 3 files changed, 85 insertions(+)

diff -r 951ffe1c5238 include/linux/compiler-gcc.h
--- a/include/linux/compiler-gcc.h	Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/compiler-gcc.h	Tue Jan 22 10:15:15 2008 +1100
@@ -53,3 +53,64 @@
 #define  noinline			__attribute__((noinline))
 #define __attribute_const__		__attribute__((__const__))
 #define __maybe_unused			__attribute__((unused))
+
+/* This is not complete: I can't figure out a way to handle enums. */
+#define ulong_compatible(arg)						\
+	(__builtin_types_compatible_p(typeof(arg), char)		\
+	 || __builtin_types_compatible_p(typeof(arg), unsigned char)	\
+	 || __builtin_types_compatible_p(typeof(arg), signed char)	\
+	 || __builtin_types_compatible_p(typeof(arg), unsigned short)	\
+	 || __builtin_types_compatible_p(typeof(arg), short)		\
+	 || __builtin_types_compatible_p(typeof(arg), unsigned int)	\
+	 || __builtin_types_compatible_p(typeof(arg), int)		\
+	 || __builtin_types_compatible_p(typeof(arg), unsigned long)	\
+	 || __builtin_types_compatible_p(typeof(arg), long))
+
+/**
+ * typesafe_fn_and_arg - cast function type and arg if compatible
+ * @fn: the function or function pointer
+ * @arg: the function argument.
+ * @ulongtype: the function pointer type if arg is an integer
+ * @safetype: the function pointer type which matches typeof(arg)
+ * @voidtype: the function pointer type which takes a void * (to cast to)
+ *
+ * This macro evaluates to two comma separated values: the function pointer,
+ * then the argument.
+ *
+ * Callback functions are usually declared to take a "void *arg"
+ * argument, which stops the compiler from doing type checking.  We
+ * can freely cast to function pointer which takes "void *" in two
+ * cases: a function which takes a different pointer type or an
+ * unsigned long.
+ *
+ * Typechecking is done by the caller when they assign or pass these
+ * values.  This macro handles the cases where @fn takes an unsigned
+ * long and @arg is compatible with that, and also the case where @fn
+ * and @arg match types.  For other cases, @fn is not cast, so using
+ * the results of this macro should cause a warning unless @fn is
+ * already of if type @voidtype.
+ *
+ * Logic looks like this:
+ * if (typeof(@arg) compatible with unsigned long) {
+ *     if (typeof(@fn) == @ulongtype)
+ *         (@voidtype)@fn and (void *)(unsigned long)@arg; // OK!
+ *     else
+ *         @fn and @arg; // @fn will warn unless it's of @voidtype already.
+ * } else if (typeof(@fn) == @safetype)
+ *     (@voidtype)@fn and @arg; // OK: @arg will warn unless it's a pointer.
+ * else
+ *     @fn and @arg; // @fn will warn unless it's of @voidtype already.
+ */
+#define typesafe_fn_and_arg(fn, arg, ulongtype, safetype, voidtype)	\
+__builtin_choose_expr((ulong_compatible(arg)				\
+		       && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+						       ulongtype))	\
+		      || (!ulong_compatible(arg)			\
+			  && __builtin_types_compatible_p(typeof(1?(fn):NULL), \
+							  safetype)),	\
+		      ((voidtype)(fn)),					\
+		      (fn)),						\
+__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(fn):NULL), \
+						   ulongtype),		\
+		      ((void *)(long)(arg)), (arg))
+
diff -r 951ffe1c5238 include/linux/compiler-intel.h
--- a/include/linux/compiler-intel.h	Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/compiler-intel.h	Tue Jan 22 10:15:15 2008 +1100
@@ -29,3 +29,6 @@
 #endif
 
 #define uninitialized_var(x) x
+
+#define typesafe_fn_and_arg(fn, arg, ulongtype, safetype, fntype) \
+	((fntype)(fn)), ((void *)arg)
diff -r 951ffe1c5238 include/linux/kernel.h
--- a/include/linux/kernel.h	Tue Jan 22 09:31:56 2008 +1100
+++ b/include/linux/kernel.h	Tue Jan 22 10:15:15 2008 +1100
@@ -379,6 +379,27 @@ static inline int __attribute__ ((format
 	(void)__tmp; \
 })
 
+/**
+ * callback_and_arg - simple one-argument typesafe callback with argument
+ * @fn: the function or function pointer
+ * @arg: the function argument.
+ * @rettype: the return type of fn
+ *
+ * This macro evaluates to two comma separated values: the function pointer,
+ * then the argument.  It will check that @fn and @arg are compatible with
+ * each other and with a void * callback.  One of
+ * - fn takes a void * and arg is a pointer
+ * - fn takes a typeof(arg) and arg is a pointer
+ * - fn takes an unsigned long and arg is an integer type.
+ *
+ * See typesafe_fn_and_arg() for the gory details.
+ */
+#define callback_and_arg(fn, arg, rettype)		\
+	typesafe_fn_and_arg((fn), (arg),		\
+			    rettype (*)(unsigned long),	\
+			    rettype (*)(typeof(arg)),	\
+			    rettype (*)(void *))
+
 struct sysinfo;
 extern int do_sysinfo(struct sysinfo *info);
 

  reply	other threads:[~2008-01-21 23:28 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-01-20  9:46 [PATCH 0/6] RFC: Typesafe callbacks Rusty Russell
2008-01-20  9:47 ` [PATCH 1/6] typesafe: Convert stop_machine and callers Rusty Russell
2008-01-20  9:48   ` [PATCH 2/6] typesafe: kthread_create and kthread_run Rusty Russell
2008-01-20  9:50     ` [PATCH 3/6] typesafe: convert kthread users Rusty Russell
2008-01-20  9:51       ` [PATCH 4/6] typesafe: cast_if_type to allow macros functions which take more than one type Rusty Russell
2008-01-20  9:54         ` [PATCH 5/6] typesafe: request_irq and devm_request_irq Rusty Russell
2008-01-20  9:57           ` [PATCH 6/6] typesafe: timers Rusty Russell
2008-01-20 11:25     ` [PATCH 2/6] typesafe: kthread_create and kthread_run Jan Engelhardt
2008-01-20 12:07       ` Bert Wesarg
2008-01-20 16:24         ` Johannes Weiner
2008-01-20 16:43           ` Bert Wesarg
2008-01-20 22:04             ` Rusty Russell
2008-01-21  7:56               ` Bert Wesarg
2008-01-20 12:56 ` [PATCH 0/6] RFC: Typesafe callbacks Tejun Heo
2008-01-20 13:00   ` Tejun Heo
2008-01-20 22:17     ` Rusty Russell
2008-01-21 11:33       ` Rusty Russell
2008-01-21 12:38         ` Tejun Heo
2008-01-21 23:27           ` Rusty Russell [this message]
2008-01-21 23:57             ` Linus Torvalds
2008-01-22  7:16               ` Rusty Russell
2008-01-22 15:53                 ` Linus Torvalds
2008-01-22  4:20             ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200801221027.15002.rusty@rustcorp.com.au \
    --to=rusty@rustcorp.com.au \
    --cc=akpm@linux-foundation.org \
    --cc=htejun@gmail.com \
    --cc=jeff@garzik.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.