All of lore.kernel.org
 help / color / mirror / Atom feed
* Casting away noderef and address spaces?
@ 2008-12-22  5:36 Rusty Russell
  2008-12-22 20:06 ` Christopher Li
  0 siblings, 1 reply; 18+ messages in thread
From: Rusty Russell @ 2008-12-22  5:36 UTC (permalink / raw)
  To: linux-sparse

Hi all,

  I need to use typeof(), but I want to change address spaces.  I can't see
how to do that: AFAICT it's not possible.  This doesn't work:

#define __percpu __attribute__((noderef, address_space(3)))

/* Turn v back into a normal var. */
#define convert(v) \
	(*(__attribute__((address_space(0), force)) typeof(&v))(v))

int main(int argc, char *argv)
{
	unsigned int __percpu x;

	convert(x) = 0;
	return 0;
}

Thanks,
Rusty.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22  5:36 Casting away noderef and address spaces? Rusty Russell
@ 2008-12-22 20:06 ` Christopher Li
  2008-12-22 20:57   ` Al Viro
  0 siblings, 1 reply; 18+ messages in thread
From: Christopher Li @ 2008-12-22 20:06 UTC (permalink / raw)
  To: Rusty Russell; +Cc: linux-sparse

On Sun, Dec 21, 2008 at 9:36 PM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> #define convert(v) \
>        (*(__attribute__((address_space(0), force)) typeof(&v))(v))
>
Am I reading it right? You are trying to dereferenc a type instead of a pointer?

I don't think you can do that with sparse.

Are you trying to declare the per_cpu as the third address space
and force every usage of the per_cpu variable going through the conversion?

Chris

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 20:06 ` Christopher Li
@ 2008-12-22 20:57   ` Al Viro
  2008-12-22 21:23     ` Christopher Li
  2008-12-23  2:14     ` Rusty Russell
  0 siblings, 2 replies; 18+ messages in thread
From: Al Viro @ 2008-12-22 20:57 UTC (permalink / raw)
  To: Christopher Li; +Cc: Rusty Russell, linux-sparse

On Mon, Dec 22, 2008 at 12:06:03PM -0800, Christopher Li wrote:
> On Sun, Dec 21, 2008 at 9:36 PM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> > #define convert(v) \
> >        (*(__attribute__((address_space(0), force)) typeof(&v))(v))
> >
> Am I reading it right? You are trying to dereferenc a type instead of a pointer?
> 
> I don't think you can do that with sparse.

The right solution is
	(*(typeof(v) __attribute__((address_space(0), force)) *)(&v))

Cast there will take a pointer to type of V and force-cast it to pointer to
unqualified type of V.  *(cast)&v will do the obvious thing.  Will trim
both the AS and noderef.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 20:57   ` Al Viro
@ 2008-12-22 21:23     ` Christopher Li
  2008-12-22 21:39       ` Al Viro
  2008-12-23  2:14     ` Rusty Russell
  1 sibling, 1 reply; 18+ messages in thread
From: Christopher Li @ 2008-12-22 21:23 UTC (permalink / raw)
  To: Al Viro; +Cc: Rusty Russell, linux-sparse

On Mon, Dec 22, 2008 at 12:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> The right solution is
>        (*(typeof(v) __attribute__((address_space(0), force)) *)(&v))
>
> Cast there will take a pointer to type of V and force-cast it to pointer to
> unqualified type of V.  *(cast)&v will do the obvious thing.  Will trim
> both the AS and noderef.

Thanks, that is much better. However sparse don't know how to handle it yet.

/tmp/typeof.c:11:64: warning: incorrect type in assignment (invalid types)
/tmp/typeof.c:11:64:    expected unknown type 11 <noident>
/tmp/typeof.c:11:64:    got int

classify_type does not know how to handle SYM_TYPEOF yet.
Let me see if I can make it to work.

Chris

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 21:23     ` Christopher Li
@ 2008-12-22 21:39       ` Al Viro
  2008-12-22 22:33         ` Christopher Li
  0 siblings, 1 reply; 18+ messages in thread
From: Al Viro @ 2008-12-22 21:39 UTC (permalink / raw)
  To: Christopher Li; +Cc: Rusty Russell, linux-sparse

On Mon, Dec 22, 2008 at 01:23:47PM -0800, Christopher Li wrote:
> On Mon, Dec 22, 2008 at 12:57 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> > The right solution is
> >        (*(typeof(v) __attribute__((address_space(0), force)) *)(&v))
> >
> > Cast there will take a pointer to type of V and force-cast it to pointer to
> > unqualified type of V.  *(cast)&v will do the obvious thing.  Will trim
> > both the AS and noderef.
> 
> Thanks, that is much better. However sparse don't know how to handle it yet.
> 
> /tmp/typeof.c:11:64: warning: incorrect type in assignment (invalid types)
> /tmp/typeof.c:11:64:    expected unknown type 11 <noident>
> /tmp/typeof.c:11:64:    got int
> 
> classify_type does not know how to handle SYM_TYPEOF yet.
> Let me see if I can make it to work.

Works here (built from 8f208e215a531d2b32aec0428fd5eaa24ae3100b)...

But yes, SYM_TYPEOF is a brittle mess, so whether that works or not
is, er, version-dependent ;-/

I really ought to resurrect lazy-type-expressions branch...

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 21:39       ` Al Viro
@ 2008-12-22 22:33         ` Christopher Li
  2008-12-22 22:42           ` Harvey Harrison
  2008-12-22 22:57           ` Sam Ravnborg
  0 siblings, 2 replies; 18+ messages in thread
From: Christopher Li @ 2008-12-22 22:33 UTC (permalink / raw)
  To: Al Viro; +Cc: Rusty Russell, linux-sparse

On Mon, Dec 22, 2008 at 1:39 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> Works here (built from 8f208e215a531d2b32aec0428fd5eaa24ae3100b)...
>
> But yes, SYM_TYPEOF is a brittle mess, so whether that works or not
> is, er, version-dependent ;-/

Very strange. That is exactly what I have in my clean sparse git tree.
I just clone it a few minutes ago. It give me errors on your example.

On my clean tree, I need the attached patch to get it to work.

>
> I really ought to resurrect lazy-type-expressions branch...
>

Are you sure you don't have some of those bits left over on your
git tree? If you submit your lazy-type-expressions patch, I can help to
review it.

BTW, I am normally lazy enough that I am happy about just submitting
patches. On the other hand, I am tried of these sparse patches floating
around the mailing list. I can start a branch to merge the proper patches.
Maybe some thing like a development branch for sparse.
Is that some thing other people want?

Chris

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 22:33         ` Christopher Li
@ 2008-12-22 22:42           ` Harvey Harrison
  2008-12-22 22:57           ` Sam Ravnborg
  1 sibling, 0 replies; 18+ messages in thread
From: Harvey Harrison @ 2008-12-22 22:42 UTC (permalink / raw)
  To: Christopher Li; +Cc: Al Viro, Rusty Russell, linux-sparse

On Mon, 2008-12-22 at 14:33 -0800, Christopher Li wrote:
> BTW, I am normally lazy enough that I am happy about just submitting
> patches. On the other hand, I am tried of these sparse patches floating
> around the mailing list. I can start a branch to merge the proper patches.
> Maybe some thing like a development branch for sparse.
> Is that some thing other people want?
> 

I'd use/test such a branch rather than scraping the mailing list for
useful bits.

Harvey


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 22:33         ` Christopher Li
  2008-12-22 22:42           ` Harvey Harrison
@ 2008-12-22 22:57           ` Sam Ravnborg
  2008-12-22 23:53             ` Alexey Zaytsev
  1 sibling, 1 reply; 18+ messages in thread
From: Sam Ravnborg @ 2008-12-22 22:57 UTC (permalink / raw)
  To: Christopher Li; +Cc: Al Viro, Rusty Russell, linux-sparse

> 
> BTW, I am normally lazy enough that I am happy about just submitting
> patches. On the other hand, I am tried of these sparse patches floating
> around the mailing list. I can start a branch to merge the proper patches.
> Maybe some thing like a development branch for sparse.
> Is that some thing other people want?

Please do so. We need some progress on sparse and current maintainer
seems to be occupied by other things at the moment.

	Sam

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 22:57           ` Sam Ravnborg
@ 2008-12-22 23:53             ` Alexey Zaytsev
  2008-12-22 23:55               ` Johannes Berg
  0 siblings, 1 reply; 18+ messages in thread
From: Alexey Zaytsev @ 2008-12-22 23:53 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Christopher Li, Al Viro, Rusty Russell, linux-sparse,
	Johannes Berg, Josh Triplett

On Tue, Dec 23, 2008 at 01:57, Sam Ravnborg <sam@ravnborg.org> wrote:
>>
>> BTW, I am normally lazy enough that I am happy about just submitting
>> patches. On the other hand, I am tried of these sparse patches floating
>> around the mailing list. I can start a branch to merge the proper patches.
>> Maybe some thing like a development branch for sparse.
>> Is that some thing other people want?
>
> Please do so. We need some progress on sparse and current maintainer
> seems to be occupied by other things at the moment.
>
>        Sam

