/*
* Copyright ( C ) 2018 The Android Open Source Project
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
#include "membarrier.h"
#include <gtest/gtest.h>
namespace {
class ScopedErrnoCleaner {
public :
ScopedErrnoCleaner() { errno = 0 ; }
~ScopedErrnoCleaner() { errno = 0 ; }
};
bool HasMembarrier(art::MembarrierCommand cmd) {
ScopedErrnoCleaner errno_cleaner;
int supported_cmds = art::membarrier(art::MembarrierCommand::kQuery);
return (supported_cmds > 0 ) && ((supported_cmds & static_cast <int >(cmd)) != 0 );
}
// The membarrier registration APIs modify process state and cannot be undone.
// As such, it is useful to test these APIs in a child process.
// WARNING: This helper can only be safely used in single threaded tests.
class ForkHelper {
public :
ForkHelper() {}
~ForkHelper() {}
template <class Callback>
pid_t RunInForkedProcess(Callback action) {
pid_t pid = fork();
EXPECT_GE(pid, 0 ) << "fork" ;
if (pid == 0 ) {
// Child process.
action();
_exit (testing::Test::HasFailure());
}
child_ = pid;
return pid;
}
testing::AssertionResult WaitForChild() {
while (true ) {
int wstatus = 0 ;
pid_t pid = wait(&wstatus);
if (pid == -1 ) {
if (errno == EINTR) {
continue ;
}
if (errno == ECHILD) {
// Done!
return testing::AssertionSuccess();
}
// Unexpected result.
return testing::AssertionFailure() << "wait error: " << strerror(errno);
}
if (pid != child_) {
return testing::AssertionFailure() << "unexpected pid: " << pid;
}
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0 ) {
return testing::AssertionFailure()
<< "unexpected exit status: "
<< "wait_status: WIFEXITED(wstatus) = " << WIFEXITED(wstatus)
<< ", WEXITSTATUS(wstatus) = " << WEXITSTATUS(wstatus)
<< ", WTERMSIG(wstatus) = " << WTERMSIG(wstatus);
}
}
}
private :
pid_t child_{0 };
};
} // namespace
TEST(membarrier, query) {
ScopedErrnoCleaner errno_cleaner;
int supported = art::membarrier(art::MembarrierCommand::kQuery);
if (errno == 0 ) {
ASSERT_LE(0 , supported);
} else {
ASSERT_TRUE(errno == ENOSYS && supported == -1 );
}
}
TEST(membarrier, global_barrier) {
if (!HasMembarrier(art::MembarrierCommand::kGlobal)) {
GTEST_LOG_(INFO) << "MembarrierCommand::kGlobal not supported, skipping test." ;
return ;
}
ASSERT_EQ(0 , art::membarrier(art::MembarrierCommand::kGlobal));
}
static const char * MembarrierCommandToName(art::MembarrierCommand cmd) {
#define CASE_VALUE(x) \
case (x): \
return #x ;
switch (cmd) {
CASE_VALUE(art::MembarrierCommand::kQuery);
CASE_VALUE(art::MembarrierCommand::kGlobal);
CASE_VALUE(art::MembarrierCommand::kGlobalExpedited);
CASE_VALUE(art::MembarrierCommand::kRegisterGlobalExpedited);
CASE_VALUE(art::MembarrierCommand::kPrivateExpedited);
CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpedited);
CASE_VALUE(art::MembarrierCommand::kPrivateExpeditedSyncCore);
CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore);
}
}
static void TestRegisterAndBarrierCommands(art::MembarrierCommand membarrier_cmd_register,
art::MembarrierCommand membarrier_cmd_barrier) {
if (!HasMembarrier(membarrier_cmd_register)) {
GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register)
<< " not supported, skipping test." ;
return ;
}
if (!HasMembarrier(membarrier_cmd_barrier)) {
GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier)
<< " not supported, skipping test." ;
return ;
}
ScopedErrnoCleaner errno_cleaner;
// Check barrier use without prior registration.
if (membarrier_cmd_register == art::MembarrierCommand::kRegisterGlobalExpedited) {
// Global barrier use is always okay.
ASSERT_EQ(0 , art::membarrier(membarrier_cmd_barrier));
} else {
// Private barrier should fail.
ASSERT_EQ(-1 , art::membarrier(membarrier_cmd_barrier));
ASSERT_EQ(EPERM, errno);
errno = 0 ;
}
// Check registration for barrier succeeds.
ASSERT_EQ(0 , art::membarrier(membarrier_cmd_register));
// Check barrier use after registration succeeds.
ASSERT_EQ(0 , art::membarrier(membarrier_cmd_barrier));
}
TEST(membarrier, global_expedited) {
TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterGlobalExpedited,
art::MembarrierCommand::kGlobalExpedited);
}
TEST(membarrier, private_expedited) {
ForkHelper helper;
helper.RunInForkedProcess([]() {
TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpedited,
art::MembarrierCommand::kPrivateExpedited);
});
ASSERT_TRUE(helper.WaitForChild());
}
TEST(membarrier, private_expedited_sync_core) {
ForkHelper helper;
helper.RunInForkedProcess([]() {
TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore,
art::MembarrierCommand::kPrivateExpeditedSyncCore);
});
ASSERT_TRUE(helper.WaitForChild());
}
Messung V0.5 in Prozent C=89 H=97 G=93
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland