Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
292 andreas 1
/*
2
 * Copyright (C) 2023 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <vector>
20
#include <thread>
21
 
22
#include "terror.h"
23
 
24
using std::vector;
25
using std::thread;
26
 
27
static std::vector<__LOCKLIST_t> _locks;
28
 
29
template<typename _TMutex>
30
TLock<_TMutex>::TLock(TLock::mutex_type& __m)
31
    : _M_device(__m)
32
{
33
    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m)");
34
 
35
    bool death = false;
36
    bool l = addLock(&death);
37
 
38
    if ((mNoDeathLock || death) && !l)
39
        return;
40
 
41
    _M_device.lock();
42
}
43
 
44
template<typename _TMutex>
45
TLock<_TMutex>::TLock(TLock::mutex_type& __m, char *file, int line)
46
    : _M_device(__m),
47
      mFilename(file),
48
      mLineNumber(line)
49
{
50
    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m)");
51
 
293 andreas 52
    stripFileName();
292 andreas 53
    bool death = false;
54
    bool l = addLock(&death);
55
 
56
    if ((mNoDeathLock || death) && !l)
57
        return;
58
 
59
    _M_device.lock();
60
}
61
 
62
template<typename _TMutex>
299 andreas 63
TLock<_TMutex>::TLock(mutex_type& __m, bool tryit, char *file, int line)
64
    : _M_device(__m),
65
      mFilename(file),
66
      mLineNumber(line),
67
      mNoDeathLock(tryit)
68
{
69
    DECL_TRACER("TLock<_TMutex>::TLock(mutex_type& __m, bool tryit, char *file, int line)");
70
 
71
    stripFileName();
72
    bool death = false;
73
    bool l = addLock(&death);
74
 
75
    if ((mNoDeathLock || death) && !l)
76
        return;
77
 
78
    if (tryit)
79
        _M_device.try_lock();
80
    else
81
        _M_device.lock();
82
}
83
 
84
template<typename _TMutex>
292 andreas 85
TLock<_TMutex>::TLock(TLock::mutex_type& __m, std::adopt_lock_t) noexcept
86
    : _M_device(__m)
87
{
88
    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m, std::adopt_lock_t) noexcept");
89
}
90
 
91
template<typename _TMutex>
92
TLock<_TMutex>::~TLock()
93
{
94
    DECL_TRACER("TLock<_TMutex>::~TLock()");
95
 
96
    if (removeLock())
97
        _M_device.unlock();
98
}
99
 
100
template<typename _TMutex>
101
void TLock<_TMutex>::unlock()
102
{
103
    DECL_TRACER("TLock<_TMutex>::unlock()");
104
 
105
    if (_locks.empty())
106
        return;
107
 
108
    vector<__LOCKLIST_t>::iterator iter;
109
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
110
 
111
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
112
    {
113
        if (iter->native_handle == nhandle && iter->state)
114
        {
115
            iter->state = false;
116
            iter->noDeathLock = false;
117
            _M_device.unlock();
293 andreas 118
 
119
            if (mFilename.empty())
120
            {
121
                MSG_DEBUG("The mutex handle " << iter->native_handle << " was released!");
122
            }
123
            else
124
            {
125
                MSG_DEBUG("The mutex handle " << iter->native_handle << " was released on file " << mFilename << " at line " << mLineNumber << "!");
126
            }
127
 
292 andreas 128
            return;
129
        }
130
    }
131
}
132
 
133
template<typename _TMutex>
134
void TLock<_TMutex>::unlock(char* file, int line)
135
{
136
    DECL_TRACER("TLock<_TMutex>::unlock(char* file, int line)");
137
 
293 andreas 138
    mFilename = file;
139
    mLineNumber = line;
140
    stripFileName();
141
 
292 andreas 142
    unlock();
143
}
144
 
145
template<typename _TMutex>
146
void TLock<_TMutex>::relock()
147
{
148
    DECL_TRACER("TLock<_TMutex>::relock(TLock::mutex_type& __m)");
149
 
150
    if (_locks.empty())
151
        return;
152
 
153
    vector<__LOCKLIST_t>::iterator iter;
154
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
155
 
156
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
157
    {
158
        if (iter->native_handle == nhandle && !iter->state)
159
        {
160
            iter->state = true;
161
            _M_device.lock();
162
            return;
163
        }
164
    }
165
}
166
 
167
template<typename _TMutex>
168
bool TLock<_TMutex>::isLocked()
169
{
170
    if (_locks.empty())
171
        return false;
172
 
173
    vector<__LOCKLIST_t>::iterator iter;
174
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
175
 
176
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
177
    {
178
        if (iter->native_handle == nhandle && iter->state)
179
            return true;
180
    }
181
 
182
    return false;
183
}
184
 
185
template<typename _TMutex>
186
void TLock<_TMutex>::setNoDeathLock(bool l)
187
{
188
    DECL_TRACER("TLock<_TMutex>::setNoDeathLock(bool l)");
189
 
190
    mNoDeathLock = l;
191
    vector<__LOCKLIST_t>::iterator iter;
192
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
193
 
194
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
195
    {
196
        if (iter->native_handle == nhandle)
197
        {
198
            iter->noDeathLock = l;
199
            break;
200
        }
201
    }
202
}
203
 
204
 
205
template<typename _TMutex>
206
bool TLock<_TMutex>::addLock(bool *death)
207
{
208
    DECL_TRACER("TLock<_TMutex>::addLock(bool *death)");
209
 
210
    __LOCKLIST_t lc;
211
    lc.state = true;
212
    lc.noDeathLock = mNoDeathLock;
213
    lc.native_handle = _M_device.native_handle();
214
 
215
    if (_locks.empty())
216
    {
217
        _locks.push_back(lc);
218
 
293 andreas 219
        if (mFilename.empty())
220
        {
221
            MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added.");
222
        }
223
        else
224
        {
225
            MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added on file " << mFilename << " at line " << mLineNumber << ".");
226
        }
227
 
292 andreas 228
        if (death)
229
            *death = lc.noDeathLock;
230
 
231
        return true;
232
    }
233
 
234
    vector<__LOCKLIST_t>::iterator iter;
235
 
236
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
237
    {
238
        if (iter->native_handle == lc.native_handle)
239
        {
240
            if (death)
241
                *death = iter->noDeathLock;
242
 
243
            if (iter->state)
244
            {
245
                if (mNoDeathLock || iter->noDeathLock)
246
                {
247
                    if (mFilename.empty())
248
                    {
249
                        MSG_WARNING("The mutex handle " << iter->native_handle << " is already locked!");
250
                    }
251
                    else
252
                    {
253
                        MSG_WARNING("The mutex handle " << iter->native_handle << " is already locked on file " << mFilename << " at line " << mLineNumber << "!");
254
                    }
255
                }
256
                else
257
                {
258
                    if (mFilename.empty())
259
                    {
260
                        MSG_ERROR("Death lock detected! The mutex handle " << iter->native_handle << " is already locked.");
261
                    }
262
                    else
263
                    {
264
                        MSG_ERROR("Death lock detected! The mutex handle " << iter->native_handle << " is already locked on file " << mFilename << " at line " << mLineNumber << ".");
265
                    }
266
                }
267
 
268
                return false;
269
            }
270
            else
271
            {
272
                iter->state = true;
273
 
274
                if (mFilename.empty())
275
                {
276
                    MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " was reactivated.");
277
                }
278
                else
279
                {
280
                    MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " was reactivated on file " << mFilename << " at line " << mLineNumber << ".");
281
                }
282
 
283
                return true;
284
            }
285
        }
286
    }
287
 
288
    _locks.push_back(lc);
289
 
290
    if (mFilename.empty())
291
    {
292
        MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added.");
293
    }
294
    else
295
    {
296
        MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added on file " << mFilename << " at line " << mLineNumber << ".");
297
    }
298
 
299
    if (death)
300
        *death = lc.noDeathLock;
301
 
302
    return true;
303
}
304
 
305
template<typename _TMutex>
306
bool TLock<_TMutex>::removeLock()
307
{
308
    DECL_TRACER("TLock<_TMutex>::removeLock(__LOCKLIST_t& e)");
309
 
310
    if (_locks.empty())
311
        return false;
312
 
313
    vector<__LOCKLIST_t>::iterator iter;
314
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
315
 
316
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
317
    {
318
        if (iter->native_handle == nhandle)
319
        {
293 andreas 320
            if (mFilename.empty())
321
            {
322
                MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " will be removed.");
323
            }
324
            else
325
            {
326
                MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " will be removed on file " << mFilename << " at line " << mLineNumber << ".");
327
            }
328
 
292 andreas 329
            bool ret = iter->state;
330
            _locks.erase(iter);
331
            return ret;
332
        }
333
    }
334
 
335
    return false;
336
}
293 andreas 337
 
338
template<typename _TMutex>
339
void TLock<_TMutex>::stripFileName()
340
{
341
    DECL_TRACER("TLock<_TMutex>::stripFileName()");
342
 
343
    if (mFilename.empty())
344
        return;
345
 
346
    size_t pos = mFilename.find_last_of("/");
347
 
348
    if (pos != std::string::npos)
349
        mFilename = mFilename.substr(pos + 1);
350
}