Coverage Report

Created: 2025-11-09 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/threading/mutex.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2008-2012 Tobias Brunner
3
 * Copyright (C) 2008 Martin Willi
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#define _GNU_SOURCE
19
#include <pthread.h>
20
#include <stdint.h>
21
#include <time.h>
22
#include <errno.h>
23
24
#include <library.h>
25
#include <utils/debug.h>
26
27
#include "thread.h"
28
#include "condvar.h"
29
#include "mutex.h"
30
#include "lock_profiler.h"
31
32
typedef struct private_mutex_t private_mutex_t;
33
typedef struct private_r_mutex_t private_r_mutex_t;
34
typedef struct private_condvar_t private_condvar_t;
35
36
/**
37
 * private data of mutex
38
 */
39
struct private_mutex_t {
40
41
  /**
42
   * public functions
43
   */
44
  mutex_t public;
45
46
  /**
47
   * wrapped pthread mutex
48
   */
49
  pthread_mutex_t mutex;
50
51
  /**
52
   * is this a recursive mutex, implementing private_r_mutex_t?
53
   */
54
  bool recursive;
55
56
  /**
57
   * profiling info, if enabled
58
   */
59
  lock_profile_t profile;
60
};
61
62
/**
63
 * private data of mutex, extended by recursive locking information
64
 */
65
struct private_r_mutex_t {
66
67
  /**
68
   * Extends private_mutex_t
69
   */
70
  private_mutex_t generic;
71
72
  /**
73
   * thread which currently owns mutex
74
   */
75
  thread_t *thread;
76
77
  /**
78
   * times the current thread locked the mutex
79
   */
80
  u_int times;
81
};
82
83
/**
84
 * private data of condvar
85
 */
86
struct private_condvar_t {
87
88
  /**
89
   * public functions
90
   */
91
  condvar_t public;
92
93
  /**
94
   * wrapped pthread condvar
95
   */
96
  pthread_cond_t condvar;
97
98
};
99
100
101
METHOD(mutex_t, lock, void,
102
  private_mutex_t *this)
103
7
{
104
7
  int err;
105
106
7
  profiler_start(&this->profile);
107
7
  err = pthread_mutex_lock(&this->mutex);
108
7
  if (err)
109
0
  {
110
0
    DBG1(DBG_LIB, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
111
0
  }
112
7
  profiler_end(&this->profile);
113
7
}
114
115
METHOD(mutex_t, unlock, void,
116
  private_mutex_t *this)
117
7
{
118
7
  int err;
119
120
7
  err = pthread_mutex_unlock(&this->mutex);
121
7
  if (err)
122
0
  {
123
0
    DBG1(DBG_LIB, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
124
0
  }
125
7
}
126
127
METHOD(mutex_t, lock_r, void,
128
  private_r_mutex_t *this)
129
0
{
130
0
  thread_t *self = thread_current();
131
132
0
  if (cas_ptr(&this->thread, self, self))
133
0
  {
134
0
    this->times++;
135
0
  }
136
0
  else
137
0
  {
138
0
    lock(&this->generic);
139
0
    cas_ptr(&this->thread, NULL, self);
140
0
    this->times = 1;
141
0
  }
142
0
}
143
144
METHOD(mutex_t, unlock_r, void,
145
  private_r_mutex_t *this)
146
0
{
147
0
  if (--this->times == 0)
148
0
  {
149
0
    cas_ptr(&this->thread, thread_current(), NULL);
150
0
    unlock(&this->generic);
151
0
  }
152
0
}
153
154
METHOD(mutex_t, mutex_destroy, void,
155
  private_mutex_t *this)
156
8
{
157
8
  profiler_cleanup(&this->profile);
158
8
  pthread_mutex_destroy(&this->mutex);
159
8
  free(this);
160
8
}
161
162
METHOD(mutex_t, mutex_destroy_r, void,
163
  private_r_mutex_t *this)
164
1
{
165
1
  profiler_cleanup(&this->generic.profile);
166
1
  pthread_mutex_destroy(&this->generic.mutex);
167
1
  free(this);
168
1
}
169
170
/*
171
 * see header file
172
 */
173
mutex_t *mutex_create(mutex_type_t type)
174
9
{
175
9
  switch (type)
176
9
  {
177
1
    case MUTEX_TYPE_RECURSIVE:
178
1
    {
179
1
      private_r_mutex_t *this;
180
181
1
      INIT(this,
182
1
        .generic = {
183
1
          .public = {
184
1
            .lock = _lock_r,
185
1
            .unlock = _unlock_r,
186
1
            .destroy = _mutex_destroy_r,
187
1
          },
188
1
          .recursive = TRUE,
189
1
        },
190
1
      );
191
192
1
      pthread_mutex_init(&this->generic.mutex, NULL);
193
1
      profiler_init(&this->generic.profile);
194
195
1
      return &this->generic.public;
196
0
    }
197
8
    case MUTEX_TYPE_DEFAULT:
198
8
    default:
199
8
    {
200
8
      private_mutex_t *this;
201
202
8
      INIT(this,
203
8
        .public = {
204
8
          .lock = _lock,
205
8
          .unlock = _unlock,
206
8
          .destroy = _mutex_destroy,
207
8
        },
208
8
      );
209
210
8
      pthread_mutex_init(&this->mutex, NULL);
211
8
      profiler_init(&this->profile);
212
213
8
      return &this->public;
214
8
    }
215
9
  }
216
9
}
217
218
219
METHOD(condvar_t, wait_, void,
220
  private_condvar_t *this, private_mutex_t *mutex)
221
0
{
222
0
  if (mutex->recursive)
223
0
  {
224
0
    private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
225
0
    thread_t *self = thread_current();
226
0
    u_int times;
227
228
    /* keep track of the number of times this thread locked the mutex */
229
0
    times = recursive->times;
230
    /* mutex owner gets cleared during condvar wait */
231
0
    cas_ptr(&recursive->thread, self, NULL);
232
0
    pthread_cond_wait(&this->condvar, &mutex->mutex);
233
0
    cas_ptr(&recursive->thread, NULL, self);
234
0
    recursive->times = times;
235
0
  }
236
0
  else
237
0
  {
238
0
    pthread_cond_wait(&this->condvar, &mutex->mutex);
239
0
  }
240
0
}
241
242
/* use the monotonic clock based version of this function if available */
243
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) && \
244
  !defined(HAVE_CONDATTR_CLOCK_MONOTONIC)
245
#define pthread_cond_timedwait pthread_cond_timedwait_monotonic
246
#endif
247
248
METHOD(condvar_t, timed_wait_abs, bool,
249
  private_condvar_t *this, private_mutex_t *mutex, timeval_t time)
250
0
{
251
0
  struct timespec ts;
252
0
  bool timed_out;
253
254
0
  ts.tv_sec = time.tv_sec;
255
0
  ts.tv_nsec = time.tv_usec * 1000;
256
257
0
  if (mutex->recursive)
258
0
  {
259
0
    private_r_mutex_t* recursive = (private_r_mutex_t*)mutex;
260
0
    thread_t *self = thread_current();
261
0
    u_int times;
262
263
0
    times = recursive->times;
264
0
    cas_ptr(&recursive->thread, self, NULL);
265
0
    timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
266
0
                       &ts) == ETIMEDOUT;
267
0
    cas_ptr(&recursive->thread, NULL, self);
268
0
    recursive->times = times;
269
0
  }
270
0
  else
271
0
  {
272
0
    timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex,
273
0
                       &ts) == ETIMEDOUT;
274
0
  }
