]> granicus.if.org Git - icinga2/blob - lib/base/objectlock.hpp
Build fix for Win64
[icinga2] / lib / base / objectlock.hpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #ifndef OBJECTLOCK_H
21 #define OBJECTLOCK_H
22
23 #include "base/object.hpp"
24
25 #define I2MUTEX_UNLOCKED 0
26 #define I2MUTEX_LOCKED 1
27
28 namespace icinga
29 {
30
31 /**
32  * A scoped lock for Objects.
33  */
34 struct I2_BASE_API ObjectLock {
35 public:
36         inline ObjectLock(void)
37                 : m_Object(NULL), m_Locked(false)
38         { }
39
40         inline ~ObjectLock(void)
41         {
42                 Unlock();
43         }
44
45         inline ObjectLock(const Object::Ptr& object)
46                 : m_Object(object.get()), m_Locked(false)
47         {
48                 if (m_Object)
49                         Lock();
50         }
51
52         inline ObjectLock(const Object *object)
53                 : m_Object(object), m_Locked(false)
54         {
55                 if (m_Object)
56                         Lock();
57         }
58
59         inline static void LockMutex(const Object *object)
60         {
61                 unsigned int it = 0;
62
63 #ifdef _WIN32
64 #       ifdef _WIN64
65                 while (InterlockedCompareExchange64((LONGLONG *)&object->m_Mutex, I2MUTEX_LOCKED, I2MUTEX_UNLOCKED) != I2MUTEX_UNLOCKED) {
66 #       else /* _WIN64 */
67                 while (InterlockedCompareExchange(&object->m_Mutex, I2MUTEX_LOCKED, I2MUTEX_UNLOCKED) != I2MUTEX_UNLOCKED) {
68 #       endif /* _WIN64 */
69 #else /* _WIN32 */
70                 while (!__sync_bool_compare_and_swap(&object->m_Mutex, I2MUTEX_UNLOCKED, I2MUTEX_LOCKED)) {
71 #endif /* _WIN32 */
72                         if (object->m_Mutex > I2MUTEX_LOCKED) {
73                                 boost::recursive_mutex *mtx = reinterpret_cast<boost::recursive_mutex *>(object->m_Mutex);
74                                 mtx->lock();
75
76                                 return;
77                         }
78
79                         Spin(it);
80                         it++;
81                 }
82
83                 boost::recursive_mutex *mtx = new boost::recursive_mutex();
84                 mtx->lock();
85 #ifdef _WIN32
86 #       ifdef _WIN64
87                 InterlockedCompareExchange64((LONGLONG *)&object->m_Mutex, reinterpret_cast<LONGLONG>(mtx), I2MUTEX_LOCKED);
88 #       else /* _WIN64 */
89                 InterlockedCompareExchange(&object->m_Mutex, reinterpret_cast<LONG>(mtx), I2MUTEX_LOCKED);
90 #       endif /* _WIN64 */
91 #else /* _WIN32 */
92                 __sync_bool_compare_and_swap(&object->m_Mutex, I2MUTEX_LOCKED, reinterpret_cast<uintptr_t>(mtx));
93 #endif /* _WIN32 */
94         }
95
96         inline void Lock(void)
97         {
98                 ASSERT(!m_Locked && m_Object != NULL);
99
100                 LockMutex(m_Object);
101
102                 m_Locked = true;
103
104 #ifdef I2_DEBUG
105 #       ifdef _WIN32
106                 InterlockedExchange(&m_Object->m_LockOwner, GetCurrentThreadId());
107 #       else /* _WIN32 */
108                 __sync_lock_test_and_set(&m_Object->m_LockOwner, pthread_self());
109 #       endif /* _WIN32 */
110 #endif /* I2_DEBUG */
111         }
112
113         inline static void Spin(unsigned int it)
114         {
115                 if (it < 8) {
116                         /* Do nothing. */
117                 }
118 #ifdef SPIN_PAUSE
119                 else if (it < 16) {
120                         SPIN_PAUSE();
121                 }
122 #endif /* SPIN_PAUSE */
123                 else {
124 #ifdef _WIN32
125                         Sleep(0);
126 #else /* _WIN32 */
127                         sched_yield();
128 #endif /* _WIN32 */
129                 }
130         }
131
132         inline void Unlock(void)
133         {
134 #ifdef I2_DEBUG
135                 if (m_Locked) {
136 #       ifdef _WIN32
137                         InterlockedExchange(&m_Object->m_LockOwner, 0);
138 #       else /* _WIN32 */
139                         __sync_lock_release(&m_Object->m_LockOwner);
140 #       endif /* _WIN32 */
141                 }
142 #endif /* I2_DEBUG */
143
144                 if (m_Locked) {
145                         reinterpret_cast<boost::recursive_mutex *>(m_Object->m_Mutex)->unlock();
146                         m_Locked = false;
147                 }
148         }
149
150 private:
151         const Object *m_Object;
152         bool m_Locked;
153 };
154
155 }
156
157 #endif /* OBJECTLOCK_H */