Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
447 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 "tlock.h"
20
#include <vector>
21
#include <thread>
22
 
23
#include "terror.h"
24
 
25
using std::vector;
26
using std::thread;
27
 
28
static std::vector<__LOCKLIST_t> _locks;
29
 
30
template<typename _TMutex>
31
TLock<_TMutex>::TLock(TLock::mutex_type& __m)
32
    : _M_device(__m)
33
{
34
//    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m)");
35
 
36
    bool death = false;
37
    bool l = addLock(&death);
38
 
39
    if ((mNoDeathLock || death) && !l)
40
        return;
41
 
42
    _M_device.lock();
43
}
44
 
45
template<typename _TMutex>
46
TLock<_TMutex>::TLock(TLock::mutex_type& __m, char *file, int line)
47
    : _M_device(__m),
48
      mFilename(file),
49
      mLineNumber(line)
50
{
51
//    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m)");
52
 
53
    stripFileName();
54
    bool death = false;
55
    bool l = addLock(&death);
56
 
57
//    if ((mNoDeathLock || death) && !l)
58
//        return;
59
 
60
    if (!l && (mNoDeathLock || death))
61
    {
62
        wait();
63
 
64
        if (isLocked())
65
            return;
66
    }
67
 
68
    _M_device.lock();
69
}
70
 
71
template<typename _TMutex>
72
TLock<_TMutex>::TLock(mutex_type& __m, bool tryit, char *file, int line)
73
    : _M_device(__m),
74
      mNoDeathLock(tryit),
75
      mFilename(file),
76
      mLineNumber(line)
77
{
78
//    DECL_TRACER("TLock<_TMutex>::TLock(mutex_type& __m, bool tryit, char *file, int line)");
79
 
80
    stripFileName();
81
    bool death = false;
82
    bool l = addLock(&death);
83
 
84
//    if ((mNoDeathLock || death) && !l)
85
//        return;
86
 
87
    if (!l && tryit)
88
    {
89
        wait();
90
 
91
        if (isLocked())
92
            return;
93
    }
94
 
95
    _M_device.lock();
96
}
97
 
98
template<typename _TMutex>
99
TLock<_TMutex>::TLock(TLock::mutex_type& __m, std::adopt_lock_t) noexcept
100
    : _M_device(__m)
101
{
102
//    DECL_TRACER("TLock<_TMutex>::TLock(TLock::mutex_type& __m, std::adopt_lock_t) noexcept");
103
}
104
 
105
template<typename _TMutex>
106
TLock<_TMutex>::~TLock()
107
{
108
//    DECL_TRACER("TLock<_TMutex>::~TLock()");
109
 
110
    if (removeLock())
111
        _M_device.unlock();
112
}
113
 
114
template<typename _TMutex>
115
void TLock<_TMutex>::unlock()
116
{
117
//    DECL_TRACER("TLock<_TMutex>::unlock()");
118
 
119
    if (_locks.empty())
120
        return;
121
 
122
    vector<__LOCKLIST_t>::iterator iter;
123
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
124
 
125
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
126
    {
127
        if (iter->native_handle == nhandle && iter->state)
128
        {
129
            iter->state = false;
130
            iter->noDeathLock = false;
131
            _M_device.unlock();
132
 
133
            if (mFilename.empty())
134
            {
135
                MSG_DEBUG("The mutex handle " << iter->native_handle << " was released!");
136
            }
137
            else
138
            {
139
                MSG_DEBUG("The mutex handle " << iter->native_handle << " was released on file " << mFilename << " at line " << mLineNumber << "!");
140
            }
141
 
142
            return;
143
        }
144
    }
145
}
146
 
147
template<typename _TMutex>
148
void TLock<_TMutex>::unlock(char* file, int line)
149
{
150
//    DECL_TRACER("TLock<_TMutex>::unlock(char* file, int line)");
151
 
152
    mFilename = file;
153
    mLineNumber = line;
154
    stripFileName();
155
 
156
    unlock();
157
}
158
 
159
template<typename _TMutex>
160
void TLock<_TMutex>::relock()
161
{
162
//    DECL_TRACER("TLock<_TMutex>::relock(TLock::mutex_type& __m)");
163
 
164
    if (_locks.empty())
165
        return;
166
 
167
    vector<__LOCKLIST_t>::iterator iter;
168
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
169
 
170
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
171
    {
172
        if (iter->native_handle == nhandle && !iter->state)
173
        {
174
            iter->state = true;
175
            _M_device.lock();
176
            return;
177
        }
178
    }
179
}
180
 
181
template<typename _TMutex>
182
bool TLock<_TMutex>::isLocked()
183
{
184
    if (_locks.empty())
185
        return false;
186
 
187
    vector<__LOCKLIST_t>::iterator iter;
188
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
189
 
190
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
191
    {
192
        if (iter->native_handle == nhandle && iter->state)
193
            return true;
194
    }
195
 
196
    return false;
197
}
198
 
