All of lore.kernel.org
 help / color / mirror / Atom feed
* [Cocci] Out of tree instrumentation with coccinelle demo
@ 2016-05-06 23:26 Luis R. Rodriguez
  2016-05-07 10:49 ` SF Markus Elfring
  2016-05-08 11:50 ` Sasha Levin
  0 siblings, 2 replies; 9+ messages in thread
From: Luis R. Rodriguez @ 2016-05-06 23:26 UTC (permalink / raw)
  To: cocci

Julia and I had discussed the possibility to instrument Linux code as
an alternative to complex debugging strategies (lockdep is one) that
often may be frowned upon due to how intrusive some changes may be or
how much extra stuff would be needed upstream. It has been hard to
explain the idea to folks who might make some use of it so I've gone
ahead and created a demo tree for userspace code that shows some basic
instrumentation ideas. You can fetch it here:

https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git

  Luis

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-06 23:26 [Cocci] Out of tree instrumentation with coccinelle demo Luis R. Rodriguez
@ 2016-05-07 10:49 ` SF Markus Elfring
  2016-05-08 11:50 ` Sasha Levin
  1 sibling, 0 replies; 9+ messages in thread
From: SF Markus Elfring @ 2016-05-07 10:49 UTC (permalink / raw)
  To: cocci

> You can fetch it here:
> https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git

* Can any source files be also reviewed by a web interface?

* Under which addresses would you like to discuss the suggested software developments?

