![]() |
Ansel 0.0
A darktable fork - bloat + design vision
|
#include "external/ThreadSafetyAnalysis.h"#include "system/dtpthread.h"#include <pthread.h>#include <stdarg.h>#include <stddef.h>#include <setjmp.h>#include <stdint.h>#include <cmocka.h>
Include dependency graph for test_dtpthread_recursive.c:Go to the source code of this file.
Functions | |
| static void | _a_null_attr_mutex_is_recursive (void **state) NO_THREAD_SAFETY_ANALYSIS |
| 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 |
| int | main (void) |
Locks initialised with a NULL attribute are recursive.
A thread re-entering a lock it already holds cannot race itself, so the data stays protected; a non-recursive mutex answers that situation with a deadlock, which is a worse outcome than the one it prevents. dt_pthread_mutex_init(..., NULL) therefore produces a recursive mutex, and dt_pthread_rwlock_t tracks same-thread writer depth.
These tests probe with TRYLOCK rather than lock(). Both express the property, but a regression caught by trylock is a failed assertion, while a regression caught by lock() is a hung test binary that CI can only kill on timeout. The second acquisition through the real lock() path is exercised too – after trylock has already established that it cannot block. The property, stated without risking a hang: the owner can take it again.
Definition at line 56 of file test_dtpthread_recursive.c.
References dt_pthread_mutex_destroy(), dt_pthread_mutex_init(), dt_pthread_mutex_lock(), dt_pthread_mutex_trylock(), dt_pthread_mutex_unlock(), mutex, state, and void().
Referenced by main().
An explicit attribute still wins: this is the override path, not a hardcoded policy.
Definition at line 90 of file test_dtpthread_recursive.c.
References dt_pthread_mutex_destroy(), dt_pthread_mutex_init(), dt_pthread_mutex_lock(), dt_pthread_mutex_trylock(), dt_pthread_mutex_unlock(), mutex, state, and void().
Referenced by main().
The rwlock's writer may re-enter, as reader or as writer.
This is the deadlock fix rather than a convenience: glibc's default PREFER_WRITER_NONRECURSIVE policy blocks a re-entering thread as soon as another writer is queued, and dt_dev_pixelpipe_change() can re-enter while holding history_mutex.
Definition at line 114 of file test_dtpthread_recursive.c.
References dt_pthread_rwlock_destroy(), dt_pthread_rwlock_init(), dt_pthread_rwlock_rdlock(), dt_pthread_rwlock_unlock(), dt_pthread_rwlock_wrlock(), lock, state, and void().
Referenced by main().
The same through the blocking entry point, which is what callers actually use. Safe to run only because the test above already proved it cannot block.
Definition at line 74 of file test_dtpthread_recursive.c.
References dt_pthread_mutex_destroy(), dt_pthread_mutex_init(), dt_pthread_mutex_lock(), dt_pthread_mutex_trylock(), dt_pthread_mutex_unlock(), mutex, state, and void().
Referenced by main().
| int main | ( | void | ) |
Definition at line 131 of file test_dtpthread_recursive.c.
References _a_null_attr_mutex_is_recursive(), _an_explicit_attribute_is_honoured(), _an_rwlock_writer_may_re_enter(), and _the_blocking_lock_also_re_enters().