OSDN Git Service

2009-01-07 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / std / mutex
1 // <mutex> -*- C++ -*-
2
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16
17 // You should have received a copy of the GNU General Public License
18 // along with this library; see the file COPYING.  If not, write to
19 // the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction.  Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License.  This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
30
31 /** @file mutex
32  *  This is a Standard C++ Library header.
33  */
34
35 #ifndef _GLIBCXX_MUTEX
36 #define _GLIBCXX_MUTEX 1
37
38 #pragma GCC system_header
39
40 #ifndef __GXX_EXPERIMENTAL_CXX0X__
41 # include <c++0x_warning.h>
42 #else
43
44 #include <tuple>
45 #include <cstddef>
46 #include <chrono>
47 #include <exception>
48 #include <type_traits>
49 #include <functional>
50 #include <system_error>
51 #include <bits/functexcept.h>
52 #include <bits/gthr.h>
53 #include <bits/move.h> // for std::swap
54
55 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
56
57 namespace std
58 {
59   /// mutex
60   class mutex
61   {
62   public:
63     typedef __gthread_mutex_t* native_handle_type;
64
65     mutex()
66     {
67       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
68 #ifdef __GTHREAD_MUTEX_INIT
69       __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
70       _M_mutex = __tmp;
71 #else
72       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
73 #endif
74     }
75
76     mutex(const mutex&) = delete;
77     mutex& operator=(const mutex&) = delete;
78
79     void
80     lock()
81     {
82       int __e = __gthread_mutex_lock(&_M_mutex);
83
84       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
85       if (__e)
86         __throw_system_error(__e);
87     }
88
89     bool
90     try_lock()
91     {
92       // XXX EINVAL, EAGAIN, EBUSY
93       return !__gthread_mutex_trylock(&_M_mutex);
94     }
95
96     void
97     unlock()
98     {
99       // XXX EINVAL, EAGAIN, EPERM
100       __gthread_mutex_unlock(&_M_mutex);
101     }
102
103     native_handle_type
104     native_handle()
105     { return &_M_mutex; }
106
107   private:
108     __gthread_mutex_t _M_mutex;
109   };
110
111   /// recursive_mutex
112   class recursive_mutex
113   {
114   public:
115     typedef __gthread_recursive_mutex_t* native_handle_type;
116
117     recursive_mutex()
118     {
119       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
120 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
121       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
122       _M_mutex = __tmp;
123 #else
124       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
125 #endif
126     }
127
128     recursive_mutex(const recursive_mutex&) = delete;
129     recursive_mutex& operator=(const recursive_mutex&) = delete;
130
131     void
132     lock()
133     {
134       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
135
136       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
137       if (__e)
138         __throw_system_error(__e);
139     }
140
141     bool
142     try_lock()
143     {
144       // XXX EINVAL, EAGAIN, EBUSY
145       return !__gthread_recursive_mutex_trylock(&_M_mutex);
146     }
147
148     void
149     unlock()
150     {
151       // XXX EINVAL, EAGAIN, EBUSY
152       __gthread_recursive_mutex_unlock(&_M_mutex);
153     }
154
155     native_handle_type
156     native_handle()
157     { return &_M_mutex; }
158
159   private:
160     __gthread_recursive_mutex_t  _M_mutex;
161   };
162
163   /// timed_mutex
164   class timed_mutex
165   {  
166   public:
167     typedef __gthread_mutex_t* native_handle_type;
168
169     timed_mutex()
170     {
171 #ifdef __GTHREAD_MUTEX_INIT
172       __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
173       _M_mutex = __tmp;
174 #else
175       __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
176 #endif
177     }
178
179     timed_mutex(const timed_mutex&) = delete;
180     timed_mutex& operator=(const timed_mutex&) = delete;
181
182     void
183     lock()
184     {
185       int __e = __gthread_mutex_lock(&_M_mutex);
186
187       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
188       if (__e)
189         __throw_system_error(__e);
190     }
191
192     bool
193     try_lock()
194     {
195       // XXX EINVAL, EAGAIN, EBUSY
196       return !__gthread_mutex_trylock(&_M_mutex);
197     }
198
199     template <class _Rep, class _Period>
200       bool
201       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
202       { return __try_lock_for_impl(__rtime); }
203
204     template <class _Clock, class _Duration>
205       bool
206       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
207       { 
208         chrono::time_point<_Clock, chrono::seconds> __s =
209           chrono::time_point_cast<chrono::seconds>(__atime);
210
211         chrono::nanoseconds __ns =
212           chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
213
214         __gthread_time_t __ts = {
215           static_cast<std::time_t>(__s.time_since_epoch().count()),
216           static_cast<long>(__ns.count())
217         };
218
219         return !__gthread_mutex_timedlock(&_M_mutex, &__ts);    
220       }
221
222     void
223     unlock()
224     {
225       // XXX EINVAL, EAGAIN, EBUSY
226       __gthread_mutex_unlock(&_M_mutex);
227     }
228
229     native_handle_type
230     native_handle()
231     { return &_M_mutex; }
232     
233   private:
234     __gthread_mutex_t _M_mutex;
235     
236 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
237     typedef chrono::monotonic_clock __clock_t;
238 #else
239     typedef chrono::high_resolution_clock __clock_t;
240 #endif
241
242     template<typename _Rep, typename _Period>
243       typename enable_if<
244         ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
245       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
246       {
247         __clock_t::time_point __atime = __clock_t::now()
248           + chrono::duration_cast<__clock_t::duration>(__rtime);
249
250         return try_lock_until(__atime);
251       }
252
253     template <typename _Rep, typename _Period>
254       typename enable_if<
255         !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
256       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
257       {
258         __clock_t::time_point __atime = __clock_t::now()
259           + ++chrono::duration_cast<__clock_t::duration>(__rtime);
260
261         return try_lock_until(__atime);
262       }
263   };
264
265   /// recursive_timed_mutex
266   class recursive_timed_mutex
267   {
268   public:
269     typedef __gthread_recursive_mutex_t* native_handle_type;
270
271     recursive_timed_mutex()
272     {
273       // XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
274 #ifdef __GTHREAD_RECURSIVE_MUTEX_INIT
275       __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
276       _M_mutex = __tmp;
277 #else
278       __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
279 #endif
280     }
281
282     recursive_timed_mutex(const recursive_timed_mutex&) = delete;
283     recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
284
285     void
286     lock()
287     {
288       int __e = __gthread_recursive_mutex_lock(&_M_mutex);
289
290       // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
291       if (__e)
292         __throw_system_error(__e);
293     }
294
295     bool
296     try_lock()
297     {
298       // XXX EINVAL, EAGAIN, EBUSY
299       return !__gthread_recursive_mutex_trylock(&_M_mutex);
300     }
301
302     template <class _Rep, class _Period>
303       bool
304       try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
305       { return __try_lock_for_impl(__rtime); }
306
307     template <class _Clock, class _Duration>
308       bool
309       try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
310       { 
311         chrono::time_point<_Clock, chrono::seconds>  __s =
312           chrono::time_point_cast<chrono::seconds>(__atime);
313
314         chrono::nanoseconds __ns =
315           chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
316
317         __gthread_time_t __ts = {
318           static_cast<std::time_t>(__s.time_since_epoch().count()),
319           static_cast<long>(__ns.count())
320         };
321
322         return !__gthread_recursive_mutex_timedlock(&_M_mutex, &__ts);
323       }
324
325     void
326     unlock()
327     {
328       // XXX EINVAL, EAGAIN, EBUSY
329       __gthread_recursive_mutex_unlock(&_M_mutex);
330     }
331
332     native_handle_type
333     native_handle()
334     { return &_M_mutex; }
335
336   private:
337     __gthread_recursive_mutex_t _M_mutex;
338
339 #ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
340     typedef chrono::monotonic_clock __clock_t;
341 #else
342     typedef chrono::high_resolution_clock __clock_t;
343 #endif
344
345     template<typename _Rep, typename _Period>
346       typename enable_if<
347         ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
348       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
349       {
350         __clock_t::time_point __atime = __clock_t::now()
351           + chrono::duration_cast<__clock_t::duration>(__rtime);
352
353         return try_lock_until(__atime);
354       }
355
356     template <typename _Rep, typename _Period>
357       typename enable_if<
358         !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type
359       __try_lock_for_impl(const chrono::duration<_Rep, _Period>& __rtime)
360       {
361         __clock_t::time_point __atime = __clock_t::now()
362           + ++chrono::duration_cast<__clock_t::duration>(__rtime);
363
364         return try_lock_until(__atime);
365       }
366   };
367
368   /// Do not acquire ownership of the mutex.
369   struct defer_lock_t { };
370
371   /// Try to acquire ownership of the mutex without blocking.
372   struct try_to_lock_t { };
373
374   /// Assume the calling thread has already obtained mutex ownership
375   /// and manage it.
376   struct adopt_lock_t { };
377
378   extern const defer_lock_t     defer_lock;
379   extern const try_to_lock_t    try_to_lock;
380   extern const adopt_lock_t     adopt_lock;
381
382   /// Thrown to indicate errors with lock operations.
383   class lock_error : public exception
384   {
385   public:
386     virtual const char*
387     what() const throw();
388   };
389
390   /// @brief  Scoped lock idiom.
391   // Acquire the mutex here with a constructor call, then release with
392   // the destructor call in accordance with RAII style.
393   template<typename _Mutex>
394     class lock_guard
395     {
396     public:
397       typedef _Mutex mutex_type;
398
399       explicit lock_guard(mutex_type& __m) : _M_device(__m)
400       { _M_device.lock(); }
401
402       lock_guard(mutex_type& __m, adopt_lock_t __a) : _M_device(__m)
403       { _M_device.lock(); }
404
405       ~lock_guard()
406       { _M_device.unlock(); }
407
408       lock_guard(const lock_guard&) = delete;
409       lock_guard& operator=(const lock_guard&) = delete;
410
411     private:
412       mutex_type&  _M_device;
413     };
414
415   /// unique_lock
416   template<typename _Mutex>
417     class unique_lock
418     {
419     public:
420       typedef _Mutex mutex_type;
421       
422       unique_lock()
423       : _M_device(0), _M_owns(false)
424       { }
425
426       explicit unique_lock(mutex_type& __m)
427       : _M_device(&__m), _M_owns(false)
428       {
429         lock();
430         _M_owns = true;
431       }
432
433       unique_lock(mutex_type& __m, defer_lock_t)
434       : _M_device(&__m), _M_owns(false)
435       { }
436
437       unique_lock(mutex_type& __m, try_to_lock_t)
438       : _M_device(&__m), _M_owns(_M_device->try_lock())
439       { }
440
441       unique_lock(mutex_type& __m, adopt_lock_t)
442       : _M_device(&__m), _M_owns(true)
443       {
444         // XXX calling thread owns mutex
445       }
446
447       template<typename _Clock, typename _Duration>
448         unique_lock(mutex_type& __m, 
449                     const chrono::time_point<_Clock, _Duration>& __atime)
450         : _M_device(&__m), _M_owns(_M_device->try_lock_until(__atime))
451         { }
452
453       template<typename _Rep, typename _Period>
454         unique_lock(mutex_type& __m, 
455                     const chrono::duration<_Rep, _Period>& __rtime)
456         : _M_device(&__m), _M_owns(_M_device->try_lock_for(__rtime))
457         { }
458
459       ~unique_lock()
460       {
461         if (_M_owns)
462           unlock();
463       }
464
465       unique_lock(const unique_lock&) = delete;
466       unique_lock& operator=(const unique_lock&) = delete;
467
468       unique_lock(unique_lock&& __u)
469       : _M_device(__u._M_device), _M_owns(__u._M_owns)
470       {
471         __u._M_device = 0;
472         __u._M_owns = false;
473       }
474
475       unique_lock& operator=(unique_lock&& __u)
476       {
477         if(_M_owns)
478           unlock();
479         
480         unique_lock(std::move(__u)).swap(*this);
481
482         __u._M_device = 0;
483         __u._M_owns = false;
484         
485         return *this;
486       }
487
488       void
489       lock()
490       {
491         if (!_M_device)
492           __throw_system_error((int)errc::operation_not_permitted);
493         else if (_M_owns)
494           __throw_system_error((int)errc::resource_deadlock_would_occur);
495         else
496           {
497             _M_device->lock();
498             _M_owns = true;
499           }
500       }
501
502       bool
503       try_lock()
504       {
505         if (!_M_device)
506           __throw_system_error((int)errc::operation_not_permitted);
507         else if (_M_owns)
508           __throw_system_error((int)errc::resource_deadlock_would_occur);
509         else
510           {
511             _M_owns = _M_device->try_lock();        
512             return _M_owns;
513           }
514       }
515
516       template<typename _Clock, typename _Duration>
517         bool
518         try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
519         {
520           if (!_M_device)
521             __throw_system_error((int)errc::operation_not_permitted);
522           else if (_M_owns)
523             __throw_system_error((int)errc::resource_deadlock_would_occur);
524           else
525             {
526               _M_owns = _M_device->try_lock_until(__atime);
527               return _M_owns;
528             }
529         }
530       
531       template<typename _Rep, typename _Period>
532         bool
533         try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
534         {
535           if (!_M_device)
536             __throw_system_error((int)errc::operation_not_permitted);
537           else if (_M_owns)
538             __throw_system_error((int)errc::resource_deadlock_would_occur);
539           else
540             {
541               _M_owns = _M_device->try_lock_for(__rtime);
542               return _M_owns;
543             }
544          }
545
546       void
547       unlock()
548       {
549         if (!_M_owns)
550           __throw_system_error((int)errc::operation_not_permitted);
551         else if (_M_device)
552           {
553             _M_device->unlock();
554             _M_owns = false;
555           }
556       }
557       
558       void
559       swap(unique_lock&& __u)
560       {
561         std::swap(_M_device, __u._M_device);
562         std::swap(_M_owns, __u._M_owns);
563       }
564
565       mutex_type*
566       release()
567       {
568         mutex_type* __ret = _M_device;
569         _M_device = 0;
570         _M_owns = false;
571         return __ret;
572       }
573
574       bool
575       owns_lock() const
576       { return _M_owns; }
577
578       /* explicit */ operator bool () const
579       { return owns_lock(); }
580
581       mutex_type*
582       mutex() const
583       { return _M_device; }
584
585     private:
586       mutex_type*       _M_device;
587       bool              _M_owns; // XXX use atomic_bool
588     };
589
590   template<typename _Mutex>
591     inline void
592     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y)
593     { __x.swap(__y); }
594
595   template<typename _Mutex>
596     inline void
597     swap(unique_lock<_Mutex>&& __x, unique_lock<_Mutex>& __y)
598     { __x.swap(__y); }
599
600   template<typename _Mutex>
601     inline void
602     swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>&& __y)
603     { __x.swap(__y); }
604
605   template<int _Idx>
606     struct __unlock_impl
607     {
608       template<typename... _Lock>
609         static void
610         __do_unlock(tuple<_Lock&...>& __locks)
611         {
612           std::get<_Idx>(__locks).unlock();
613           __unlock_impl<_Idx - 1>::__do_unlock(__locks);
614         }
615     };
616   
617   template<>
618     struct __unlock_impl<-1>
619     {
620       template<typename... _Lock>
621         static void
622         __do_unlock(tuple<_Lock&...>&)
623         { }
624     };
625
626   template<int _Idx, bool _Continue = true>
627     struct __try_lock_impl
628     {
629       template<typename... _Lock>
630         static int
631         __do_try_lock(tuple<_Lock&...>& __locks)
632         {
633           if(std::get<_Idx>(__locks).try_lock())
634             {
635               return __try_lock_impl<_Idx + 1,
636                 _Idx + 2 < sizeof...(_Lock)>::__do_try_lock(__locks);
637             }
638           else
639             {
640               __unlock_impl<_Idx>::__do_unlock(__locks);
641               return _Idx;
642             }
643         }
644     };
645   
646   template<int _Idx>
647     struct __try_lock_impl<_Idx, false>
648     {
649       template<typename... _Lock>
650         static int
651         __do_try_lock(tuple<_Lock&...>& __locks)
652         {
653           if(std::get<_Idx>(__locks).try_lock())
654             return -1;
655           else
656             {
657               __unlock_impl<_Idx>::__do_unlock(__locks);
658               return _Idx;
659             }
660         }
661     };
662   
663   /** @brief Generic try_lock.
664    *  @param __l1 Meets Mutex requirements (try_lock() may throw).
665    *  @param __l2 Meets Mutex requirements (try_lock() may throw).
666    *  @param __l3 Meets Mutex requirements (try_lock() may throw).
667    *  @return Returns -1 if all try_lock() calls return true. Otherwise returns 
668    *          a 0-based index corresponding to the argument that returned false.
669    *  @post Either all arguments are locked, or none will be.
670    *
671    *  Sequentially calls try_lock() on each argument.
672    */
673   template<typename _Lock1, typename _Lock2, typename... _Lock3>
674     int
675     try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
676     {
677       tuple<_Lock1&, _Lock2&, _Lock3&...> __locks(__l1, __l2, __l3...);
678       return __try_lock_impl<0>::__do_try_lock(__locks);
679     }
680
681   template<typename _L1, typename _L2, typename ..._L3>
682     void
683     lock(_L1&, _L2&, _L3&...);
684
685   /// once_flag
686   struct once_flag
687   {
688     typedef __gthread_once_t __native_type;
689
690     once_flag()
691     {
692       __gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
693       _M_once = __tmp;
694     }
695     
696     once_flag(const once_flag&) = delete;
697     once_flag& operator=(const once_flag&) = delete;
698
699     template<typename _Callable, typename... _Args>
700       friend void
701       call_once(once_flag& __once, _Callable __f, _Args&&... __args);
702
703   private:
704     __native_type  _M_once;
705   };
706
707 #ifdef _GLIBCXX_HAVE_TLS
708   extern __thread void* __once_callable;
709   extern __thread void (*__once_call)();
710
711   template<typename _Callable>
712     inline void 
713     __once_call_impl()
714     {
715       (*(_Callable*)__once_callable)();
716     }
717 #else
718   extern function<void()> __once_functor;
719
720   extern unique_lock<mutex>&
721   __get_once_functor_lock();
722 #endif
723
724   extern "C" void __once_proxy();
725
726   template<typename _Callable, typename... _Args>
727     void
728     call_once(once_flag& __once, _Callable __f, _Args&&... __args)
729     {
730 #ifdef _GLIBCXX_HAVE_TLS
731       auto __bound_functor = bind(__f, __args...);
732       __once_callable = &__bound_functor;
733       __once_call = &__once_call_impl<decltype(__bound_functor)>;
734 #else
735       unique_lock<mutex>& __functor_lock = __get_once_functor_lock();
736       __functor_lock.lock();
737       __once_functor = bind(__f, __args...);
738 #endif
739      
740       int __e = __gthread_once(&(__once._M_once), &__once_proxy);
741
742 #ifndef _GLIBCXX_HAVE_TLS      
743       if (__functor_lock)
744         __functor_lock.unlock();
745 #endif
746
747       if (__e)
748         __throw_system_error(__e);
749     }
750 }
751
752 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
753
754 #endif // __GXX_EXPERIMENTAL_CXX0X__
755
756 #endif // _GLIBCXX_MUTEX