Regards,
Markus

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-06 23:26 [Cocci] Out of tree instrumentation with coccinelle demo Luis R. Rodriguez
  2016-05-07 10:49 ` SF Markus Elfring
@ 2016-05-08 11:50 ` Sasha Levin
  2016-05-08 19:23   ` Luis R. Rodriguez
  1 sibling, 1 reply; 9+ messages in thread
From: Sasha Levin @ 2016-05-08 11:50 UTC (permalink / raw)
  To: cocci

On 05/06/2016 07:26 PM, Luis R. Rodriguez wrote:
> Julia and I had discussed the possibility to instrument Linux code as
> an alternative to complex debugging strategies (lockdep is one) that
> often may be frowned upon due to how intrusive some changes may be or
> how much extra stuff would be needed upstream. It has been hard to
> explain the idea to folks who might make some use of it so I've gone
> ahead and created a demo tree for userspace code that shows some basic
> instrumentation ideas. You can fetch it here:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git

Thanks Luis! I haven't reviewed it yet, just Cc'ing Quentin and Vegard
who are also working on the lock poisoning patchset.


Thanks,
Sasha

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-08 11:50 ` Sasha Levin
@ 2016-05-08 19:23   ` Luis R. Rodriguez
  2016-05-08 19:51     ` Julia Lawall
  2016-05-11 20:55     ` Luis R. Rodriguez
  0 siblings, 2 replies; 9+ messages in thread
From: Luis R. Rodriguez @ 2016-05-08 19:23 UTC (permalink / raw)
  To: cocci

On Sun, May 08, 2016 at 07:50:23AM -0400, Sasha Levin wrote:
> On 05/06/2016 07:26 PM, Luis R. Rodriguez wrote:
> > Julia and I had discussed the possibility to instrument Linux code as
> > an alternative to complex debugging strategies (lockdep is one) that
> > often may be frowned upon due to how intrusive some changes may be or
> > how much extra stuff would be needed upstream. It has been hard to
> > explain the idea to folks who might make some use of it so I've gone
> > ahead and created a demo tree for userspace code that shows some basic
> > instrumentation ideas. You can fetch it here:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git
> 
> Thanks Luis! I haven't reviewed it yet, just Cc'ing Quentin and Vegard
> who are also working on the lock poisoning patchset.

Another strategy can be to do instrumentation internally in Coccinelle
with the help of its standard rule dependency or extending use by
using Python scripting for a replacement for internall book keeping.

The patch below is a simple alternative to adding C instrumentation
code but instead it actually tries to fix the code given a certain
set of conditions and rules.

The cocci script doesn't work yet as I haven't figured out how to tell
coccinelle what is needed, but I'm confident its posible:

  * remove_helper_lock rule should take effect if
    helper_accessing_with_lock was found, but so was
    helper_accessing_without_lock, check_helpers,
    check_fn_access.

  * Likewise for fix_top_level -- we want to add the lock
    to the top level if helpers of both types were found,
    one which adds a lock and others which missed it

Oh and I forgot to place the unlock before pthread_exit() but
that's an easy fix. It should be possible to address all
these requirements within coccinelle, its just not clear
right now to me exactly how -- perhaps python variables?

  Luis

@ find_drv_name @
identifier drv;
identifier mutex;
@@

pthread_mutex_protects_3(&drv->mutex, ...);

@ find_hint @
type T;
T *drv;
identifier mutex, item_1, item_2, item_3;
@@

pthread_mutex_protects_3(&drv->mutex, drv->item_1, drv->item_2, drv->item_3);

@ find_pthread_fn depends on find_hint @
identifier fn, ret;
expression thread, attr, val;
@@

ret = pthread_create(thread, attr, fn, val);

@ check_fn_access @
identifier find_pthread_fn.fn;
type find_hint.T;
T *drv;
identifier find_hint.item_1;
identifier find_hint.item_2;
identifier find_hint.item_3;
@@

fn (...)
{
	<+...
(
	drv->item_1
|
	drv->item_2
|
	drv->item_3
)
        ...+>
}

@ check_helpers depends on find_pthread_fn @
identifier helper;
identifier find_pthread_fn.fn;
identifier find_hint.mutex;
type find_hint.T;
T *drv;
@@

fn (...)
{
	<+... when != pthread_mutex_lock(&drv->mutex);
	helper(...);
	...+>
}

@ helper_accessing_with_lock exists @
identifier check_helpers.helper;
type find_hint.T;
T *drv;
identifier find_hint.mutex;
identifier find_hint.item_1;
identifier find_hint.item_2;
identifier find_hint.item_3;
position p1, p2;
@@

helper(...)
{
	...
	pthread_mutex_lock at p1(&drv->mutex);
	<+...
(
	drv->item_1
|
	drv->item_2
|
	drv->item_3
)
        ...+>
	pthread_mutex_unlock at p2(&drv->mutex);
}

@ helper_accessing_without_lock exists @
identifier check_helpers.helper;
type find_hint.T;
T *drv;
identifier find_hint.mutex;
identifier find_hint.item_1;
identifier find_hint.item_2;
identifier find_hint.item_3;
@@

helper(...)
{
	<+... when != pthread_mutex_lock(&drv->mutex);
(
	drv->item_1
|
	drv->item_2
|
	drv->item_3
)
        ...+>
}

@ remove_helper_lock @
identifier check_helpers.helper;
type find_hint.T;
T *drv;
identifier find_hint.mutex;
identifier find_hint.item_1;
identifier find_hint.item_2;
identifier find_hint.item_3;
position helper_accessing_with_lock.p1, helper_accessing_with_lock.p2;
@@

helper(...)
{
	...
-	pthread_mutex_lock at p1(&drv->mutex);
	...
-	pthread_mutex_unlock at p2(&drv->mutex);
}


@ fix_top_level @
identifier find_pthread_fn.fn;
identifier find_hint.mutex;
identifier find_drv_name.drv;
@@

fn (...)
{
+	pthread_mutex_lock(&drv->mutex);
	...
+	pthread_mutex_unlock(&drv->mutex);
}

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-08 19:23   ` Luis R. Rodriguez
@ 2016-05-08 19:51     ` Julia Lawall
  2016-05-09 21:10       ` Luis R. Rodriguez
  2016-05-11 20:55     ` Luis R. Rodriguez
  1 sibling, 1 reply; 9+ messages in thread
From: Julia Lawall @ 2016-05-08 19:51 UTC (permalink / raw)
  To: cocci



On Sun, 8 May 2016, Luis R. Rodriguez wrote:

> On Sun, May 08, 2016 at 07:50:23AM -0400, Sasha Levin wrote:
> > On 05/06/2016 07:26 PM, Luis R. Rodriguez wrote:
> > > Julia and I had discussed the possibility to instrument Linux code as
> > > an alternative to complex debugging strategies (lockdep is one) that
> > > often may be frowned upon due to how intrusive some changes may be or
> > > how much extra stuff would be needed upstream. It has been hard to
> > > explain the idea to folks who might make some use of it so I've gone
> > > ahead and created a demo tree for userspace code that shows some basic
> > > instrumentation ideas. You can fetch it here:
> > > 
> > > https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git
> > 
> > Thanks Luis! I haven't reviewed it yet, just Cc'ing Quentin and Vegard
> > who are also working on the lock poisoning patchset.
> 
> Another strategy can be to do instrumentation internally in Coccinelle
> with the help of its standard rule dependency or extending use by
> using Python scripting for a replacement for internall book keeping.
> 
> The patch below is a simple alternative to adding C instrumentation
> code but instead it actually tries to fix the code given a certain
> set of conditions and rules.
> 
> The cocci script doesn't work yet as I haven't figured out how to tell
> coccinelle what is needed, but I'm confident its posible:
> 
>   * remove_helper_lock rule should take effect if
>     helper_accessing_with_lock was found, but so was
>     helper_accessing_without_lock, check_helpers,
>     check_fn_access.
> 
>   * Likewise for fix_top_level -- we want to add the lock
>     to the top level if helpers of both types were found,
>     one which adds a lock and others which missed it
> 
> Oh and I forgot to place the unlock before pthread_exit() but
> that's an easy fix. It should be possible to address all
> these requirements within coccinelle, its just not clear
> right now to me exactly how -- perhaps python variables?
> 
>   Luis
> 
> @ find_drv_name @
> identifier drv;
> identifier mutex;
> @@
> 
> pthread_mutex_protects_3(&drv->mutex, ...);
> 
> @ find_hint @
> type T;
> T *drv;
> identifier mutex, item_1, item_2, item_3;
> @@
> 
> pthread_mutex_protects_3(&drv->mutex, drv->item_1, drv->item_2, drv->item_3);

Why do you need both of the above rules?  I think that the second one 
should be fine.

> @ find_pthread_fn depends on find_hint @
> identifier fn, ret;
> expression thread, attr, val;
> @@
> 
> ret = pthread_create(thread, attr, fn, val);

The connection to find_hint is rather weak here.  Is there any way that 
they could be better tied together?

> @ check_fn_access @
> identifier find_pthread_fn.fn;
> type find_hint.T;
> T *drv;
> identifier find_hint.item_1;
> identifier find_hint.item_2;
> identifier find_hint.item_3;
> @@
> 
> fn (...)
> {
> 	<+...
> (
> 	drv->item_1
> |
> 	drv->item_2
> |
> 	drv->item_3
> )
>         ...+>
> }
>
> @ check_helpers depends on find_pthread_fn @
> identifier helper;
> identifier find_pthread_fn.fn;
> identifier find_hint.mutex;
> type find_hint.T;
> T *drv;
> @@
> 
> fn (...)
> {
> 	<+... when != pthread_mutex_lock(&drv->mutex);
> 	helper(...);
> 	...+>
> }

The depends on should not be needed in the above two rules, because they 
can only match if fn has a value, which can only happen if find_pthread_fn 
matched.

In each case, fn is the callback function of the thread_create.  I guess 
it is the function to be run by the thread.  The first rule looks for a 
direct reference to one of the protected fields.  The second rule looks 
for a call to another function, in the case where the protecting lock is 
not taken anywhere in the function.

I'm surprised that there is no consideration of the lock in the first 
rule.  The rules seem to be doing sort of the same thing, but don't have 
the same constraints.

But in general, I think that there are two cases that are wanted:

... when != lock()
XXX
... when any

and

... when any
unlock()
... when != lock()
XXX
... when any

That is, in the first case there has been no lock yet and in the second 
case there was an unlock and there was no subsequent lock.

> @ helper_accessing_with_lock exists @
> identifier check_helpers.helper;
> type find_hint.T;
> T *drv;
> identifier find_hint.mutex;
> identifier find_hint.item_1;
> identifier find_hint.item_2;
> identifier find_hint.item_3;
> position p1, p2;
> @@
> 
> helper(...)
> {
> 	...
> 	pthread_mutex_lock at p1(&drv->mutex);
> 	<+...
> (
> 	drv->item_1
> |
> 	drv->item_2
> |
> 	drv->item_3
> )
>         ...+>
> 	pthread_mutex_unlock at p2(&drv->mutex);
> }

This requires the unlock to be at the end of the function.  The whole 
function body should be surrounded in <+... ...+>

This is finding that everything is OK for the helper, because the helper 
has a lock of its own.

> @ helper_accessing_without_lock exists @
> identifier check_helpers.helper;
> type find_hint.T;
> T *drv;
> identifier find_hint.mutex;
> identifier find_hint.item_1;
> identifier find_hint.item_2;
> identifier find_hint.item_3;
> @@
> 
> helper(...)
> {
> 	<+... when != pthread_mutex_lock(&drv->mutex);
> (
> 	drv->item_1
> |
> 	drv->item_2
> |
> 	drv->item_3
> )
>         ...+>
> }

This one is finding that the helper is not correct, because it doesn't 
have a lock either, and it does have references.  See the above two 
patterns for a better way to match the case where the references are not 
in a lock.

> @ remove_helper_lock @
> identifier check_helpers.helper;
> type find_hint.T;
> T *drv;
> identifier find_hint.mutex;
> identifier find_hint.item_1;
> identifier find_hint.item_2;
> identifier find_hint.item_3;
> position helper_accessing_with_lock.p1, helper_accessing_with_lock.p2;
> @@
> 
> helper(...)
> {
> 	...
> -	pthread_mutex_lock at p1(&drv->mutex);
> 	...
> -	pthread_mutex_unlock at p2(&drv->mutex);
> }
> 
> 
> @ fix_top_level @
> identifier find_pthread_fn.fn;
> identifier find_hint.mutex;
> identifier find_drv_name.drv;
> @@
> 
> fn (...)
> {
> +	pthread_mutex_lock(&drv->mutex);
> 	...
> +	pthread_mutex_unlock(&drv->mutex);
> }

Hmm, not sure to understand the goal of the above two rules.  Why do you 
want to put the lock around the entire body of the callback function?

The weakness seems to be that helper has to be called directly from the 
callback function.  One would have to use iteration to trace the calls 
down more deeply.

Also, the whole set of rules would be needed for 1, 2, 3, ...  With 
iteration, one could schedule the work on the protected fields one by one, 
if the protection declaration could take any number of arguments.

julia

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-08 19:51     ` Julia Lawall
@ 2016-05-09 21:10       ` Luis R. Rodriguez
  2016-05-09 21:24         ` Julia Lawall
  0 siblings, 1 reply; 9+ messages in thread
