Coverage Report

Created: 2025-07-12 06:06

/src/strongswan/src/libstrongswan/threading/mutex.c
Line
Count
Source (jump to first uncovered line)
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
114k
{
104
114k
  int err;
105
106
114k
  profiler_start(&this->profile);
107
114k
  err = pthread_mutex_lock(&this->mutex);
108
114k
  if (err)
109
0
  {
110
0
    DBG1(DBG_LIB, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err));
111
0
  }
112
114k
  profiler_end(&this->profile);
113
114k
}
114
115
METHOD(mutex_t, unlock, void,
116
  private_mutex_t *this)
117
114k
{
118
114k
  int err;
119
120
114k
  err = pthread_mutex_unlock(&this->mutex);
121
114k
  if (err)
122
0
  {
123
0
    DBG1(DBG_LIB, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err));
124
0
  }
125
114k
}
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
131k
{
157
131k
  profiler_cleanup(&this->profile);
158
131k
  pthread_mutex_destroy(&this->mutex);
159
131k
  free(this);
160
131k
}
161
162
METHOD(mutex_t, mutex_destroy_r, void,
163
  private_r_mutex_t *this)
164
16.3k
{
165
16.3k
  profiler_cleanup(&this->generic.profile);
166
16.3k
  pthread_mutex_destroy(&this->generic.mutex);
167
16.3k
  free(this);
168
16.3k
}
169
170
/*
171
 * see header file
172
 */
173
mutex_t *mutex_create(mutex_type_t type)
174
147k
{
175
147k
  switch (type)
176
147k
  {
177
16.3k
    case MUTEX_TYPE_RECURSIVE:
178
16.3k
    {
179
16.3k
      private_r_mutex_t *this;
180
181
16.3k
      INIT(this,
182
16.3k
        .generic = {
183
16.3k
          .public = {
184
16.3k
            .lock = _lock_r,
185
16.3k
            .unlock = _unlock_r,
186
16.3k
            .destroy = _mutex_destroy_r,
187
16.3k
          },
188
16.3k
          .recursive = TRUE,
189
16.3k
        },
190
16.3k
      );
191
192
16.3k
      pthread_mutex_init(&this->generic.mutex, NULL);
193
16.3k
      profiler_init(&this->generic.profile);
194
195
16.3k
      return &this->generic.public;
196
0
    }
197
131k
    case MUTEX_TYPE_DEFAULT:
198
131k
    default:
199
131k
    {
200
131k
      private_mutex_t *this;
201
202
131k
      INIT(this,
203
131k
        .public = {
204
131k
          .lock = _lock,
205
131k
          .unlock = _unlock,
206
131k
          .destroy = _mutex_destroy,
207
131k
        },
208
131k
      );
209
210
131k
      pthread_mutex_init(&this->mutex, NULL);
211
131k
      profiler_init(&this->profile);
212
213
131k
      return &this->public;
214
131k
    }
215
147k
  }
216
147k
}
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
32.7k
{
297
32.7k
  pthread_cond_signal(&this->condvar);
298
32.7k
}
299
300
METHOD(condvar_t, broadcast, void,
301
  private_condvar_t *this)
302
16.3k
{
303
16.3k
  pthread_cond_broadcast(&this->condvar);
304
16.3k
}
305
306
METHOD(condvar_t, condvar_destroy, void,
307
  private_condvar_t *this)
308
81.9k
{
309
81.9k
  pthread_cond_destroy(&this->condvar);
310
81.9k
  free(this);
311
81.9k
}
312
313
/*
314
 * see header file
315
 */
316
condvar_t *condvar_create(condvar_type_t type)
317
81.9k
{
318
81.9k
  switch (type)
319
81.9k
  {
320
81.9k
    case CONDVAR_TYPE_DEFAULT:
321
81.9k
    default:
322
81.9k
    {
323
81.9k
      private_condvar_t *this;
324
325
81.9k
      INIT(this,
326
81.9k
        .public = {
327
81.9k
          .wait = (void*)_wait_,
328
81.9k
          .timed_wait = (void*)_timed_wait,
329
81.9k
          .timed_wait_abs = (void*)_timed_wait_abs,
330
81.9k
          .signal = _signal_,
331
81.9k
          .broadcast = _broadcast,
332
81.9k
          .destroy = _condvar_destroy,
333
81.9k
        }
334
81.9k
      );
335
336
81.9k
#ifdef HAVE_PTHREAD_CONDATTR_INIT
337
81.9k
      {
338
81.9k
        pthread_condattr_t condattr;
339
81.9k
        pthread_condattr_init(&condattr);
340
81.9k
#ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
341
81.9k
        pthread_condattr_setclock(&condattr, TIME_CLOCK_ID);
342
81.9k
#endif
343
81.9k
        pthread_cond_init(&this->condvar, &condattr);
344
81.9k
        pthread_condattr_destroy(&condattr);
345
81.9k
      }
346
81.9k
#endif
347
348
81.9k
      return &this->public;
349
81.9k
    }
350
81.9k
  }
351
81.9k
}
352