diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2022-05-27 21:36:31 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2022-05-28 06:34:55 +0930 |
commit | a8c1858cf2bb6efb35c0678d135fd522ece9e2a4 (patch) | |
tree | e7b37d5013b2918dac57bb1bacbae00eb82655c4 /src/cairo-mutex-impl-private.h | |
parent | 5dafd7411660f153219abceab64d5cc3be1c59a6 (diff) | |
download | cairo-a8c1858cf2bb6efb35c0678d135fd522ece9e2a4.tar.gz |
Fix deadlock in cairo-scaled-font.c
When cairo_scaled_glyph_page_cache needs to remove entries,
cairo-cache calls _cairo_hash_table_random_entry() with the predicate
_cairo_scaled_glyph_page_can_remove(). This function checks that the
glyph_page scaled_font is not locked by testing
scaled_font->cache_frozen. The scaled font is locked in the
cache-cache destroy entry callback: _cairo_scaled_glyph_page_pluck().
There is a race condition here between testing
scaled_font->cache_frozen and locking the font. Fix this by adding a
new CAIRO_MUTEX_TRY_LOCK mutex operation, and using it to test and
lock the scaled font in _cairo_scaled_glyph_page_can_remove().
Fixes the multithreaded case in #440
Diffstat (limited to 'src/cairo-mutex-impl-private.h')
-rw-r--r-- | src/cairo-mutex-impl-private.h | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h index 9f208aaa9..a8599d47e 100644 --- a/src/cairo-mutex-impl-private.h +++ b/src/cairo-mutex-impl-private.h @@ -87,6 +87,9 @@ * No trailing semicolons are needed (in any macro you define here). * You should be able to compile the following snippet: * + * - #define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) to try locking the mutex object, + * returning TRUE if the lock is acquired, FALSE if the mutex could not be locked. + * * <programlisting> * cairo_mutex_impl_t _cairo_some_mutex; * @@ -163,6 +166,7 @@ # define CAIRO_MUTEX_IMPL_NO 1 # define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP # define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) (CAIRO_MUTEX_IMPL_NOOP1(mutex), TRUE) # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) # define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0 @@ -190,6 +194,7 @@ # define CAIRO_MUTEX_IMPL_WIN32 1 # define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) TryEnterCriticalSection (&(mutex)) # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex)) # define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex)) # define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex)) @@ -208,6 +213,7 @@ # define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL) #endif # define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex)) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) (pthread_mutex_trylock (&(mutex)) == 0) # define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) #if HAVE_LOCKDEP # define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex)) |