Hello.

How about?
http://git.zaytsev.su/git?p=sparse.git;a=shortlog;h=discuss

This branch holds the two patch collections* I recently sent to the
mailing list. I
think it includes every useful patch that does not break the kernel check, and
even some that do. ;)
The last time we spoke (yesterday) Josh was going to merge the patches really
soon. The idea was to merge everything except the context patches, make a
release, add the context patches, and wait for someone to fix them.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 23:53             ` Alexey Zaytsev
@ 2008-12-22 23:55               ` Johannes Berg
  2008-12-23  0:20                 ` Alexey Zaytsev
  0 siblings, 1 reply; 18+ messages in thread
From: Johannes Berg @ 2008-12-22 23:55 UTC (permalink / raw)
  To: Alexey Zaytsev
  Cc: Sam Ravnborg, Christopher Li, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

[-- Attachment #1: Type: text/plain, Size: 384 bytes --]

On Tue, 2008-12-23 at 02:53 +0300, Alexey Zaytsev wrote:

> The last time we spoke (yesterday) Josh was going to merge the patches really
> soon. The idea was to merge everything except the context patches, make a
> release, add the context patches, and wait for someone to fix them.

Make sure to revert those that are in the tree now though, before the
release.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 23:55               ` Johannes Berg
@ 2008-12-23  0:20                 ` Alexey Zaytsev
  2008-12-23  0:35                   ` Johannes Berg
  2008-12-23  0:37                   ` Johannes Berg
  0 siblings, 2 replies; 18+ messages in thread
From: Alexey Zaytsev @ 2008-12-23  0:20 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Sam Ravnborg, Christopher Li, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

On Tue, Dec 23, 2008 at 02:55, Johannes Berg <johannes@sipsolutions.net> wrote:
> On Tue, 2008-12-23 at 02:53 +0300, Alexey Zaytsev wrote:
>
>> The last time we spoke (yesterday) Josh was going to merge the patches really
>> soon. The idea was to merge everything except the context patches, make a
>> release, add the context patches, and wait for someone to fix them.
>
> Make sure to revert those that are in the tree now though, before the
> release.
>

By the way, are you sure the latest series you have sent is correct? To me it
seems that it does not make any warnings go away, and adds quite some more:
http://zaytsev.su/tmp/build.diff.txt

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  0:20                 ` Alexey Zaytsev
@ 2008-12-23  0:35                   ` Johannes Berg
  2008-12-23  0:37                   ` Johannes Berg
  1 sibling, 0 replies; 18+ messages in thread
From: Johannes Berg @ 2008-12-23  0:35 UTC (permalink / raw)
  To: Alexey Zaytsev
  Cc: Sam Ravnborg, Christopher Li, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

