Skip to content

Commit

Permalink
A probe for compiler thread local storage support.
Browse files Browse the repository at this point in the history
Not needed on Win32, as UV already exposes it there.
  • Loading branch information
nwc10 committed Oct 31, 2020
1 parent ac941c0 commit 8d68b18
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Configure.pl
Expand Up @@ -490,12 +490,14 @@ sub uniq {
if ($config{crossconf}) {
build::auto::detect_cross(\%config, \%defaults);
build::probe::static_inline_cross(\%config, \%defaults);
build::probe::thread_local_cross(\%config, \%defaults);
build::probe::unaligned_access_cross(\%config, \%defaults);
build::probe::ptr_size_cross(\%config, \%defaults);
}
else {
build::auto::detect_native(\%config, \%defaults);
build::probe::static_inline_native(\%config, \%defaults);
build::probe::thread_local_native(\%config, \%defaults);
build::probe::unaligned_access(\%config, \%defaults);
build::probe::ptr_size_native(\%config, \%defaults);
}
Expand Down
5 changes: 5 additions & 0 deletions build/config.h.in
Expand Up @@ -46,6 +46,11 @@
/* How this compiler does static inline functions. */
#define MVM_STATIC_INLINE @static_inline@

#if @has_thread_local@
/* How this compiler declares thread local storage. */
#define MVM_THREAD_LOCAL @thread_local@
#endif

#if @can_unaligned_int32@
#define MVM_CAN_UNALIGNED_INT32
#endif
Expand Down
126 changes: 126 additions & 0 deletions build/probe.pm
Expand Up @@ -227,6 +227,132 @@ sub static_inline_cross {
$config->{static_inline} = 'static';
}

sub thread_local_cross {
my ($config) = @_;
$config->{has_thread_local} = 0;
$config->{thread_local} = "";
}

sub thread_local_native {
my ($config) = @_;

# We don't need to probe for this on Win32, as UV sets it for us
if ($^O eq 'MSWin32') {
$config->{has_thread_local} = 0;
$config->{thread_local} = "";
return;
}

my $restore = _to_probe_dir();

print ::dots(' probing if your compiler offers thread local storage');
my $file = 'thread_local.c';
_spew($file, <<'EOT');
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static int plus_one = 1;
static int minus_one = -1;
THREAD_LOCAL int *minion;
int callback (const void *a, const void *b) {
int val_a = *minion * *(const int *)a;
int val_b = *minion * *(const int *)b;
return val_a < val_b ? -1 : val_a > val_b;
}
#define SIZE 8
void *thread_function(void *arg) {
/* thread local variables should start zeroed in each thread. */
if (minion != NULL) {
fprintf(stderr, "__thread variable started with %p, should be NULL\n",
minion);
exit(2);
}
minion = &minus_one;
int array[SIZE];
unsigned int i;
for (i = 0; i < SIZE; ++i) {
/* "Hash randomisation" - this array isn't in sorted order: */
array[i ^ 5] = i * i;
}
qsort(array, SIZE, sizeof(int), callback);
int bad = 0;
for (i = 0; i < SIZE; ++i) {
int want = (SIZE - 1 - i) * (SIZE - 1 - i);
int have = array[i];
if (want != have) {
++bad;
fprintf(stderr, "array[%u] - want %i, have %i\n", i, want, have);
}
}
if (bad)
exit(3);
return NULL;
}
int main(int argc, char **argv) {
if (minion != NULL) {
fprintf(stderr, "__thread variable started with %p, should be NULL\n",
minion);
exit(4);
}
minion = &plus_one;
pthread_t tid;
int result = pthread_create(&tid, NULL, thread_function, NULL);
if (result) {
fprintf(stderr, "pthread_create failed (%d)\n", result);
exit(5);
}
result = pthread_join(tid, NULL);
if (result) {
fprintf(stderr, "pthread_join failed (%d)\n", result);
exit(6);
}
if (minion == NULL) {
fprintf(stderr, "__thread variable should not be NULL\n");
exit(7);
}
if (!(minion == &plus_one && *minion == 1)) {
fprintf(stderr, "__thread variable should be %d @ %p, not %d @ %p\n",
1, &plus_one, *minion, minion);
exit(8);
}
return 0;
}
EOT

my @try = qw(_Thread_local __thread);

my $t_l;
while ($t_l = shift @try) {
next unless compile($config, 'thread_local', ["THREAD_LOCAL=$t_l"]);
last if !system "./thread_local";
}

if ($t_l) {
print "$t_l\n";
$config->{has_thread_local} = 1;
$config->{thread_local} = $t_l;
} else {
print "it doesn't, so falling back to UV's API\n";
$config->{has_thread_local} = 0;
$config->{thread_local} = "";
}
}

sub specific_werror {
my ($config) = @_;
my $restore = _to_probe_dir();
Expand Down

0 comments on commit 8d68b18

Please sign in to comment.