Coverage Report

Created: 2025-07-23 07:02

/src/wxwidgets/include/wx/thrimpl.cpp
Line
Count
Source (jump to first uncovered line)
1
/////////////////////////////////////////////////////////////////////////////
2
// Name:        wx/thrimpl.cpp
3
// Purpose:     common part of wxThread Implementations
4
// Author:      Vadim Zeitlin
5
// Created:     04.06.02 (extracted from src/*/thread.cpp files)
6
// Copyright:   (c) Vadim Zeitlin (2002)
7
// Licence:     wxWindows licence
8
/////////////////////////////////////////////////////////////////////////////
9
10
// this file is supposed to be included only by the various thread.cpp
11
12
// ----------------------------------------------------------------------------
13
// wxMutex
14
// ----------------------------------------------------------------------------
15
16
wxMutex::wxMutex(wxMutexType mutexType)
17
8
{
18
8
    m_internal = new wxMutexInternal(mutexType);
19
20
8
    if ( !m_internal->IsOk() )
21
0
    {
22
0
        delete m_internal;
23
0
        m_internal = nullptr;
24
0
    }
25
8
}
26
27
wxMutex::~wxMutex()
28
0
{
29
0
    delete m_internal;
30
0
}
31
32
bool wxMutex::IsOk() const
33
0
{
34
0
    return m_internal != nullptr;
35
0
}
36
37
wxMutexError wxMutex::Lock()
38
8
{
39
8
    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
40
8
                 wxT("wxMutex::Lock(): not initialized") );
41
42
8
    return m_internal->Lock();
43
8
}
44
45
wxMutexError wxMutex::LockTimeout(unsigned long ms)
46
0
{
47
0
    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
48
0
                 wxT("wxMutex::Lock(): not initialized") );
49
50
0
    return m_internal->Lock(ms);
51
0
}
52
53
wxMutexError wxMutex::TryLock()
54
0
{
55
0
    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
56
0
                 wxT("wxMutex::TryLock(): not initialized") );
57
58
0
    return m_internal->TryLock();
59
0
}
60
61
wxMutexError wxMutex::Unlock()
62
8
{
63
8
    wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
64
8
                 wxT("wxMutex::Unlock(): not initialized") );
65
66
8
    return m_internal->Unlock();
67
8
}
68
69
// --------------------------------------------------------------------------
70
// wxConditionInternal
71
// --------------------------------------------------------------------------
72
73
// Win32 doesn't have explicit support for the POSIX condition
74
// variables and its events/event semaphores have quite different semantics,
75
// so we reimplement the conditions from scratch using the mutexes and
76
// semaphores
77
#if defined(__WINDOWS__)
78
79
class wxConditionInternal
80
{
81
public:
82
    wxConditionInternal(wxMutex& mutex);
83
84
    bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
85
86
    wxCondError Wait();
87
    wxCondError WaitTimeout(unsigned long milliseconds);
88
89
    wxCondError Signal();
90
    wxCondError Broadcast();
91
92
private:
93
    // the number of threads currently waiting for this condition
94
    LONG m_numWaiters;
95
96
    // the critical section protecting m_numWaiters
97
    wxCriticalSection m_csWaiters;
98
99
    wxMutex& m_mutex;
100
    wxSemaphore m_semaphore;
101
102
    wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
103
};
104
105
wxConditionInternal::wxConditionInternal(wxMutex& mutex)
106
                   : m_mutex(mutex)
