Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/threading/thread.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2009-2012 Tobias Brunner
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#define _GNU_SOURCE
18
#include <pthread.h>
19
#include <signal.h>
20
21
#ifdef HAVE_GETTID
22
#include <sys/types.h>
23
#include <unistd.h>
24
#endif
25
26
#ifdef HAVE_SYS_GETTID
27
#include <sys/syscall.h>
28
static inline pid_t gettid()
29
{
30
  return syscall(SYS_gettid);
31
}
32
#endif
33
34
#include <library.h>
35
#include <utils/debug.h>
36
37
#include <threading/thread_value.h>
38
#include <threading/mutex.h>
39
#include <collections/linked_list.h>
40
41
#include "thread.h"
42
43
typedef struct private_thread_t private_thread_t;
44
45
struct private_thread_t {
46
  /**
47
   * Public interface.
48
   */
49
  thread_t public;
50
51
  /**
52
   * Identifier of this thread (human-readable/thread ID).
53
   */
54
  u_int id;
55
56
  /**
57
   * ID of the underlying thread.
58
   */
59
  pthread_t thread_id;
60
61
  /**
62
   * Main function of this thread (NULL for the main thread).
63
   */
64
  thread_main_t main;
65
66
  /**
67
   * Argument for the main function.
68
   */
69
  void *arg;
70
71
  /**
72
   * Stack of cleanup handlers.
73
   */
74
  linked_list_t *cleanup_handlers;
75
76
  /**
77
   * Mutex to make modifying thread properties safe.
78
   */
79
  mutex_t *mutex;
80
81
  /**
82
   * TRUE if this thread has been detached or joined, i.e. can be cleaned
83
   * up after terminating.
84
   */
85
  bool detached_or_joined;
86
87
  /**
88
   * TRUE if the threads has terminated (canceled, via thread_exit or
89
   * returned from the main function)
90
   */
91
  bool terminated;
92
93
};
94
95
typedef struct {
96
  /**
97
   * Cleanup callback function.
98
   */
99
  thread_cleanup_t cleanup;
100
101
  /**
102
   * Argument provided to the cleanup function.
103
   */
104
  void *arg;
105
106
} cleanup_handler_t;
107
108
109
/**
110
 * Next thread ID.
111
 */
112
static u_int next_id;
113
114
/**
115
 * Mutex to safely access the next thread ID.
116
 */
117
static mutex_t *id_mutex;
118
119
/**
120
 * Store the thread object in a thread-specific value.
121
 */
122
static thread_value_t *current_thread;
123
124
125
#ifndef HAVE_PTHREAD_CANCEL
126
/* if pthread_cancel is not available, we emulate it using a signal */
127
#ifdef ANDROID
128
#define SIG_CANCEL SIGUSR2
129
#else
130
#define SIG_CANCEL (SIGRTMIN+7)
131
#endif
132
133
/* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
134
 * "canceled" thread */
135
static void cancel_signal_handler(int sig)
136
{
137
  pthread_exit(NULL);
138
}
139
#endif
140
141
142
/**
143
 * Destroy an internal thread object.
144
 *
145
 * @note The mutex of this thread object has to be locked, it gets unlocked
146
 * automatically.
147
 */
148
static void thread_destroy(private_thread_t *this)
149
3.51k
{
150
3.51k
  if (!this->terminated || !this->detached_or_joined)
151
0
  {
152
0
    this->mutex->unlock(this->mutex);
153
0
    return;
154
0
  }
155
3.51k
  this->cleanup_handlers->destroy(this->cleanup_handlers);
156
3.51k
  this->mutex->unlock(this->mutex);
157
3.51k
  this->mutex->destroy(this->mutex);
158
3.51k
  free(this);
159
3.51k
}
160
161
/**
162
 * Determine the ID of the current thread
163
 */
164
static u_int get_thread_id()
165
3.51k
{
166
3.51k
  u_int id;
167
168
#if defined(USE_THREAD_IDS) && defined(HAVE_GETTID)
169
  id = gettid();
170
#else
171
3.51k
  id_mutex->lock(id_mutex);
172
3.51k
  id = next_id++;
173
3.51k
  id_mutex->unlock(id_mutex);
174
3.51k
#endif
175
3.51k
  return id;
176
3.51k
}
177
178
METHOD(thread_t, cancel, void,
179
  private_thread_t *this)
