/* * Exercise multithread-safety warnings from clang 9.0 * http://releases.llvm.org/9.0.0/tools/clang/docs/ThreadSafetyAnalysis.html */ #include #include 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 */