From: Luis R. Rodriguez @ 2016-05-09 21:10 UTC (permalink / raw)
  To: cocci

On Sun, May 08, 2016 at 09:51:43PM +0200, Julia Lawall wrote:
> On Sun, 8 May 2016, Luis R. Rodriguez wrote:
> > @ find_drv_name @
> > identifier drv;
> > identifier mutex;
> > @@
> > 
> > pthread_mutex_protects_3(&drv->mutex, ...);
> > 
> > @ find_hint @
> > type T;
> > T *drv;
> > identifier mutex, item_1, item_2, item_3;
> > @@
> > 
> > pthread_mutex_protects_3(&drv->mutex, drv->item_1, drv->item_2, drv->item_3);
> 
> Why do you need both of the above rules?  I think that the second one 
> should be fine.

The second one infers the type but does not care for the location of
drv, the first one is used to get the name of the global variable.
We cannot share *drv from the second rule on further rules.

> > @ find_pthread_fn depends on find_hint @
> > identifier fn, ret;
> > expression thread, attr, val;
> > @@
> > 
> > ret = pthread_create(thread, attr, fn, val);
> 
> The connection to find_hint is rather weak here.  Is there any way that 
> they could be better tied together?

The hint would be very application and domain specific, in the pthread case we
could for instance extend the hint support to be pthread related and also
require the hint to require the callback.

To make emphasis of this as a desired change I'll go ahead and do that
but also document how this is application specific.

> > @ check_fn_access @
> > identifier find_pthread_fn.fn;
> > type find_hint.T;
> > T *drv;
> > identifier find_hint.item_1;
> > identifier find_hint.item_2;
> > identifier find_hint.item_3;
> > @@
> > 
> > fn (...)
> > {
> > 	<+...
> > (
> > 	drv->item_1
> > |
> > 	drv->item_2
> > |
> > 	drv->item_3
> > )
> >         ...+>
> > }
> >
> > @ check_helpers depends on find_pthread_fn @
> > identifier helper;
> > identifier find_pthread_fn.fn;
> > identifier find_hint.mutex;
> > type find_hint.T;
> > T *drv;
> > @@
> > 
> > fn (...)
> > {
> > 	<+... when != pthread_mutex_lock(&drv->mutex);
> > 	helper(...);
> > 	...+>
> > }
> 
> The depends on should not be needed in the above two rules, because they 
> can only match if fn has a value, which can only happen if find_pthread_fn 
> matched.

Amended, thanks!

> In each case, fn is the callback function of the thread_create.  I guess 
> it is the function to be run by the thread.

Right, each thread.

> The first rule looks for a 
> direct reference to one of the protected fields.  The second rule looks 
> for a call to another function, in the case where the protecting lock is 
> not taken anywhere in the function.

Right. Its the same routine though, and now I understand why you mentioned
that the hint was rather loose with respect to fn.


> I'm surprised that there is no consideration of the lock in the first 
> rule.  The rules seem to be doing sort of the same thing, but don't have 
> the same constraints.

Right, so since fn is the same (but could have been any as you noted, but
constrained in the iteration I posted to pthread_create()) I split this up to
enable to query if fn made reference to any of the protected fields, separately
from querying if fn had the lock but also had helpers.  Its certainly possible
to combine them but I cared more for knowing the lock was not held during each
helper's use. Since fn is the same for both (this is made stronger with the
suggestion you made of making a stringer link, which I'm now implementing
by requiring the hint to be explicit about the call that we'd start
caring about the critical areas for), I could later ask simply if both
cases were true, and likewise a mismatch of helpers with / without locks
existed, then the right thing to do would be move to move the lock to
the initial fn call.

Technically this would miss the case where fn() accesses the critical sections
with a lock but does not hold the lock for the helpers. Will fix this then
by joining the rules.

> But in general, I think that there are two cases that are wanted:
> 
> ... when != lock()
> XXX
> ... when any
> 
> and
> 
> ... when any
> unlock()
> ... when != lock()
> XXX
> ... when any
> 
> That is, in the first case there has been no lock yet and in the second 
> case there was an unlock and there was no subsequent lock.

Yes, for simplicity, given this is just an example, can we just
consense this as follows:

fn (...)
{
	<+... when != \(pthread_mutex_lock(&drv->mutex)\|pthread_mutex_lock(&drv->mutex)\)
(
	drv->item_1
|
	drv->item_2
|
	drv->item_3
|
	helper(...)
)
	...+>
}