275
0
  return timed_out;
276
0
}
277
278
METHOD(condvar_t, timed_wait, bool,
279
  private_condvar_t *this, private_mutex_t *mutex, u_int timeout)
280
0
{
281
0
  timeval_t tv;
282
0
  u_int s, ms;
283
284
0
  time_monotonic(&tv);
285
286
0
  s = timeout / 1000;
287
0
  ms = timeout % 1000;
288
289
0
  tv.tv_sec += s;
290
0
  timeval_add_ms(&tv, ms);
291
0
  return timed_wait_abs(this, mutex, tv);
292
0
}
293
294
METHOD(condvar_t, signal_, void,
295
  private_condvar_t *this)
296
2
{
297
2
  pthread_cond_signal(&this->condvar);
298
2
}
299
300
METHOD(condvar_t, broadcast, void,
301
  private_condvar_t *this)
302
1
{
303
1
  pthread_cond_broadcast(&this->condvar);
304
1
}
305
306
METHOD(condvar_t, condvar_destroy, void,
307
  private_condvar_t *this)
308
5
{
309
5
  pthread_cond_destroy(&this->condvar);
310
5
  free(this);
311
5
}
312
313
/*
314
 * see header file
315
 */
316
condvar_t *condvar_create(condvar_type_t type)
317
5
{
318
5
  switch (type)
319
5
  {
320
5
    case CONDVAR_TYPE_DEFAULT:
321
5
    default:
322
5
    {
323
5
      private_condvar_t *this;
324
325
5
      INIT(this,
326
5
        .public = {
327
5
          .wait = (void*)_wait_,
328
5
          .timed_wait = (void*)_timed_wait,
329
5
          .timed_wait_abs = (void*)_timed_wait_abs,
330
5
          .signal = _signal_,
331
5
          .broadcast = _broadcast,
332
5
          .destroy = _condvar_destroy,
333
5
        }
334
5
      );
335
336
5
#ifdef HAVE_PTHREAD_CONDATTR_INIT
337
5
      {
338
5
        pthread_condattr_t condattr;
339
5
        pthread_condattr_init(&condattr);
340
5
#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
341
5
        pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
342
5
#endif
343
5
        pthread_cond_init(&this->condvar, &condattr);
344
5
        pthread_condattr_destroy(&condattr);
345
5
      }
346
5
#endif
347
348
5
      return &this->public;
349
5
    }
350
5
  }
351
5
}
352