summaryrefslogtreecommitdiff
path: root/lib/locale_threads.t
blob: cda570be3a3d611f0e72fc6aec98cfc97082a9d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use strict;
use warnings;

# This file tests interactions with locale and threads

BEGIN {
    chdir 't' if -d 't';
    require './test.pl';
    set_up_inc('../lib');
    require './loc_tools.pl';
    skip_all("No locales") unless locales_enabled();
    skip_all_without_config('useithreads');
    $| = 1;
    eval { require POSIX; POSIX->import(qw(locale_h  unistd_h)) };
    if ($@) {
	skip_all("could not load the POSIX module"); # running minitest?
    }
}

# reset the locale environment
local @ENV{'LANG', (grep /^LC_/, keys %ENV)};

SKIP: { # perl #127708
    my @locales = grep { $_ !~ / ^ C \b | POSIX /x } find_locales('LC_MESSAGES');
    skip("No valid locale to test with", 1) unless @locales;

    local $ENV{LC_MESSAGES} = $locales[0];

    # We're going to try with all possible error numbers on this platform
    my $error_count = keys(%!) + 1;

    print fresh_perl("
        use threads;
        use strict;
        use warnings;

        my \$errnum = 1;

        my \@threads = map +threads->create(sub {
            sleep 0.1;

            for (1..5_000) {
                \$errnum = (\$errnum + 1) % $error_count;
                \$! = \$errnum;

                # no-op to trigger stringification
                next if \"\$!\" eq \"\";
            }
        }), (0..1);
        \$_->join for splice \@threads;",
    {}
    );

    pass("Didn't segfault");
}

SKIP: {
    skip("POSIX version doesn't support thread-safe locale operations", 1)
                                                unless ${^SAFE_LOCALES};

    my @locales = find_locales( 'LC_NUMERIC' );
    skip("No LC_NUMERIC locales available", 1) unless @locales;

    my $dot = "";
    my $comma = "";
    for (@locales) { # prefer C for the base if available
        use locale;
        setlocale(LC_NUMERIC, $_) or next;
        my $in = 4.2; # avoid any constant folding bugs
        if ((my $s = sprintf("%g", $in)) eq "4.2")  {
            $dot ||= $_;
        } else {
            my $radix = localeconv()->{decimal_point};
            $comma ||= $_ if $radix eq ',';
        }

        last if $dot && $comma;
    }

    # See if multiple threads can simultaneously change the locale, and give
    # the expected radix results.  On systems without a comma radix locale,
    # run this anyway skipping the use of that, to verify that we don't
    # segfault
    fresh_perl_is("
        use threads;
        use strict;
        use warnings;
        use POSIX qw(locale_h);

        my \$result = 1;

        my \@threads = map +threads->create(sub {
            sleep 0.1;
            for (1..5_000) {
                my \$s;
                my \$in = 4.2; # avoid any constant folding bugs

                if ('$comma') {
                    setlocale(&LC_NUMERIC, '$comma');
                    use locale;
                    \$s = sprintf('%g', \$in);
                    return 0 if (\$s ne '4,2');
                }

                setlocale(&LC_NUMERIC, '$dot');
                \$s = sprintf('%g', \$in);
                return 0 if (\$s ne '4.2');
            }

            return 1;

        }), (0..3);
        \$result &= \$_->join for splice \@threads;
        print \$result",
    1, {}, "Verify there were no failures with simultaneous running threads"
    );
}

done_testing();