199
template<typename _TMutex>
200
void TLock<_TMutex>::setNoDeathLock(bool l)
201
{
202
//    DECL_TRACER("TLock<_TMutex>::setNoDeathLock(bool l)");
203
 
204
    mNoDeathLock = l;
205
    vector<__LOCKLIST_t>::iterator iter;
206
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
207
 
208
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
209
    {
210
        if (iter->native_handle == nhandle)
211
        {
212
            iter->noDeathLock = l;
213
            break;
214
        }
215
    }
216
}
217
 
218
 
219
template<typename _TMutex>
220
bool TLock<_TMutex>::addLock(bool *death)
221
{
222
//    DECL_TRACER("TLock<_TMutex>::addLock(bool *death)");
223
 
224
    __LOCKLIST_t lc;
225
    lc.state = true;
226
    lc.noDeathLock = mNoDeathLock;
227
    lc.native_handle = _M_device.native_handle();
228
 
229
    if (_locks.empty())
230
    {
231
        _locks.push_back(lc);
232
 
233
        if (mFilename.empty())
234
        {
235
            MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added.");
236
        }
237
        else
238
        {
239
            MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added on file " << mFilename << " at line " << mLineNumber << ".");
240
        }
241
 
242
        if (death)
243
            *death = lc.noDeathLock;
244
 
245
        return true;
246
    }
247
 
248
    vector<__LOCKLIST_t>::iterator iter;
249
 
250
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
251
    {
252
        if (iter->native_handle == lc.native_handle)
253
        {
254
            if (death)
255
                *death = iter->noDeathLock;
256
 
257
            if (iter->state)
258
            {
259
                if (mNoDeathLock || iter->noDeathLock)
260
                {
261
                    if (mFilename.empty())
262
                    {
263
                        MSG_WARNING("The mutex handle " << iter->native_handle << " is already locked!");
264
                    }
265
                    else
266
                    {
267
                        MSG_WARNING("The mutex handle " << iter->native_handle << " is already locked on file " << mFilename << " at line " << mLineNumber << "!");
268
                    }
269
                }
270
                else
271
                {
272
                    if (mFilename.empty())
273
                    {
274
                        MSG_ERROR("Death lock detected! The mutex handle " << iter->native_handle << " is already locked.");
275
                    }
276
                    else
277
                    {
278
                        MSG_ERROR("Death lock detected! The mutex handle " << iter->native_handle << " is already locked on file " << mFilename << " at line " << mLineNumber << ".");
279
                    }
280
                }
281
 
282
                return false;
283
            }
284
            else
285
            {
286
                iter->state = true;
287
 
288
                if (mFilename.empty())
289
                {
290
                    MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " was reactivated.");
291
                }
292
                else
293
                {
294
                    MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " was reactivated on file " << mFilename << " at line " << mLineNumber << ".");
295
                }
296
 
297
                return true;
298
            }
299
        }
300
    }
301
 
302
    _locks.push_back(lc);
303
 
304
    if (mFilename.empty())
305
    {
306
        MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added.");
307
    }
308
    else
309
    {
310
        MSG_DEBUG("Lock for mutex handle " << lc.native_handle << " was added on file " << mFilename << " at line " << mLineNumber << ".");
311
    }
312
 
313
    if (death)
314
        *death = lc.noDeathLock;
315
 
316
    return true;
317
}
318
 
319
template<typename _TMutex>
320
void TLock<_TMutex>::wait()
321
{
322
//    DECL_TRACER("TLock<_TMutex>::wait()");
323
 
324
    int loops = 100;
325
 
326
    while (!_M_device.try_lock() && loops >= 0)
327
    {
328
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
329
        loops--;
330
    }
331
 
332
    if (loops >= 0)
333
        addLock(nullptr);
334
}
335
 
336
template<typename _TMutex>
337
bool TLock<_TMutex>::removeLock()
338
{
339
//    DECL_TRACER("TLock<_TMutex>::removeLock(__LOCKLIST_t& e)");
340
 
341
    if (_locks.empty())
342
        return false;
343
 
344
    vector<__LOCKLIST_t>::iterator iter;
345
    std::mutex::native_handle_type nhandle = _M_device.native_handle();
346
 
347
    for (iter = _locks.begin(); iter != _locks.end(); ++iter)
348
    {
349
        if (iter->native_handle == nhandle)
350
        {
351
            if (mFilename.empty())
352
            {
353
                MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " will be removed.");
354
            }
355
            else
356
            {
357
                MSG_DEBUG("Lock for mutex handle " << iter->native_handle << " will be removed on file " << mFilename << " at line " << mLineNumber << ".");
358
            }
359
 
360
            bool ret = iter->state;
361
            _locks.erase(iter);
362
            return ret;
363
        }
364
    }
365
 
366
    return false;
367
}
368
 
369
template<typename _TMutex>
370
void TLock<_TMutex>::stripFileName()
371
{
372
//    DECL_TRACER("TLock<_TMutex>::stripFileName()");
373
 
374
    if (mFilename.empty())
375
        return;
376
 
377
    size_t pos = mFilename.find_last_of("/");
378
 
379
    if (pos != std::string::npos)
380
        mFilename = mFilename.substr(pos + 1);
381
}