Ben Pfaff wrote:
> The compiler analyzes the code and reports violations of the
> annotations where possible.
>
> Details:
> https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
>
> The Clang docs mostly talk about C++ but it also supports C.
Indeed, this is a very nice feature. Find attached a test case, where
the compiler warns about locking violations:
$ clang -O -Wthread-safety mt-warnings.c
mt-warnings.c:72:47: warning: reading variable 'account_balance' requires
holding mutex 'account_lock' [-Wthread-safety-analysis]
printf ("Final balance unlocked = %0.2f\n", account_balance);
^
1 warning generated.
To make this easier to use on glibc systems, a couple of annotations in glibc's
<pthread.h> would be needed. Reported as
https://sourceware.org/bugzilla/show_bug.cgi?id=25238
Bruno
/*
* Exercise multithread-safety warnings from clang 9.0
* http://releases.llvm.org/9.0.0/tools/clang/docs/ThreadSafetyAnalysis.html
*/
#include <pthread.h>
#include <stdio.h>
typedef pthread_mutex_t mutex_t __attribute__((capability("mutex")));
extern int pthread_mutex_lock (mutex_t *arg) __attribute__((acquire_capability(*arg)));
extern int pthread_mutex_unlock (mutex_t *arg) __attribute__((release_capability(*arg)));
static mutex_t account_lock = PTHREAD_MUTEX_INITIALIZER;
static double account_balance __attribute__((guarded_by(account_lock))) = 0.0;
static void account_add (double delta) /*__attribute__((locks_excluded(account_lock)))*/
{
pthread_mutex_lock (&account_lock);
account_balance += delta;
pthread_mutex_unlock (&account_lock);
}
static double get_balance (void) /*__attribute__((locks_excluded(account_lock))) */
{
pthread_mutex_lock (&account_lock);
double value = account_balance;
pthread_mutex_unlock (&account_lock);
return value;
}
static mutex_t purse_lock = PTHREAD_MUTEX_INITIALIZER;
static double purse_contents __attribute__((guarded_by(purse_lock))) = 0.0;
static void withdraw (double delta)
{
pthread_mutex_lock (&account_lock);
pthread_mutex_lock (&purse_lock);
account_balance -= delta;
purse_contents += delta;
pthread_mutex_unlock (&purse_lock);
pthread_mutex_unlock (&account_lock);
}
static void spend (double amount)
{
pthread_mutex_lock (&purse_lock);
purse_contents -= amount;
pthread_mutex_unlock (&purse_lock);
}
static double peek_into_purse (void)
{
pthread_mutex_lock (&purse_lock);
double value = purse_contents;
pthread_mutex_unlock (&purse_lock);
return value;
}
int main ()
{
account_add (37.02);
withdraw (10.00);
account_add (12.07);
spend (1.99);
printf ("Final balance = %0.2f\n", get_balance ());
printf ("Final balance unlocked = %0.2f\n", account_balance);
printf ("Purse contents = %0.2f\n", peek_into_purse ());
}
/*
* Compile-command: ~/inst-clang/9.0.0/bin/clang -O -Wthread-safety mt-warnings.c
*/