1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 // membarrier(2) is only supported for bionic builds (b/111199492).
20 #if defined(__BIONIC__)
21 
22 #include <linux/membarrier.h>
23 #include <sys/syscall.h>
24 
25 #include "utils.h"
26 
27 class ScopedErrnoCleaner {
28  public:
ScopedErrnoCleaner()29   ScopedErrnoCleaner() { errno = 0; }
~ScopedErrnoCleaner()30   ~ScopedErrnoCleaner() { errno = 0; }
31 };
32 
HasMembarrier(int membarrier_cmd)33 static bool HasMembarrier(int membarrier_cmd) {
34   ScopedErrnoCleaner errno_cleaner;
35   int supported_cmds = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
36   return (supported_cmds > 0) && ((supported_cmds & membarrier_cmd) != 0);
37 }
38 
TEST(membarrier,query)39 TEST(membarrier, query) {
40   ScopedErrnoCleaner errno_cleaner;
41   int supported = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0);
42   if (supported == -1 && errno == ENOSYS) GTEST_SKIP() << "no membarrier() in this kernel";
43   ASSERT_GE(supported, 0);
44 }
45 
TEST(membarrier,global_barrier)46 TEST(membarrier, global_barrier) {
47   if (!HasMembarrier(MEMBARRIER_CMD_GLOBAL)) {
48     GTEST_SKIP() << "MEMBARRIER_CMD_GLOBAL not supported";
49   }
50   ASSERT_EQ(0, syscall(__NR_membarrier, MEMBARRIER_CMD_GLOBAL, 0));
51 }
52 
MembarrierCommandToName(int membarrier_cmd)53 static const char* MembarrierCommandToName(int membarrier_cmd) {
54   switch (membarrier_cmd) {
55   case MEMBARRIER_CMD_QUERY:
56     return "MEMBARRIER_CMD_QUERY";
57   case MEMBARRIER_CMD_GLOBAL:
58     return "MEMBARRIER_CMD_GLOBAL";
59   case MEMBARRIER_CMD_GLOBAL_EXPEDITED:
60     return "MEMBARRIER_CMD_GLOBAL_EXPEDITED";
61   case MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED:
62     return "MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED";
63   case MEMBARRIER_CMD_PRIVATE_EXPEDITED:
64     return "MEMBARRIER_CMD_PRIVATE_EXPEDITED";
65   case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
66     return "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED";
67   case MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE:
68     return "MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE";
69   case MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE:
70     return "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE";
71   default:
72     return "MEMBARRIER_UNKNOWN";
73   }
74 }
75 
TestRegisterAndBarrierCommands(int membarrier_cmd_register,int membarrier_cmd_barrier)76 static void TestRegisterAndBarrierCommands(int membarrier_cmd_register,
77                                            int membarrier_cmd_barrier) {
78   if (!HasMembarrier(membarrier_cmd_register)) {
79     GTEST_SKIP() << MembarrierCommandToName(membarrier_cmd_register) << " not supported";
80   }
81   if (!HasMembarrier(membarrier_cmd_barrier)) {
82     GTEST_SKIP() << MembarrierCommandToName(membarrier_cmd_barrier) << " not supported";
83   }
84 
85   ScopedErrnoCleaner errno_cleaner;
86 
87   // Check barrier use without prior registration.
88   if (membarrier_cmd_register == MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED) {
89     // Global barrier use is always okay.
90     ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
91   } else {
92     // Private barrier should fail.
93     ASSERT_EQ(-1, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
94     ASSERT_ERRNO(EPERM);
95     errno = 0;
96   }
97 
98   // Check registration for barrier succeeds.
99   ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_register, 0));
100 
101   // Check barrier use after registration succeeds.
102   ASSERT_EQ(0, syscall(__NR_membarrier, membarrier_cmd_barrier, 0));
103 }
104 
TEST(membarrier,global_expedited)105 TEST(membarrier, global_expedited) {
106   TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
107                                  MEMBARRIER_CMD_GLOBAL_EXPEDITED);
108 }
109 
TEST(membarrier,private_expedited)110 TEST(membarrier, private_expedited) {
111   TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
112                                  MEMBARRIER_CMD_PRIVATE_EXPEDITED);
113 }
114 
TEST(membarrier,private_expedited_sync_core)115 TEST(membarrier, private_expedited_sync_core) {
116   TestRegisterAndBarrierCommands(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
117                                  MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE);
118 }
119 
120 #endif  // __BIONIC__
121