MADNESS  version 0.9
worldmutex.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 
31  $Id$
32 */
33 #ifndef MADNESS_WORLD_WORLDMUTEX_H__INCLUDED
34 #define MADNESS_WORLD_WORLDMUTEX_H__INCLUDED
35 
36 #include <madness/TAU.h>
37 #include <madness/madness_config.h>
38 #include <pthread.h>
39 #ifdef ON_A_MAC
40 #include <libkern/OSAtomic.h>
41 typedef OSSpinLock pthread_spinlock_t;
42 
43 inline void pthread_spin_init(pthread_spinlock_t* p, int /*mode*/) {
44  *p=0;
45 }
46 inline int pthread_spin_trylock(pthread_spinlock_t* p) {
47  return !OSSpinLockTry(p);
48 }
49 inline int pthread_spin_lock(pthread_spinlock_t* p) {
50  OSSpinLockLock(p);
51  return 0;
52 }
53 inline int pthread_spin_unlock(pthread_spinlock_t* p) {
54  OSSpinLockUnlock(p);
55  return 0;
56 }
57 inline void pthread_spin_destroy(pthread_spinlock_t* /*p*/) {}
58 #endif
59 
60 
64 #include <madness/world/worldexc.h>
65 
68 
69 
70 namespace madness {
71 
72  class MutexWaiter {
73  private:
74  unsigned int count;
75 
78  void yield(int us) {
79 #if !defined(HAVE_IBMBGP) && !defined(HAVE_IBMBGQ)
80  myusleep(us);
81 #endif
82  }
83 
84  public:
85  MutexWaiter() : count(0) { }
86 
87  void reset() { count = 0; }
88 
89  void wait();
90  }; // class MutexWaiter
91 
92 
94  class Mutex {
95  private:
96  mutable pthread_mutex_t mutex;
97 
99  Mutex(const Mutex&);
100 
102  void operator=(const Mutex&);
103 
104  public:
106  Mutex(int junk=0) // Junk so that can force initializer in mraX.cc
107  {
108  const int result = pthread_mutex_init(&mutex, 0);
109  if (result) MADNESS_EXCEPTION("failed to initialize mutex", result);
110  }
111 
113  bool try_lock() const {
114  return pthread_mutex_trylock(&mutex)==0;
115  }
116 
118  void lock() const {
119  const int result = pthread_mutex_lock(&mutex);
120  if (result) MADNESS_EXCEPTION("failed acquiring mutex", result);
121  }
122 
124  void unlock() const {
125  const int result = pthread_mutex_unlock(&mutex);
126  if (result) MADNESS_EXCEPTION("failed releasing mutex", result);
127  }
128 
130  pthread_mutex_t* ptr() const {
131  return &mutex;
132  }
133 
134  virtual ~Mutex() {
135  pthread_mutex_destroy(&mutex);
136  }
137  }; // class Mutex
138 
141  private:
142  mutable pthread_mutex_t mutex;
143 
146 
148  void operator=(const RecursiveMutex&);
149 
150  public:
152  RecursiveMutex();
153 
155  bool try_lock() const {
156  return pthread_mutex_trylock(&mutex)==0;
157  }
158 
160  void lock() const {
161  int result = pthread_mutex_lock(&mutex);
162  if (result) MADNESS_EXCEPTION("failed acquiring mutex", result);
163  }
164 
166  void unlock() const {
167  int result = pthread_mutex_unlock(&mutex);
168  if (result) MADNESS_EXCEPTION("failed releasing mutex", result);
169  }
170 
172  pthread_mutex_t* ptr() const {
173  return &mutex;
174  }
175 
177  pthread_mutex_destroy(&mutex);
178  }
179  }; // class Mutex
180 
181 
183 
185  template <class mutexT = Mutex>
186  class ScopedMutex {
187  const mutexT* mutex;
188  public:
189  ScopedMutex(const mutexT* m) : mutex(m) { mutex->lock(); }
190 
191  ScopedMutex(const mutexT& m) : mutex(&m) { mutex->lock(); }
192 
193  virtual ~ScopedMutex() { mutex->unlock(); }
194  }; // class ScopedMutex
195 
196 #ifdef NEVER_SPIN
197  typedef Mutex Spinlock;
198 #else
199  class Spinlock {
201  private:
202  //mutable pthread_spinlock_t spinlock __attribute__ ((aligned (64)));
203  mutable pthread_spinlock_t spinlock;
204 
206  Spinlock(const Spinlock&);
207 
209  void operator=(const Spinlock&);
210 
211  public:
213  Spinlock(int junk=0) // Junk so that can force initializer in mraX.cc
214  {
215  pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
216  }
217 
219  bool try_lock() const {
220  return pthread_spin_trylock(&spinlock)==0;
221  }
222 
224  void lock() const {
225  int result = pthread_spin_lock(&spinlock);
226  if (result) MADNESS_EXCEPTION("failed acquiring spinlock", result);
227  }
228 
230  void unlock() const {
231  int result = pthread_spin_unlock(&spinlock);
232  if (result) MADNESS_EXCEPTION("failed releasing spinlock", result);
233  }
234 
235  virtual ~Spinlock() {
236  pthread_spin_destroy(&spinlock);
237  }
238  }; // class Spinlock
239 #endif
240 
241 
242 #define OLDXXX
243 #ifdef OLDXXX
244  // This version uses a spin lock
245  class MutexReaderWriter : private Spinlock, private NO_DEFAULTS {
246  volatile mutable int nreader;
247  volatile mutable bool writeflag;
248  public:
249  static const int NOLOCK=0;
250  static const int READLOCK=1;
251  static const int WRITELOCK=2;
252 
253  MutexReaderWriter() : nreader(0), writeflag(false) {}
254 
255  bool try_read_lock() const {
256  ScopedMutex<Spinlock> protect(this);
257  bool gotit = !writeflag;
258  if (gotit) ++nreader;
259  return gotit;
260  }
261 
262  bool try_write_lock() const {
263  ScopedMutex<Spinlock> protect(this);
264  bool gotit = (!writeflag) && (nreader==0);
265  if (gotit) writeflag = true;
266  return gotit;
267  }
268 
269  bool try_lock(int lockmode) const {
270  if (lockmode == READLOCK) {
271  return try_read_lock();
272  }
273  else if (lockmode == WRITELOCK) {
274  return try_write_lock();
275  }
276  else if (lockmode == NOLOCK) {
277  return true;
278  }
279  else {
280  MADNESS_EXCEPTION("MutexReaderWriter: try_lock: invalid lock mode", lockmode);
281  }
282  }
283 
285  ScopedMutex<Spinlock> protect(this);
286  bool gotit = (!writeflag) && (nreader==1);
287  if (gotit) {
288  nreader = 0;
289  writeflag = true;
290  }
291  return gotit;
292  }
293 
294  void read_lock() const {
295  while (!try_read_lock()) cpu_relax();
296  }
297 
298  void write_lock() const {
299  while (!try_write_lock()) cpu_relax();
300  }
301 
302  void lock(int lockmode) const {
303  while (!try_lock(lockmode)) cpu_relax();
304  }
305 
306  void read_unlock() const {
307  ScopedMutex<Spinlock> protect(this);
308  nreader--;
309  }
310 
311  void write_unlock() const {
312  // Only a single thread should be setting writeflag but
313  // probably still need the mutex just to get memory fence?
314  ScopedMutex<Spinlock> protect(this);
315  writeflag = false;
316  }
317 
318  void unlock(int lockmode) const {
319  if (lockmode == READLOCK) read_unlock();
320  else if (lockmode == WRITELOCK) write_unlock();
321  else if (lockmode != NOLOCK) MADNESS_EXCEPTION("MutexReaderWriter: try_lock: invalid lock mode", lockmode);
322  }
323 
325 
329  }
330 
333  ScopedMutex<Spinlock> protect(this);
334  ++nreader;
335  writeflag=false;
336  }
337  virtual ~MutexReaderWriter() {}
338  };
339 
340 #else
341 
342  // This version uses AtomicInt and CAS
343  class MutexReaderWriter : private NO_DEFAULTS {
344  mutable AtomicInt nreader;
345  mutable AtomicInt writeflag;
346  enum {UNLOCKED, LOCKED};
347 
348  public:
349  enum lockT {NOLOCK, READLOCK, WRITELOCK};
350 
351  MutexReaderWriter() {nreader=0; writeflag=0;}
352 
353  bool try_read_lock() const {
354  nreader++;
355  if (writeflag == UNLOCKED) return true;
356  nreader--;
357  return false;
358  }
359 
360  bool try_write_lock() const {
361  return (writeflag.compare_and_swap((int) UNLOCKED, (int) LOCKED) == 0);
362  }
363 
364  bool try_lock(int lockmode) const {
365  if (lockmode == READLOCK) {
366  return try_read_lock();
367  }
368  else if (lockmode == WRITELOCK) {
369  return try_write_lock();
370  }
371  else if (lockmode == NOLOCK) {
372  return true;
373  }
374  else {
375  MADNESS_EXCEPTION("MutexReaderWriter: try_lock: invalid lock mode", lockmode);
376  }
377  }
378 
380  if (!try_write_lock()) return false;
381  if (nreader > 1) {
382  write_unlock();
383  return false;
384  }
385  nreader = 0;
386  return true;
387  }
388 
389  void read_lock() const {
390  while (!try_read_lock()) cpu_relax();
391  }
392 
393  void write_lock() const {
394  while (!try_write_lock()) cpu_relax();
395  }
396 
397  void lock(int lockmode) const {
398  while (!try_lock(lockmode)) cpu_relax();
399  }
400 
401  void read_unlock() const {
402  nreader--;
403  }
404 
405  void write_unlock() const {
406  writeflag = UNLOCKED;
407  }
408 
409  void unlock(int lockmode) const {
410  if (lockmode == READLOCK) read_unlock();
411  else if (lockmode == WRITELOCK) write_unlock();
412  else if (lockmode != NOLOCK) MADNESS_EXCEPTION("MutexReaderWriter: try_lock: invalid lock mode", lockmode);
413  }
414 
416 
418  void convert_read_lock_to_write_lock() const {
420  }
421 
423  void convert_write_lock_to_read_lock() const {
424  nreader++;
425  writeflag = UNLOCKED;
426  }
427  };
428 #endif
429 
431  class ConditionVariable : public Spinlock {
432  public:
433  static const int MAX_NTHREAD = 64;
434  mutable volatile int back;
435  mutable volatile int front;
436  mutable volatile bool* volatile q[MAX_NTHREAD]; // Circular buffer of flags
437 
438  public:
439  ConditionVariable() : back(0), front(0) { }
440 
442  void wait() const {
443  // We put a pointer to a thread-local variable at the
444  // end of the queue and wait for that value to be set,
445  // thus generate no memory traffic while waiting.
446  TAU_START("madness:ConditionVariable::wait()");
447  volatile bool myturn = false;
448  int b = back;
449  q[b] = &myturn;
450  ++b;
451  if (b >= MAX_NTHREAD) back = 0;
452  else back = b;
453 
454  unlock(); // Release lock before blocking
455  while (!myturn) cpu_relax();
456  lock();
457  TAU_STOP("madness:ConditionVariable::wait()");
458  }
459 
461  void signal() const {
462  if (front != back) {
463  int f = front;
464  int ff = f + 1;
465  if (ff >= MAX_NTHREAD)
466  front = 0;
467  else
468  front = ff;
469 
470  *q[f] = true;
471  }
472  }
473 
475  void broadcast() const {
476  while (front != back)
477  signal();
478  }
479 
480 
481  virtual ~ConditionVariable() {}
482  };
483 
484 
486 
489  class MutexFair : private Spinlock {
490  private:
491  static const int MAX_NTHREAD = 64;
492  mutable volatile bool* volatile q[MAX_NTHREAD];
493  mutable volatile int n;
494  mutable volatile int front;
495  mutable volatile int back;
496 
497  public:
498  MutexFair() : n(0), front(0), back(0) {};
499 
500  void lock() const {
501  // TAU_START("MutexFair::lock()");
502  volatile bool myturn = false;
503  Spinlock::lock();
504  ++n;
505  if (n == 1) {
506  myturn = true;
507  }
508  else {
509  int b = back + 1;
510  if (b >= MAX_NTHREAD) b = 0;
511  q[b] = &myturn;
512  back = b;
513  }
515 
516  while (!myturn) cpu_relax();
517  // TAU_STOP("MutexFair::lock()");
518  }
519 
520  void unlock() const {
521  //TAU_START("MutexFair::unlock()");
522  volatile bool* p = 0;
523  Spinlock::lock();
524  n--;
525  if (n > 0) {
526  int f = front + 1;
527  if (f >= MAX_NTHREAD) f = 0;
528  p = q[f];
529  front = f;
530  }
532  if (p) *p = true;
533  //TAU_STOP("MutexFair::unlock()");
534  }
535 
536  bool try_lock() const {
537  bool got_lock;
538 
539  Spinlock::lock();
540  int nn = n;
541  got_lock = (nn == 0);
542  if (got_lock) n = nn + 1;
544 
545  return got_lock;
546  }
547  };
548 
549 
551 
554  inline bool try_two_locks(const Mutex& m1, const Mutex& m2) {
555  if (!m1.try_lock()) return false;
556  if (m2.try_lock()) return true;
557  m1.unlock();
558  return false;
559  }
560 
561 
563 
567  private:
568  mutable pthread_cond_t cv;
569  mutable pthread_mutex_t mutex;
570 
571  public:
573  pthread_cond_init(&cv, NULL);
574  pthread_mutex_init(&mutex, 0);
575  }
576 
577  pthread_mutex_t& get_pthread_mutex() {
578  return mutex;
579  }
580 
581  void lock() const {
582  int result = pthread_mutex_lock(&mutex);
583  if (result) MADNESS_EXCEPTION("ConditionVariable: acquiring mutex", result);
584  }
585 
586  void unlock() const {
587  int result = pthread_mutex_unlock(&mutex);
588  if (result) MADNESS_EXCEPTION("ConditionVariable: releasing mutex", result);
589  }
590 
592  void wait() const {
593  pthread_cond_wait(&cv,&mutex);
594  }
595 
596  void signal() const {
597  int result = pthread_cond_signal(&cv);
598  if (result) MADNESS_EXCEPTION("ConditionalVariable: signalling failed", result);
599  }
600 
601  void broadcast() const {
602  int result = pthread_cond_broadcast(&cv);
603  if (result) MADNESS_EXCEPTION("ConditionalVariable: signalling failed", result);
604  }
605 
607  pthread_mutex_destroy(&mutex);
608  pthread_cond_destroy(&cv);
609  }
610  }; // class PthreadConditionVariable
611 
612 #ifdef USE_SPINLOCKS
613  typedef ConditionVariable CONDITION_VARIABLE_TYPE ;
614  typedef Spinlock SPINLOCK_TYPE;
615  typedef MutexFair SCALABLE_MUTEX_TYPE;
616 #else
620 #endif
621 
622  class Barrier {
623  const int nthread;
624  volatile bool sense;
625  AtomicInt nworking;
626  volatile bool* pflags[64];
627 
628  public:
629  Barrier(int nthread)
630  : nthread(nthread)
631  , sense(true)
632  {
633  nworking = nthread;
634  }
635 
637 
640  void register_thread(int id, volatile bool* pflag) {
641  if (id > 63) MADNESS_EXCEPTION("Barrier : hard dimension failed", id);
642  pflags[id] = pflag;
643  *pflag=!sense;
644  }
645 
647 
651  bool enter(const int id) {
652  if (nthread <= 1) {
653  return true;
654  }
655  else {
656  if (id > 63) MADNESS_EXCEPTION("Barrier : hard dimension failed", id);
657  bool lsense = sense; // Local copy of sense
658  bool result = nworking.dec_and_test();
659  if (result) {
660  // Reset counter and sense for next entry
661  nworking = nthread;
662  sense = !sense;
663  __asm__ __volatile__("" : : : "memory");
664 
665  // Notify everyone including me
666  for (int i = 0; i < nthread; ++i)
667  *(pflags[i]) = lsense;
668  } else {
669  volatile bool* myflag = pflags[id]; // Local flag;
670  while (*myflag != lsense) {
671  cpu_relax();
672  }
673  }
674  return result;
675  }
676  }
677  }; // class Barrier
678 }
679 
680 #endif // MADNESS_WORLD_WORLDMUTEX_H__INCLUDED
Mutex that is applied/released at start/end of a scope.
Definition: worldmutex.h:186
Mutex(int junk=0)
Make and initialize a mutex ... initial state is unlocked.
Definition: worldmutex.h:106
void unlock(int lockmode) const
Definition: worldmutex.h:318
Mutex using pthread mutex operations.
Definition: worldmutex.h:94
virtual ~MutexReaderWriter()
Definition: worldmutex.h:337
void lock() const
Definition: worldmutex.h:581
volatile int front
Definition: worldmutex.h:435
Simple wrapper for Pthread condition variable with its own mutex.
Definition: worldmutex.h:566
PthreadConditionVariable()
Definition: worldmutex.h:572
virtual ~ScopedMutex()
Definition: worldmutex.h:193
void signal() const
Definition: worldmutex.h:596
ConditionVariable()
Definition: worldmutex.h:439
bool try_two_locks(const Mutex &m1, const Mutex &m2)
Attempt to acquire two locks without blocking holding either one.
Definition: worldmutex.h:554
static const int READLOCK
Definition: worldmutex.h:250
void broadcast() const
You should acquire the mutex before broadcasting.
Definition: worldmutex.h:475
PthreadConditionVariable CONDITION_VARIABLE_TYPE
Definition: worldmutex.h:617
static const int NOLOCK
Definition: worldmutex.h:249
void broadcast() const
Definition: worldmutex.h:601
volatile bool *volatile q[MAX_NTHREAD]
Definition: worldmutex.h:436
void unlock() const
Free a spinlock owned by this thread.
Definition: worldmutex.h:230
bool try_lock() const
Try to acquire the mutex ... return true on success, false on failure.
Definition: worldmutex.h:113
Mutex SCALABLE_MUTEX_TYPE
Definition: worldmutex.h:619
bool enter(const int id)
Each thread calls this with its id (0,..,nthread-1) to enter the barrier.
Definition: worldmutex.h:651
bool try_lock() const
Definition: worldmutex.h:536
MutexWaiter()
Definition: worldmutex.h:85
void lock() const
Acquire the spinlock waiting if necessary.
Definition: worldmutex.h:224
virtual ~Spinlock()
Definition: worldmutex.h:235
void lock() const
Acquire the mutex waiting if necessary.
Definition: worldmutex.h:160
Definition: worldmutex.h:72
void lock() const
Definition: worldmutex.h:500
pthread_mutex_t * ptr() const
Return a pointer to the pthread mutex for use by a condition variable.
Definition: worldmutex.h:130
bool try_lock(int lockmode) const
Definition: worldmutex.h:269
NDIM & f
Definition: mra.h:2179
void wait()
Definition: worldmutex.cc:43
void unlock() const
Definition: worldmutex.h:586
bool dec_and_test()
Decrements the counter and returns true if the new value is zero.
Definition: atomicint.h:178
~RecursiveMutex()
Definition: worldmutex.h:176
Recursive mutex using pthread mutex operations.
Definition: worldmutex.h:140
pthread_mutex_t * ptr() const
Return a pointer to the pthread mutex for use by a condition variable.
Definition: worldmutex.h:172
bool try_lock() const
Try to acquire the spinlock ... return true on success, false on failure.
Definition: worldmutex.h:219
void convert_write_lock_to_read_lock() const
Always succeeds immediately.
Definition: worldmutex.h:332
void wait() const
You should have acquired the mutex before entering here.
Definition: worldmutex.h:592
void cpu_relax()
Do nothing and especially do not touch memory.
Definition: worldtime.h:141
void unlock() const
Free a mutex owned by this thread.
Definition: worldmutex.h:166
void lock(int lockmode) const
Definition: worldmutex.h:302
ScopedMutex(const mutexT *m)
Definition: worldmutex.h:189
void convert_read_lock_to_write_lock() const
Converts read to write lock without releasing the read lock.
Definition: worldmutex.h:327
virtual ~Mutex()
Definition: worldmutex.h:134
bool try_convert_read_lock_to_write_lock() const
Definition: worldmutex.h:284
MutexFair()
Definition: worldmutex.h:498
Mutex SPINLOCK_TYPE
Definition: worldmutex.h:618
void reset()
Definition: worldmutex.h:87
void write_lock() const
Definition: worldmutex.h:298
An integer with atomic set, get, read+inc, read+dec, dec+test operations.
Definition: atomicint.h:73
Definition: worldmutex.h:622
void register_thread(int id, volatile bool *pflag)
Each thread calls this once before first use.
Definition: worldmutex.h:640
Spinlock(int junk=0)
Make and initialize a spinlock ... initial state is unlocked.
Definition: worldmutex.h:213
void signal() const
You should acquire the mutex before signalling.
Definition: worldmutex.h:461
Implements NO_DEFAULTS.
Scalable and fair condition variable (spins on local value)
Definition: worldmutex.h:431
const double m
Definition: gfit.cc:199
void unlock() const
Definition: worldmutex.h:520
virtual ~ConditionVariable()
Definition: worldmutex.h:481
ScopedMutex(const mutexT &m)
Definition: worldmutex.h:191
static const int MAX_NTHREAD
Definition: worldmutex.h:433
void read_unlock() const
Definition: worldmutex.h:306
RecursiveMutex()
Make and initialize a mutex ... initial state is unlocked.
Definition: worldmutex.cc:67
bool try_write_lock() const
Definition: worldmutex.h:262
MutexReaderWriter()
Definition: worldmutex.h:253
static const int WRITELOCK
Definition: worldmutex.h:251
void wait() const
You should acquire the mutex before waiting.
Definition: worldmutex.h:442
Definition: worldmutex.h:245
bool try_lock() const
Try to acquire the mutex ... return true on success, false on failure.
Definition: worldmutex.h:155
void read_lock() const
Definition: worldmutex.h:294
virtual ~PthreadConditionVariable()
Definition: worldmutex.h:606
Implements MadnessException.
Wrappers around platform dependent timers and performance info.
bool try_read_lock() const
Definition: worldmutex.h:255
#define MADNESS_EXCEPTION(msg, value)
Definition: worldexc.h:88
#define TAU_STOP(a)
Definition: TAU.h:7
Barrier(int nthread)
Definition: worldmutex.h:629
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
volatile int back
Definition: worldmutex.h:434
void write_unlock() const
Definition: worldmutex.h:311
FLOAT b(int j, FLOAT z)
Definition: y1.cc:79
void unlock() const
Free a mutex owned by this thread.
Definition: worldmutex.h:124
#define TAU_START(a)
Definition: TAU.h:6
void lock() const
Acquire the mutex waiting if necessary.
Definition: worldmutex.h:118
A scalable and fair mutex (not recursive)
Definition: worldmutex.h:489
pthread_mutex_t & get_pthread_mutex()
Definition: worldmutex.h:577
Disables default copy constructor and assignment operators.
Definition: nodefaults.h:49