180
0
{
181
0
  this->mutex->lock(this->mutex);
182
0
  if (pthread_equal(this->thread_id, pthread_self()))
183
0
  {
184
0
    this->mutex->unlock(this->mutex);
185
0
    DBG1(DBG_LIB, "!!! CANNOT CANCEL CURRENT THREAD !!!");
186
0
    return;
187
0
  }
188
0
#ifdef HAVE_PTHREAD_CANCEL
189
0
  pthread_cancel(this->thread_id);
190
#else
191
  pthread_kill(this->thread_id, SIG_CANCEL);
192
#endif /* HAVE_PTHREAD_CANCEL */
193
0
  this->mutex->unlock(this->mutex);
194
0
}
195
196
METHOD(thread_t, kill_, void,
197
  private_thread_t *this, int sig)
198
0
{
199
0
  this->mutex->lock(this->mutex);
200
0
  if (pthread_equal(this->thread_id, pthread_self()))
201
0
  {
202
    /* it might actually be possible to send a signal to pthread_self (there
203
     * is an example in raise(3) describing that), the problem is though,
204
     * that the thread only returns here after the signal handler has
205
     * returned, so depending on the signal, the lock might not get
206
     * unlocked. */
207
0
    this->mutex->unlock(this->mutex);
208
0
    DBG1(DBG_LIB, "!!! CANNOT SEND SIGNAL TO CURRENT THREAD !!!");
209
0
    return;
210
0
  }
211
0
  pthread_kill(this->thread_id, sig);
212
0
  this->mutex->unlock(this->mutex);
213
0
}
214
215
METHOD(thread_t, detach, void,
216
  private_thread_t *this)
217
0
{
218
0
  this->mutex->lock(this->mutex);
219
0
  pthread_detach(this->thread_id);
220
0
  this->detached_or_joined = TRUE;
221
0
  thread_destroy(this);
222
0
}
223
224
METHOD(thread_t, join, void*,
225
  private_thread_t *this)
226
0
{
227
0
  pthread_t thread_id;
228
0
  void *val;
229
230
0
  this->mutex->lock(this->mutex);
231
0
  if (pthread_equal(this->thread_id, pthread_self()))
232
0
  {
233
0
    this->mutex->unlock(this->mutex);
234
0
    DBG1(DBG_LIB, "!!! CANNOT JOIN CURRENT THREAD !!!");
235
0
    return NULL;
236
0
  }
237
0
  if (this->detached_or_joined)
238
0
  {
239
0
    this->mutex->unlock(this->mutex);
240
0
    DBG1(DBG_LIB, "!!! CANNOT JOIN DETACHED THREAD !!!");
241
0
    return NULL;
242
0
  }
243
0
  thread_id = this->thread_id;
244
0
  this->detached_or_joined = TRUE;
245
0
  if (this->terminated)
246
0
  {
247
    /* thread has terminated before the call to join */
248
0
    thread_destroy(this);
249
0
  }
250
0
  else
251
0
  {
252
    /* thread_destroy is called when the thread terminates normally */
253
0
    this->mutex->unlock(this->mutex);
254
0
  }
255
0
  pthread_join(thread_id, &val);
256
257
0
  return val;
258
0
}
259
260
/**
261
 * Create an internal thread object.
262
 */
263
static private_thread_t *thread_create_internal()
264
3.51k
{
265
3.51k
  private_thread_t *this;
266
267
3.51k
  INIT(this,
268
3.51k
    .public = {
269
3.51k
      .cancel = _cancel,
270
3.51k
      .kill = _kill_,
271
3.51k
      .detach = _detach,
272
3.51k
      .join = _join,
273
3.51k
    },
274
3.51k
    .cleanup_handlers = linked_list_create(),
275
3.51k
    .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
276
3.51k
  );
277
278
3.51k
  return this;
279
3.51k
}
280
281
/**
282
 * Remove and run all cleanup handlers in reverse order.
283
 */
