<div dir="ltr">Hey David,<div><br></div><div>Sorry for the delayed reply and thanks for your explanation,</div><div><br></div><div>I did modification below to add this new "c_wthread_safety" so that it can be checked by "__has_feature()". Is this what you mean?</div>
<div><br></div><div>Hope to hear more comments,</div><div><br></div><div>Kind Regards,</div><div>Alex Wang,</div><div><br></div><div>Index: lib/Lex/PPMacroExpansion.cpp</div><div>===================================================================</div>
<div>--- lib/Lex/PPMacroExpansion.cpp<span class="" style="white-space:pre">    </span>(revision 186655)</div><div>+++ lib/Lex/PPMacroExpansion.cpp<span class="" style="white-space:pre">  </span>(working copy)</div><div>@@ -727,6 +727,7 @@</div>
<div>            .Case("attribute_unavailable_with_message", true)</div><div>            .Case("attribute_unused_on_fields", true)</div><div>            .Case("blocks", LangOpts.Blocks)</div>
<div>+           .Case("c_wthread_safety", true)</div><div>            .Case("cxx_exceptions", LangOpts.Exceptions)</div><div>            .Case("cxx_rtti", LangOpts.RTTI)</div><div>            .Case("enumerator_attributes", true)</div>
<div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Jul 25, 2013 at 2:57 PM, David Chisnall <span dir="ltr"><<a href="mailto:David.Chisnall@cl.cam.ac.uk" target="_blank">David.Chisnall@cl.cam.ac.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Alex,<br>
<br>
I think you misunderstand.  If I want to use these in, for example, pthread.h, then I want to make sure that the attributes are only used when a compiler that knows about them is being used.  Clang provides the __has_feature() mechanism in the preprocessor for these checks at a coarse granularity, so that library headers can conditionally expose compiler and compiler-version specific features.<br>

<br>
How do I check, from within a header, that I am using a version of clang that supports thread-safety annotations in C?<br>
<span class="HOEnZb"><font color="#888888"><br>
David<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
On 25 Jul 2013, at 18:04, Alex Wang <<a href="mailto:alexw@nicira.com">alexw@nicira.com</a>> wrote:<br>
<br>
> Hey David,<br>
><br>
> Thanks for your reply, please correct me if my understanding is wrong,<br>
><br>
> Since I only use the thread safety attributes defined in clang, there should be no requirement on gcc extension.<br>
><br>
> Actually, I think it does not make very much sense to check for each of the attributes individually, since we only use these attributes for semantic analysis and your cpp test (warn-thread-safety-analysis.cpp) is every detailed.<br>