[-- Attachment #1: Type: text/plain, Size: 467 bytes --]

On Tue, 2008-12-23 at 03:20 +0300, Alexey Zaytsev wrote:

> By the way, are you sure the latest series you have sent is correct? To me it
> seems that it does not make any warnings go away, and adds quite some more:
> http://zaytsev.su/tmp/build.diff.txt

Yes, because the context name wasn't previously used it messes up in
places with that patch set... This was discussed a few times previously,
you should be able to find it on list archives.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  0:20                 ` Alexey Zaytsev
  2008-12-23  0:35                   ` Johannes Berg
@ 2008-12-23  0:37                   ` Johannes Berg
  2008-12-23  1:25                     ` Christopher Li
  1 sibling, 1 reply; 18+ messages in thread
From: Johannes Berg @ 2008-12-23  0:37 UTC (permalink / raw)
  To: Alexey Zaytsev
  Cc: Sam Ravnborg, Christopher Li, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

[-- Attachment #1: Type: text/plain, Size: 468 bytes --]

On Tue, 2008-12-23 at 03:20 +0300, Alexey Zaytsev wrote:

> By the way, are you sure the latest series you have sent is correct? To me it
> seems that it does not make any warnings go away, and adds quite some more:
> http://zaytsev.su/tmp/build.diff.txt

include/net/sch_generic.h:225:2: warning: label 'continue' already bound

This, of course, shouldn't happen. I thought I'd fixed it, but who
knows. I think it should all just be reverted :)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  0:37                   ` Johannes Berg
@ 2008-12-23  1:25                     ` Christopher Li
  2008-12-23  9:59                       ` Johannes Berg
  0 siblings, 1 reply; 18+ messages in thread
From: Christopher Li @ 2008-12-23  1:25 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Alexey Zaytsev, Sam Ravnborg, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

On Mon, Dec 22, 2008 at 4:37 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2008-12-23 at 03:20 +0300, Alexey Zaytsev wrote:
>
>> By the way, are you sure the latest series you have sent is correct? To me it
>> seems that it does not make any warnings go away, and adds quite some more:
>> http://zaytsev.su/tmp/build.diff.txt
>
> include/net/sch_generic.h:225:2: warning: label 'continue' already bound
>
> This, of course, shouldn't happen. I thought I'd fixed it, but who
> knows. I think it should all just be reverted :)

Hi,

Do you want to resend your change which revert the context changes?
Make it base on Josh's git's tree and I will merge your changes in my
branch.

It will take me a while to get up to speed with the git goodness.
I will start with merging Alexey's resend patches.

Chris

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-22 20:57   ` Al Viro
  2008-12-22 21:23     ` Christopher Li
@ 2008-12-23  2:14     ` Rusty Russell
  2008-12-23  3:02       ` Christopher Li
  1 sibling, 1 reply; 18+ messages in thread
From: Rusty Russell @ 2008-12-23  2:14 UTC (permalink / raw)
  To: Al Viro; +Cc: Christopher Li, linux-sparse

On Tuesday 23 December 2008 07:27:50 Al Viro wrote:
> The right solution is
> 	(*(typeof(v) __attribute__((address_space(0), force)) *)(&v))
> 
> Cast there will take a pointer to type of V and force-cast it to pointer to
> unqualified type of V.  *(cast)&v will do the obvious thing.  Will trim
> both the AS and noderef.

Thanks Al, that worked, but seems to tickle another bug (sparse 0.4.1, Ubuntu).

rusty@vivaldi:/tmp$ sparse foo.c
foo.c:11:20: warning: incorrect type in assignment (invalid types)
foo.c:11:20:    expected unknown type 11<noident>
foo.c:11:20:    got int

Here's my sample program now:

#define __percpu __attribute__((noderef, address_space(3)))

/* Turn v back into a normal var. */
#define convert(v) \
        (*(typeof(v) __attribute__((address_space(0), force)) *)(&v))

int main(int argc, char *argv)
{
        unsigned int __percpu x;

        convert(x) = 0;
        return 0;
}


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  2:14     ` Rusty Russell
@ 2008-12-23  3:02       ` Christopher Li
  0 siblings, 0 replies; 18+ messages in thread
From: Christopher Li @ 2008-12-23  3:02 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Al Viro, linux-sparse

[-- Attachment #1: Type: text/plain, Size: 388 bytes --]

On Mon, Dec 22, 2008 at 6:14 PM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> rusty@vivaldi:/tmp$ sparse foo.c
> foo.c:11:20: warning: incorrect type in assignment (invalid types)
> foo.c:11:20:    expected unknown type 11<noident>
> foo.c:11:20:    got int
>

I think you need this patch for sparse. The version of sparse you
have does not handle typeof based type compare yet.

Chris

[-- Attachment #2: evaluate-typeof --]
[-- Type: application/octet-stream, Size: 594 bytes --]

Teach classify_type to handle typeof

Signed-Off-By: Christopher Li <sparse@chrisli.org>

Index: sparse/evaluate.c
===================================================================
--- sparse.orig/evaluate.c
+++ sparse/evaluate.c
@@ -362,6 +362,11 @@ static inline int classify_type(struct s
 	};
 	if (type->type == SYM_NODE)
 		type = type->ctype.base_type;
+	if (type->type == SYM_TYPEOF) {
+		type = evaluate_expression(type->initializer);
+		if (type->type == SYM_NODE)
+			type = type->ctype.base_type;
+	}
 	if (type->type == SYM_ENUM)
 		type = type->ctype.base_type;
 	*base = type;

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  1:25                     ` Christopher Li
@ 2008-12-23  9:59                       ` Johannes Berg
  2008-12-24  8:34                         ` Christopher Li
  0 siblings, 1 reply; 18+ messages in thread
From: Johannes Berg @ 2008-12-23  9:59 UTC (permalink / raw)
  To: Christopher Li
  Cc: Alexey Zaytsev, Sam Ravnborg, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

On Mon, 2008-12-22 at 17:25 -0800, Christopher Li wrote:

> Do you want to resend your change which revert the context changes?
> Make it base on Josh's git's tree and I will merge your changes in my
> branch.

Below. Or I can give it to you in git if you prefer. I still think we
should redo this in some form so that annotations with different
contexts can work properly, but I don't have time to take care of it
right now.

> It will take me a while to get up to speed with the git goodness.
> I will start with merging Alexey's resend patches.

Mind you, he sent a few of my patches, so ignore those.

johannes

From ca95b62edf1600a2b55ed9ca0515d049807a84fc Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes@sipsolutions.net>
Date: Tue, 23 Dec 2008 10:53:19 +0100
Subject: [PATCH] Revert context tracking code

---
 inline.c                       |   12 +-
 linearize.c                    |   31 ++-
 linearize.h                    |    7 +-
 parse.c                        |  134 +---------
 parse.h                        |    3 +-
 sparse.1                       |   41 +---
 sparse.c                       |  424 ++++---------------------------
 symbol.h                       |    3 +-
 validation/context-dynamic.c   |  171 -------------
 validation/context-named.c     |  553 ----------------------------------------
 validation/context-statement.c |   69 -----
 validation/context.c           |  114 +-------
 12 files changed, 107 insertions(+), 1455 deletions(-)
 delete mode 100644 validation/context-dynamic.c
 delete mode 100644 validation/context-named.c
 delete mode 100644 validation/context-statement.c

diff --git a/inline.c b/inline.c
index 09d176a..860c0ee 100644
--- a/inline.c
+++ b/inline.c
@@ -331,18 +331,10 @@ static struct statement *copy_one_statement(struct statement *stmt)
 	case STMT_CONTEXT:
 	case STMT_EXPRESSION: {
 		struct expression *expr = copy_expression(stmt->expression);
-		struct statement *newstmt;
 		if (expr == stmt->expression)
 			break;
-		newstmt = dup_statement(stmt);
-		newstmt->expression = expr;
-		if (stmt->required) {
-			expr = copy_expression(stmt->required);
-			if (expr == stmt->required)
-				break;
-			newstmt->required = expr;
-		}
-		stmt = newstmt;
+		stmt = dup_statement(stmt);
+		stmt->expression = expr;
 		break;
 	}
 	case STMT_RANGE: {
diff --git a/linearize.c b/linearize.c
index 526a710..1a19214 100644
--- a/linearize.c
+++ b/linearize.c
@@ -68,6 +68,7 @@ static struct entrypoint *alloc_entrypoint(void)
 static struct basic_block *alloc_basic_block(struct entrypoint *ep, struct position pos)
 {
 	struct basic_block *bb = __alloc_basic_block(0);
+	bb->context = -1;
 	bb->pos = pos;
 	bb->ep = ep;
 	return bb;
@@ -440,7 +441,7 @@ const char *show_instruction(struct instruction *insn)
 		break;
 
 	case OP_CONTEXT:
-		buf += sprintf(buf, "%s%d,%d", "", insn->increment, insn->inc_false);
+		buf += sprintf(buf, "%s%d", insn->check ? "check: " : "", insn->increment);
 		break;
 	case OP_RANGE:
 		buf += sprintf(buf, "%s between %s..%s", show_pseudo(insn->src1), show_pseudo(insn->src2), show_pseudo(insn->src3));
@@ -1234,12 +1235,22 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi
 		FOR_EACH_PTR(ctype->contexts, context) {
 			int in = context->in;
 			int out = context->out;
-
-			if (out - in || context->out_false - in) {
+			int check = 0;
+			int context_diff;
+			if (in < 0) {
+				check = 1;
+				in = 0;
+			}
+			if (out < 0) {
+				check = 0;
+				out = 0;
+			}
+			context_diff = out - in;
+			if (check || context_diff) {
 				insn = alloc_instruction(OP_CONTEXT, 0);
-				insn->increment = out - in;
+				insn->increment = context_diff;
+				insn->check = check;
 				insn->context_expr = context->context;
-				insn->inc_false = context->out_false - in;
 				add_one_insn(ep, insn);
 			}
 		} END_FOR_EACH_PTR(context);
@@ -1674,16 +1685,6 @@ static pseudo_t linearize_context(struct entrypoint *ep, struct statement *stmt)
 		value = expr->value;
 
 	insn->increment = value;
-	insn->inc_false = value;
-
-	expr = stmt->required;
-	value = 0;
-
-	if (expr && expr->type == EXPR_VALUE)
-		value = expr->value;
-
-	insn->required = value;
-
 	insn->context_expr = stmt->context;
 	add_one_insn(ep, insn);
 	return VOID;
diff --git a/linearize.h b/linearize.h
index 0c5e4ef..2205082 100644
--- a/linearize.h
+++ b/linearize.h
@@ -117,7 +117,8 @@ struct instruction {
 			struct pseudo_list *arguments;
 		};
 		struct /* context */ {
-			int increment, required, inc_false;
+			int increment;
+			int check;
 			struct expression *context_expr;
 		};
 		struct /* asm */ {
@@ -220,13 +221,11 @@ enum opcode {
 
 struct basic_block_list;
 struct instruction_list;
-struct context_list_list;
 
 struct basic_block {
 	struct position pos;
 	unsigned long generation;
-	int context_check_recursion;
-	struct context_list_list *checked_contexts;
+	int context;
 	struct entrypoint *ep;
 	struct basic_block_list *parents; /* sources */
 	struct basic_block_list *children; /* destinations */
diff --git a/parse.c b/parse.c
index eb31871..a78012a 100644
--- a/parse.c
+++ b/parse.c
@@ -64,8 +64,6 @@ static struct token *attribute_address_space(struct token *token, struct symbol
 static struct token *attribute_aligned(struct token *token, struct symbol *attr, struct ctype *ctype);
 static struct token *attribute_mode(struct token *token, struct symbol *attr, struct ctype *ctype);
 static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype);
-static struct token *attribute_conditional_context(struct token *token, struct symbol *attr, struct ctype *ctype);
-static struct token *attribute_exact_context(struct token *token, struct symbol *attr, struct ctype *ctype);
 static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype);
 static struct token *ignore_attribute(struct token *token, struct symbol *attr, struct ctype *ctype);
 
@@ -184,14 +182,6 @@ static struct symbol_op context_op = {
 	.attribute = attribute_context,
 };
 
-static struct symbol_op conditional_context_op = {
-	.attribute = attribute_conditional_context,
-};
-
-static struct symbol_op exact_context_op = {
-	.attribute = attribute_exact_context,
-};
-
 static struct symbol_op transparent_union_op = {
 	.attribute = attribute_transparent_union,
 };
@@ -273,8 +263,6 @@ static struct init_keyword {
 	{ "address_space",NS_KEYWORD,	.op = &address_space_op },
 	{ "mode",	NS_KEYWORD,	.op = &mode_op },
 	{ "context",	NS_KEYWORD,	.op = &context_op },
-	{ "conditional_context",	NS_KEYWORD,	.op = &conditional_context_op },
-	{ "exact_context",	NS_KEYWORD,	.op = &exact_context_op },
 	{ "__transparent_union__",	NS_KEYWORD,	.op = &transparent_union_op },
 
 	{ "__mode__",	NS_KEYWORD,	.op = &mode_op },
@@ -875,7 +863,7 @@ static struct token *attribute_mode(struct token *token, struct symbol *attr, st
 	return token;
 }
 
-static struct token *_attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype, int exact)
+static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype)
 {
 	struct context *context = alloc_context();
 	struct expression *args[3];
@@ -889,8 +877,6 @@ static struct token *_attribute_context(struct token *token, struct symbol *attr
 			break;
 		if (argc < 3)
 			args[argc++] = expr;
-		else
-			argc++;
 		if (!match_op(token, ','))
 			break;
 		token = token->next;
@@ -912,14 +898,8 @@ static struct token *_attribute_context(struct token *token, struct symbol *attr
 		context->in = get_expression_value(args[1]);
 		context->out = get_expression_value(args[2]);
 		break;
-	default:
-		sparse_error(token->pos, "too many arguments to context attribute");
-		break;
 	}
 
-	context->exact = exact;
-	context->out_false = context->out;
-
 	if (argc)
 		add_ptr_list(&ctype->contexts, context);
 
@@ -927,61 +907,6 @@ static struct token *_attribute_context(struct token *token, struct symbol *attr
 	return token;
 }
 
-static struct token *attribute_context(struct token *token, struct symbol *attr, struct ctype *ctype)
-{
-	return _attribute_context(token, attr, ctype, 0);
-}
-
-static struct token *attribute_exact_context(struct token *token, struct symbol *attr, struct ctype *ctype)
-{
-	return _attribute_context(token, attr, ctype, 1);
-}
-
-static struct token *attribute_conditional_context(struct token *token, struct symbol *attr, struct ctype *ctype)
-{
-	struct context *context = alloc_context();
-	struct expression *args[4];
-	int argc = 0;
-
-	token = expect(token, '(', "after conditional_context attribute");
-	while (!match_op(token, ')')) {
-		struct expression *expr = NULL;
-		token = conditional_expression(token, &expr);
-		if (!expr)
-			break;
-		if (argc < 4)
-			args[argc++] = expr;
-		else
-			argc++;
-		if (!match_op(token, ','))
-			break;
-		token = token->next;
-	}
-
-	switch(argc) {
-	case 3:
-		context->in = get_expression_value(args[0]);
-		context->out = get_expression_value(args[1]);
-		context->out_false = get_expression_value(args[2]);
-		break;
-	case 4:
-		context->context = args[0];
-		context->in = get_expression_value(args[1]);
-		context->out = get_expression_value(args[2]);
-		context->out_false = get_expression_value(args[3]);
-		break;
-	default:
-		sparse_error(token->pos, "invalid number of arguments to conditional_context attribute");
-		break;
-	}
-
-	if (argc)
-		add_ptr_list(&ctype->contexts, context);
-
-	token = expect(token, ')', "after conditional_context attribute");
-	return token;
-}
-
 static struct token *attribute_transparent_union(struct token *token, struct symbol *attr, struct ctype *ctype)
 {
 	if (Wtransparent_union)
@@ -1813,56 +1738,17 @@ static struct token *parse_goto_statement(struct token *token, struct statement
 
 static struct token *parse_context_statement(struct token *token, struct statement *stmt)
 {
-	struct expression *args[3];
-	int argc = 0;
-
 	stmt->type = STMT_CONTEXT;
-	token = token->next;
-	token = expect(token, '(', "after __context__ statement");
-	while (!match_op(token, ')')) {
-		struct expression *expr = NULL;
-		token = conditional_expression(token, &expr);
-		if (!expr)
-			break;
-		if (argc < 3)
-			args[argc++] = expr;
-		else
-			argc++;
-		if (!match_op(token, ','))
-			break;
-		token = token->next;
-	}
-
-	stmt->expression = args[0];
-	stmt->context = NULL;
-
-	switch (argc) {
-	case 0:
-		sparse_error(token->pos, "__context__ statement needs argument(s)");
-		return token;
-	case 1:
-		/* already done */
-		break;
-	case 2:
-		if (args[0]->type != STMT_EXPRESSION) {
-			stmt->context = args[0];
-			stmt->expression = args[1];
-		} else {
-			stmt->expression = args[0];
-			stmt->required = args[1];
-		}
-		break;
-	case 3:
-		stmt->context = args[0];
-		stmt->expression = args[1];
-		stmt->required = args[2];
-		break;
-	default:
-		sparse_error(token->pos, "too many arguments for __context__ statement");
-		return token->next;
+	token = parse_expression(token->next, &stmt->expression);
+	if(stmt->expression->type == EXPR_PREOP
+	   && stmt->expression->op == '('
+	   && stmt->expression->unop->type == EXPR_COMMA) {
+		struct expression *expr;
+		expr = stmt->expression->unop;
+		stmt->context = expr->left;
+		stmt->expression = expr->right;
 	}
-
-	return expect(token, ')', "at end of __context__");
+	return expect(token, ';', "at end of statement");
 }
 
 static struct token *parse_range_statement(struct token *token, struct statement *stmt)
diff --git a/parse.h b/parse.h
index a2b9aa3..609910f 100644
--- a/parse.h
+++ b/parse.h
@@ -39,10 +39,9 @@ struct statement {
 			struct symbol *label;
 			struct statement *label_statement;
 		};
-		struct { /* __context__ */
+		struct {
 			struct expression *expression;
 			struct expression *context;
-			struct expression *required;
 		};
 		struct /* return_statement */ {
 			struct expression *ret_value;
diff --git a/sparse.1 b/sparse.1
index 92a1cae..c44e3a5 100644
--- a/sparse.1
+++ b/sparse.1
@@ -73,43 +73,20 @@ Warn about potential errors in synchronization or other delimited contexts.
 Sparse supports several means of designating functions or statements that
 delimit contexts, such as synchronization.  Functions with the extended
 attribute
-.BI __attribute__((context( [expression ,] in_context , out_context ))
-require the context \fIexpression\fR (for instance, a lock) to have at least the value
+.BI __attribute__((context( expression , in_context , out_context ))
+require the context \fIexpression\fR (for instance, a lock) to have the value
 \fIin_context\fR (a constant nonnegative integer) when called, and return with
-the value adjusted by \fIout_context - in_context\fR (where
-\fIout_context\fR is a constant nonnegative integer).  To change the value
-of a context (for example in macros), use the statement
-.BI __context__( [expression , ]adjust_value[ , required] )
-where \fIadjust_value\fR is a constant integer and \fIrequired\fR is a
-constant nonnegative integer. Not giving \fIrequired\fR is equivalent to
-giving zero and means that the statement does not need the context as a
-precondition, when given it means that the context must at least have the
-value of \fIrequired\fR.
-
-To indicate that a function requires
-.BI exactly
-a certain lock context (not "at least" as above), use the form
-.BI __attribute__((exact_context( [expression ,] in_context , out_context ))
-There currently is no corresponding
-.BI __exact_context__( [expression , ]adjust_value[ , required] )
-statement.
-
-To indicate that a certain function acquires a context depending on its
-return value, use
-.BI __attribute__((conditional_context( [expression ,] in_context , out_success , out_failure ))
-where \fIout_success\fR and \fIout_failure\fR indicate the context change
-done depending on success (non-zero) or failure (zero) return of the
-function. Note that currently, using this attribute on a function means that
-the function itself won't be checked for context handling at all. See the
-testsuite for examples.
-
-Sparse will warn when it sees a function change a
-context without indicating this with a \fBcontext\fR or \fBexact_context\fR attribute, either by
+the value \fIout_context\fR (a constant nonnegative integer).  For APIs
+defined via macros, use the statement form
+.BI __context__( expression , in_value , out_value )
+in the body of the macro.
+
+With \fB-Wcontext\fR Sparse will warn when it sees a function change the
+context without indicating this with a \fBcontext\fR attribute, either by
 decreasing a context below zero (such as by releasing a lock without acquiring
 it), or returning with a changed context (such as by acquiring a lock without
 releasing it).  Sparse will also warn about blocks of code which may
-potentially execute with different contexts and about functions that are
-executed without a lock they require.
+potentially execute with different contexts.
 
 Sparse issues these warnings by default.  To turn them off, use
 \fB\-Wno\-context\fR.
diff --git a/sparse.c b/sparse.c
index 785a6f6..4026ba7 100644
--- a/sparse.c
+++ b/sparse.c
@@ -24,389 +24,77 @@
 #include "expression.h"
 #include "linearize.h"
 
-struct context_check {
-	int val, val_false;
-	char name[32];
-};
-
-DECLARE_ALLOCATOR(context_check);
-DECLARE_PTR_LIST(context_check_list, struct context_check);
-DECLARE_PTR_LIST(context_list_list, struct context_check_list);
-ALLOCATOR(context_check, "context check list");
-
-static const char *unnamed_context = "<unnamed>";
-
-static const char *context_name(struct context *context)
-{
-	if (context->context && context->context->symbol_name)
-		return show_ident(context->context->symbol_name);
-	return unnamed_context;
-}
-
-static void context_add(struct context_check_list **ccl, const char *name,
-			int offs, int offs_false)
-{
-	struct context_check *check, *found = NULL;
-
-	FOR_EACH_PTR(*ccl, check) {
-		if (strcmp(name, check->name))
-			continue;
-		found = check;
-		break;
-	} END_FOR_EACH_PTR(check);
-
-	if (!found) {
-		found = __alloc_context_check(0);
-		strncpy(found->name, name, sizeof(found->name));
-		found->name[sizeof(found->name) - 1] = '\0';
-		add_ptr_list(ccl, found);
-	}
-	found->val += offs;
-	found->val_false += offs_false;
-}
-
-static int context_list_has(struct context_check_list *ccl,
-			    struct context_check *c)
+static int context_increase(struct basic_block *bb, int entry)
 {
-	struct context_check *check;
+	int sum = 0;
+	struct instruction *insn;
 
-	FOR_EACH_PTR(ccl, check) {
-		if (strcmp(c->name, check->name))
+	FOR_EACH_PTR(bb->insns, insn) {
+		int val;
+		if (insn->opcode != OP_CONTEXT)
 			continue;
-		return check->val == c->val &&
-		       check->val_false == c->val_false;
-	} END_FOR_EACH_PTR(check);
-
-	/* not found is equal to 0 */
-	return c->val == 0 && c->val_false == 0;
-}
-
-static int context_lists_equal(struct context_check_list *ccl1,
-			       struct context_check_list *ccl2)
-{
-	struct context_check *check;
-
-	/* can be optimised... */
-
-	FOR_EACH_PTR(ccl1, check) {
-		if (!context_list_has(ccl2, check))
-			return 0;
-	} END_FOR_EACH_PTR(check);
-
-	FOR_EACH_PTR(ccl2, check) {
-		if (!context_list_has(ccl1, check))
-			return 0;
-	} END_FOR_EACH_PTR(check);
-
-	return 1;
-}
-
-static struct context_check_list *checked_copy(struct context_check_list *ccl)
-{
-	struct context_check_list *result = NULL;
-	struct context_check *c;
-
-	FOR_EACH_PTR(ccl, c) {
-		context_add(&result, c->name, c->val_false, c->val_false);
-	} END_FOR_EACH_PTR(c);
-
-	return result;
-}
-
-#define IMBALANCE_IN "context imbalance in '%s': "
-#define DEFAULT_CONTEXT_DESCR "   default context: "
-
-static void get_context_string(char **buf, const char **name)
-{
-	if (strcmp(*name, unnamed_context)) {
-		*buf = malloc(strlen(*name) + 16);
-		sprintf(*buf, "   context '%s': ", *name);
-		*name = *buf;
-	} else {
-		*name = DEFAULT_CONTEXT_DESCR;
-		*buf = NULL;
-	}
-}
-
-static int context_list_check(struct entrypoint *ep, struct position pos,
-			      struct context_check_list *ccl_cur,
-			      struct context_check_list *ccl_target)
-{
-	struct context_check *c1, *c2;
-	int cur, tgt;
-	const char *name;
-	char *buf;
-
-	/* make sure the loop below checks all */
-	FOR_EACH_PTR(ccl_target, c1) {
-		context_add(&ccl_cur, c1->name, 0, 0);
-	} END_FOR_EACH_PTR(c1);
-
-	FOR_EACH_PTR(ccl_cur, c1) {
-		cur = c1->val;
-		tgt = 0;
-
-		FOR_EACH_PTR(ccl_target, c2) {
-			if (strcmp(c2->name, c1->name))
+		val = insn->increment;
+		if (insn->check) {
+			int current = sum + entry;
+			if (!val) {
+				if (!current)
+					continue;
+			} else if (current >= val)
 				continue;
-			tgt = c2->val;
-			break;
-		} END_FOR_EACH_PTR(c2);
-
-		if (cur == tgt || !Wcontext)
+			warning(insn->pos, "context check failure");
 			continue;
-
-		if (cur > tgt)
-			warning(pos, IMBALANCE_IN "wrong count at exit",
-				show_ident(ep->name->ident));
-		else if (cur < tgt)
-			warning(pos, IMBALANCE_IN "unexpected unlock",
-				show_ident(ep->name->ident));
-
-		name = c1->name;
-		get_context_string(&buf, &name);
-
-		info(pos, "%swanted %d, got %d",
-		     name, tgt, cur);
-
-		free(buf);
-
-		return -1;
-	} END_FOR_EACH_PTR(c1);
-
-	return 0;
-}
-
-static int handle_call(struct entrypoint *ep, struct basic_block *bb,
-		       struct instruction *insn,
-		       struct context_check_list *combined)
-{
-	struct context *ctx;
-	struct context_check *c;
-	const char *name, *call, *cmp;
-	char *buf;
-	int val, ok;
-
-	if (!insn->func || !insn->func->sym ||
-	    insn->func->type != PSEUDO_SYM)
-		return 0;
-
-	/*
-	 * Check all contexts the function wants.
-	 */
-	FOR_EACH_PTR(insn->func->sym->ctype.contexts, ctx) {
-		name = context_name(ctx);
-		val = 0;
-
-		FOR_EACH_PTR(combined, c) {
-			if (strcmp(c->name, name) == 0) {
-				val = c->val;
-				break;
-			}
-		} END_FOR_EACH_PTR(c);
-
-		if (ctx->exact) {
-			ok = ctx->in == val;
-			cmp = "";
-		} else {
-			ok = ctx->in <= val;
-			cmp = ">= ";
-		}
-
-		if (!ok && Wcontext) {
-			get_context_string(&buf, &name);
-			call = strdup(show_ident(insn->func->ident));
-
-			warning(insn->pos, "context problem in '%s': "
-				"'%s' expected different context",
-				show_ident(ep->name->ident), call);
-
-			info(insn->pos, "%swanted %s%d, got %d",
-			     name, cmp, ctx->in, val);
-
-			free((void *)call);
-			free(buf);
-
-			return -1;
 		}
-	} END_FOR_EACH_PTR (ctx);
-
-	return 0;
+		sum += val;
+	} END_FOR_EACH_PTR(insn);
+	return sum;
 }
 
-static int handle_context(struct entrypoint *ep, struct basic_block *bb,
-			  struct instruction *insn,
-			  struct context_check_list **combined)
+static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
 {
-	struct context_check *c;
-	const char *name;
-	char *buf;
-	int val, ok;
-
-	val = 0;
-
-	name = unnamed_context;
-	if (insn->context_expr)
-		name = show_ident(insn->context_expr->symbol_name);
-
-	FOR_EACH_PTR(*combined, c) {
-		if (strcmp(c->name, name) == 0) {
-			val = c->val;
-			break;
-		}
-	} END_FOR_EACH_PTR(c);
-
-	ok = insn->required <= val;
-
-	if (!ok && Wcontext) {
-		get_context_string(&buf, &name);
-
-		warning(insn->pos,
-			IMBALANCE_IN
-			"__context__ statement expected different context",
-			show_ident(ep->name->ident));
-
-		info(insn->pos, "%swanted >= %d, got %d",
-		     name, insn->required, val);
-
-		free(buf);
-		return -1;
+	if (Wcontext) {
+		struct symbol *sym = ep->name;
+		warning(bb->pos, "context imbalance in '%s' - %s", show_ident(sym->ident), why);
 	}
-
-	context_add(combined, name, insn->increment, insn->inc_false);
-
-	return 0;
+	return -1;
 }
 
-static int check_bb_context(struct entrypoint *ep, struct basic_block *bb,
-			    struct context_check_list *ccl_in,
-			    struct context_check_list *ccl_target,
-			    int in_false)
+static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit);
+
+static int check_children(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
 {
-	struct context_check_list *combined = NULL, *done;
-	struct context_check *c;
 	struct instruction *insn;
-	struct multijmp *mj;
-	int err = -1;
-
-	/*
-	 * Recurse in once to catch bad loops.
-	 */
-	if (bb->context_check_recursion > 1)
-		return 0;
-	bb->context_check_recursion++;
-
-	/*
-	 * Abort if we have already checked this block out of the same context.
-	 */
-	FOR_EACH_PTR(bb->checked_contexts, done) {
-		if (context_lists_equal(done, ccl_in))
-			return 0;
-	} END_FOR_EACH_PTR(done);
-
-	/*
-	 * We're starting with a completely new local list of contexts, so
-	 * initialise it according to what we got from the parent block.
-	 * That may use either the 'false' or the 'true' part of the context
-	 * for the conditional_context() attribute.
-	 */
-	FOR_EACH_PTR(ccl_in, c) {
-		if (in_false)
-			context_add(&combined, c->name, c->val_false, c->val_false);
-		else
-			context_add(&combined, c->name, c->val, c->val);
-	} END_FOR_EACH_PTR(c);
-
-	/* Add the new context to the list of already-checked contexts */
-	done = checked_copy(combined);
-	add_ptr_list(&bb->checked_contexts, done);
-
-	/*
-	 * Now walk the instructions for this block, recursing into any
-	 * instructions that have children. We need to have the right
-	 * order so we cannot iterate bb->children instead.
-	 */
-	FOR_EACH_PTR(bb->insns, insn) {
-		switch (insn->opcode) {
-		case OP_INLINED_CALL:
-		case OP_CALL:
-			if (handle_call(ep, bb, insn, combined))
-				goto out;
-			break;
-		case OP_CONTEXT:
-			if (handle_context(ep, bb, insn, &combined))
-				goto out;
-			break;
-		case OP_BR:
-			if (insn->bb_true)
-				if (check_bb_context(ep, insn->bb_true,
-						     combined, ccl_target, 0))
-					goto out;
-			if (insn->bb_false)
-				if (check_bb_context(ep, insn->bb_false,
-						     combined, ccl_target, 1))
-					goto out;
-			break;
-		case OP_SWITCH:
-		case OP_COMPUTEDGOTO:
-			FOR_EACH_PTR(insn->multijmp_list, mj) {
-				if (check_bb_context(ep, mj->target,
-					             combined, ccl_target, 0))
-					goto out;
-			} END_FOR_EACH_PTR(mj);
-			break;
-		}
-	} END_FOR_EACH_PTR(insn);
+	struct basic_block *child;
 
 	insn = last_instruction(bb->insns);
 	if (!insn)
-		goto out_good;
-
-	if (insn->opcode == OP_RET) {
-		err = context_list_check(ep, insn->pos, combined, ccl_target);
-		goto out;
-	}
+		return 0;
+	if (insn->opcode == OP_RET)
+		return entry != exit ? imbalance(ep, bb, entry, exit, "wrong count at exit") : 0;
 
- out_good:
-	err = 0;
- out:
-	/* contents will be freed once we return out of recursion */
-	free_ptr_list(&combined);
-	bb->context_check_recursion--;
-	return err;
+	FOR_EACH_PTR(bb->children, child) {
+		if (check_bb_context(ep, child, entry, exit))
+			return -1;
+	} END_FOR_EACH_PTR(child);
+	return 0;
 }
 
-static void free_bb_context_lists(struct basic_block *bb)
+static int check_bb_context(struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
 {
-	struct context_check_list *done;
-	struct instruction *insn;
-	struct multijmp *mj;
-
-	if (!bb->checked_contexts)
-		return;
+	if (!bb)
+		return 0;
+	if (bb->context == entry)
+		return 0;
 
-	FOR_EACH_PTR(bb->checked_contexts, done) {
-		free_ptr_list(&done);
-	} END_FOR_EACH_PTR(done);
+	/* Now that's not good.. */
+	if (bb->context >= 0)
+		return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
 
-	free_ptr_list(&bb->checked_contexts);
+	bb->context = entry;
+	entry += context_increase(bb, entry);
+	if (entry < 0)
+		return imbalance(ep, bb, entry, exit, "unexpected unlock");
 
-	FOR_EACH_PTR(bb->insns, insn) {
-		switch (insn->opcode) {
-		case OP_BR:
-			if (insn->bb_true)
-				free_bb_context_lists(insn->bb_true);
-			if (insn->bb_false)
-				free_bb_context_lists(insn->bb_false);
-			break;
-		case OP_SWITCH:
-		case OP_COMPUTEDGOTO:
-			FOR_EACH_PTR(insn->multijmp_list, mj) {
-				free_bb_context_lists(mj->target);
-			} END_FOR_EACH_PTR(mj);
-			break;
-		}
-	} END_FOR_EACH_PTR(insn);
+	return check_children(ep, bb, entry, exit);
 }
 
 static void check_cast_instruction(struct instruction *insn)
@@ -547,7 +235,7 @@ static void check_context(struct entrypoint *ep)
 {
 	struct symbol *sym = ep->name;
 	struct context *context;
-	struct context_check_list *ccl_in = NULL, *ccl_target = NULL;
+	unsigned int in_context = 0, out_context = 0;
 
 	if (Wuninitialized && verbose && ep->entry->bb->needs) {
 		pseudo_t pseudo;
@@ -561,20 +249,10 @@ static void check_context(struct entrypoint *ep)
 	check_instructions(ep);
 
 	FOR_EACH_PTR(sym->ctype.contexts, context) {
-		const char *name = context_name(context);
-
-		context_add(&ccl_in, name, context->in, context->in);
-		context_add(&ccl_target, name, context->out, context->out_false);
-		/* we don't currently check the body of trylock functions */
-		if (context->out != context->out_false)
-			return;
+		in_context += context->in;
+		out_context += context->out;
 	} END_FOR_EACH_PTR(context);
-
-	check_bb_context(ep, ep->entry->bb, ccl_in, ccl_target, 0);
-	free_ptr_list(&ccl_in);
-	free_ptr_list(&ccl_target);
-	free_bb_context_lists(ep->entry->bb);
-	clear_context_check_alloc();
+	check_bb_context(ep, ep->entry->bb, in_context, out_context);
 }
 
 static void check_symbols(struct symbol_list *list)
diff --git a/symbol.h b/symbol.h
index c4d7f28..4155b46 100644
--- a/symbol.h
+++ b/symbol.h
@@ -71,8 +71,7 @@ enum keyword {
 
 struct context {
 	struct expression *context;
-	unsigned int in, out, out_false;
-	int exact;
+	unsigned int in, out;
 };
 
 extern struct context *alloc_context(void);
diff --git a/validation/context-dynamic.c b/validation/context-dynamic.c
deleted file mode 100644
index 5e172f0..0000000
--- a/validation/context-dynamic.c
+++ /dev/null
@@ -1,171 +0,0 @@
-static void a(void) __attribute__ ((context(A, 0, 1)))
-{
-    __context__(A, 1);
-}
-
-static void r(void) __attribute__ ((context(A, 1, 0)))
-{
-    __context__(A, -1);
-}
-
-extern int condition, condition2;
-
-static int tl(void) __attribute__ ((conditional_context(A, 0, 1, 0)))
-{
-    if (condition) {
-        a();
-        return 1;
-    }
-    return 0;
-}
-
-static int tl2(void) __attribute__ ((conditional_context(A, 0, 0, 1)))
-{
-    if (condition) {
-        a();
-        return 1;
-    }
-    return 0;
-}
-
-static int dummy(void)
-{
-    return condition + condition2;
-}
-
-static int good_trylock1(void)
-{
-    if (tl()) {
-        r();
-    }
-}
-
-static int good_trylock2(void)
-{
-    if (tl()) {
-        r();
-    }
-
-    if (tl()) {
-        r();
-    }
-}
-static int good_trylock3(void)
-{
-    a();
-    if (tl()) {
-        r();
-    }
-    r();
-    if (tl()) {
-        r();
-    }
-}
-
-static int good_trylock4(void)
-{
-    a();
-    if (tl()) {
-        r();
-    }
-    if (tl()) {
-        r();
-    }
-    r();
-}
-
-static void bad_trylock1(void)
-{
-    a();
-    if (dummy()) {
-        r();
-    }
-    r();
-}
-
-static int good_trylock5(void)
-{
-    if (!tl2()) {
-        r();
-    }
-}
-
-static int good_trylock6(void)
-{
-    if (!tl2()) {
-        r();
-    }
-
-    if (!tl2()) {
-        r();
-    }
-}
-static int good_trylock7(void)
-{
-    a();
-    if (!tl2()) {
-        r();
-    }
-    r();
-    if (!tl2()) {
-        r();
-    }
-}
-
-static int good_trylock8(void)
-{
-    a();
-    if (!tl2()) {
-        r();
-    }
-    if (!tl2()) {
-        r();
-    }
-    r();
-}
-
-static void bad_trylock2(void)
-{
-    a();
-    if (!dummy()) {
-        r();
-    }
-    r();
-}
-
-static int good_switch(void)
-{
-    switch (condition) {
-    case 1:
-        a();
-        break;
-    case 2:
-        a();
-        break;
-    case 3:
-        a();
-        break;
-    default:
-        a();
-    }
-    r();
-}
-
-static void bad_lock1(void)
-{
-    r();
-    a();
-}
-
-/*
- * check-name: Check -Wcontext with lock trylocks
- *
- * check-error-start
-context-dynamic.c:83:6: warning: context problem in 'bad_trylock1': 'r' expected different context
-context-dynamic.c:83:6:    context 'A': wanted >= 1, got 0
-context-dynamic.c:133:6: warning: context problem in 'bad_trylock2': 'r' expected different context
-context-dynamic.c:133:6:    context 'A': wanted >= 1, got 0
-context-dynamic.c:156:6: warning: context problem in 'bad_lock1': 'r' expected different context
-context-dynamic.c:156:6:    context 'A': wanted >= 1, got 0
- * check-error-end
- */
diff --git a/validation/context-named.c b/validation/context-named.c
deleted file mode 100644
index 58310e9..0000000
--- a/validation/context-named.c
+++ /dev/null
@@ -1,553 +0,0 @@
-static void a(void) __attribute__((context(TEST,0,1)))
-{
-	__context__(TEST,1);
-}
-
-static void r(void) __attribute__((context(TEST,1,0)))
-{
-	__context__(TEST,-1,1);
-}
-
-static void a2(void) __attribute__((context(TEST2,0,1)))
-{
-	__context__(TEST2,1);
-}
-
-static void r2(void) __attribute__((context(TEST2,1,0)))
-{
-	__context__(TEST2,-1,1);
-}
-
-#define check_test2() __context__(TEST2,0,1)
-
-static void good_paired1(void)
-{
-	a();
-	a2();
-	r();
-	r2();
-}
-
-static void good_paired2(void)
-{
-	a();
-	r();
-	a();
-	r();
-	a2();
-	r2();
-}
-
-static void good_paired3(void)
-{
-	a();
-	a();
-	r();
-	r();
-	a2();
-	a2();
-	r2();
-	r2();
-}
-
-static void good_lock1(void) __attribute__((context(TEST,0,1)))
-{
-	a();
-}
-
-static void good_lock2(void) __attribute__((context(TEST,0,1)))
-{
-	a();
-	r();
-	a();
-}
-
-static void good_lock3(void) __attribute__((context(TEST,0,1)))
-{
-	a();
-	a();
-	r();
-}
-
-static void good_unlock1(void) __attribute__((context(TEST,1,0)))
-{
-	r();
-}
-
-static void good_unlock2(void) __attribute__((context(TEST,1,0)))
-{
-	a();
-	r();
-	r();
-}
-
-static void warn_lock1(void)
-{
-	a();
-}
-
-static void warn_lock2(void)
-{
-	a();
-	r();
-	a();
-}
-
-static void warn_lock3(void)
-{
-	a();
-	a();
-	r();
-}
-
-static void warn_unlock1(void)
-{
-	r();
-}
-
-static void warn_unlock2(void)
-{
-	a();
-	r();
-	r();
-}
-
-extern int condition, condition2;
-
-static int good_if1(void)
-{
-	a();
-	if(condition) {
-		r();
-		return -1;
-	}
-	r();
-	return 0;
-}
-
-static void good_if2(void)
-{
-	if(condition) {
-		a();
-		r();
-	}
-}
-
-static void good_if3(void)
-{
-	a();
-	if(condition) {
-		a();
-		r();
-	}
-	r();
-}
-
-static int warn_if1(void)
-{
-	a();
-	if(condition)
-		return -1;
-	r();
-	return 0;
-}
-
-static int warn_if2(void)
-{
-	a();
-	if(condition) {
-		r();
-		return -1;
-	}
-	return 0;
-}
-
-static void good_while1(void)
-{
-	a();
-	while(condition)
-		;
-	r();
-}
-
-static void good_while2(void)
-{
-	while(condition) {
-		a();
-		r();
-	}
-}
-
-static void good_while3(void)
-{
-	while(condition) {
-		a();
-		r();
-		if(condition2)
-			break;
-		a();
-		r();
-	}
-}
-
-static void good_while4(void)
-{
-	a();
-	while(1) {
-		if(condition2) {
-			r();
-			break;
-		}
-	}
-}
-
-static void good_while5(void)
-{
-	a();
-	while(1) {
-		r();
-		if(condition2)
-			break;
-		a();
-	}
-}
-
-static void warn_while1(void)
-{
-	while(condition) {
-		a();
-	}
-}
-
-static void warn_while2(void)
-{
-	while(condition) {
-		r();
-	}
-}
-
-static void warn_while3(void)
-{
-	while(condition) {
-		a();
-		if(condition2)
-			break;
-		r();
-	}
-}
-
-static void good_goto1(void)
-{
-    a();
-    goto label;
-label:
-    r();
-}
-
-static void good_goto2(void)
-{
-    a();
-    goto label;
-    a();
-    r();
-label:
-    r();
-}
-
-static void good_goto3(void)
-{
-    a();
-    if(condition)
-        goto label;
-    a();
-    r();
-label:
-    r();
-}
-
-static void good_goto4(void)
-{
-    if(condition)
-        goto label;
-    a();
-    r();
-label:
-    ;
-}
-
-static void good_goto5(void)
-{
-    a();
-    if(condition)
-        goto label;
-    r();
-    return;
-label:
-    r();
-}
-
-static void warn_goto1(void)
-{
-    a();
-    goto label;
-    r();
-label:
-    ;
-}
-
-static void warn_goto2(void)
-{
-    a();
-    goto label;
-    r();
-label:
-    a();
-    r();
-}
-
-static void warn_goto3(void)
-{
-    a();
-    if(condition)
-        goto label;
-    r();
-label:
-    r();
-}
-
-static void warn_multiple1(void)
-{
-    a();
-    a2();
-}
-
-static void warn_multiple2(void)
-{
-    a2();
-    a();
-}
-
-static void warn_mixed1(void)
-{
-    a2();
-    r();
-}
-
-static void warn_mixed2(void)
-{
-    a2();
-    if (condition) {
-        a();
-        r2();
-    }
-    r();
-}
-
-static void warn_mixed3(void)
-{
-    a2();
-    if (condition) {
-        r2();
-        return;
-    }
-    r();
-}
-
-static void warn_mixed4(void)
-{
-    a2();
-    if (condition) {
-        a();
-        r();
-        return;
-    }
-    r();
-}
-
-static void good_mixed1(void)
-{
-    if (condition) {
-        a();
-        r();
-    } else {
-        a2();
-        r2();
-    }
-}
-
-static void good_mixed2(void)
-{
-    if (condition) {
-        a();
-        r();
-    }
-    a2();
-    r2();
-}
-
-static int need_lock(void) __attribute__((context(TEST,1,1)))
-{
-}
-
-static void need_lock_exact(void) __attribute__((exact_context(TEST,1,1)))
-{
-}
-
-static void need_lock2(void) __attribute__((context(TEST,1,1)))
-{
-    need_lock();
-}
-
-static void good_fn(void)
-{
-    a();
-    need_lock();
-    r();
-}
-
-static void good_fn2(void)
-{
-    a();
-    a();
-    need_lock();
-    r();
-    r();
-}
-
-static void good_fn2(void)
-{
-    a();
-    if (condition)
-        need_lock();
-    r();
-}
-
-static void good_fn3(void) __attribute__((context(TEST,1,1)))
-{
-    if (condition)
-        need_lock2();
-}
-
-static void warn_fn(void)
-{
-    a2();
-    need_lock();
-    r2();
-}
-
-static void warn_fn2(void)
-{
-    a2();
-    need_lock2();
-    r2();
-}
-
-static void good_exact_fn(void)
-{
-    a();
-    need_lock_exact();
-    r();
-}
-
-static void warn_exact_fn1(void)
-{
-    a();
-    a();
-    need_lock_exact();
-    r();
-    r();
-}
-
-static void warn_exact_fn2(void)
-{
-    a2();
-    need_lock_exact();
-    r2();
-}
-
-static inline void need_lock3(void) __attribute__((context(TEST,1,1)))
-{
-}
-
-static void warn_fn3(void)
-{
-    a2();
-    need_lock3();
-    r2();
-}
-
-#define __acquire(x)	__context__(x,1)
-#define __release(x)	__context__(x,-1)
-
-#define rl() \
-  do { __acquire(RCU); } while (0)
-
-#define ru() \
-  do { __release(RCU); } while (0)
-
-static void good_mixed_with_if(void)
-{
-    rl();
-
-    if (condition) {
-        a();
-        r();
-    }
-
-    ru();
-}
-
-/*
- * check-name: Check -Wcontext with lock names
- *
- * check-error-start
-context-named.c:86:3: warning: context imbalance in 'warn_lock1': wrong count at exit
-context-named.c:86:3:    context 'TEST': wanted 0, got 1
-context-named.c:93:3: warning: context imbalance in 'warn_lock2': wrong count at exit
-context-named.c:93:3:    context 'TEST': wanted 0, got 1
-context-named.c:100:3: warning: context imbalance in 'warn_lock3': wrong count at exit
-context-named.c:100:3:    context 'TEST': wanted 0, got 1
-context-named.c:105:3: warning: context problem in 'warn_unlock1': 'r' expected different context
-context-named.c:105:3:    context 'TEST': wanted >= 1, got 0
-context-named.c:112:3: warning: context problem in 'warn_unlock2': 'r' expected different context
-context-named.c:112:3:    context 'TEST': wanted >= 1, got 0
-context-named.c:152:9: warning: context imbalance in 'warn_if1': wrong count at exit
-context-named.c:152:9:    context 'TEST': wanted 0, got 1
-context-named.c:162:9: warning: context imbalance in 'warn_if2': wrong count at exit
-context-named.c:162:9:    context 'TEST': wanted 0, got 1
-context-named.c:218:4: warning: context imbalance in 'warn_while1': wrong count at exit
-context-named.c:218:4:    context 'TEST': wanted 0, got 1
-context-named.c:225:4: warning: context problem in 'warn_while2': 'r' expected different context
-context-named.c:225:4:    context 'TEST': wanted >= 1, got 0
-context-named.c:235:4: warning: context imbalance in 'warn_while3': wrong count at exit
-context-named.c:235:4:    context 'TEST': wanted 0, got 1
-context-named.c:295:5: warning: context imbalance in 'warn_goto1': wrong count at exit
-context-named.c:295:5:    context 'TEST': wanted 0, got 1
-context-named.c:305:6: warning: context imbalance in 'warn_goto2': wrong count at exit
-context-named.c:305:6:    context 'TEST': wanted 0, got 1
-context-named.c:315:6: warning: context problem in 'warn_goto3': 'r' expected different context
-context-named.c:315:6:    context 'TEST': wanted >= 1, got 0
-context-named.c:321:7: warning: context imbalance in 'warn_multiple1': wrong count at exit
-context-named.c:321:7:    context 'TEST': wanted 0, got 1
-context-named.c:327:6: warning: context imbalance in 'warn_multiple2': wrong count at exit
-context-named.c:327:6:    context 'TEST2': wanted 0, got 1
-context-named.c:333:6: warning: context problem in 'warn_mixed1': 'r' expected different context
-context-named.c:333:6:    context 'TEST': wanted >= 1, got 0
-context-named.c:343:6: warning: context problem in 'warn_mixed2': 'r' expected different context
-context-named.c:343:6:    context 'TEST': wanted >= 1, got 0
-context-named.c:353:6: warning: context problem in 'warn_mixed3': 'r' expected different context
-context-named.c:353:6:    context 'TEST': wanted >= 1, got 0
-context-named.c:364:6: warning: context imbalance in 'warn_mixed4': wrong count at exit
-context-named.c:364:6:    context 'TEST2': wanted 0, got 1
-context-named.c:434:14: warning: context problem in 'warn_fn': 'need_lock' expected different context
-context-named.c:434:14:    context 'TEST': wanted >= 1, got 0
-context-named.c:441:15: warning: context problem in 'warn_fn2': 'need_lock2' expected different context
-context-named.c:441:15:    context 'TEST': wanted >= 1, got 0
-context-named.c:456:20: warning: context problem in 'warn_exact_fn1': 'need_lock_exact' expected different context
-context-named.c:456:20:    context 'TEST': wanted 1, got 2
-context-named.c:464:20: warning: context problem in 'warn_exact_fn2': 'need_lock_exact' expected different context
-context-named.c:464:20:    context 'TEST': wanted 1, got 0
-context-named.c:475:15: warning: context problem in 'warn_fn3': 'need_lock3' expected different context
-context-named.c:475:15:    context 'TEST': wanted >= 1, got 0
- * check-error-end
- */
diff --git a/validation/context-statement.c b/validation/context-statement.c
deleted file mode 100644
index fd79a6a..0000000
--- a/validation/context-statement.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#define a() __context__(LOCK, 1)
-#define r() __context__(LOCK, -1)
-#define m() __context__(LOCK, 0, 1)
-#define m2() __context__(LOCK, 0, 2)
-
-static void good_ar(void)
-{
-    a();
-    r();
-}
-
-static void bad_arr(void)
-{
-    a();
-    r();
-    r();
-}
-
-static void good_macro1(void)
-{
-    a();
-    m();
-    r();
-}
-
-static void good_macro2(void)
-{
-    a();
-    a();
-    m();
-    m2();
-    r();
-    r();
-}
-
-static void bad_macro1(void)
-{
-    m();
-    a();
-    r();
-}
-
-static void bad_macro2(void)
-{
-    a();
-    r();
-    m();
-}
-
-static void bad_macro3(void)
-{
-    r();
-    a();
-}
-
-/*
- * check-name: Check __context__ statement with required context
- *
- * check-error-start
-context-statement.c:16:8: warning: context imbalance in 'bad_arr': unexpected unlock
-context-statement.c:16:8:    context 'LOCK': wanted 0, got -1
-context-statement.c:38:5: warning: context imbalance in 'bad_macro1': __context__ statement expected different context
-context-statement.c:38:5:    context 'LOCK': wanted >= 1, got 0
-context-statement.c:47:5: warning: context imbalance in 'bad_macro2': __context__ statement expected different context
-context-statement.c:47:5:    context 'LOCK': wanted >= 1, got 0
-context-statement.c:53:5: warning: context imbalance in 'bad_macro3': __context__ statement expected different context
-context-statement.c:53:5:    context 'LOCK': wanted >= 0, got -1
- * check-error-end
- */
diff --git a/validation/context.c b/validation/context.c
index 0b45ba3..4b15e75 100644
--- a/validation/context.c
+++ b/validation/context.c
@@ -314,109 +314,23 @@ static void warn_cond_lock1(void)
         condition2 = 1; /* do stuff */
     r();
 }
-
-static void warn_odd_looping(void)
-{
-    int i;
-
-    for (i = 0; i < 2; i++)
-        a();
-    for (i = 0; i < 2; i++)
-        r();
-}
-
-static void warn_huge_switch(void)
-{
-    a();
-
-    switch(condition) {
-    case 1:
-        r();
-        break;
-    case 2:
-        r();
-        break;
-    case 3:
-        r();
-        break;
-    case 4:
-        r();
-        break;
-    case 5:
-        r();
-        break;
-    case 11:
-        r();
-        break;
-    case 12:
-        r();
-        break;
-    case 13:
-        r();
-        break;
-    case 14:
-        r();
-    case 15:
-        r();
-        break;
-    case 16:
-        r();
-        break;
-    case 17:
-        r();
-        break;
-    }
-}
-
-static int warn_conditional(void)
-{
-    if (condition)
-        return 0;
-
-    a();
-    if (condition == 0)
-        return 1;
-    r();
-    return 0;
-}
-
 /*
  * check-name: Check -Wcontext
  *
  * check-error-start
-context.c:71:3: warning: context imbalance in 'warn_lock1': wrong count at exit
-context.c:71:3:    default context: wanted 0, got 1
-context.c:78:3: warning: context imbalance in 'warn_lock2': wrong count at exit
-context.c:78:3:    default context: wanted 0, got 1
-context.c:85:3: warning: context imbalance in 'warn_lock3': wrong count at exit
-context.c:85:3:    default context: wanted 0, got 1
-context.c:90:3: warning: context problem in 'warn_unlock1': 'r' expected different context
-context.c:90:3:    default context: wanted >= 1, got 0
-context.c:97:3: warning: context problem in 'warn_unlock2': 'r' expected different context
-context.c:97:3:    default context: wanted >= 1, got 0
-context.c:137:9: warning: context imbalance in 'warn_if1': wrong count at exit
-context.c:137:9:    default context: wanted 0, got 1
-context.c:147:9: warning: context imbalance in 'warn_if2': wrong count at exit
-context.c:147:9:    default context: wanted 0, got 1
-context.c:203:4: warning: context imbalance in 'warn_while1': wrong count at exit
-context.c:203:4:    default context: wanted 0, got 1
-context.c:210:4: warning: context problem in 'warn_while2': 'r' expected different context
-context.c:210:4:    default context: wanted >= 1, got 0
-context.c:220:4: warning: context imbalance in 'warn_while3': wrong count at exit
-context.c:220:4:    default context: wanted 0, got 1
-context.c:280:5: warning: context imbalance in 'warn_goto1': wrong count at exit
-context.c:280:5:    default context: wanted 0, got 1
-context.c:290:6: warning: context imbalance in 'warn_goto2': wrong count at exit
-context.c:290:6:    default context: wanted 0, got 1
-context.c:300:6: warning: context problem in 'warn_goto3': 'r' expected different context
-context.c:300:6:    default context: wanted >= 1, got 0
-context.c:315:6: warning: context problem in 'warn_cond_lock1': 'r' expected different context
-context.c:315:6:    default context: wanted >= 1, got 0
-context.c:325:10: warning: context problem in 'warn_odd_looping': 'r' expected different context
-context.c:325:10:    default context: wanted >= 1, got 0
-context.c:360:10: warning: context problem in 'warn_huge_switch': 'r' expected different context
-context.c:360:10:    default context: wanted >= 1, got 0
-context.c:380:12: warning: context imbalance in 'warn_conditional': wrong count at exit
-context.c:380:12:    default context: wanted 0, got 1
+context.c:69:13: warning: context imbalance in 'warn_lock1' - wrong count at exit
+context.c:74:13: warning: context imbalance in 'warn_lock2' - wrong count at exit
+context.c:81:13: warning: context imbalance in 'warn_lock3' - wrong count at exit
+context.c:88:13: warning: context imbalance in 'warn_unlock1' - unexpected unlock
+context.c:93:13: warning: context imbalance in 'warn_unlock2' - unexpected unlock
+context.c:131:12: warning: context imbalance in 'warn_if1' - wrong count at exit
+context.c:140:12: warning: context imbalance in 'warn_if2' - different lock contexts for basic block
+context.c:202:2: warning: context imbalance in 'warn_while1' - different lock contexts for basic block
+context.c:210:3: warning: context imbalance in 'warn_while2' - unexpected unlock
+context.c:216:2: warning: context imbalance in 'warn_while3' - wrong count at exit
+context.c:274:13: warning: context imbalance in 'warn_goto1' - wrong count at exit
+context.c:283:13: warning: context imbalance in 'warn_goto2' - wrong count at exit
+context.c:300:5: warning: context imbalance in 'warn_goto3' - different lock contexts for basic block
+context.c:315:5: warning: context imbalance in 'warn_cond_lock1' - different lock contexts for basic block
  * check-error-end
  */
-- 
1.6.0.6




^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: Casting away noderef and address spaces?
  2008-12-23  9:59                       ` Johannes Berg
@ 2008-12-24  8:34                         ` Christopher Li
  0 siblings, 0 replies; 18+ messages in thread
From: Christopher Li @ 2008-12-24  8:34 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Alexey Zaytsev, Sam Ravnborg, Al Viro, Rusty Russell,
	linux-sparse, Josh Triplett

On Tue, Dec 23, 2008 at 1:59 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
>
> Below. Or I can give it to you in git if you prefer. I still think we
> should redo this in some form so that annotations with different
> contexts can work properly, but I don't have time to take care of it
> right now.

Thanks for the patch. It applied cleanly. I am still checking weather I use git
properly. I will publish my git tree soon.

Chris

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2008-12-24  8:34 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-22  5:36 Casting away noderef and address spaces? Rusty Russell
2008-12-22 20:06 ` Christopher Li
2008-12-22 20:57   ` Al Viro
2008-12-22 21:23     ` Christopher Li
2008-12-22 21:39       ` Al Viro
2008-12-22 22:33         ` Christopher Li
2008-12-22 22:42           ` Harvey Harrison
2008-12-22 22:57           ` Sam Ravnborg
2008-12-22 23:53             ` Alexey Zaytsev
2008-12-22 23:55               ` Johannes Berg
2008-12-23  0:20                 ` Alexey Zaytsev
2008-12-23  0:35                   ` Johannes Berg
2008-12-23  0:37                   ` Johannes Berg
2008-12-23  1:25                     ` Christopher Li
2008-12-23  9:59                       ` Johannes Berg
2008-12-24  8:34                         ` Christopher Li
2008-12-23  2:14     ` Rusty Russell
2008-12-23  3:02       ` Christopher Li

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.