NVIDIA Iray: Math API Home  Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
lock.h
Go to the documentation of this file.
1 //*****************************************************************************
2 // Copyright 1986, 2016 NVIDIA Corporation. All rights reserved.
3 //*****************************************************************************
9 //*****************************************************************************
10 
11 #ifndef MI_BASE_LOCK_H
12 #define MI_BASE_LOCK_H
13 
14 #include <cstdlib>
15 
16 #include <mi/base/assert.h>
17 #include <mi/base/config.h>
18 
19 #ifndef MI_PLATFORM_WINDOWS
20 #include <cerrno>
21 #include <pthread.h>
22 #else
23 #include <mi/base/miwindows.h>
24 #endif
25 
26 namespace mi {
27 
28 namespace base {
29 
41 class Lock
51 {
52 public:
54  Lock();
55 
57  ~Lock();
58 
62  class Block
63  {
64  public:
69  explicit Block( Lock* lock = 0);
70 
74  ~Block();
75 
84  void set( Lock* lock);
85 
96  bool try_set( Lock* lock);
97 
101  void release();
102 
103  private:
104  // The lock associated with this helper class.
105  Lock* m_lock;
106  };
107 
108 protected:
110  void lock();
111 
113  bool try_lock();
114 
116  void unlock();
117 
118 private:
119  // This class is non-copyable.
120  Lock( Lock const &);
121 
122  // This class is non-assignable.
123  Lock& operator=( Lock const &);
124 
125 #ifndef MI_PLATFORM_WINDOWS
126  // The mutex implementing the lock.
127  pthread_mutex_t m_mutex;
128 #else
129  // The critical section implementing the lock.
130  CRITICAL_SECTION m_critical_section;
131  // The flag used to ensure that the lock is non-recursive.
132  bool m_locked;
133 #endif
134 };
135 
145 {
146 public:
148  Recursive_lock();
149 
151  ~Recursive_lock();
152 
156  class Block
157  {
158  public:
163  explicit Block( Recursive_lock* lock = 0);
164 
168  ~Block();
169 
178  void set( Recursive_lock* lock);
179 
190  bool try_set( Recursive_lock* lock);
191 
195  void release();
196 
197  private:
198  // The lock associated with this helper class.
199  Recursive_lock* m_lock;
200  };
201 
202 protected:
204  void lock();
205 
207  bool try_lock();
208 
210  void unlock();
211 
212 private:
213  // This class is non-copyable.
214  Recursive_lock( Recursive_lock const &);
215 
216  // This class is non-assignable.
217  Recursive_lock& operator=( Recursive_lock const &);
218 
219 #ifndef MI_PLATFORM_WINDOWS
220  // The mutex implementing the lock.
221  pthread_mutex_t m_mutex;
222 #else
223  // The critical section implementing the lock.
224  CRITICAL_SECTION m_critical_section;
225 #endif
226 };
227 
228 #ifndef MI_FOR_DOXYGEN_ONLY
229 
230 inline Lock::Lock()
231 {
232 #ifndef MI_PLATFORM_WINDOWS
233  pthread_mutexattr_t mutex_attributes;
234  pthread_mutexattr_init( &mutex_attributes);
235  pthread_mutexattr_settype( &mutex_attributes, PTHREAD_MUTEX_ERRORCHECK);
236  pthread_mutex_init( &m_mutex, &mutex_attributes);
237 #else
238  InitializeCriticalSection( &m_critical_section);
239  m_locked = false;
240 #endif
241 };
242 
243 inline Lock::~Lock()
244 {
245 #ifndef MI_PLATFORM_WINDOWS
246  int result = pthread_mutex_destroy( &m_mutex);
247  mi_base_assert( result == 0);
248  (void) result;
249 #else
250  mi_base_assert( !m_locked);
251  DeleteCriticalSection( &m_critical_section);
252 #endif
253 };
254 
255 inline void Lock::lock()
256 {
257 #ifndef MI_PLATFORM_WINDOWS
258  int result = pthread_mutex_lock( &m_mutex);
259  if( result == EDEADLK) {
260  mi_base_assert( !"Dead lock");
261  abort();
262  }
263 #else
264  EnterCriticalSection( &m_critical_section);
265  if( m_locked) {
266  mi_base_assert( !"Dead lock");
267  abort();
268  }
269  m_locked = true;
270 #endif
271 };
272 
273 inline bool Lock::try_lock()
274 {
275 #ifndef MI_PLATFORM_WINDOWS
276  int result = pthread_mutex_trylock( &m_mutex);
277  // Old glibc versions incorrectly return EDEADLK instead of EBUSY
278  // (https://sourceware.org/bugzilla/show_bug.cgi?id=4392).
279  mi_base_assert( result == 0 || result == EBUSY || result == EDEADLK);
280  return result == 0;
281 #else
282  BOOL result = TryEnterCriticalSection( &m_critical_section);
283  if( result == 0)
284  return false;
285  if( m_locked) {
286  LeaveCriticalSection( &m_critical_section);
287  return false;
288  }
289  m_locked = true;
290  return true;
291 #endif
292 }
293 
294 inline void Lock::unlock()
295 {
296 #ifndef MI_PLATFORM_WINDOWS
297  int result = pthread_mutex_unlock( &m_mutex);
298  mi_base_assert( result == 0);
299  (void) result;
300 #else
301  mi_base_assert( m_locked);
302  m_locked = false;
303  LeaveCriticalSection( &m_critical_section);
304 #endif
305 };
306 
307 inline Lock::Block::Block( Lock* lock)
308 {
309  m_lock = lock;
310  if( m_lock)
311  m_lock->lock();
312 }
313 
314 inline Lock::Block::~Block()
315 {
316  release();
317 }
318 
319 inline void Lock::Block::set( Lock* lock)
320 {
321  if( m_lock == lock)
322  return;
323  if( m_lock)
324  m_lock->unlock();
325  m_lock = lock;
326  if( m_lock)
327  m_lock->lock();
328 }
329 
330 inline bool Lock::Block::try_set( Lock* lock)
331 {
332  if( m_lock == lock)
333  return true;
334  if( m_lock)
335  m_lock->unlock();
336  m_lock = lock;
337  if( m_lock && m_lock->try_lock())
338  return true;
339  m_lock = 0;
340  return false;
341 }
342 
343 inline void Lock::Block::release()
344 {
345  if( m_lock)
346  m_lock->unlock();
347  m_lock = 0;
348 }
349 
351 {
352 #ifndef MI_PLATFORM_WINDOWS
353  pthread_mutexattr_t mutex_attributes;
354  pthread_mutexattr_init( &mutex_attributes);
355  pthread_mutexattr_settype( &mutex_attributes, PTHREAD_MUTEX_RECURSIVE);
356  pthread_mutex_init( &m_mutex, &mutex_attributes);
357 #else
358  InitializeCriticalSection( &m_critical_section);
359 #endif
360 };
361 
363 {
364 #ifndef MI_PLATFORM_WINDOWS
365  int result = pthread_mutex_destroy( &m_mutex);
366  mi_base_assert( result == 0);
367  (void) result;
368 #else
369  DeleteCriticalSection( &m_critical_section);
370 #endif
371 };
372 
373 inline void Recursive_lock::lock()
374 {
375 #ifndef MI_PLATFORM_WINDOWS
376  int result = pthread_mutex_lock( &m_mutex);
377  mi_base_assert( result == 0);
378  (void) result;
379 #else
380  EnterCriticalSection( &m_critical_section);
381 #endif
382 };
383 
384 inline bool Recursive_lock::try_lock()
385 {
386 #ifndef MI_PLATFORM_WINDOWS
387  int result = pthread_mutex_trylock( &m_mutex);
388  mi_base_assert( result == 0 || result == EBUSY);
389  return result == 0;
390 #else
391  BOOL result = TryEnterCriticalSection( &m_critical_section);
392  return result != 0;
393 #endif
394 }
395 
396 inline void Recursive_lock::unlock()
397 {
398 #ifndef MI_PLATFORM_WINDOWS
399  int result = pthread_mutex_unlock( &m_mutex);
400  mi_base_assert( result == 0);
401  (void) result;
402 #else
403  LeaveCriticalSection( &m_critical_section);
404 #endif
405 };
406 
407 inline Recursive_lock::Block::Block( Recursive_lock* lock)
408 {
409  m_lock = lock;
410  if( m_lock)
411  m_lock->lock();
412 }
413 
415 {
416  release();
417 }
418 
419 inline void Recursive_lock::Block::set( Recursive_lock* lock)
420 {
421  if( m_lock == lock)
422  return;
423  if( m_lock)
424  m_lock->unlock();
425  m_lock = lock;
426  if( m_lock)
427  m_lock->lock();
428 }
429 
430 inline bool Recursive_lock::Block::try_set( Recursive_lock* lock)
431 {
432  if( m_lock == lock)
433  return true;
434  if( m_lock)
435  m_lock->unlock();
436  m_lock = lock;
437  if( m_lock && m_lock->try_lock())
438  return true;
439  m_lock = 0;
440  return false;
441 }
442 
443 inline void Recursive_lock::Block::release()
444 {
445  if( m_lock)
446  m_lock->unlock();
447  m_lock = 0;
448 }
449 
450 #endif // MI_FOR_DOXYGEN_ONLY
451  // end group mi_base_threads
453 
454 } // namespace base
455 
456 } // namespace mi
457 
458 #endif // MI_BASE_LOCK_H