liblzma: Use __attribute__((__constructor__)) if available.

This uses it for CRC table initializations when using --disable-small.
It avoids mythread_once() overhead. It also means that then
--disable-small --disable-threads is thread-safe if this attribute
is supported.
This commit is contained in:
Lasse Collin 2022-11-14 16:00:52 +02:00
parent 6553f49b11
commit eb0f1450ad
6 changed files with 59 additions and 5 deletions

View File

@ -48,6 +48,7 @@
cmake_minimum_required(VERSION 3.13...3.16 FATAL_ERROR)
include(CMakePushCheckState)
include(CheckSymbolExists)
include(CheckStructHasMember)
include(cmake/tuklib_integer.cmake)
@ -387,6 +388,20 @@ if(NOT TUKLIB_CPUCORES_FOUND OR NOT TUKLIB_PHYSMEM_FOUND)
"To build anyway, edit this CMakeLists.txt to ignore this error.")
endif()
# Check for __attribute__((__constructor__)) support.
# This needs -Werror because some compilers just warn
# about this being unsupported.
cmake_push_check_state()
set(CMAKE_REQUIRED_FLAGS "-Werror")
check_c_source_compiles("
__attribute__((__constructor__))
static void my_constructor_func(void) { return; }
int main(void) { return 0; }
"
HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
cmake_pop_check_state()
tuklib_add_definition_if(liblzma HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
# immintrin.h:
include(CheckIncludeFile)
check_include_file(immintrin.h HAVE_IMMINTRIN_H)

View File

@ -456,7 +456,9 @@ XZ Utils Installation
no Disable threading support. This is the
same as using --disable-threads.
NOTE: If combined with --enable-small, the
NOTE: If combined with --enable-small
and the compiler doesn't support
__attribute__((__constructor__)), the
resulting liblzma won't be thread safe,
that is, if a multi-threaded application
calls any liblzma functions from more than

View File

@ -768,6 +768,29 @@ AC_CHECK_MEMBERS([
AC_SYS_LARGEFILE
AC_C_BIGENDIAN
# __attribute__((__constructor__)) can be used for one-time initializations.
# Use -Werror because some compilers accept unknown attributes and just
# give a warning. If it works this should give no warnings, even
# clang -Weverything should be fine.
# dnl This doesn't need AC_LANG_SOURCE, minimal code is enough.
AC_MSG_CHECKING([if __attribute__((__constructor__)) can be used])
have_func_attribute_constructor=no
OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
AC_COMPILE_IFELSE([
__attribute__((__constructor__))
static void my_constructor_func(void) { return; }
], [
AC_DEFINE([HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR], [1],
[Define to 1 if __attribute__((__constructor__))
is supported for functions.])
have_func_attribute_constructor=yes
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
CFLAGS="$OLD_CFLAGS"
###############################################################################
# Checks for library functions.
@ -1005,9 +1028,11 @@ if test x$tuklib_cv_cpucores_method = xunknown; then
echo "No supported method to detect the number of CPU cores."
fi
if test "x$enable_threads$enable_small" = xnoyes; then
if test "x$enable_threads$enable_small$have_func_attribute_constructor" \
= xnoyesno; then
echo
echo "NOTE:"
echo "liblzma will be thread unsafe due the combination"
echo "of --disable-threads --enable-small."
echo "liblzma will be thread-unsafe due to the combination"
echo "of --disable-threads --enable-small when using a compiler"
echo "that doesn't support __attribute__((__constructor__))."
fi

View File

@ -16,6 +16,9 @@
uint32_t lzma_crc32_table[1][256];
#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
__attribute__((__constructor__))
#endif
static void
crc32_init(void)
{
@ -37,18 +40,22 @@ crc32_init(void)
}
#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
extern void
lzma_crc32_init(void)
{
mythread_once(crc32_init);
return;
}
#endif
extern LZMA_API(uint32_t)
lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
{
#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
lzma_crc32_init();
#endif
crc = ~crc;

View File

@ -16,6 +16,9 @@
static uint64_t crc64_table[256];
#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
__attribute__((__constructor__))
#endif
static void
crc64_init(void)
{
@ -40,7 +43,9 @@ crc64_init(void)
extern LZMA_API(uint64_t)
lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
{
#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR
mythread_once(crc64_init);
#endif
crc = ~crc;

View File

@ -543,7 +543,7 @@ lzma_lz_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_allocator *allocator, const void *options,
lzma_lz_options *lz_options))
{
#ifdef HAVE_SMALL
#if defined(HAVE_SMALL) && !defined(HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR)
// We need that the CRC32 table has been initialized.
lzma_crc32_init();
#endif