107
{
108
    // another thread can't access it until we return from ctor, so no need to
109
    // protect access to m_numWaiters here
110
    m_numWaiters = 0;
111
}
112
113
wxCondError wxConditionInternal::Wait()
114
{
115
    // increment the number of waiters
116
    {
117
        wxCriticalSectionLocker lock(m_csWaiters);
118
        m_numWaiters++;
119
    }
120
121
    m_mutex.Unlock();
122
123
    // after unlocking the mutex other threads may Signal() us, but it is ok
124
    // now as we had already incremented m_numWaiters so Signal() will post the
125
    // semaphore and decrement m_numWaiters back even if it is called before we
126
    // start to Wait()
127
    const wxSemaError err = m_semaphore.Wait();
128
129
    m_mutex.Lock();
130
131
    if ( err == wxSEMA_NO_ERROR )
132
    {
133
        // m_numWaiters was decremented by Signal()
134
        return wxCOND_NO_ERROR;
135
    }
136
137
    // but in case of an error we need to do it manually
138
    {
139
        wxCriticalSectionLocker lock(m_csWaiters);
140
        m_numWaiters--;
141
    }
142
143
    return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
144
}
145
146
wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
147
{
148
    {
149
        wxCriticalSectionLocker lock(m_csWaiters);
150
        m_numWaiters++;
151
    }
152
153
    m_mutex.Unlock();
154
155
    wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
156
157
    m_mutex.Lock();
158
159
    if ( err == wxSEMA_NO_ERROR )
160
        return wxCOND_NO_ERROR;
161
162
    if ( err == wxSEMA_TIMEOUT )
163
    {
164
        // a potential race condition exists here: it happens when a waiting
165
        // thread times out but doesn't have time to decrement m_numWaiters yet
166
        // before Signal() is called in another thread
167
        //
168
        // to handle this particular case, check the semaphore again after
169
        // acquiring m_csWaiters lock -- this will catch the signals missed
170
        // during this window
171
        wxCriticalSectionLocker lock(m_csWaiters);
172
173
        err = m_semaphore.WaitTimeout(0);
174
        if ( err == wxSEMA_NO_ERROR )
175
            return wxCOND_NO_ERROR;
176
177
        // we need to decrement m_numWaiters ourselves as it wasn't done by
178
        // Signal()
179
        m_numWaiters--;
180
181
        return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
182
    }
183
184
    // undo m_numWaiters++ above in case of an error
185
    {
186
        wxCriticalSectionLocker lock(m_csWaiters);
187
        m_numWaiters--;
188
    }
189
190
    return wxCOND_MISC_ERROR;
191
}
192
193
wxCondError wxConditionInternal::Signal()
194
{
195
    wxCriticalSectionLocker lock(m_csWaiters);
196
197
    if ( m_numWaiters > 0 )
198
    {
199
        // increment the semaphore by 1
200
        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
201
            return wxCOND_MISC_ERROR;
202
203
        m_numWaiters--;
204
    }
205
206
    return wxCOND_NO_ERROR;
207
}
208
209
wxCondError wxConditionInternal::Broadcast()
210
{
211
    wxCriticalSectionLocker lock(m_csWaiters);
212
213
    while ( m_numWaiters > 0 )
214
    {
215
        if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
216
            return wxCOND_MISC_ERROR;
217
218
        m_numWaiters--;
219
    }
220
221
    return wxCOND_NO_ERROR;
222
}
223
224
#endif // __WINDOWS__
225
226
// ----------------------------------------------------------------------------
227
// wxCondition
228
// ----------------------------------------------------------------------------
229
230
wxCondition::wxCondition(wxMutex& mutex)
231
0
{
232
0
    m_internal = new wxConditionInternal(mutex);
233
234
0
    if ( !m_internal->IsOk() )
235
0
    {
236
0
        delete m_internal;
237
0
        m_internal = nullptr;
238
0
    }
239
0
}
240
241
wxCondition::~wxCondition()
242
0
{
243
0
    delete m_internal;
244
0
}
245
246
bool wxCondition::IsOk() const
247
0
{
248
0
    return m_internal != nullptr;
249
0
}
250
251
wxCondError wxCondition::Wait()
252
0
{
253
0
    wxCHECK_MSG( m_internal, wxCOND_INVALID,
254
0
                 wxT("wxCondition::Wait(): not initialized") );
255
256
0
    return m_internal->Wait();
257
0
}
258
259
wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
260
0
{
261
0
    wxCHECK_MSG( m_internal, wxCOND_INVALID,
262
0
                 wxT("wxCondition::Wait(): not initialized") );
263
264
0
    return m_internal->WaitTimeout(milliseconds);
265
0
}
266
267
wxCondError wxCondition::Signal()
268
0
{
269
0
    wxCHECK_MSG( m_internal, wxCOND_INVALID,
270
0
                 wxT("wxCondition::Signal(): not initialized") );
271
272
0
    return m_internal->Signal();
273
0
}
274
275
wxCondError wxCondition::Broadcast()
276
0
{
277
0
    wxCHECK_MSG( m_internal, wxCOND_INVALID,
278
0
                 wxT("wxCondition::Broadcast(): not initialized") );
279
280
0
    return m_internal->Broadcast();
281
0
}
282
283
// --------------------------------------------------------------------------
284
// wxSemaphore
285
// --------------------------------------------------------------------------
286
287
wxSemaphore::wxSemaphore(int initialcount, int maxcount)
288
0
{
289
0
    m_internal = new wxSemaphoreInternal( initialcount, maxcount );
290
0
    if ( !m_internal->IsOk() )
291
0
    {
292
0
        delete m_internal;
293
0
        m_internal = nullptr;
294
0
    }
295
0
}
296
297
wxSemaphore::~wxSemaphore()
298
0
{
299
0
    delete m_internal;
300
0
}
301
302
bool wxSemaphore::IsOk() const
303
0
{
304
0
    return m_internal != nullptr;
305
0
}
306
307
wxSemaError wxSemaphore::Wait()
308
0
{
309
0
    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
310
0
                 wxT("wxSemaphore::Wait(): not initialized") );
311
312
0
    return m_internal->Wait();
313
0
}
314
315
wxSemaError wxSemaphore::TryWait()
316
0
{
317
0
    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
318
0
                 wxT("wxSemaphore::TryWait(): not initialized") );
319
320
0
    return m_internal->TryWait();
321
0
}
322
323
wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
324
0
{
325
0
    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
326
0
                 wxT("wxSemaphore::WaitTimeout(): not initialized") );
327
328
0
    return m_internal->WaitTimeout(milliseconds);
329
0
}
330
331
wxSemaError wxSemaphore::Post()
332
0
{
333
0
    wxCHECK_MSG( m_internal, wxSEMA_INVALID,
334
0
                 wxT("wxSemaphore::Post(): not initialized") );
335
336
0
    return m_internal->Post();
337
0
}
338
339
// ----------------------------------------------------------------------------
340
// wxThread
341
// ----------------------------------------------------------------------------
342
343
#include "wx/utils.h"
344
345
void wxThread::Sleep(unsigned long milliseconds)
346
0
{
347
0
    wxMilliSleep(milliseconds);
348
0
}