mdbx: temporary workaround for Elbrus's libc bug.

https://bugs.mcst.ru/bugzilla/show_bug.cgi?id=2820
This commit is contained in:
Leo Yuriev 2018-03-19 14:40:15 +03:00
parent 195b53374e
commit c05d179035
2 changed files with 147 additions and 0 deletions

36
mdbx.h
View File

@ -1818,6 +1818,42 @@ LIBMDBX_API int mdbx_cursor_get_attr(MDBX_cursor *mc, MDBX_val *key,
LIBMDBX_API int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
MDBX_val *data, mdbx_attr_t *attrptr);
/*----------------------------------------------------------------------------*/
/* LY: temporary workaround for Elbrus's memcmp() bug. */
#ifndef __GLIBC_PREREQ
#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
#define __GLIBC_PREREQ(maj, min) \
((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min))
#else
#define __GLIBC_PREREQ(maj, min) (0)
#endif
#endif /* __GLIBC_PREREQ */
#if defined(__e2k__) && !__GLIBC_PREREQ(2, 24)
LIBMDBX_API int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
size_t n);
LIBMDBX_API int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2);
LIBMDBX_API int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
size_t n);
LIBMDBX_API size_t mdbx_e2k_strlen_bug_workaround(const char *s);
LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
size_t maxlen);
#include <string.h>
#include <strings.h>
#undef memcmp
#define memcmp mdbx_e2k_memcmp_bug_workaround
#undef bcmp
#define bcmp mdbx_e2k_memcmp_bug_workaround
#undef strcmp
#define strcmp mdbx_e2k_strcmp_bug_workaround
#undef strncmp
#define strncmp mdbx_e2k_strncmp_bug_workaround
#undef strlen
#define strlen mdbx_e2k_strlen_bug_workaround
#undef strnlen
#define strnlen mdbx_e2k_strnlen_bug_workaround
#endif /* Elbrus's memcmp() bug. */
#ifdef __cplusplus
}
#endif

View File

@ -37,6 +37,117 @@
#include "./bits.h"
/* LY: temporary workaround for Elbrus's memcmp() bug. */
#if defined(__e2k__) && !__GLIBC_PREREQ(2, 24)
int __hot mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
size_t n) {
if (unlikely(n > 42
/* LY: align followed access if reasonable possible */ &&
(((uintptr_t)s1) & 7) != 0 &&
(((uintptr_t)s1) & 7) == (((uintptr_t)s2) & 7))) {
if (((uintptr_t)s1) & 1) {
const int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
if (diff)
return diff;
s1 = (char *)s1 + 1;
s2 = (char *)s2 + 1;
n -= 1;
}
if (((uintptr_t)s1) & 2) {
const uint16_t a = *(uint16_t *)s1;
const uint16_t b = *(uint16_t *)s2;
if (likely(a != b))
return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
s1 = (char *)s1 + 2;
s2 = (char *)s2 + 2;
n -= 2;
}
if (((uintptr_t)s1) & 4) {
const uint32_t a = *(uint32_t *)s1;
const uint32_t b = *(uint32_t *)s2;
if (likely(a != b))
return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
s1 = (char *)s1 + 4;
s2 = (char *)s2 + 4;
n -= 4;
}
}
while (n >= 8) {
const uint64_t a = *(uint64_t *)s1;
const uint64_t b = *(uint64_t *)s2;
if (likely(a != b))
return (__builtin_bswap64(a) > __builtin_bswap64(b)) ? 1 : -1;
s1 = (char *)s1 + 8;
s2 = (char *)s2 + 8;
n -= 8;
}
if (n & 4) {
const uint32_t a = *(uint32_t *)s1;
const uint32_t b = *(uint32_t *)s2;
if (likely(a != b))
return (__builtin_bswap32(a) > __builtin_bswap32(b)) ? 1 : -1;
s1 = (char *)s1 + 4;
s2 = (char *)s2 + 4;
}
if (n & 2) {
const uint16_t a = *(uint16_t *)s1;
const uint16_t b = *(uint16_t *)s2;
if (likely(a != b))
return (__builtin_bswap16(a) > __builtin_bswap16(b)) ? 1 : -1;
s1 = (char *)s1 + 2;
s2 = (char *)s2 + 2;
}
return (n & 1) ? *(uint8_t *)s1 - *(uint8_t *)s2 : 0;
}
int __hot mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
while (true) {
int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
if (likely(diff != 0) || *s1 == '\0')
return diff;
s1 += 1;
s2 += 1;
}
}
int __hot mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
size_t n) {
while (n > 0) {
int diff = *(uint8_t *)s1 - *(uint8_t *)s2;
if (likely(diff != 0) || *s1 == '\0')
return diff;
s1 += 1;
s2 += 1;
n -= 1;
}
return 0;
}
size_t __hot mdbx_e2k_strlen_bug_workaround(const char *s) {
size_t n = 0;
while (*s) {
s += 1;
n += 1;
}
return n;
}
size_t __hot mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
size_t n = 0;
while (maxlen > n && *s) {
s += 1;
n += 1;
}
return n;
}
#endif /* Elbrus's memcmp() bug. */
/*----------------------------------------------------------------------------*/
/* rthc (tls keys and destructors) */