f7076b7d35867a9a0512577272b40dcfb7a03812
[serna.git] / sfworks / common / ThreadingPolicies.h
1 // 
2 // Copyright(c) 2009 Syntext, Inc. All Rights Reserved.
3 // Contact: info@syntext.com, http://www.syntext.com
4 // 
5 // This file is part of Syntext Serna XML Editor.
6 // 
7 // COMMERCIAL USAGE
8 // Licensees holding valid Syntext Serna commercial licenses may use this file
9 // in accordance with the Syntext Serna Commercial License Agreement provided
10 // with the software, or, alternatively, in accorance with the terms contained
11 // in a written agreement between you and Syntext, Inc.
12 // 
13 // GNU GENERAL PUBLIC LICENSE USAGE
14 // Alternatively, this file may be used under the terms of the GNU General 
15 // Public License versions 2.0 or 3.0 as published by the Free Software 
16 // Foundation and appearing in the file LICENSE.GPL included in the packaging 
17 // of this file. In addition, as a special exception, Syntext, Inc. gives you
18 // certain additional rights, which are described in the Syntext, Inc. GPL 
19 // Exception for Syntext Serna Free Edition, included in the file 
20 // GPL_EXCEPTION.txt in this package.
21 // 
22 // You should have received a copy of appropriate licenses along with this 
23 // package. If not, see <http://www.syntext.com/legal/>. If you are unsure
24 // which license is appropriate for your use, please contact the sales 
25 // department at sales@syntext.com.
26 // 
27 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 // 
30 /*! \file
31     This file contains lightweight, policy-based threading library
32     Windows part is derived from free Loki C++ library
33
34     Template classes defined below are not intended for general use;
35     rather they should be used for parametrization of other template
36     classes who needs threading policies (like Singleton, Ptr, etc).
37  */
38 #ifndef THREADING_POLICIES_H_
39 #define THREADING_POLICIES_H_
40
41 #include "common/common_defs.h"
42 #include "common/ThreadMutex.h"
43
44
45 // Specifies default threading model
46
47 #ifndef DEFAULT_THREADING
48 # ifdef MULTI_THREADED
49 #  define DEFAULT_THREADING    COMMON_NS::ObjectLevelLockable
50 #  define DEFAULT_THREADING_CL COMMON_NS::ClassLevelLockable
51 # else
52 #  define DEFAULT_THREADING    COMMON_NS::SingleThreaded
53 #  define DEFAULT_THREADING_CL COMMON_NS::SingleThreaded
54 # endif
55 #endif // DEFAULT_THREADING
56
57 COMMON_NS_BEGIN
58
59 // This is not a template because certain compilers have problem
60 // with empty base optimization.
61 #define ATOMIC_OPS_FORWARDERS__ \
62     typedef typename M::IntType         IntType; \
63     typedef typename M::VolatileIntType VolatileIntType; \
64     typedef typename M::MutexType       MutexType; \
65     \
66     typedef M ThreadMutexClass; \
67     \
68     static IntType atomicIncrement(VolatileIntType& lval) { \
69         return M::atomicIncrement(lval); \
70     } \
71     static IntType atomicDecrement(VolatileIntType& lval) { \
72         return M::atomicDecrement(lval); \
73     } \
74     static IntType atomicRead(VolatileIntType& lval) { \
75         return M::atomicRead(lval); \
76     } \
77     static void    atomicAssign(VolatileIntType& lval, IntType rval) { \
78         M::atomicAssign(lval, rval); \
79     }
80
81 /*! Implementation of the SingleThreaded (no-synchronization) ThreadingModel
82     policy used by various classes.
83     It is desirable for all policies that class Lock should be constructed
84     given a reference to the host class (a class which holds the lock
85     instance). This reference is used only for ObjectLevelLockable,
86     for all other threading policies it is ignored.
87     Classes which do not initalize Lock with lock holder will not be
88     able to use ObjectLevelLockable.
89
90     T template argument is used for obtaining thread-specific type
91     traits (e.g. volatile type).
92  */
93 template <class M = NullThreadMutex>
94   class SingleThreaded {
95 public:
96     ATOMIC_OPS_FORWARDERS__;
97     enum { multiThreaded = false }; // not really multithreaded
98
99     /*! A lock guard primitive
100      */
101     class Lock
102     {
103     public:
104         Lock() {}
105         Lock(const SingleThreaded&) {}
106         Lock(const Lock&) {}
107         ~Lock() {} // GCC warning buster
108     };
109     // out-of-class traits use only
110     typedef M VolatileType;
111 };
112
113 /*! An implementation of ObjectLevelLockable ThreadingModel policy.
114  */
115 template <class M = ThreadMutex>
116   class ObjectLevelLockable {
117 public:
118     ATOMIC_OPS_FORWARDERS__;
119     enum { multiThreaded = true };
120
121     ObjectLevelLockable() {
122         M::initialize(&mtx_);
123     }
124
125     ~ObjectLevelLockable() {
126         M::destroy(&mtx_);
127     }
128     class Lock;
129     friend class Lock;
130
131     class Lock
132     {
133     private:
134         ObjectLevelLockable& host_;
135
136         Lock& operator=(const Lock&);
137     public:
138         Lock(ObjectLevelLockable& host) : host_(host)
139         {
140             M::lock(&host_.mtx_);
141         }
142         ~Lock()
143         {
144             M::unlock(&host_.mtx_);
145         }
146         Lock(const Lock& other) : host_(other.host_) {}
147     };
148     // out-of-class traits use only
149     typedef volatile M VolatileType;
150
151 private:
152     MutexType mtx_;
153 };
154
155 template <class M = ThreadMutex>
156   class ClassLevelLockable {
157 public:
158     ATOMIC_OPS_FORWARDERS__;
159     enum { multiThreaded = true };
160
161     class Lock;
162     friend class Lock;
163
164     class Lock
165     {
166         Lock& operator=(const Lock&);
167     public:
168         Lock()
169         {
170             if (!initialized_) {
171                 M::initialize(&mtx_);
172                 initialized_ = true;
173             }
174             M::lock(&mtx_);
175         }
176         Lock(ClassLevelLockable&)
177         {
178             if (!initialized_) {
179                 M::initialize(&mtx_);
180                 initialized_ = true;
181             }
182             M::lock(&mtx_);
183         }
184         ~Lock()
185         {
186             M::unlock(&mtx_);
187         }
188         Lock(const Lock&) {} // do nothing on copy
189     };
190     // out-of-class traits use only
191     typedef volatile M VolatileType;
192
193 private:
194     static MutexType mtx_;
195     static bool initialized_;
196
197     struct Initializer;
198     friend struct Initializer;
199     struct Initializer
200     {
201         Initializer()
202         {
203             if (!initialized_)
204                 M::initialize(&mtx_);
205             initialized_ = true;
206         }
207         ~Initializer()
208         {
209             if (initialized_)
210                 M::destroy(&mtx_);
211         }
212     };
213     static Initializer initializer_;
214 };
215
216 template <class M> typename ClassLevelLockable<M>::MutexType
217     ClassLevelLockable<M>::mtx_;
218 template <class M> bool ClassLevelLockable<M>::initialized_ = false;
219 template <class M> typename ClassLevelLockable<M>::Initializer
220     ClassLevelLockable<M>::initializer_;
221
222 #undef ATOMIC_OPS_FORWARDERS__
223
224 COMMON_NS_END
225
226 #endif // THREADING_POLICIES_H_