PostgreSQL Source Code  git master
pg_crc32c_armv8_choose.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_crc32c_armv8_choose.c
4  * Choose between ARMv8 and software CRC-32C implementation.
5  *
6  * On first call, checks if the CPU we're running on supports the ARMv8
7  * CRC Extension. If it does, use the special instructions for CRC-32C
8  * computation. Otherwise, fall back to the pure software implementation
9  * (slicing-by-8).
10  *
11  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  *
15  * IDENTIFICATION
16  * src/port/pg_crc32c_armv8_choose.c
17  *
18  *-------------------------------------------------------------------------
19  */
20 
21 #ifndef FRONTEND
22 #include "postgres.h"
23 #else
24 #include "postgres_fe.h"
25 #endif
26 
27 #include <setjmp.h>
28 #include <signal.h>
29 
30 #include "port/pg_crc32c.h"
31 
32 
33 static sigjmp_buf illegal_instruction_jump;
34 
35 /*
36  * Probe by trying to execute pg_comp_crc32c_armv8(). If the instruction
37  * isn't available, we expect to get SIGILL, which we can trap.
38  */
39 static void
41 {
42  siglongjmp(illegal_instruction_jump, 1);
43 }
44 
45 static bool
47 {
48  uint64 data = 42;
49  int result;
50 
51  /*
52  * Be careful not to do anything that might throw an error while we have
53  * the SIGILL handler set to a nonstandard value.
54  */
56  if (sigsetjmp(illegal_instruction_jump, 1) == 0)
57  {
58  /* Rather than hard-wiring an expected result, compare to SB8 code */
59  result = (pg_comp_crc32c_armv8(0, &data, sizeof(data)) ==
60  pg_comp_crc32c_sb8(0, &data, sizeof(data)));
61  }
62  else
63  {
64  /* We got the SIGILL trap */
65  result = -1;
66  }
67  pqsignal(SIGILL, SIG_DFL);
68 
69 #ifndef FRONTEND
70  /* We don't expect this case, so complain loudly */
71  if (result == 0)
72  elog(ERROR, "crc32 hardware and software results disagree");
73 
74  elog(DEBUG1, "using armv8 crc32 hardware = %d", (result > 0));
75 #endif
76 
77  return (result > 0);
78 }
79 
80 /*
81  * This gets called on the first call. It replaces the function pointer
82  * so that subsequent calls are routed directly to the chosen implementation.
83  */
84 static pg_crc32c
85 pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
86 {
89  else
91 
92  return pg_comp_crc32c(crc, data, len);
93 }
94 
95 pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
#define DEBUG1
Definition: elog.h:25
static bool pg_crc32c_armv8_available(void)
uint32 pg_crc32c
Definition: pg_crc32c.h:38
static pg_crc32c pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len)
Definition: pg_crc32c_sb8.c:35
static sigjmp_buf illegal_instruction_jump
#define ERROR
Definition: elog.h:43
pg_crc32c(* pg_comp_crc32c)(pg_crc32c crc, const void *data, size_t len)
pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len)
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
#define SIG_DFL
Definition: win32_port.h:149
#define SIGNAL_ARGS
Definition: c.h:1259
#define elog(elevel,...)
Definition: elog.h:226
static void illegal_instruction_handler(SIGNAL_ARGS)