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