There may be more complex fn() where things get intertwined, for instance a
lock here and there, but some code without a lock, but since this is an example,
I think simply ensuring no lock is used at all is fair. Thoughts ?

> > @ helper_accessing_with_lock exists @
> > identifier check_helpers.helper;
> > type find_hint.T;
> > T *drv;
> > identifier find_hint.mutex;
> > identifier find_hint.item_1;
> > identifier find_hint.item_2;
> > identifier find_hint.item_3;
> > position p1, p2;
> > @@
> > 
> > helper(...)
> > {
> > 	...
> > 	pthread_mutex_lock at p1(&drv->mutex);
> > 	<+...
> > (
> > 	drv->item_1
> > |
> > 	drv->item_2
> > |
> > 	drv->item_3
> > )
> >         ...+>
> > 	pthread_mutex_unlock at p2(&drv->mutex);
> > }
> 
> This requires the unlock to be at the end of the function.  The whole 
> function body should be surrounded in <+... ...+>

Indeed, thanks.

> This is finding that everything is OK for the helper, because the helper 
> has a lock of its own.

Correct.

> > @ helper_accessing_without_lock exists @
> > identifier check_helpers.helper;
> > type find_hint.T;
> > T *drv;
> > identifier find_hint.mutex;
> > identifier find_hint.item_1;
> > identifier find_hint.item_2;
> > identifier find_hint.item_3;
> > @@
> > 
> > helper(...)
> > {
> > 	<+... when != pthread_mutex_lock(&drv->mutex);
> > (
> > 	drv->item_1
> > |
> > 	drv->item_2
> > |
> > 	drv->item_3
> > )
> >         ...+>
> > }
> 
> This one is finding that the helper is not correct, because it doesn't 
> have a lock either, and it does have references.  See the above two 
> patterns for a better way to match the case where the references are not 
> in a lock.

Thanks.

> > @ remove_helper_lock @
> > identifier check_helpers.helper;
> > type find_hint.T;
> > T *drv;
> > identifier find_hint.mutex;
> > identifier find_hint.item_1;
> > identifier find_hint.item_2;
> > identifier find_hint.item_3;
> > position helper_accessing_with_lock.p1, helper_accessing_with_lock.p2;
> > @@
> > 
> > helper(...)
> > {
> > 	...
> > -	pthread_mutex_lock at p1(&drv->mutex);
> > 	...
> > -	pthread_mutex_unlock at p2(&drv->mutex);
> > }
> > 
> > 
> > @ fix_top_level @
> > identifier find_pthread_fn.fn;
> > identifier find_hint.mutex;
> > identifier find_drv_name.drv;
> > @@
> > 
> > fn (...)
> > {
> > +	pthread_mutex_lock(&drv->mutex);
> > 	...
> > +	pthread_mutex_unlock(&drv->mutex);
> > }
> 
> Hmm, not sure to understand the goal of the above two rules.  Why do you 
> want to put the lock around the entire body of the callback function?

Great question.

That's because the state machine used is a bit fragile, it requires
that the thread state (party->tid_status[tid]) must be in sync with
an action, in this case eat() or cleanup(). So there are two fixes
to the locking of this program with the current sample implementation:

0. Although the program has fed us hints about the critical section a
   mutex protects it has not provided any hints about the state machine
   used. When that's true, one can only assume all variables that are
   critical could be part of the state machine as it is difficult
   to infer what defines the state machine. If a state machine is used
   and relied as part of the critical sections protected by a lock
   its access must be held serially over full access to all other
   critical variables. To see this one can try a simple fix by locking
   only whenever any critical section is accessed, and see how it has
   issues:

diff --git a/main.c b/main.c
index 2fe9a0f9919f..3685d27425d3 100644
--- a/main.c
+++ b/main.c
@@ -65,6 +65,7 @@ void cleanup(long tid)
 	bool clean_follow = true;
 	long t;
 
+	pthread_mutex_lock(&party->mutex);
 	for (t=0; t < NUM_THREADS; t++) {
 		if (t == tid)
 			continue;
@@ -75,13 +76,16 @@ void cleanup(long tid)
 
 	if (clean_follow)
 		party->trash[tid] = 1;
+	pthread_mutex_unlock(&party->mutex);
 }
 
 void *thread_party(void *t)
 {
 	long tid = (long)t;
 
+	pthread_mutex_lock(&party->mutex);
 	party->tid_status[tid] = THREAD_AT_PARTY;
+	pthread_mutex_unlock(&party->mutex);
 
 	eat(tid);
 
@@ -90,7 +94,9 @@ void *thread_party(void *t)
 
 	cleanup(tid);
 
+	pthread_mutex_lock(&party->mutex);
 	party->tid_status[tid] = THREAD_DONE;
+	pthread_mutex_unlock(&party->mutex);
 
 	pthread_exit(NULL);
 }

   With this in place all critical sections are now locked, however
   there are still issues seen at run time. In lack of any information
   about the state machine implementation one can only assume the worst,
   and lock serially, as follows:

diff --git a/main.c b/main.c
index 2fe9a0f9919f..1bd89b9186c0 100644
--- a/main.c
+++ b/main.c
@@ -42,7 +42,6 @@ void eat(long tid)
 	bool eat_in_order = true;
 	long t;
 
-	pthread_mutex_lock(&party->mutex);
 	/* If anyone ate out of place lets take notice of that... */
 	for (t=0; t < NUM_THREADS; t++) {
 		if (t == tid)
@@ -57,7 +56,6 @@ void eat(long tid)
 	if (party->food[tid])
 		if (eat_in_order)
 			party->food[tid] = 0;
-	pthread_mutex_unlock(&party->mutex);
 }
 
 void cleanup(long tid)
@@ -81,6 +79,7 @@ void *thread_party(void *t)
 {
 	long tid = (long)t;
 
+	pthread_mutex_lock(&party->mutex);
 	party->tid_status[tid] = THREAD_AT_PARTY;
 
 	eat(tid);
@@ -91,6 +90,7 @@ void *thread_party(void *t)
 	cleanup(tid);
 
 	party->tid_status[tid] = THREAD_DONE;
+	pthread_mutex_unlock(&party->mutex);
 
 	pthread_exit(NULL);
 }


   This is the strategy the current SmPL patch tries to address.

1. With access to state machine hints Coccinelle may be able
   to do more, that would be step 2 in optimization for a solution
   here, the outlook of the hint and SmPL patch should be considered
   as a secondary step in evolving this instrumentation, but the
   results are as follows:

