mirror of
https://github.com/postgres/postgres.git
synced 2025-05-21 15:54:08 +03:00
Andrew Gierth pointed out that commit 1c72ec6f4 would yield the wrong answer on big-endian ARM systems, because the data being CRC'd would be different. To fix that, and avoid the rather unsightly hard-wired constant, simply compare the hardware and software implementations' results. While we're at it, also log the resulting decision at DEBUG1, and error out if the hw and sw results unexpectedly differ. Also, since this file must compile for both frontend and backend, avoid incorrect dependencies on backend-only headers. In passing, add a comment to postmaster.c about when the CRC function pointer will get initialized. Thomas Munro, based on complaints from Andrew Gierth and Tom Lane Discussion: https://postgr.es/m/HE1PR0801MB1323D171938EABC04FFE7FA9E3110@HE1PR0801MB1323.eurprd08.prod.outlook.com
96 lines
2.4 KiB
C
96 lines
2.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* pg_crc32c_armv8_choose.c
|
|
* Choose between ARMv8 and software CRC-32C implementation.
|
|
*
|
|
* On first call, checks if the CPU we're running on supports the ARMv8
|
|
* CRC Extension. If it does, use the special instructions for CRC-32C
|
|
* computation. Otherwise, fall back to the pure software implementation
|
|
* (slicing-by-8).
|
|
*
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/port/pg_crc32c_armv8_choose.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef FRONTEND
|
|
#include "postgres.h"
|
|
#else
|
|
#include "postgres_fe.h"
|
|
#endif
|
|
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
|
|
#include "port/pg_crc32c.h"
|
|
|
|
|
|
static sigjmp_buf illegal_instruction_jump;
|
|
|
|
/*
|
|
* Probe by trying to execute pg_comp_crc32c_armv8(). If the instruction
|
|
* isn't available, we expect to get SIGILL, which we can trap.
|
|
*/
|
|
static void
|
|
illegal_instruction_handler(SIGNAL_ARGS)
|
|
{
|
|
siglongjmp(illegal_instruction_jump, 1);
|
|
}
|
|
|
|
static bool
|
|
pg_crc32c_armv8_available(void)
|
|
{
|
|
uint64 data = 42;
|
|
int result;
|
|
|
|
/*
|
|
* Be careful not to do anything that might throw an error while we have
|
|
* the SIGILL handler set to a nonstandard value.
|
|
*/
|
|
pqsignal(SIGILL, illegal_instruction_handler);
|
|
if (sigsetjmp(illegal_instruction_jump, 1) == 0)
|
|
{
|
|
/* Rather than hard-wiring an expected result, compare to SB8 code */
|
|
result = (pg_comp_crc32c_armv8(0, &data, sizeof(data)) ==
|
|
pg_comp_crc32c_sb8(0, &data, sizeof(data)));
|
|
}
|
|
else
|
|
{
|
|
/* We got the SIGILL trap */
|
|
result = -1;
|
|
}
|
|
pqsignal(SIGILL, SIG_DFL);
|
|
|
|
#ifndef FRONTEND
|
|
/* We don't expect this case, so complain loudly */
|
|
if (result == 0)
|
|
elog(ERROR, "crc32 hardware and software results disagree");
|
|
|
|
elog(DEBUG1, "using armv8 crc32 hardware = %d", (result > 0));
|
|
#endif
|
|
|
|
return (result > 0);
|
|
}
|
|
|
|
/*
|
|
* This gets called on the first call. It replaces the function pointer
|
|
* so that subsequent calls are routed directly to the chosen implementation.
|
|
*/
|
|
static pg_crc32c
|
|
pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
|
|
{
|
|
if (pg_crc32c_armv8_available())
|
|
pg_comp_crc32c = pg_comp_crc32c_armv8;
|
|
else
|
|
pg_comp_crc32c = pg_comp_crc32c_sb8;
|
|
|
|
return pg_comp_crc32c(crc, data, len);
|
|
}
|
|
|
|
pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
|