Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_dtpthread_recursive.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
33#include "external/ThreadSafetyAnalysis.h"
34#include "system/dtpthread.h"
35
36#include <pthread.h>
37#include <stdarg.h>
38#include <stddef.h>
39// cmocka.h declares `extern jmp_buf global_expect_assert_env' at file scope without including
40// <setjmp.h> itself. Same suppression as the other tests here, and for the same reason.
41#include <setjmp.h> // NOLINT(misc-include-cleaner)
42#include <stdint.h>
43#include <cmocka.h>
44
45/*
46 * These four exercise re-entrant locking on purpose, which is exactly the pattern clang's
47 * thread-safety analysis is built to reject: it models a lock as held or not held, so a
48 * second acquisition by the owner reads as "acquiring a lock that is already held" and the
49 * matching second release as "releasing a lock that was not held". The behaviour under test
50 * is real and deliberate (see dtpthread.h); the analysis simply has no way to express it.
51 * Exempting the test bodies keeps the tree's finding count honest -- these are not defects
52 * anyone can fix, and left in they would mask ones that are.
53 */
54
57{
58 (void)state;
59 dt_pthread_mutex_t mutex;
60 assert_int_equal(dt_pthread_mutex_init(&mutex, NULL), 0);
61
62 assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
63
64 // On a non-recursive mutex this returns EBUSY (NORMAL) or EDEADLK (ERRORCHECK).
65 assert_int_equal(dt_pthread_mutex_trylock(&mutex), 0);
66 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
67
68 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
69 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
70}
71
75{
76 (void)state;
77 dt_pthread_mutex_t mutex;
78 assert_int_equal(dt_pthread_mutex_init(&mutex, NULL), 0);
79
80 for(int depth = 0; depth < 4; depth++) assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
81 for(int depth = 0; depth < 4; depth++) assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
82
83 // Fully released: a fresh acquisition still succeeds.
84 assert_int_equal(dt_pthread_mutex_trylock(&mutex), 0);
85 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
86 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
87}
88
91{
92 (void)state;
93 pthread_mutexattr_t errorcheck;
94 assert_int_equal(pthread_mutexattr_init(&errorcheck), 0);
95 assert_int_equal(pthread_mutexattr_settype(&errorcheck, PTHREAD_MUTEX_ERRORCHECK), 0);
96
97 dt_pthread_mutex_t mutex;
98 assert_int_equal(dt_pthread_mutex_init(&mutex, &errorcheck), 0);
99 assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
100
101 // Not recursive, because the caller asked for something else.
102 assert_int_not_equal(dt_pthread_mutex_trylock(&mutex), 0);
103
104 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
105 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
106 pthread_mutexattr_destroy(&errorcheck);
107}
108
115{
116 (void)state;
117 dt_pthread_rwlock_t lock;
118 assert_int_equal(dt_pthread_rwlock_init(&lock, NULL), 0);
119
120 assert_int_equal(dt_pthread_rwlock_wrlock(&lock), 0);
121 assert_int_equal(dt_pthread_rwlock_wrlock(&lock), 0); // same thread, as writer
122 assert_int_equal(dt_pthread_rwlock_rdlock(&lock), 0); // same thread, as reader
123
124 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
125 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
126 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
127
128 assert_int_equal(dt_pthread_rwlock_destroy(&lock), 0);
129}
130
131int main(void)
132{
133 const struct CMUnitTest tests[] = {
134 cmocka_unit_test(_a_null_attr_mutex_is_recursive),
135 cmocka_unit_test(_the_blocking_lock_also_re_enters),
136 cmocka_unit_test(_an_explicit_attribute_is_honoured),
137 cmocka_unit_test(_an_rwlock_writer_may_re_enter),
138 };
139
140 return cmocka_run_group_tests(tests, NULL, NULL);
141}
142
143// clang-format off
144// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
145// vim: shiftwidth=2 expandtab tabstop=2 cindent
146// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
147// clang-format on
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static int rwlock NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:340
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:299
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:217
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:267
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...
Definition dtpthread.h:104
static int mutex
Definition dtpthread.h:123
static int dt_pthread_rwlock_destroy(dt_pthread_rwlock_t *lock)
Definition dtpthread.h:212
static int dt_pthread_mutex_trylock(dt_pthread_mutex_t *mutex) TRY_ACQUIRE(0
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:132
static int dt_pthread_rwlock_init(dt_pthread_rwlock_t *lock, const pthread_rwlockattr_t *attr)
Definition dtpthread.h:192
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
const float uint32_t state[4]
dt_pthread_mutex_t lock
Definition supervisor.c:123
int main(void)
static void _the_blocking_lock_also_re_enters(void **state) NO_THREAD_SAFETY_ANALYSIS
static void _an_explicit_attribute_is_honoured(void **state) NO_THREAD_SAFETY_ANALYSIS
static void _an_rwlock_writer_may_re_enter(void **state) NO_THREAD_SAFETY_ANALYSIS
static void _a_null_attr_mutex_is_recursive(void **state) NO_THREAD_SAFETY_ANALYSIS