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#ifdef _WIN32
46#include "win/main_wrapper.h"
47#endif
48
49/*
50 * These four exercise re-entrant locking on purpose, which is exactly the pattern clang's
51 * thread-safety analysis is built to reject: it models a lock as held or not held, so a
52 * second acquisition by the owner reads as "acquiring a lock that is already held" and the
53 * matching second release as "releasing a lock that was not held". The behaviour under test
54 * is real and deliberate (see dtpthread.h); the analysis simply has no way to express it.
55 * Exempting the test bodies keeps the tree's finding count honest -- these are not defects
56 * anyone can fix, and left in they would mask ones that are.
57 */
58
61{
62 (void)state;
63 dt_pthread_mutex_t mutex;
64 assert_int_equal(dt_pthread_mutex_init(&mutex, NULL), 0);
65
66 assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
67
68 // On a non-recursive mutex this returns EBUSY (NORMAL) or EDEADLK (ERRORCHECK).
69 assert_int_equal(dt_pthread_mutex_trylock(&mutex), 0);
70 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
71
72 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
73 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
74}
75
79{
80 (void)state;
81 dt_pthread_mutex_t mutex;
82 assert_int_equal(dt_pthread_mutex_init(&mutex, NULL), 0);
83
84 for(int depth = 0; depth < 4; depth++) assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
85 for(int depth = 0; depth < 4; depth++) assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
86
87 // Fully released: a fresh acquisition still succeeds.
88 assert_int_equal(dt_pthread_mutex_trylock(&mutex), 0);
89 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
90 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
91}
92
95{
96 (void)state;
97 pthread_mutexattr_t errorcheck;
98 assert_int_equal(pthread_mutexattr_init(&errorcheck), 0);
99 assert_int_equal(pthread_mutexattr_settype(&errorcheck, PTHREAD_MUTEX_ERRORCHECK), 0);
100
101 dt_pthread_mutex_t mutex;
102 assert_int_equal(dt_pthread_mutex_init(&mutex, &errorcheck), 0);
103 assert_int_equal(dt_pthread_mutex_lock(&mutex), 0);
104
105 // Not recursive, because the caller asked for something else.
106 assert_int_not_equal(dt_pthread_mutex_trylock(&mutex), 0);
107
108 assert_int_equal(dt_pthread_mutex_unlock(&mutex), 0);
109 assert_int_equal(dt_pthread_mutex_destroy(&mutex), 0);
110 pthread_mutexattr_destroy(&errorcheck);
111}
112
119{
120 (void)state;
121 dt_pthread_rwlock_t lock;
122 assert_int_equal(dt_pthread_rwlock_init(&lock, NULL), 0);
123
124 assert_int_equal(dt_pthread_rwlock_wrlock(&lock), 0);
125 assert_int_equal(dt_pthread_rwlock_wrlock(&lock), 0); // same thread, as writer
126 assert_int_equal(dt_pthread_rwlock_rdlock(&lock), 0); // same thread, as reader
127
128 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
129 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
130 assert_int_equal(dt_pthread_rwlock_unlock(&lock), 0);
131
132 assert_int_equal(dt_pthread_rwlock_destroy(&lock), 0);
133}
134
135int main(int argc, char *argv[])
136{
137 const struct CMUnitTest tests[] = {
138 cmocka_unit_test(_a_null_attr_mutex_is_recursive),
139 cmocka_unit_test(_the_blocking_lock_also_re_enters),
140 cmocka_unit_test(_an_explicit_attribute_is_honoured),
141 cmocka_unit_test(_an_rwlock_writer_may_re_enter),
142 };
143
144 return cmocka_run_group_tests(tests, NULL, NULL);
145}
146
147// clang-format off
148// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
149// vim: shiftwidth=2 expandtab tabstop=2 cindent
150// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
151// 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
int main()
Definition prova.c:47
const float uint32_t state[4]
dt_pthread_mutex_t lock
Definition supervisor.c:123
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