284
static void thread_cleanup_popall_internal(private_thread_t *this)
285
0
{
286
0
  cleanup_handler_t *handler;
287
288
0
  while (this->cleanup_handlers->remove_last(this->cleanup_handlers,
289
0
                        (void**)&handler) == SUCCESS)
290
0
  {
291
0
    handler->cleanup(handler->arg);
292
0
    free(handler);
293
0
  }
294
0
}
295
296
/**
297
 * Main cleanup function for threads.
298
 */
299
static void thread_cleanup(private_thread_t *this)
300
0
{
301
0
  thread_cleanup_popall_internal(this);
302
0
  this->mutex->lock(this->mutex);
303
0
  this->terminated = TRUE;
304
0
  thread_destroy(this);
305
0
}
306
307
/**
308
 * Main function wrapper for threads.
309
 *
310
 * Excluded from AddressSanitizer because some newer versions have an issue that
311
 * causes an "AddressSanitizer CHECK failed" error for canceled threads.
312
 */
313
ADDRESS_SANITIZER_EXCLUDE
314
static void *thread_main(private_thread_t *this)
315
0
{
316
0
  void *res;
317
318
0
  this->id = get_thread_id();
319
320
0
  current_thread->set(current_thread, this);
321
0
  pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this);
322
323
  /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e.
324
   * could be of any size, or even a struct) */
325
0
#ifdef HAVE_GETTID
326
0
  DBG2(DBG_LIB, "created thread %.2d [%u]",
327
0
     this->id, gettid());
328
#elif defined(WIN32)
329
  DBG2(DBG_LIB, "created thread %.2d [%p]",
330
     this->id, this->thread_id.p);
331
#else
332
  DBG2(DBG_LIB, "created thread %.2d [%lx]",
333
     this->id, (u_long)this->thread_id);
334
#endif
335
336
0
  res = this->main(this->arg);
337
0
  pthread_cleanup_pop(TRUE);
338
339
0
  return res;
340
0
}
341
342
/**
343
 * Described in header.
344
 */
345
thread_t *thread_create(thread_main_t main, void *arg)
346
0
{
347
0
  private_thread_t *this = thread_create_internal();
348
349
0
  this->main = main;
350
0
  this->arg = arg;
351
352
0
  if (pthread_create(&this->thread_id, NULL, (void*)thread_main, this) != 0)
353
0
  {
354
0
    DBG1(DBG_LIB, "failed to create thread!");
355
0
    this->mutex->lock(this->mutex);
356
0
    this->terminated = TRUE;
357
0
    this->detached_or_joined = TRUE;
358
0
    thread_destroy(this);
359
0
    return NULL;
360
0
  }
361
362
0
  return &this->public;
363
0
}
364
365
/**
366
 * Described in header.
367
 */
368
thread_t *thread_current()
369
3.51k
{
370
3.51k
  private_thread_t *this;
371
372
3.51k
  this = (private_thread_t*)current_thread->get(current_thread);
373
3.51k
  if (!this)
374
0
  {
375
0
    this = thread_create_internal();
376
0
    this->id = get_thread_id();
377
0
    current_thread->set(current_thread, (void*)this);
378
0
  }
379
3.51k
  return &this->public;
380
3.51k
}
381
382
/**
383
 * Described in header.
384
 */
385
u_int thread_current_id()
386
0
{
387
0
  private_thread_t *this = (private_thread_t*)thread_current();
388
389
0
  return this ? this->id : 0;
390
0
}
391
392
/**
393
 * Described in header.
394
 */
395
void thread_cleanup_push(thread_cleanup_t cleanup, void *arg)
396
0
{
397
0
  private_thread_t *this = (private_thread_t*)thread_current();
398
0
  cleanup_handler_t *handler;
399
400
0
  INIT(handler,
401
0
    .cleanup = cleanup,
402
0
    .arg = arg,
403
0
  );
404
405
0
  this->cleanup_handlers->insert_last(this->cleanup_handlers, handler);
406
0
}
407
408
/**
409
 * Described in header.
410
 */