diff --git a/main.c b/main.c
index 2fe9a0f9919f..518b8c5c843b 100644
--- a/main.c
+++ b/main.c
@@ -42,7 +42,6 @@ void eat(long tid)
 	bool eat_in_order = true;
 	long t;
 
-	pthread_mutex_lock(&party->mutex);
 	/* If anyone ate out of place lets take notice of that... */
 	for (t=0; t < NUM_THREADS; t++) {
 		if (t == tid)
@@ -57,7 +56,6 @@ void eat(long tid)
 	if (party->food[tid])
 		if (eat_in_order)
 			party->food[tid] = 0;
-	pthread_mutex_unlock(&party->mutex);
 }
 
 void cleanup(long tid)
@@ -81,16 +79,20 @@ void *thread_party(void *t)
 {
 	long tid = (long)t;
 
+	pthread_mutex_lock(&party->mutex);
 	party->tid_status[tid] = THREAD_AT_PARTY;
 
 	eat(tid);
+	pthread_mutex_unlock(&party->mutex);
 
 	if (tid % 2 == 1)
 		sleep_random();
 
+	pthread_mutex_lock(&party->mutex);
 	cleanup(tid);
 
 	party->tid_status[tid] = THREAD_DONE;
+	pthread_mutex_unlock(&party->mutex);
 
 	pthread_exit(NULL);
 }

   In this case the state machine, party->tid_status is only
   locked serially against access helpers to the critical
   sections.

> The weakness seems to be that helper has to be called directly from the 
> callback function.

In this case yes, that is true.

> One would have to use iteration to trace the calls  down more deeply.

I see, thanks!

> Also, the whole set of rules would be needed for 1, 2, 3, ...  With 
> iteration, one could schedule the work on the protected fields one by one, 
> if the protection declaration could take any number of arguments.

Interesting, thanks. Its not clear how we could devise a strategy in C
to enable overloading, if that's what you mean, otherwise I was not able
to follow what you hinted at here.

  Luis

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-09 21:10       ` Luis R. Rodriguez
@ 2016-05-09 21:24         ` Julia Lawall
  0 siblings, 0 replies; 9+ messages in thread
From: Julia Lawall @ 2016-05-09 21:24 UTC (permalink / raw)
  To: cocci



On Mon, 9 May 2016, Luis R. Rodriguez wrote:

> On Sun, May 08, 2016 at 09:51:43PM +0200, Julia Lawall wrote:
> > On Sun, 8 May 2016, Luis R. Rodriguez wrote:
> > > @ find_drv_name @
> > > identifier drv;
> > > identifier mutex;
> > > @@
> > > 
> > > pthread_mutex_protects_3(&drv->mutex, ...);
> > > 
> > > @ find_hint @
> > > type T;
> > > T *drv;
> > > identifier mutex, item_1, item_2, item_3;
> > > @@
> > > 
> > > pthread_mutex_protects_3(&drv->mutex, drv->item_1, drv->item_2, drv->item_3);
> > 
> > Why do you need both of the above rules?  I think that the second one 
> > should be fine.
> 
> The second one infers the type but does not care for the location of
> drv, the first one is used to get the name of the global variable.
> We cannot share *drv from the second rule on further rules.

What global variable?  Why can't you use the drv from the second rule in 
other rules?

> > > @ find_pthread_fn depends on find_hint @
> > > identifier fn, ret;
> > > expression thread, attr, val;
> > > @@
> > > 
> > > ret = pthread_create(thread, attr, fn, val);
> > 
> > The connection to find_hint is rather weak here.  Is there any way that 
> > they could be better tied together?
> 
> The hint would be very application and domain specific, in the pthread case we
> could for instance extend the hint support to be pthread related and also
> require the hint to require the callback.
> 
> To make emphasis of this as a desired change I'll go ahead and do that
> but also document how this is application specific.
> 
> > > @ check_fn_access @
> > > identifier find_pthread_fn.fn;
> > > type find_hint.T;
> > > T *drv;
> > > identifier find_hint.item_1;
> > > identifier find_hint.item_2;
> > > identifier find_hint.item_3;
> > > @@
> > > 
> > > fn (...)
> > > {
> > > 	<+...
> > > (
> > > 	drv->item_1
> > > |
> > > 	drv->item_2
> > > |
> > > 	drv->item_3
> > > )
> > >         ...+>
> > > }
> > >
> > > @ check_helpers depends on find_pthread_fn @
> > > identifier helper;
> > > identifier find_pthread_fn.fn;
> > > identifier find_hint.mutex;
> > > type find_hint.T;
> > > T *drv;
> > > @@
> > > 
> > > fn (...)
> > > {
> > > 	<+... when != pthread_mutex_lock(&drv->mutex);
> > > 	helper(...);
> > > 	...+>
> > > }
> > 
> > The depends on should not be needed in the above two rules, because they 
> > can only match if fn has a value, which can only happen if find_pthread_fn 
> > matched.
> 
> Amended, thanks!
> 
> > In each case, fn is the callback function of the thread_create.  I guess 
> > it is the function to be run by the thread.
> 
> Right, each thread.
> 
> > The first rule looks for a 
> > direct reference to one of the protected fields.  The second rule looks 
> > for a call to another function, in the case where the protecting lock is 
> > not taken anywhere in the function.
> 
> Right. Its the same routine though, and now I understand why you mentioned
> that the hint was rather loose with respect to fn.
> 
> 
> > I'm surprised that there is no consideration of the lock in the first 
> > rule.  The rules seem to be doing sort of the same thing, but don't have 
> > the same constraints.
> 
> Right, so since fn is the same (but could have been any as you noted, but
> constrained in the iteration I posted to pthread_create()) I split this up to
> enable to query if fn made reference to any of the protected fields, separately
> from querying if fn had the lock but also had helpers.  Its certainly possible
> to combine them but I cared more for knowing the lock was not held during each
> helper's use. Since fn is the same for both (this is made stronger with the
> suggestion you made of making a stringer link, which I'm now implementing
> by requiring the hint to be explicit about the call that we'd start
> caring about the critical areas for), I could later ask simply if both
> cases were true, and likewise a mismatch of helpers with / without locks
> existed, then the right thing to do would be move to move the lock to
> the initial fn call.
> 
> Technically this would miss the case where fn() accesses the critical sections
> with a lock but does not hold the lock for the helpers. Will fix this then
> by joining the rules.
> 
> > But in general, I think that there are two cases that are wanted:
> > 
> > ... when != lock()
> > XXX
> > ... when any
> > 
> > and
> > 
> > ... when any
> > unlock()
> > ... when != lock()
> > XXX
> > ... when any
> > 
> > That is, in the first case there has been no lock yet and in the second 
> > case there was an unlock and there was no subsequent lock.
> 
> Yes, for simplicity, given this is just an example, can we just
> consense this as follows:
> 
> fn (...)
> {
> 	<+... when != \(pthread_mutex_lock(&drv->mutex)\|pthread_mutex_lock(&drv->mutex)\)
> (
> 	drv->item_1
> |
> 	drv->item_2
> |
> 	drv->item_3
> |
> 	helper(...)
> )
> 	...+>
> }
> 
> There may be more complex fn() where things get intertwined, for instance a
> lock here and there, but some code without a lock, but since this is an example,
> I think simply ensuring no lock is used at all is fair. Thoughts ?