><br>
> Kind Regards,<br>
> Alex Wang,<br>
><br>
><br>
> On Thu, Jul 25, 2013 at 4:31 AM, David Chisnall <<a href="mailto:David.Chisnall@cl.cam.ac.uk">David.Chisnall@cl.cam.ac.uk</a>> wrote:<br>
> Hi,<br>
><br>
> What is the __has_extension() variable to check for support for these?  Or do we need to check for each of the attributes individually?<br>
><br>
> David<br>
><br>
> On 25 Jul 2013, at 02:16, Alex Wang <<a href="mailto:alexw@nicira.com">alexw@nicira.com</a>> wrote:<br>
><br>
> > This commit adds test to the -Wthread-safety check for C code.<br>
> ><br>
> > Co-authored-by: Ethan Jackson <<a href="mailto:ethan@nicira.com">ethan@nicira.com</a>><br>
> > Signed-off-by: Alex Wang <<a href="mailto:alexw@nicira.com">alexw@nicira.com</a>><br>
> ><br>
> > Index: warn-thread-safety-analysis.c<br>
> > ===================================================================<br>
> > --- warn-thread-safety-analysis.c     (revision 0)<br>
> > +++ warn-thread-safety-analysis.c     (revision 0)<br>
> > @@ -0,0 +1,132 @@<br>
> > +// RUN: %clang -fsyntax-only -verify -Wthread-safety -Wthread-safety-beta -fcxx-exceptions %s<br>
> > +<br>
> > +#include <assert.h><br>
> > +<br>
> > +#define LOCKABLE            __attribute__ ((lockable))<br>
> > +#define SCOPED_LOCKABLE     __attribute__ ((scoped_lockable))<br>
> > +#define GUARDED_BY(x)       __attribute__ ((guarded_by(x)))<br>
> > +#define GUARDED_VAR         __attribute__ ((guarded_var))<br>
> > +#define PT_GUARDED_BY(x)    __attribute__ ((pt_guarded_by(x)))<br>
> > +#define PT_GUARDED_VAR      __attribute__ ((pt_guarded_var))<br>
> > +#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))<br>
> > +#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))<br>
> > +#define EXCLUSIVE_LOCK_FUNCTION(...)    __attribute__ ((exclusive_lock_function(__VA_ARGS__)))<br>
> > +#define SHARED_LOCK_FUNCTION(...)       __attribute__ ((shared_lock_function(__VA_ARGS__)))<br>
> > +#define ASSERT_EXCLUSIVE_LOCK(...)      __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))<br>
> > +#define ASSERT_SHARED_LOCK(...)         __attribute__ ((assert_shared_lock(__VA_ARGS__)))<br>
> > +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))<br>
> > +#define SHARED_TRYLOCK_FUNCTION(...)    __attribute__ ((shared_trylock_function(__VA_ARGS__)))<br>
> > +#define UNLOCK_FUNCTION(...)            __attribute__ ((unlock_function(__VA_ARGS__)))<br>
> > +#define LOCK_RETURNED(x)    __attribute__ ((lock_returned(x)))<br>
> > +#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))<br>
> > +#define EXCLUSIVE_LOCKS_REQUIRED(...) \<br>
> > +  __attribute__ ((exclusive_locks_required(__VA_ARGS__)))<br>
> > +#define SHARED_LOCKS_REQUIRED(...) \<br>
> > +  __attribute__ ((shared_locks_required(__VA_ARGS__)))<br>
> > +#define NO_THREAD_SAFETY_ANALYSIS  __attribute__ ((no_thread_safety_analysis))<br>
> > +<br>
> > +// Define the mutex struct.<br>
> > +// Simplified only for test purpose.<br>
> > +struct LOCKABLE Mutex {};<br>
> > +<br>
> > +struct Foo {<br>
> > +  struct Mutex *mu_;<br>
> > +};<br>
> > +<br>
> > +// Define mutex lock/unlock functions.<br>
> > +void mutex_exclusive_lock(struct Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) {<br>
> > +}<br>
> > +<br>
> > +void mutex_shared_lock(struct Mutex *mu) SHARED_LOCK_FUNCTION(mu) {<br>
> > +}<br>
> > +<br>
> > +void mutex_unlock(struct Mutex *mu) UNLOCK_FUNCTION(mu) {<br>
> > +}<br>
> > +<br>
> > +// Define global variables.<br>
> > +struct Mutex mu1;<br>
> > +struct Mutex mu2 ACQUIRED_AFTER(mu1);<br>
> > +struct Foo foo_ = {&mu1};<br>
> > +int a_ GUARDED_BY(foo_.mu_);<br>
> > +int *b_ PT_GUARDED_BY(foo_.mu_) = &a_;<br>
> > +int c_ GUARDED_VAR;<br>
> > +int *d_ PT_GUARDED_VAR = &c_;<br>
> > +<br>
> > +// Define test functions.<br>
> > +int Foo_fun1(int i) SHARED_LOCKS_REQUIRED(mu2) EXCLUSIVE_LOCKS_REQUIRED(mu1) {<br>
> > +  return i;<br>
> > +}<br>
> > +<br>
> > +int Foo_fun2(int i) EXCLUSIVE_LOCKS_REQUIRED(mu2) SHARED_LOCKS_REQUIRED(mu1) {<br>
> > +  return i;<br>
> > +}<br>
> > +<br>
> > +int Foo_func3(int i) LOCKS_EXCLUDED(mu1, mu2) {<br>
> > +  return i;<br>
> > +}<br>
> > +<br>
> > +static int Bar_fun1(int i) EXCLUSIVE_LOCKS_REQUIRED(mu1) {<br>
> > +  return i;<br>
> > +}<br>
> > +<br>
> > +void set_value(int *a, int value) EXCLUSIVE_LOCKS_REQUIRED(foo_.mu_) {<br>
> > +  *a = value;<br>
> > +}<br>
> > +<br>
> > +int get_value(int *p) SHARED_LOCKS_REQUIRED(foo_.mu_){<br>
> > +  return *p;<br>
> > +}<br>
> > +<br>
> > +int main() {<br>
> > +<br>
> > +  Foo_fun1(1); // \<br>
> > +      // expected-warning{{calling function 'Foo_fun1' requires shared lock on 'mu2'}}<br>
> > +      // expected-warning{{calling function 'Foo_fun1' requires exclusive lock on 'mu1'}}<br>
> > +<br>
> > +  mutex_exclusive_lock(&mu1);<br>
> > +  mutex_shared_lock(&mu2);<br>
> > +  Foo_fun1(1);<br>
> > +<br>
> > +  mutex_shared_lock(&mu1);  // \<br>
> > +      // expected-warning{{locking 'mu1' that is already locked}}<br>
> > +  mutex_unlock(&mu1);<br>
> > +  mutex_unlock(&mu2);<br>
> > +  mutex_shared_lock(&mu1);<br>
> > +  mutex_exclusive_lock(&mu2);<br>
> > +  Foo_fun2(2);<br>
> > +<br>
> > +  mutex_unlock(&mu2);<br>
> > +  mutex_unlock(&mu1);<br>
> > +  mutex_exclusive_lock(&mu1);<br>
> > +  Bar_fun1(3);<br>
> > +  mutex_unlock(&mu1);<br>
> > +<br>
> > +  mutex_exclusive_lock(&mu1);<br>
> > +  Foo_func3(4);  // \<br>
> > +      // expected-warning{{cannot call function 'Foo_func3' while mutex 'mu1' is locked}}<br>
> > +  mutex_unlock(&mu1);<br>
> > +<br>
> > +  Foo_func3(5);<br>
> > +<br>
> > +  set_value(&a_, 0);  // \<br>
> > +      // expected-warning{{calling function 'setA' requires exclusive lock on 'foo_.mu_'}}<br>
> > +  get_value(b_);  // \<br>
> > +      // expected-warning{{calling function 'getB' requires shared lock on 'foo_.mu_'}}<br>
> > +  mutex_exclusive_lock(foo_.mu_);<br>
> > +  set_value(&a_, 1);<br>
> > +  mutex_unlock(foo_.mu_);<br>
> > +  mutex_shared_lock(foo_.mu_);<br>
> > +  assert(get_value(b_) == 1);<br>
> > +  mutex_unlock(foo_.mu_);<br>
> > +<br>
> > +  c_ = 0;  // \<br>
> > +      // expected-warning{{writing variable 'c_' requires locking any mutex exclusively}}<br>
> > +  assert(*d_ == 0);  // \<br>
> > +      // expected-warning{{reading the value pointed to by 'd_' requires locking any mutex}}<br>
> > +  mutex_exclusive_lock(foo_.mu_);<br>
> > +  c_ = 1;<br>
> > +  assert(*d_ == 1);<br>
> > +  mutex_unlock(foo_.mu_);<br>
> > +<br>
> > +  return 0;<br>
> > +}<br>
> > _______________________________________________<br>
> > cfe-dev mailing list<br>
> > <a href="mailto:cfe-dev@cs.uiuc.edu">cfe-dev@cs.uiuc.edu</a><br>
> > <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev</a><br>
><br>
><br>
<br>
</div></div></blockquote></div><br></div>