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
 */

Reply via email to