This doesn't work.  Actually, the original check_helpers didn't work 
either.  The problem is that helper is inside a <+... ...+> and it is 
inherited by a later rule.  Due to the inheritance, there has to be a 
single value of helper that covers the entire rule.  But the function 
could call more than one helper function.  To allow that you need

... when any
helper(...)
... when any

You may as well further put exists on the rule header also.  Basically you 
want to consider each called function individually.

> > > @ helper_accessing_with_lock exists @
> > > identifier check_helpers.helper;
> > > type find_hint.T;
> > > T *drv;
> > > identifier find_hint.mutex;
> > > identifier find_hint.item_1;
> > > identifier find_hint.item_2;
> > > identifier find_hint.item_3;
> > > position p1, p2;
> > > @@
> > > 
> > > helper(...)
> > > {
> > > 	...
> > > 	pthread_mutex_lock at p1(&drv->mutex);
> > > 	<+...
> > > (
> > > 	drv->item_1
> > > |
> > > 	drv->item_2
> > > |
> > > 	drv->item_3
> > > )
> > >         ...+>
> > > 	pthread_mutex_unlock at p2(&drv->mutex);
> > > }
> > 
> > This requires the unlock to be at the end of the function.  The whole 
> > function body should be surrounded in <+... ...+>
> 
> Indeed, thanks.
> 
> > This is finding that everything is OK for the helper, because the helper 
> > has a lock of its own.
> 
> Correct.
> 
> > > @ helper_accessing_without_lock exists @
> > > identifier check_helpers.helper;
> > > type find_hint.T;
> > > T *drv;
> > > identifier find_hint.mutex;
> > > identifier find_hint.item_1;
> > > identifier find_hint.item_2;
> > > identifier find_hint.item_3;
> > > @@
> > > 
> > > helper(...)
> > > {
> > > 	<+... when != pthread_mutex_lock(&drv->mutex);
> > > (
> > > 	drv->item_1
> > > |
> > > 	drv->item_2
> > > |
> > > 	drv->item_3
> > > )
> > >         ...+>
> > > }
> > 
> > This one is finding that the helper is not correct, because it doesn't 
> > have a lock either, and it does have references.  See the above two 
> > patterns for a better way to match the case where the references are not 
> > in a lock.
> 
> Thanks.
> 
> > > @ remove_helper_lock @
> > > identifier check_helpers.helper;
> > > type find_hint.T;
> > > T *drv;
> > > identifier find_hint.mutex;
> > > identifier find_hint.item_1;
> > > identifier find_hint.item_2;
> > > identifier find_hint.item_3;
> > > position helper_accessing_with_lock.p1, helper_accessing_with_lock.p2;
> > > @@
> > > 
> > > helper(...)
> > > {
> > > 	...
> > > -	pthread_mutex_lock at p1(&drv->mutex);
> > > 	...
> > > -	pthread_mutex_unlock at p2(&drv->mutex);
> > > }
> > > 
> > > 
> > > @ fix_top_level @
> > > identifier find_pthread_fn.fn;
> > > identifier find_hint.mutex;
> > > identifier find_drv_name.drv;
> > > @@
> > > 
> > > fn (...)
> > > {
> > > +	pthread_mutex_lock(&drv->mutex);
> > > 	...
> > > +	pthread_mutex_unlock(&drv->mutex);
> > > }
> > 
> > Hmm, not sure to understand the goal of the above two rules.  Why do you 
> > want to put the lock around the entire body of the callback function?
> 
> Great question.
> 
> That's because the state machine used is a bit fragile, it requires
> that the thread state (party->tid_status[tid]) must be in sync with
> an action, in this case eat() or cleanup(). So there are two fixes
> to the locking of this program with the current sample implementation:
> 
> 0. Although the program has fed us hints about the critical section a
>    mutex protects it has not provided any hints about the state machine
>    used. When that's true, one can only assume all variables that are
>    critical could be part of the state machine as it is difficult
>    to infer what defines the state machine. If a state machine is used
>    and relied as part of the critical sections protected by a lock
>    its access must be held serially over full access to all other
>    critical variables. To see this one can try a simple fix by locking
>    only whenever any critical section is accessed, and see how it has
>    issues:
> 
> diff --git a/main.c b/main.c
> index 2fe9a0f9919f..3685d27425d3 100644
> --- a/main.c
> +++ b/main.c
> @@ -65,6 +65,7 @@ void cleanup(long tid)
>  	bool clean_follow = true;
>  	long t;
>  
> +	pthread_mutex_lock(&party->mutex);
>  	for (t=0; t < NUM_THREADS; t++) {
>  		if (t == tid)
>  			continue;
> @@ -75,13 +76,16 @@ void cleanup(long tid)
>  
>  	if (clean_follow)
>  		party->trash[tid] = 1;
> +	pthread_mutex_unlock(&party->mutex);
>  }
>  
>  void *thread_party(void *t)
>  {
>  	long tid = (long)t;
>  
> +	pthread_mutex_lock(&party->mutex);
>  	party->tid_status[tid] = THREAD_AT_PARTY;
> +	pthread_mutex_unlock(&party->mutex);
>  
>  	eat(tid);
>  
> @@ -90,7 +94,9 @@ void *thread_party(void *t)
>  
>  	cleanup(tid);
>  
> +	pthread_mutex_lock(&party->mutex);
>  	party->tid_status[tid] = THREAD_DONE;
> +	pthread_mutex_unlock(&party->mutex);
>  
>  	pthread_exit(NULL);
>  }
> 
>    With this in place all critical sections are now locked, however
>    there are still issues seen at run time. In lack of any information
>    about the state machine implementation one can only assume the worst,
>    and lock serially, as follows:
> 
> diff --git a/main.c b/main.c
> index 2fe9a0f9919f..1bd89b9186c0 100644
> --- a/main.c
> +++ b/main.c
> @@ -42,7 +42,6 @@ void eat(long tid)
>  	bool eat_in_order = true;
>  	long t;
>  
> -	pthread_mutex_lock(&party->mutex);
>  	/* If anyone ate out of place lets take notice of that... */
>  	for (t=0; t < NUM_THREADS; t++) {
>  		if (t == tid)
> @@ -57,7 +56,6 @@ void eat(long tid)
>  	if (party->food[tid])
>  		if (eat_in_order)
>  			party->food[tid] = 0;
> -	pthread_mutex_unlock(&party->mutex);
>  }
>  
>  void cleanup(long tid)
> @@ -81,6 +79,7 @@ void *thread_party(void *t)
>  {
>  	long tid = (long)t;
>  
> +	pthread_mutex_lock(&party->mutex);
>  	party->tid_status[tid] = THREAD_AT_PARTY;
>  
>  	eat(tid);
> @@ -91,6 +90,7 @@ void *thread_party(void *t)
>  	cleanup(tid);
>  
>  	party->tid_status[tid] = THREAD_DONE;
> +	pthread_mutex_unlock(&party->mutex);
>  
>  	pthread_exit(NULL);
>  }
> 
> 
>    This is the strategy the current SmPL patch tries to address.
> 
> 1. With access to state machine hints Coccinelle may be able
>    to do more, that would be step 2 in optimization for a solution
>    here, the outlook of the hint and SmPL patch should be considered
>    as a secondary step in evolving this instrumentation, but the
>    results are as follows:
> 
> diff --git a/main.c b/main.c
> index 2fe9a0f9919f..518b8c5c843b 100644
> --- a/main.c
> +++ b/main.c
> @@ -42,7 +42,6 @@ void eat(long tid)
>  	bool eat_in_order = true;
>  	long t;
>  
> -	pthread_mutex_lock(&party->mutex);
>  	/* If anyone ate out of place lets take notice of that... */
>  	for (t=0; t < NUM_THREADS; t++) {
>  		if (t == tid)
> @@ -57,7 +56,6 @@ void eat(long tid)
>  	if (party->food[tid])
>  		if (eat_in_order)
>  			party->food[tid] = 0;
> -	pthread_mutex_unlock(&party->mutex);
>  }
>  
>  void cleanup(long tid)
> @@ -81,16 +79,20 @@ void *thread_party(void *t)
>  {
>  	long tid = (long)t;
>  
> +	pthread_mutex_lock(&party->mutex);
>  	party->tid_status[tid] = THREAD_AT_PARTY;
>  
>  	eat(tid);
> +	pthread_mutex_unlock(&party->mutex);
>  
>  	if (tid % 2 == 1)
>  		sleep_random();
>  
> +	pthread_mutex_lock(&party->mutex);
>  	cleanup(tid);
>  
>  	party->tid_status[tid] = THREAD_DONE;
> +	pthread_mutex_unlock(&party->mutex);
>  
>  	pthread_exit(NULL);
>  }
> 
>    In this case the state machine, party->tid_status is only
>    locked serially against access helpers to the critical
>    sections.
> 
> > The weakness seems to be that helper has to be called directly from the 
> > callback function.
> 
> In this case yes, that is true.
> 
> > One would have to use iteration to trace the calls  down more deeply.
> 
> I see, thanks!
> 
> > Also, the whole set of rules would be needed for 1, 2, 3, ...  With 
> > iteration, one could schedule the work on the protected fields one by one, 
> > if the protection declaration could take any number of arguments.
> 
> Interesting, thanks. Its not clear how we could devise a strategy in C
> to enable overloading, if that's what you mean, otherwise I was not able
> to follow what you hinted at here.