411
void thread_cleanup_pop(bool execute)
412
0
{
413
0
  private_thread_t *this = (private_thread_t*)thread_current();
414
0
  cleanup_handler_t *handler;
415
416
0
  if (this->cleanup_handlers->remove_last(this->cleanup_handlers,
417
0
                      (void**)&handler) != SUCCESS)
418
0
  {
419
0
    DBG1(DBG_LIB, "!!! THREAD CLEANUP ERROR !!!");
420
0
    return;
421
0
  }
422
423
0
  if (execute)
424
0
  {
425
0
    handler->cleanup(handler->arg);
426
0
  }
427
0
  free(handler);
428
0
}
429
430
/**
431
 * Described in header.
432
 */
433
void thread_cleanup_popall()
434
0
{
435
0
  private_thread_t *this = (private_thread_t*)thread_current();
436
437
0
  thread_cleanup_popall_internal(this);
438
0
}
439
440
/**
441
 * Described in header.
442
 */
443
bool thread_cancelability(bool enable)
444
0
{
445
0
#ifdef HAVE_PTHREAD_CANCEL
446
0
  int old;
447
448
0
  pthread_setcancelstate(enable ? PTHREAD_CANCEL_ENABLE
449
0
                  : PTHREAD_CANCEL_DISABLE, &old);
450
451
0
  return old == PTHREAD_CANCEL_ENABLE;
452
#else
453
  sigset_t new, old;
454
455
  sigemptyset(&new);
456
  sigaddset(&new, SIG_CANCEL);
457
  pthread_sigmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &new, &old);
458
459
  return sigismember(&old, SIG_CANCEL) == 0;
460
#endif /* HAVE_PTHREAD_CANCEL */
461
0
}
462
463
/**
464
 * Described in header.
465
 */
466
void thread_cancellation_point()
467
0
{
468
0
  bool old = thread_cancelability(TRUE);
469
470
0
#ifdef HAVE_PTHREAD_CANCEL
471
0
  pthread_testcancel();
472
0
#endif /* HAVE_PTHREAD_CANCEL */
473
0
  thread_cancelability(old);
474
0
}
475
476
/**
477
 * Described in header.
478
 */
479
void thread_exit(void *val)
480
0
{
481
0
  pthread_exit(val);
482
0
}
483
484
/**
485
 * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11
486
 * library mangles this key, without owning it, so we allocate it for them.
487
 */
488
static thread_value_t *dummy1;
489
490
/**
491
 * Described in header.
492
 */
493
void threads_init()
494
3.51k
{
495
3.51k
  private_thread_t *main_thread = thread_create_internal();
496
497
3.51k
  dummy1 = thread_value_create(NULL);
498
499
3.51k
  next_id = 0;
500
3.51k
  main_thread->thread_id = pthread_self();
501
3.51k
  current_thread = thread_value_create(NULL);
502
3.51k
  current_thread->set(current_thread, (void*)main_thread);
503
3.51k
  id_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
504
3.51k
  main_thread->id = get_thread_id();
505
506
#ifndef HAVE_PTHREAD_CANCEL
507
  { /* install a signal handler for our custom SIG_CANCEL */
508
    struct sigaction action = {
509
      .sa_handler = cancel_signal_handler
510
    };
511
    sigaction(SIG_CANCEL, &action, NULL);
512
  }
513
#endif /* HAVE_PTHREAD_CANCEL */
514
3.51k
}
515
516
/**
517
 * Described in header.
518
 */
519
void threads_deinit()
520
3.51k
{
521
3.51k
  private_thread_t *main_thread = (private_thread_t*)thread_current();
522
523
3.51k
  dummy1->destroy(dummy1);
524
525
3.51k
  main_thread->mutex->lock(main_thread->mutex);
526
3.51k
  main_thread->terminated = TRUE;
527
3.51k
  main_thread->detached_or_joined = TRUE;
528
3.51k
  thread_destroy(main_thread);
529
3.51k
  current_thread->destroy(current_thread);
530
3.51k
  id_mutex->destroy(id_mutex);
531
3.51k
}