mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Initial implementation of ConditionVariable and Mutex
PiperOrigin-RevId: 394293910
This commit is contained in:
committed by
Copybara-Service
parent
2a629b2c1b
commit
e895f3c100
@@ -56,6 +56,8 @@ cc_library(
|
||||
"bluetooth_classic_medium.h",
|
||||
"bluetooth_classic_server_socket.h",
|
||||
"bluetooth_classic_socket.h",
|
||||
"condition_variable.h",
|
||||
"mutex.h",
|
||||
"server_sync.h",
|
||||
"webrtc.h",
|
||||
"wifi.h",
|
||||
@@ -93,6 +95,8 @@ cc_library(
|
||||
"bluetooth_classic_medium.cc",
|
||||
"bluetooth_classic_server_socket.cc",
|
||||
"bluetooth_classic_socket.cc",
|
||||
"condition_variable.cc",
|
||||
"mutex.cc",
|
||||
"platform.cc",
|
||||
"utils.cc",
|
||||
],
|
||||
@@ -102,6 +106,8 @@ cc_library(
|
||||
"bluetooth_classic_medium.h",
|
||||
"bluetooth_classic_server_socket.h",
|
||||
"bluetooth_classic_socket.h",
|
||||
"condition_variable.h",
|
||||
"mutex.h",
|
||||
],
|
||||
compatible_with = ["//buildenv/target:non_prod"],
|
||||
copts = ["-Ithird_party/nearby_connections/cpp/platform/impl/windows/generated"],
|
||||
@@ -143,8 +149,10 @@ cc_test(
|
||||
srcs = [
|
||||
"atomic_boolean_test.cc",
|
||||
"atomic_reference_test.cc",
|
||||
"condition_variable_test.cc",
|
||||
"crypto_test.cc",
|
||||
"input_file_test.cc",
|
||||
"mutex_test.cc",
|
||||
"output_file_test.cc",
|
||||
],
|
||||
copts = ["-Iplatform/impl/windows/generated"],
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
|
||||
#include "platform/impl/windows/bluetooth_classic_medium.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <regex> // NOLINT
|
||||
#include <string>
|
||||
|
||||
#include "platform/base/cancellation_flag.h"
|
||||
@@ -116,12 +120,22 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cancellation_flag == nullptr) {
|
||||
const std::regex pattern(
|
||||
"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]"
|
||||
"{12}$");
|
||||
|
||||
// Must check for valid pattern as the guid constructor will throw on an
|
||||
// invalid format
|
||||
if (!regex_match(service_uuid, pattern)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::guid service(service_uuid);
|
||||
|
||||
if (cancellation_flag == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BluetoothDevice* currentDevice =
|
||||
dynamic_cast<BluetoothDevice*>(&remote_device);
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
#ifndef PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "platform/api/bluetooth_classic.h"
|
||||
#include "platform/impl/windows/bluetooth_classic_device.h"
|
||||
#include "platform/impl/windows/bluetooth_classic_server_socket.h"
|
||||
|
||||
@@ -14,54 +14,68 @@
|
||||
|
||||
#include "platform/impl/windows/bluetooth_classic_medium.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "platform/api/bluetooth_adapter.h"
|
||||
#include "platform/api/bluetooth_classic.h"
|
||||
#include "platform/impl/windows/bluetooth_adapter.h"
|
||||
#include "platform/impl/windows/bluetooth_classic_device.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// TODO(jfcarroll): Find a way to mock winrt components in order to properly
|
||||
// unit test this. Once that's done, unit tests can be written, in a later C/L.
|
||||
//
|
||||
// CAUTION: THIS IS NOT A REAL TEST, THIS EXERCISES THE SCANNER, IT DOES NOT
|
||||
// STOP AND IS INTENDED SOLELY FOR DEBUG AND DEMONSTRATION PURPOSES. DO NOT
|
||||
// ATTEMPT TO BUILD AND RUN THIS TEST ON GOOGLE3 YOU HAVE BEEN WARNED
|
||||
static int callcount = 0;
|
||||
static std::map<std::string, location::nearby::api::BluetoothDevice*>
|
||||
deviceList;
|
||||
|
||||
void device_discovered_cb(location::nearby::api::BluetoothDevice& device) {
|
||||
const std::string address = device.GetMacAddress();
|
||||
using location::nearby::windows::BluetoothDevice;
|
||||
|
||||
std::map<std::string, location::nearby::api::BluetoothDevice*>::const_iterator
|
||||
it = deviceList.find(address);
|
||||
typedef std::map<const std::string, location::nearby::api::BluetoothDevice*>
|
||||
DeviceMap;
|
||||
|
||||
std::string buffer =
|
||||
absl::StrFormat("processing device %s : ", address.c_str());
|
||||
class BluetoothClassicMediumTests : public testing::Test {
|
||||
protected:
|
||||
static void device_discovered_cb(
|
||||
location::nearby::api::BluetoothDevice& device) {
|
||||
const std::string address = device.GetMacAddress();
|
||||
|
||||
OutputDebugStringA(buffer.c_str());
|
||||
std::map<std::string,
|
||||
location::nearby::api::BluetoothDevice*>::const_iterator it =
|
||||
deviceList.find(address);
|
||||
|
||||
if (it == deviceList.end()) {
|
||||
buffer = absl::StrFormat("adding device %s\n", address.c_str());
|
||||
std::string buffer =
|
||||
absl::StrFormat("processing device %s : ", address.c_str());
|
||||
|
||||
OutputDebugStringA(buffer.c_str());
|
||||
deviceList[device.GetMacAddress()] = &device;
|
||||
|
||||
if (it == deviceList.end()) {
|
||||
buffer = absl::StrFormat("adding device %s\n", address.c_str());
|
||||
|
||||
OutputDebugStringA(buffer.c_str());
|
||||
deviceList[device.GetMacAddress()] = &device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void device_name_changed_cb(location::nearby::api::BluetoothDevice& device) {}
|
||||
static void device_name_changed_cb(
|
||||
location::nearby::api::BluetoothDevice& device) {}
|
||||
|
||||
void device_lost_cb(location::nearby::api::BluetoothDevice& device) {
|
||||
deviceList.erase(device.GetMacAddress());
|
||||
}
|
||||
static void device_lost_cb(location::nearby::api::BluetoothDevice& device) {
|
||||
deviceList.erase(device.GetMacAddress());
|
||||
}
|
||||
|
||||
TEST(TestCaseName, TestName) {
|
||||
int callcount = 0;
|
||||
static inline DeviceMap deviceList = {};
|
||||
};
|
||||
|
||||
#ifdef TESTING_LOCALLY
|
||||
TEST_F(BluetoothClassicMediumTests, ManualTest) {
|
||||
auto bluetoothAdapter = location::nearby::windows::BluetoothAdapter();
|
||||
|
||||
std::string bluetoothAdapterName = bluetoothAdapter.GetName();
|
||||
@@ -97,3 +111,74 @@ TEST(TestCaseName, TestName) {
|
||||
EXPECT_EQ(1, 1);
|
||||
EXPECT_TRUE(true);
|
||||
}
|
||||
#endif
|
||||
TEST_F(BluetoothClassicMediumTests, ConnectToServiceNullUuid) {
|
||||
// Arrange
|
||||
auto bluetoothAdapter = location::nearby::windows::BluetoothAdapter();
|
||||
|
||||
std::unique_ptr<location::nearby::windows::BluetoothClassicMedium>
|
||||
bluetoothClassicMedium =
|
||||
std::make_unique<location::nearby::windows::BluetoothClassicMedium>(
|
||||
bluetoothAdapter);
|
||||
|
||||
location::nearby::windows::BluetoothDevice bluetoothDevice =
|
||||
location::nearby::windows::BluetoothDevice(
|
||||
std::string("1D:EA:DB:EE:B9:00"));
|
||||
location::nearby::CancellationFlag cancellationFlag;
|
||||
|
||||
auto bluetoothClassicMediumImpl = bluetoothClassicMedium.get();
|
||||
|
||||
// Act
|
||||
auto asyncResult = bluetoothClassicMediumImpl->ConnectToService(
|
||||
bluetoothDevice, std::string(), &cancellationFlag);
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(asyncResult.get() == nullptr);
|
||||
}
|
||||
|
||||
TEST_F(BluetoothClassicMediumTests, ConnectToServiceNullCancellationFlag) {
|
||||
// Arrange
|
||||
auto bluetoothAdapter = location::nearby::windows::BluetoothAdapter();
|
||||
|
||||
std::unique_ptr<location::nearby::windows::BluetoothClassicMedium>
|
||||
bluetoothClassicMedium =
|
||||
std::make_unique<location::nearby::windows::BluetoothClassicMedium>(
|
||||
bluetoothAdapter);
|
||||
|
||||
location::nearby::windows::BluetoothDevice bluetoothDevice =
|
||||
location::nearby::windows::BluetoothDevice(
|
||||
std::string("1D:EA:DB:EE:B9:00"));
|
||||
|
||||
auto bluetoothClassicMediumImpl = bluetoothClassicMedium.get();
|
||||
|
||||
// Act
|
||||
auto asyncResult = bluetoothClassicMediumImpl->ConnectToService(
|
||||
bluetoothDevice, std::string("test service"), nullptr);
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(asyncResult.get() == nullptr);
|
||||
}
|
||||
|
||||
TEST_F(BluetoothClassicMediumTests, ConnectToServiceWithInvalidServiceUuid) {
|
||||
// Arrange
|
||||
auto bluetoothAdapter = location::nearby::windows::BluetoothAdapter();
|
||||
|
||||
std::unique_ptr<location::nearby::windows::BluetoothClassicMedium>
|
||||
bluetoothClassicMedium =
|
||||
std::make_unique<location::nearby::windows::BluetoothClassicMedium>(
|
||||
bluetoothAdapter);
|
||||
|
||||
location::nearby::windows::BluetoothDevice bluetoothDevice =
|
||||
location::nearby::windows::BluetoothDevice(
|
||||
std::string("1D:EA:DB:EE:B9:00"));
|
||||
location::nearby::CancellationFlag cancellationFlag;
|
||||
|
||||
auto bluetoothClassicMediumImpl = bluetoothClassicMedium.get();
|
||||
|
||||
// Act
|
||||
auto asyncResult = bluetoothClassicMediumImpl->ConnectToService(
|
||||
bluetoothDevice, std::string("test service"), &cancellationFlag);
|
||||
|
||||
// Assert
|
||||
EXPECT_TRUE(asyncResult.get() == nullptr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "platform/impl/windows/condition_variable.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
// The ConditionVariable class is a synchronization primitive that can be used
|
||||
// to block a thread, or multiple threads at the same time, until another thread
|
||||
// both modifies a shared variable (the condition), and notifies the
|
||||
// ConditionVariable.
|
||||
|
||||
ConditionVariable::ConditionVariable(api::Mutex* mutex)
|
||||
: mutex_(dynamic_cast<windows::Mutex&>(*mutex)) {
|
||||
InitializeCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
// Notifies all the waiters that condition state has changed.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
void ConditionVariable::Notify() {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
condition_variable_actual_.notify_all();
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
// Waits indefinitely for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
Exception ConditionVariable::Wait() {
|
||||
std::unique_lock<std::mutex> lock =
|
||||
std::unique_lock<std::mutex>(mutex_.GetWindowsMutex());
|
||||
condition_variable_actual_.wait(lock);
|
||||
|
||||
return Exception{Exception::kSuccess};
|
||||
}
|
||||
|
||||
// Waits while timeout has not expired for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
Exception ConditionVariable::Wait(absl::Duration timeout) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
std::unique_lock<std::mutex> lock =
|
||||
std::unique_lock<std::mutex>(mutex_.GetWindowsMutex());
|
||||
if (condition_variable_actual_.wait_until(
|
||||
lock, now + absl::ToChronoMilliseconds(timeout)) ==
|
||||
std::cv_status::timeout) {
|
||||
return Exception{Exception::kInterrupted};
|
||||
} else {
|
||||
return Exception{Exception::kSuccess};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -15,7 +15,14 @@
|
||||
#ifndef PLATFORM_IMPL_WINDOWS_CONDITION_VARIABLE_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_CONDITION_VARIABLE_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
#include <mutex> // NOLINT
|
||||
|
||||
#include "platform/api/condition_variable.h"
|
||||
#include "platform/impl/windows/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
@@ -27,24 +34,31 @@ namespace windows {
|
||||
// ConditionVariable.
|
||||
class ConditionVariable : public api::ConditionVariable {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
ConditionVariable(api::Mutex* mutex);
|
||||
|
||||
~ConditionVariable() override = default;
|
||||
|
||||
// Notifies all the waiters that condition state has changed.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
void Notify() override {}
|
||||
void Notify() override;
|
||||
|
||||
// Waits indefinitely for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
Exception Wait() override { return Exception{}; }
|
||||
Exception Wait() override;
|
||||
|
||||
// Waits while timeout has not expired for Notify to be called.
|
||||
// May return prematurely in case of interrupt, if supported by platform.
|
||||
// Returns kSuccess, or kInterrupted on interrupt.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
Exception Wait(absl::Duration timeout) override { return Exception{}; }
|
||||
Exception Wait(absl::Duration timeout) override;
|
||||
|
||||
private:
|
||||
location::nearby::windows::Mutex& mutex_;
|
||||
|
||||
std::condition_variable condition_variable_actual_;
|
||||
std::condition_variable& condition_variable_ = condition_variable_actual_;
|
||||
|
||||
std::unique_lock<std::mutex> lock;
|
||||
CRITICAL_SECTION critical_section_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "platform/impl/windows/condition_variable.h"
|
||||
|
||||
#include <future> // NOLINT
|
||||
|
||||
#include "absl/time/clock.h"
|
||||
#include "platform/base/exception.h"
|
||||
#include "platform/impl/windows/mutex.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class ConditionVariableTests : public testing::Test {
|
||||
public:
|
||||
class ConditionVariableTest {
|
||||
public:
|
||||
ConditionVariableTest() {}
|
||||
|
||||
std::future<bool> WaitForEvent(bool timedWait, // NOLINT
|
||||
const absl::Duration* timeout) {
|
||||
return std::async(
|
||||
std::launch::async,
|
||||
[this, timedWait, timeout]() mutable {
|
||||
std::thread::id currentThread = std::this_thread::get_id();
|
||||
|
||||
if (timedWait == true) {
|
||||
auto result = this->condition_variable_actual_.Wait(*timeout);
|
||||
if (result.value == location::nearby::Exception::kSuccess) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this->condition_variable_actual_.Wait();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void PostEvent() {
|
||||
std::lock_guard<std::mutex> guard(mutex_actual_.GetWindowsMutex());
|
||||
condition_variable_actual_.Notify();
|
||||
}
|
||||
|
||||
private:
|
||||
location::nearby::windows::Mutex mutex_actual_ =
|
||||
location::nearby::windows::Mutex(
|
||||
location::nearby::windows::Mutex::Mode::kRegular);
|
||||
location::nearby::windows::Mutex& mutex_ = mutex_actual_;
|
||||
location::nearby::windows::ConditionVariable condition_variable_actual_ =
|
||||
location::nearby::windows::ConditionVariable(&mutex_);
|
||||
location::nearby::windows::ConditionVariable& condition_variable_ =
|
||||
condition_variable_actual_;
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(ConditionVariableTests, SuccessfulCreation) {
|
||||
// Arrange
|
||||
ConditionVariableTest conditionVariableTest;
|
||||
|
||||
auto result = conditionVariableTest.WaitForEvent(false, nullptr);
|
||||
|
||||
Sleep(1);
|
||||
|
||||
// Act
|
||||
conditionVariableTest.PostEvent();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result.get());
|
||||
}
|
||||
|
||||
TEST_F(ConditionVariableTests, TimedCreation) {
|
||||
// Arrange
|
||||
ConditionVariableTest conditionVariableTest;
|
||||
const absl::Duration duration = absl::Milliseconds(100);
|
||||
|
||||
// Act
|
||||
auto result = conditionVariableTest.WaitForEvent(true, &duration);
|
||||
|
||||
// Assert
|
||||
ASSERT_FALSE(result.get()); // Timed out
|
||||
|
||||
// Act
|
||||
result = conditionVariableTest.WaitForEvent(true, &duration);
|
||||
|
||||
Sleep(1);
|
||||
|
||||
conditionVariableTest.PostEvent();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result.get()); // Didn't timeout
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "platform/impl/windows/mutex.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
// A lock is a tool for controlling access to a shared resource by multiple
|
||||
// threads.
|
||||
//
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html
|
||||
Mutex::Mutex(Mutex::Mode mode)
|
||||
: mode_(mode), owning_thread_(std::this_thread::get_id()) {
|
||||
InitializeCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
std::thread::id currentThread = std::this_thread::get_id();
|
||||
|
||||
if ((mode_ == Mutex::Mode::kRegular ||
|
||||
mode_ == Mutex::Mode::kRegularNoCheck) &&
|
||||
!locked_) {
|
||||
mutex_actual_.lock();
|
||||
owning_thread_ = currentThread;
|
||||
locked_ = true;
|
||||
}
|
||||
|
||||
if (mode_ == Mutex::Mode::kRecursive) {
|
||||
if (!locked_) {
|
||||
owning_thread_ = currentThread;
|
||||
}
|
||||
if (owning_thread_ == currentThread) {
|
||||
try {
|
||||
recursive_mutex_actual_.lock();
|
||||
} catch ([[maybe_unused]] const std::system_error& e) {
|
||||
// Eat the exception and fail silently, argument left for debug
|
||||
}
|
||||
locked_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
std::thread::id currentThread = std::this_thread::get_id();
|
||||
|
||||
if (mode_ == Mutex::Mode::kRegular || mode_ == Mutex::Mode::kRegularNoCheck) {
|
||||
if (currentThread == owning_thread_) {
|
||||
mutex_actual_.unlock();
|
||||
locked_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode_ == Mutex::Mode::kRecursive) {
|
||||
if (currentThread == owning_thread_) {
|
||||
recursive_mutex_actual_.unlock();
|
||||
locked_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
std::mutex& Mutex::GetWindowsMutex() { return mutex_; }
|
||||
|
||||
std::recursive_mutex& Mutex::GetWindowsRecursiveMutex() {
|
||||
return recursive_mutex_;
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020 Google LLC
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,14 @@
|
||||
#ifndef PLATFORM_IMPL_WINDOWS_MUTEX_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_MUTEX_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex> // NOLINT
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "platform/api/mutex.h"
|
||||
|
||||
namespace location {
|
||||
@@ -27,13 +35,28 @@ namespace windows {
|
||||
// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html
|
||||
class Mutex : public api::Mutex {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
Mutex(Mutex::Mode mode);
|
||||
|
||||
~Mutex() override = default;
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
void Lock() override {}
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
void Unlock() override {}
|
||||
void Lock() override;
|
||||
|
||||
void Unlock() override;
|
||||
|
||||
std::mutex& GetWindowsMutex();
|
||||
|
||||
std::recursive_mutex& GetWindowsRecursiveMutex();
|
||||
|
||||
private:
|
||||
Mutex::Mode mode_;
|
||||
bool locked_ = false;
|
||||
|
||||
std::mutex mutex_actual_;
|
||||
std::mutex& mutex_ = mutex_actual_;
|
||||
std::recursive_mutex recursive_mutex_actual_;
|
||||
std::recursive_mutex& recursive_mutex_ = recursive_mutex_actual_;
|
||||
std::thread::id owning_thread_;
|
||||
CRITICAL_SECTION critical_section_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "platform/impl/windows/mutex.h"
|
||||
|
||||
#include <future> // NOLINT
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
class MutexTests : public testing::Test {
|
||||
public:
|
||||
class MutexTest {
|
||||
public:
|
||||
MutexTest(location::nearby::windows::Mutex& mutex) : mutex_(mutex) {}
|
||||
|
||||
std::future<bool> WaitForLock() { // NOLINT
|
||||
return std::async(
|
||||
std::launch::async,
|
||||
// for this lambda you need C++14
|
||||
[this]() mutable {
|
||||
std::unique_lock<std::mutex> lck(mutex_.GetWindowsMutex());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void PostEvent() {
|
||||
std::lock_guard<std::mutex> guard(mutex_.GetWindowsMutex());
|
||||
mutex_.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
location::nearby::windows::Mutex& mutex_;
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(MutexTests, SuccessfulRecursiveCreation) {
|
||||
// Arrange
|
||||
location::nearby::windows::Mutex mutex = location::nearby::windows::Mutex(
|
||||
location::nearby::windows::Mutex::Mode::kRecursive);
|
||||
|
||||
// Act
|
||||
std::recursive_mutex& actual = mutex.GetWindowsRecursiveMutex();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(actual.native_handle() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MutexTests, SuccessfulCreation) {
|
||||
// Arrange
|
||||
location::nearby::windows::Mutex mutex(
|
||||
location::nearby::windows::Mutex::Mode::kRegular);
|
||||
|
||||
// Act
|
||||
std::mutex& actual = mutex.GetWindowsMutex();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(actual.native_handle() != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MutexTests, SuccessfulSignal) {
|
||||
// Arrange
|
||||
location::nearby::windows::Mutex mutex(
|
||||
location::nearby::windows::Mutex::Mode::kRegular);
|
||||
|
||||
location::nearby::windows::Mutex& mutexRef = mutex;
|
||||
MutexTest mutexTest(mutexRef);
|
||||
|
||||
mutex.Lock();
|
||||
|
||||
// Act
|
||||
auto result = mutexTest.WaitForLock();
|
||||
mutex.Unlock();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result.get());
|
||||
}
|
||||
|
||||
TEST_F(MutexTests, SuccessfulRecursiveSignal) {
|
||||
// Arrange
|
||||
location::nearby::windows::Mutex mutex(
|
||||
location::nearby::windows::Mutex::Mode::kRecursive);
|
||||
|
||||
location::nearby::windows::Mutex& mutexRef = mutex;
|
||||
MutexTest mutexTest(mutexRef);
|
||||
|
||||
mutex.Lock();
|
||||
mutex.Lock();
|
||||
mutex.Lock();
|
||||
|
||||
// Act
|
||||
auto result = mutexTest.WaitForLock();
|
||||
mutex.Unlock();
|
||||
mutex.Unlock();
|
||||
mutex.Unlock();
|
||||
|
||||
// Assert
|
||||
ASSERT_TRUE(result.get());
|
||||
}
|
||||
@@ -66,13 +66,13 @@ std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
|
||||
return absl::make_unique<windows::Mutex>();
|
||||
return absl::make_unique<windows::Mutex>(mode);
|
||||
}
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
std::unique_ptr<ConditionVariable>
|
||||
ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
|
||||
return std::unique_ptr<ConditionVariable>(new windows::ConditionVariable());
|
||||
return absl::make_unique<location::nearby::windows::ConditionVariable>(mutex);
|
||||
}
|
||||
|
||||
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
|
||||
|
||||
Reference in New Issue
Block a user