pthread_mutex_protects_3(&drv->mutex, ..., drv->item, ...);

This will match in three ways, for the three drv->item arguments.  Care
would of course have to be taken to avoid ending up with triple locks and
unlocks.

But if in your use case, you always have three fields, then you may as well
make the rule specific to that.

julia

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-08 19:23   ` Luis R. Rodriguez
  2016-05-08 19:51     ` Julia Lawall
@ 2016-05-11 20:55     ` Luis R. Rodriguez
  2016-05-12  7:20       ` Julia Lawall
  1 sibling, 1 reply; 9+ messages in thread
From: Luis R. Rodriguez @ 2016-05-11 20:55 UTC (permalink / raw)
  To: cocci

On Sun, May 08, 2016 at 09:23:03PM +0200, Luis R. Rodriguez wrote:
> On Sun, May 08, 2016 at 07:50:23AM -0400, Sasha Levin wrote:
> > On 05/06/2016 07:26 PM, Luis R. Rodriguez wrote:
> > > Julia and I had discussed the possibility to instrument Linux code as
> > > an alternative to complex debugging strategies (lockdep is one) that
> > > often may be frowned upon due to how intrusive some changes may be or
> > > how much extra stuff would be needed upstream. It has been hard to
> > > explain the idea to folks who might make some use of it so I've gone
> > > ahead and created a demo tree for userspace code that shows some basic
> > > instrumentation ideas. You can fetch it here:
> > > 
> > > https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git
> > 
> > Thanks Luis! I haven't reviewed it yet, just Cc'ing Quentin and Vegard
> > who are also working on the lock poisoning patchset.
> 
> Another strategy can be to do instrumentation internally in Coccinelle
> with the help of its standard rule dependency or extending use by
> using Python scripting for a replacement for internall book keeping.
> 
> The patch below is a simple alternative to adding C instrumentation
> code but instead it actually tries to fix the code given a certain
> set of conditions and rules.

<-- snip -->

