Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #ifndef INCLUDED_RTL_INSTANCE_HXX
21 : #define INCLUDED_RTL_INSTANCE_HXX
22 :
23 : #include <sal/config.h>
24 :
25 : #include <osl/doublecheckedlocking.h>
26 : #if ! HAVE_THREADSAFE_STATICS
27 : #include <osl/getglobalmutex.hxx>
28 : #endif
29 :
30 : namespace {
31 :
32 : /** A non-broken version of the double-checked locking pattern.
33 :
34 : See
35 : <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
36 : for a description of double-checked locking, why it is broken, and how it
37 : can be fixed. Always use this template instead of spelling out the
38 : double-checked locking pattern explicitly, and only in those rare cases
39 : where that is not possible and you have to spell it out explicitly, at
40 : least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
41 : places. That way, all platform-dependent code to make double-checked
42 : locking work can be kept in one place.
43 :
44 : Usage scenarios:
45 :
46 : 1 Static instance (most common case)
47 :
48 : Pattern:
49 :
50 : T * getInstance()
51 : {
52 : static T * pInstance = 0;
53 : if (!pInstance)
54 : {
55 : ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
56 : if (!pInstance)
57 : {
58 : static T aInstance;
59 : pInstance = &aInstance;
60 : }
61 : }
62 : return pInstance;
63 : }
64 :
65 : Code:
66 :
67 : #include <rtl/instance.hxx>
68 : #include <osl/getglobalmutex.hxx>
69 :
70 : namespace {
71 : struct Init
72 : {
73 : T * operator()()
74 : {
75 : static T aInstance;
76 : return &aInstance;
77 : }
78 : };
79 : }
80 :
81 : T * getInstance()
82 : {
83 : return rtl_Instance< T, Init, ::osl::MutexGuard,
84 : ::osl::GetGlobalMutex >::create(
85 : Init(), ::osl::GetGlobalMutex());
86 : }
87 :
88 : 2 Dynamic instance
89 :
90 : Pattern:
91 :
92 : T * getInstance()
93 : {
94 : static T * pInstance = 0;
95 : if (!pInstance)
96 : {
97 : ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
98 : if (!pInstance)
99 : pInstance = new T;
100 : }
101 : return pInstance;
102 : }
103 :
104 : Code:
105 :
106 : #include <rtl/instance.hxx>
107 : #include <osl/getglobalmutex.hxx>
108 :
109 : namespace {
110 : struct Init
111 : {
112 : T * operator()()
113 : {
114 : return new T;
115 : }
116 : };
117 : }
118 :
119 : T * getInstance()
120 : {
121 : return rtl_Instance< T, Init, ::osl::MutexGuard,
122 : ::osl::GetGlobalMutex >::create(
123 : Init(), ::osl::GetGlobalMutex());
124 : }
125 :
126 : 3 Other guard/mutex
127 :
128 : Pattern:
129 :
130 : T * getInstance()
131 : {
132 : static T * pInstance = 0;
133 : if (!pInstance)
134 : {
135 : SomeGuard aGuard(pSomeMutex);
136 : if (!pInstance)
137 : {
138 : static T aInstance;
139 : pInstance = &aInstance;
140 : }
141 : }
142 : return pInstance;
143 : }
144 :
145 : Code:
146 :
147 : #include <rtl/instance.hxx>
148 :
149 : namespace {
150 : struct InitInstance
151 : {
152 : T * operator()()
153 : {
154 : static T aInstance;
155 : return &aInstance;
156 : }
157 : };
158 :
159 : struct InitGuard
160 : {
161 : SomeMutex * operator()()
162 : {
163 : return pSomeMutex;
164 : }
165 : };
166 : }
167 :
168 : T * getInstance()
169 : {
170 : return rtl_Instance< T, InitInstance,
171 : SomeGuard, InitGuard >::create(
172 : InitInstance(), InitMutex());
173 : }
174 :
175 : 4 Calculate extra data
176 :
177 : Pattern:
178 :
179 : T * getInstance()
180 : {
181 : static T * pInstance = 0;
182 : if (!pInstance)
183 : {
184 : Data aData(...);
185 : ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
186 : if (!pInstance)
187 : {
188 : static T aInstance(aData);
189 : pInstance = &aInstance;
190 : }
191 : }
192 : return pInstance;
193 : }
194 :
195 : Code:
196 :
197 : #include <rtl/instance.hxx>
198 : #include <osl/getglobalmutex.hxx>
199 :
200 : namespace {
201 : struct InitInstance
202 : {
203 : T * operator()()
204 : {
205 : static T aInstance;
206 : return &aInstance;
207 : }
208 : }
209 :
210 : struct InitData
211 : {
212 : Data const & operator()()
213 : {
214 : return ...;
215 : }
216 : }
217 : }
218 :
219 : T * getInstance()
220 : {
221 : return rtl_Instance< T, InitInstance,
222 : ::osl::Mutex, ::osl::GetGlobalMutex,
223 : Data, InitData >::create(
224 : InitInstance(), ::osl::GetGlobalMutex(), InitData());
225 : }
226 :
227 : Some comments:
228 :
229 : For any instantiation of rtl_Instance, at most one call to a create method
230 : may occur in the program code: Each occurrence of a create method within
231 : the program code is supposed to return a fresh object instance on the
232 : first call, and that same object instance on subsequent calls; but
233 : independent occurrences of create methods are supposed to return
234 : independent object instances. Since there is a one-to-one correspondence
235 : between object instances and instantiations of rtl_Instance, the
236 : requirement should be clear. One measure to enforce the requirement is
237 : that rtl_Instance lives in an unnamed namespace, so that instantiations of
238 : rtl_Instance in different translation units will definitely be different
239 : instantiations. A drawback of that measure is that the name of the class
240 : needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
241 : prefix like "::rtl::".
242 :
243 : A known problem with this template is when two occurrences of calls to
244 : create methods with identical template arguments appear in one translation
245 : unit. Those two places will share a single object instance. This can be
246 : avoided by using different Init structs (see the above code samples) in
247 : the two places.
248 :
249 : There is no need to make m_pInstance volatile, in order to avoid usage of
250 : stale copies of m_pInstance: At the first check, a thread will see that
251 : m_pInstance contains either 0 or a valid pointer. If it contains a valid
252 : pointer, it cannot be stale, and that pointer is used. If it contains 0,
253 : acquiring the mutex will ensure that the second check sees a non-stale
254 : value in all cases.
255 :
256 : On some compilers, the create methods would not be inlined if they
257 : contained any static variables, so m_pInstance is made a class member
258 : instead (and the create methods are inlined). But on MSC, the definition
259 : of the class member m_pInstance would cause compilation to fail with an
260 : internal compiler error. Since MSC is able to inline methods containing
261 : static variables, m_pInstance is moved into the methods there. Note that
262 : this only works well because for any instantiation of rtl_Instance at most
263 : one call to a create method should be present, anyway.
264 : */
265 : template< typename Inst, typename InstCtor,
266 : typename Guard, typename GuardCtor,
267 : typename Data = int, typename DataCtor = int >
268 : class rtl_Instance
269 : {
270 : public:
271 2089445 : static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
272 : {
273 : #if defined _MSC_VER
274 : static Inst * m_pInstance = 0;
275 : #endif // _MSC_VER
276 2089445 : Inst * p = m_pInstance;
277 2089445 : if (!p)
278 : {
279 876 : Guard aGuard(aGuardCtor());
280 876 : p = m_pInstance;
281 876 : if (!p)
282 : {
283 876 : p = aInstCtor();
284 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
285 876 : m_pInstance = p;
286 876 : }
287 : }
288 : else
289 : {
290 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
291 : }
292 2089445 : return p;
293 : }
294 :
295 154 : static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
296 : DataCtor aDataCtor)
297 : {
298 : #if defined _MSC_VER
299 : static Inst * m_pInstance = 0;
300 : #endif // _MSC_VER
301 154 : Inst * p = m_pInstance;
302 154 : if (!p)
303 : {
304 77 : Data aData(aDataCtor());
305 154 : Guard aGuard(aGuardCtor());
306 77 : p = m_pInstance;
307 77 : if (!p)
308 : {
309 77 : p = aInstCtor(aData);
310 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
311 77 : m_pInstance = p;
312 77 : }
313 : }
314 : else
315 : {
316 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
317 : }
318 154 : return p;
319 : }
320 :
321 : static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
322 : const Data &rData)
323 : {
324 : #if defined _MSC_VER
325 : static Inst * m_pInstance = 0;
326 : #endif // _MSC_VER
327 : Inst * p = m_pInstance;
328 : if (!p)
329 : {
330 : Guard aGuard(aGuardCtor());
331 : p = m_pInstance;
332 : if (!p)
333 : {
334 : p = aInstCtor(rData);
335 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
336 : m_pInstance = p;
337 : }
338 : }
339 : else
340 : {
341 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
342 : }
343 : return p;
344 : }
345 :
346 : private:
347 : #if !defined _MSC_VER
348 : static Inst * m_pInstance;
349 : #endif // _MSC_VER
350 : };
351 :
352 : #if !defined _MSC_VER
353 : template< typename Inst, typename InstCtor,
354 : typename Guard, typename GuardCtor,
355 : typename Data, typename DataCtor >
356 : Inst *
357 : rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
358 : = 0;
359 : #endif // _MSC_VER
360 :
361 : }
362 :
363 : namespace rtl {
364 :
365 : /** Helper base class for a late-initialized (default-constructed)
366 : static variable, implementing the double-checked locking pattern correctly.
367 :
368 : @derive
369 : Derive from this class (common practice), e.g.
370 : <pre>
371 : struct MyStatic : public rtl::Static<MyType, MyStatic> {};
372 : ...
373 : MyType & rStatic = MyStatic::get();
374 : ...
375 : </pre>
376 :
377 : @tparam T
378 : variable's type
379 : @tparam Unique
380 : Implementation trick to make the inner static holder unique,
381 : using the outer class
382 : (the one that derives from this base class)
383 : */
384 : #if HAVE_THREADSAFE_STATICS
385 : template<typename T, typename Unique>
386 : class Static {
387 : public:
388 : /** Gets the static. Mutual exclusion is implied by a functional
389 : -fthreadsafe-statics
390 :
391 : @return
392 : static variable
393 : */
394 15817511691 : static T & get() {
395 15817511691 : static T instance;
396 15817511695 : return instance;
397 : }
398 : };
399 : #else
400 : template<typename T, typename Unique>
401 : class Static {
402 : public:
403 : /** Gets the static. Mutual exclusion is performed using the
404 : osl global mutex.
405 :
406 : @return
407 : static variable
408 : */
409 : static T & get() {
410 : return *rtl_Instance<
411 : T, StaticInstance,
412 : ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
413 : StaticInstance(), ::osl::GetGlobalMutex() );
414 : }
415 : private:
416 : struct StaticInstance {
417 : T * operator () () {
418 : static T instance;
419 : return &instance;
420 : }
421 : };
422 : };
423 : #endif
424 :
425 : /** Helper base class for a late-initialized (default-constructed)
426 : static variable, implementing the double-checked locking pattern correctly.
427 :
428 : @derive
429 : Derive from this class (common practice), e.g.
430 : <pre>
431 : struct MyStatic : public rtl::Static<MyType, MyStatic> {};
432 : ...
433 : MyType & rStatic = MyStatic::get();
434 : ...
435 : </pre>
436 :
437 : @tparam T
438 : variable's type
439 : @tparam Unique
440 : Implementation trick to make the inner static holder unique,
441 : using the outer class
442 : (the one that derives from this base class)
443 : */
444 : #if HAVE_THREADSAFE_STATICS
445 : template<typename T, typename Data, typename Unique>
446 : class StaticWithArg {
447 : public:
448 : /** Gets the static. Mutual exclusion is implied by a functional
449 : -fthreadsafe-statics
450 :
451 : @return
452 : static variable
453 : */
454 27420580 : static T & get(const Data& rData) {
455 27420580 : static T instance(rData);
456 27420580 : return instance;
457 : }
458 :
459 : /** Gets the static. Mutual exclusion is implied by a functional
460 : -fthreadsafe-statics
461 :
462 : @return
463 : static variable
464 : */
465 25526 : static T & get(Data& rData) {
466 25526 : static T instance(rData);
467 25526 : return instance;
468 : }
469 : };
470 : #else
471 : template<typename T, typename Data, typename Unique>
472 : class StaticWithArg {
473 : public:
474 : /** Gets the static. Mutual exclusion is performed using the
475 : osl global mutex.
476 :
477 : @return
478 : static variable
479 : */
480 : static T & get(const Data& rData) {
481 : return *rtl_Instance<
482 : T, StaticInstanceWithArg,
483 : ::osl::MutexGuard, ::osl::GetGlobalMutex,
484 : Data >::create( StaticInstanceWithArg(),
485 : ::osl::GetGlobalMutex(),
486 : rData );
487 : }
488 :
489 : /** Gets the static. Mutual exclusion is performed using the
490 : osl global mutex.
491 :
492 : @return
493 : static variable
494 : */
495 : static T & get(Data& rData) {
496 : return *rtl_Instance<
497 : T, StaticInstanceWithArg,
498 : ::osl::MutexGuard, ::osl::GetGlobalMutex,
499 : Data >::create( StaticInstanceWithArg(),
500 : ::osl::GetGlobalMutex(),
501 : rData );
502 : }
503 : private:
504 : struct StaticInstanceWithArg {
505 : T * operator () (const Data& rData) {
506 : static T instance(rData);
507 : return &instance;
508 : }
509 :
510 : T * operator () (Data& rData) {
511 : static T instance(rData);
512 : return &instance;
513 : }
514 : };
515 : };
516 : #endif
517 :
518 : /** Helper class for a late-initialized static aggregate, e.g. an array,
519 : implementing the double-checked locking pattern correctly.
520 :
521 : @tparam T
522 : aggregate's element type
523 : @tparam InitAggregate
524 : initializer functor class
525 : */
526 : #if HAVE_THREADSAFE_STATICS
527 : template<typename T, typename InitAggregate>
528 : class StaticAggregate {
529 : public:
530 : /** Gets the static aggregate, late-initializing.
531 : Mutual exclusion is implied by a functional
532 : -fthreadsafe-statics
533 :
534 : @return
535 : aggregate
536 : */
537 1854968687 : static T * get() {
538 1854968687 : static T *instance = InitAggregate()();
539 1854968687 : return instance;
540 : }
541 : };
542 : #else
543 : template<typename T, typename InitAggregate>
544 : class StaticAggregate {
545 : public:
546 : /** Gets the static aggregate, late-initializing.
547 : Mutual exclusion is performed using the osl global mutex.
548 :
549 : @return
550 : aggregate
551 : */
552 : static T * get() {
553 : return rtl_Instance<
554 : T, InitAggregate,
555 : ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
556 : InitAggregate(), ::osl::GetGlobalMutex() );
557 : }
558 : };
559 : #endif
560 : /** Helper base class for a late-initialized static variable,
561 : implementing the double-checked locking pattern correctly.
562 :
563 : @derive
564 : Derive from this class (common practice),
565 : providing an initializer functor class, e.g.
566 : <pre>
567 : struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
568 : MyType operator () () {
569 : ...
570 : return MyType( ... );
571 : }
572 : };
573 : ...
574 : MyType & rStatic = MyStatic::get();
575 : ...
576 : </pre>
577 :
578 : @tparam T
579 : variable's type
580 : @tparam InitData
581 : initializer functor class
582 : @tparam Unique
583 : Implementation trick to make the inner static holder unique,
584 : using the outer class
585 : (the one that derives from this base class).
586 : Default is InitData (common practice).
587 : @tparam Data
588 : Initializer functor's return type.
589 : Default is T (common practice).
590 : */
591 : #if HAVE_THREADSAFE_STATICS
592 : template<typename T, typename InitData,
593 : typename Unique = InitData, typename Data = T>
594 : class StaticWithInit {
595 : public:
596 : /** Gets the static. Mutual exclusion is implied by a functional
597 : -fthreadsafe-statics
598 :
599 : @return
600 : static variable
601 : */
602 1938743759 : static T & get() {
603 1938743759 : static T instance = InitData()();
604 1938743759 : return instance;
605 : }
606 : };
607 : #else
608 : template<typename T, typename InitData,
609 : typename Unique = InitData, typename Data = T>
610 : class StaticWithInit {
611 : public:
612 : /** Gets the static. Mutual exclusion is performed using the
613 : osl global mutex.
614 :
615 : @return
616 : static variable
617 : */
618 : static T & get() {
619 : return *rtl_Instance<
620 : T, StaticInstanceWithInit,
621 : ::osl::MutexGuard, ::osl::GetGlobalMutex,
622 : Data, InitData >::create( StaticInstanceWithInit(),
623 : ::osl::GetGlobalMutex(),
624 : InitData() );
625 : }
626 : private:
627 : struct StaticInstanceWithInit {
628 : T * operator () ( Data d ) {
629 : static T instance(d);
630 : return &instance;
631 : }
632 : };
633 : };
634 : #endif
635 : } // namespace rtl
636 :
637 : #endif // INCLUDED_RTL_INSTANCE_HXX
638 :
639 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|