| // tls_test.cc -- test TLS variables for gold |
| |
| // Copyright (C) 2006-2021 Free Software Foundation, Inc. |
| // Written by Ian Lance Taylor <iant@google.com>. |
| |
| // This file is part of gold. |
| |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 3 of the License, or |
| // (at your option) any later version. |
| |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| // MA 02110-1301, USA. |
| |
| // This provides a set of test functions for TLS variables. The |
| // functions are called by a main function in tls_test_main.cc. This |
| // lets us test TLS access from a shared library. We currently don't |
| // bother to test TLS access between two different files, on the |
| // theory that that is no more complicated than ordinary variable |
| // access between files. |
| |
| // We start two threads, and stop the second one. Then we run the |
| // first thread through the following cases. Then we let the second |
| // thread continue, and run it through the same set of cases. All the |
| // actual thread manipulation is in tls_test_main.cc. |
| |
| // 1 Access to an uninitialized global thread variable. |
| // 2 Access to an uninitialized static thread variable. |
| // 3 Access to an initialized global thread variable. |
| // 4 Access to an initialized static thread variable. |
| // 5 Taking the address of a global thread variable. |
| // 6 Taking the address of a static thread variable. |
| // 8 Like test 1, but with the thread variable defined in another file. |
| // 9 Like test 3, but with the thread variable defined in another file. |
| // 10 Like test 5, but with the thread variable defined in another file. |
| // last Verify that the above tests left the variables set correctly. |
| |
| |
| #include "config.h" |
| #include <cstdio> |
| #include "tls_test.h" |
| |
| #define CHECK_EQ_OR_RETURN(var, expected) \ |
| do \ |
| { \ |
| if ((var) != (expected)) \ |
| { \ |
| printf(#var ": expected %d, found %d\n", expected, var); \ |
| return false; \ |
| } \ |
| } \ |
| while (0) |
| |
| __thread int v1; |
| static __thread int v2; |
| |
| // We don't use these pointers, but putting them in tests alignment on |
| // a 64-bit target. |
| __thread char* p1; |
| char dummy; |
| __thread char* p2 = &dummy; |
| |
| __thread int v3 = 3; |
| static __thread int v4 = 4; |
| __thread int v5; |
| static __thread int v6; |
| |
| struct int128 |
| { |
| long long hi; |
| long long lo; |
| }; |
| |
| static __thread struct int128 v12 = { 115, 125 }; |
| |
| bool |
| t1() |
| { |
| CHECK_EQ_OR_RETURN(v1, 0); |
| v1 = 10; |
| return true; |
| } |
| |
| bool |
| t2() |
| { |
| CHECK_EQ_OR_RETURN(v2, 0); |
| v2 = 20; |
| return true; |
| } |
| |
| bool |
| t3() |
| { |
| CHECK_EQ_OR_RETURN(v3, 3); |
| v3 = 30; |
| return true; |
| } |
| |
| bool |
| t4() |
| { |
| CHECK_EQ_OR_RETURN(v4, 4); |
| v4 = 40; |
| return true; |
| } |
| |
| // For test 5 the main function calls f5b(f5a()), then calls t5(). |
| |
| int* |
| f5a() |
| { |
| return &v5; |
| } |
| |
| void |
| f5b(int* p) |
| { |
| *p = 50; |
| } |
| |
| bool |
| t5() |
| { |
| CHECK_EQ_OR_RETURN(v5, 50); |
| return true; |
| } |
| |
| // For test 6 the main function calls f6b(f6a()), then calls t6(). |
| |
| int* |
| f6a() |
| { |
| return &v6; |
| } |
| |
| void |
| f6b(int* p) |
| { |
| *p = 60; |
| } |
| |
| bool |
| t6() |
| { |
| CHECK_EQ_OR_RETURN(v6, 60); |
| return true; |
| } |
| |
| // The slot for t7() is unused. |
| |
| bool |
| t8() |
| { |
| CHECK_EQ_OR_RETURN(o1, 0); |
| o1 = -10; |
| return true; |
| } |
| |
| bool |
| t9() |
| { |
| CHECK_EQ_OR_RETURN(o2, -2); |
| o2 = -20; |
| return true; |
| } |
| |
| // For test 10 the main function calls f10b(f10a()), then calls t10(). |
| |
| int* |
| f10a() |
| { |
| return &o3; |
| } |
| |
| void |
| f10b(int* p) |
| { |
| *p = -30; |
| } |
| |
| bool |
| t10() |
| { |
| CHECK_EQ_OR_RETURN(o3, -30); |
| return true; |
| } |
| |
| bool |
| t12() |
| { |
| struct int128 newval = { 335, 345 }; |
| CHECK_EQ_OR_RETURN((int) v12.hi, 115); |
| CHECK_EQ_OR_RETURN((int) v12.lo, 125); |
| v12 = newval; |
| return true; |
| } |
| |
| bool |
| t_last() |
| { |
| CHECK_EQ_OR_RETURN(v1, 10); |
| CHECK_EQ_OR_RETURN(v2, 20); |
| CHECK_EQ_OR_RETURN(v3, 30); |
| CHECK_EQ_OR_RETURN(v4, 40); |
| CHECK_EQ_OR_RETURN(v5, 50); |
| CHECK_EQ_OR_RETURN(v6, 60); |
| CHECK_EQ_OR_RETURN((int) v12.hi, 335); |
| CHECK_EQ_OR_RETURN((int) v12.lo, 345); |
| CHECK_EQ_OR_RETURN(o1, -10); |
| CHECK_EQ_OR_RETURN(o2, -20); |
| CHECK_EQ_OR_RETURN(o3, -30); |
| int check = t11_last(); |
| CHECK_EQ_OR_RETURN(check, 1); |
| return true; |
| } |