Lastly, it just occurred to me that if a set of Coccinelle scripts
do not suffice (I mentioned two options for instrumentation), another
alternative building off of the first Coccinelle approach I mentioned
would be to complement that with *new code* and *regular patches* that
would otherwise simply not be appropriate with just Coccinelle. For
instance, take the addition of code which initializes the instrumentation,
or helpers definitions which may be generic. This need not belong in
each piece of kernel code but perhaps more in a generic place, and if
not upstream, one alternative can be a kernel complement framework to
enable both to co-exist. It took me a bit to realize that we already
have this... but once I realized it, it became an obvious alternative:
the Linux backports infrastructure [0] already enables:

  a) serializing applying regular patches, and
  b) if one finds generalization rules also serializes
     applying series Coccinelle SmPL patches
  c) adding custom code which any of the above can use
     through its own module (compat)
  d) enables for module replacements (using depmod.d updates/),
     so your distro has iwlagn for v3.5, backports lets you get
     iwlagn update from code as of v4.3 [1]
  e) enables as an alternative kenrel integration [2]

In a way, the backports infrastructure provides a framework to let
you roll out your own customized Linux distribution but with utmost
focus upstream. For backports this makes sense -- we just re-use
upstream and port. We do this as backporting is not welcomed upstream
as it would mean having to add tons of nasty #ifdefs, and helper code..
sound familiar? Instrumentation code which may be considered
"too intrusive to have upstream" is another possible candidate
that can benefit from it given all the bells and whistles have been
ironed out already -- we strive to automate backporting ;)

Now granted, we didn't set out to write backports to make it a generic
framework, but -- its there, and if you guys have such an interest
I think we can both benefit from collaborations... that is unless
you do find a reasonable way to just shove everything upstream.

[0] https://backports.wiki.kernel.org
[1] https://backports.wiki.kernel.org/index.php/Documentation/packaging
[2] https://backports.wiki.kernel.org/index.php/Documentation/integration

  Luis

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

* [Cocci] Out of tree instrumentation with coccinelle demo
  2016-05-11 20:55     ` Luis R. Rodriguez
@ 2016-05-12  7:20       ` Julia Lawall
  0 siblings, 0 replies; 9+ messages in thread
From: Julia Lawall @ 2016-05-12  7:20 UTC (permalink / raw)
  To: cocci



On Wed, 11 May 2016, Luis R. Rodriguez wrote:

> On Sun, May 08, 2016 at 09:23:03PM +0200, Luis R. Rodriguez wrote:
> > On Sun, May 08, 2016 at 07:50:23AM -0400, Sasha Levin wrote:
> > > On 05/06/2016 07:26 PM, Luis R. Rodriguez wrote:
> > > > Julia and I had discussed the possibility to instrument Linux code as
> > > > an alternative to complex debugging strategies (lockdep is one) that
> > > > often may be frowned upon due to how intrusive some changes may be or
> > > > how much extra stuff would be needed upstream. It has been hard to
> > > > explain the idea to folks who might make some use of it so I've gone
> > > > ahead and created a demo tree for userspace code that shows some basic
> > > > instrumentation ideas. You can fetch it here:
> > > >
> > > > https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/cocci-tact.git
> > >
> > > Thanks Luis! I haven't reviewed it yet, just Cc'ing Quentin and Vegard
> > > who are also working on the lock poisoning patchset.
> >
> > Another strategy can be to do instrumentation internally in Coccinelle
> > with the help of its standard rule dependency or extending use by
> > using Python scripting for a replacement for internall book keeping.
> >
> > The patch below is a simple alternative to adding C instrumentation
> > code but instead it actually tries to fix the code given a certain
> > set of conditions and rules.
>
> <-- snip -->
>
> Lastly, it just occurred to me that if a set of Coccinelle scripts
> do not suffice (I mentioned two options for instrumentation), another
> alternative building off of the first Coccinelle approach I mentioned
> would be to complement that with *new code* and *regular patches* that
> would otherwise simply not be appropriate with just Coccinelle. For
> instance, take the addition of code which initializes the instrumentation,
> or helpers definitions which may be generic. This need not belong in
> each piece of kernel code but perhaps more in a generic place, and if
> not upstream, one alternative can be a kernel complement framework to
> enable both to co-exist. It took me a bit to realize that we already
> have this... but once I realized it, it became an obvious alternative:
> the Linux backports infrastructure [0] already enables:
>
>   a) serializing applying regular patches, and
>   b) if one finds generalization rules also serializes
>      applying series Coccinelle SmPL patches
>   c) adding custom code which any of the above can use
>      through its own module (compat)
>   d) enables for module replacements (using depmod.d updates/),
>      so your distro has iwlagn for v3.5, backports lets you get
>      iwlagn update from code as of v4.3 [1]
>   e) enables as an alternative kenrel integration [2]
>
> In a way, the backports infrastructure provides a framework to let
> you roll out your own customized Linux distribution but with utmost
> focus upstream. For backports this makes sense -- we just re-use
> upstream and port. We do this as backporting is not welcomed upstream
> as it would mean having to add tons of nasty #ifdefs, and helper code..
> sound familiar? Instrumentation code which may be considered
> "too intrusive to have upstream" is another possible candidate
> that can benefit from it given all the bells and whistles have been
> ironed out already -- we strive to automate backporting ;)
>
> Now granted, we didn't set out to write backports to make it a generic
> framework, but -- its there, and if you guys have such an interest
> I think we can both benefit from collaborations... that is unless
> you do find a reasonable way to just shove everything upstream.
>
> [0] https://backports.wiki.kernel.org
> [1] https://backports.wiki.kernel.org/index.php/Documentation/packaging
> [2] https://backports.wiki.kernel.org/index.php/Documentation/integration

I'm just throwing thi out there as another idea, but maybe what is wanted
is a domain-specific language (DSL) in which to express locking
requirements, ie the fields that a lock protects and the entry points at
which this protection is not needed, and then from the DSL one could
generate semanticpatches or something else to do the right thing.  The
downside of the approach is the need to learn yet another language.  The
upside is that the language would hopefully be very simple.

On the other hand, I think that this information would be really helpful
for developers.  So maybe some code pollution could be tolerable.  The
developer who is only interested in getting correct code and moving
forward might not care about backporting, but that person does need to
know about locking invariants.

julia

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

end of thread, other threads:[~2016-05-12  7:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-06 23:26 [Cocci] Out of tree instrumentation with coccinelle demo Luis R. Rodriguez
2016-05-07 10:49 ` SF Markus Elfring
2016-05-08 11:50 ` Sasha Levin
2016-05-08 19:23   ` Luis R. Rodriguez
2016-05-08 19:51     ` Julia Lawall
2016-05-09 21:10       ` Luis R. Rodriguez
2016-05-09 21:24         ` Julia Lawall
2016-05-11 20:55     ` Luis R. Rodriguez
2016-05-12  7:20       ` Julia Lawall

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.