Commit dff9f68c authored by Niels Möller's avatar Niels Möller

Made fat initialization more robust.

parent b686476f
2015-01-23 Niels Möller <nisse@lysator.liu.se>
* fat-setup.h (DEFINE_FAT_FUNC): Check value of function pointer,
before calling fat_init. Should be correct even without memory
barrier.
* fat-x86_64.c (fat_init): Deleted static variable initialized.
The checks of the relevant pointer in DEFINE_FAT_FUNC is more
robust.
* fat-arm.c (fat_init): Likewise.
2015-01-21 Niels Möller <nisse@lysator.liu.se>
* fat-arm.c (fat_init): Setup for use of neon assembly functions.
......
......@@ -164,13 +164,9 @@ DECLARE_FAT_FUNC_VAR(umac_nh_n, umac_nh_n_func, neon);
static void CONSTRUCTOR
fat_init (void)
{
static volatile int initialized = 0;
struct arm_features features;
int verbose;
if (initialized)
return;
get_arm_features (&features);
verbose = getenv (ENV_VERBOSE) != NULL;
......@@ -213,8 +209,6 @@ fat_init (void)
_nettle_umac_nh_vec = _nettle_umac_nh_c;
_nettle_umac_nh_n_vec = _nettle_umac_nh_n_c;
}
/* FIXME: Needs memory barrier, to enforce store ordering. */
initialized = 1;
}
DEFINE_FAT_FUNC(_nettle_aes_encrypt, void,
......
......@@ -30,10 +30,11 @@
*/
/* Fat library initialization works as follows. The main function is
fat_init. It tries to do initialization only once, but since it is
idempotent and pointer updates are atomic on x86_64, there's no
harm if it is in some cases called multiple times from several
threads.
fat_init. We try to do initialization only once, but since it is
idempotent, there's no harm if it is in some cases called multiple
times from several threads. For correctness, we rely on atomic
writes, but not on memory barriers or any other synchronization
mechanism.
The fat_init function checks the cpuid flags, and sets function
pointers, e.g, _nettle_aes_encrypt_vec, to point to the appropriate
......@@ -47,18 +48,24 @@
For the actual indirection, there are two cases.
If ifunc support is available, function pointers are statically
initialized to NULL, and we register resolver functions, e.g.,
_nettle_aes_encrypt_resolve, which call fat_init, and then return
the function pointer, e.g., the value of _nettle_aes_encrypt_vec.
If ifunc is not available, we have to define a wrapper function to
jump via the function pointer. (FIXME: For internal calls, we could
do this as a macro). We statically initialize each function pointer
to point to a special initialization function, e.g.,
_nettle_aes_encrypt_init, which calls fat_init, and then invokes
the right function. This way, all pointers are setup correctly at
the first call to any fat function.
* If ifunc support is available, function pointers are statically
initialized to NULL, and we register resolver functions, e.g.,
_nettle_aes_encrypt_resolve, which call fat_init, and then return
the function pointer, e.g., the value of _nettle_aes_encrypt_vec.
* If ifunc is not available, we have to define a wrapper function
to jump via the function pointer. (FIXME: For internal calls, we
could do this as a macro).
We statically initialize each function pointer to point to a
special initialization function, e.g., _nettle_aes_encrypt_init,
which calls fat_init, and then invokes the right function. This
way, all pointers are setup correctly at the first call to any
fat function.
And atomic writes are required for correctness in the case that
several threads do "first call to any fat function" at the same
time.
*/
#if HAVE_GCC_ATTRIBUTE
......@@ -107,7 +114,8 @@
{ \
if (getenv (ENV_VERBOSE)) \
fprintf (stderr, "libnettle: "#name"_resolve\n"); \
fat_init(); \
if (!name##_vec) \
fat_init(); \
return (void_func *) name##_vec; \
}
......@@ -125,7 +133,8 @@
static rtype name##_init prototype { \
if (getenv (ENV_VERBOSE)) \
fprintf (stderr, "libnettle: "#name"_init\n"); \
fat_init(); \
if (name##_vec == name##_init) \
fat_init(); \
assert (name##_vec != name##_init); \
return name##_vec args; \
}
......
......@@ -122,11 +122,8 @@ DECLARE_FAT_FUNC_VAR(memxor, memxor_func, sse2)
static void CONSTRUCTOR
fat_init (void)
{
static volatile int initialized = 0;
struct x86_features features;
int verbose;
if (initialized)
return;
/* FIXME: Replace all getenv calls by getenv_secure? */
verbose = getenv (ENV_VERBOSE) != NULL;
......@@ -169,11 +166,6 @@ fat_init (void)
fprintf (stderr, "libnettle: intel SSE2 will not be used for memxor.\n");
nettle_memxor_vec = _nettle_memxor_x86_64;
}
/* The x86_64 architecture should always make stores visible in the
right order to other processors (except for non-temporal stores
and the like). So we don't need any memory barrier. */
initialized = 1;
}
DEFINE_FAT_FUNC(_nettle_aes_encrypt, void,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment