Commit 1e1066e9 authored by fayang's avatar fayang Committed by Commit bot

Create a QUIC wrapper around a mutex and a mutex lock.

Merge internal change: 141451848

Review-Url: https://codereview.chromium.org/2561913003
Cr-Commit-Position: refs/heads/master@{#437734}
parent dbc9ca65
...@@ -1215,12 +1215,16 @@ ...@@ -1215,12 +1215,16 @@
'quic/platform/api/quic_ip_address_family.h', 'quic/platform/api/quic_ip_address_family.h',
'quic/platform/api/quic_ip_address.cc', 'quic/platform/api/quic_ip_address.cc',
'quic/platform/api/quic_ip_address.h', 'quic/platform/api/quic_ip_address.h',
'quic/platform/api/quic_mutex.cc',
'quic/platform/api/quic_mutex.h',
'quic/platform/api/quic_socket_address.cc', 'quic/platform/api/quic_socket_address.cc',
'quic/platform/api/quic_socket_address.h', 'quic/platform/api/quic_socket_address.h',
'quic/platform/impl/quic_chromium_clock.cc', 'quic/platform/impl/quic_chromium_clock.cc',
'quic/platform/impl/quic_chromium_clock.h', 'quic/platform/impl/quic_chromium_clock.h',
'quic/platform/impl/quic_ip_address_impl.cc', 'quic/platform/impl/quic_ip_address_impl.cc',
'quic/platform/impl/quic_ip_address_impl.h', 'quic/platform/impl/quic_ip_address_impl.h',
'quic/platform/impl/quic_mutex_impl.cc',
'quic/platform/impl/quic_mutex_impl.h',
'quic/platform/impl/quic_socket_address_impl.cc', 'quic/platform/impl/quic_socket_address_impl.cc',
'quic/platform/impl/quic_socket_address_impl.h', 'quic/platform/impl/quic_socket_address_impl.h',
'quic/quartc/quartc_alarm_factory.cc', 'quic/quartc/quartc_alarm_factory.cc',
......
...@@ -50,14 +50,14 @@ void CryptoSecretBoxer::SetKeys(const std::vector<string>& keys) { ...@@ -50,14 +50,14 @@ void CryptoSecretBoxer::SetKeys(const std::vector<string>& keys) {
for (const string& key : keys) { for (const string& key : keys) {
DCHECK_EQ(kKeySize, key.size()); DCHECK_EQ(kKeySize, key.size());
} }
base::AutoLock l(lock_); QuicWriterMutexLock l(&lock_);
keys_.swap(copy); keys_.swap(copy);
} }
string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const { string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
std::unique_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter()); std::unique_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
{ {
base::AutoLock l(lock_); QuicReaderMutexLock l(&lock_);
DCHECK_EQ(kKeySize, keys_[0].size()); DCHECK_EQ(kKeySize, keys_[0].size());
if (!encrypter->SetKey(keys_[0])) { if (!encrypter->SetKey(keys_[0])) {
DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed."; DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
...@@ -104,7 +104,7 @@ bool CryptoSecretBoxer::Unbox(StringPiece ciphertext, ...@@ -104,7 +104,7 @@ bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
size_t plaintext_length = 0; size_t plaintext_length = 0;
bool ok = false; bool ok = false;
{ {
base::AutoLock l(lock_); QuicReaderMutexLock l(&lock_);
for (const string& key : keys_) { for (const string& key : keys_) {
if (decrypter->SetKey(key)) { if (decrypter->SetKey(key)) {
decrypter->SetNoncePrefix(nonce_prefix); decrypter->SetNoncePrefix(nonce_prefix);
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_mutex.h"
namespace net { namespace net {
...@@ -51,9 +51,8 @@ class QUIC_EXPORT_PRIVATE CryptoSecretBoxer { ...@@ -51,9 +51,8 @@ class QUIC_EXPORT_PRIVATE CryptoSecretBoxer {
base::StringPiece* out) const; base::StringPiece* out) const;
private: private:
mutable base::Lock lock_; mutable QuicMutex lock_;
// GUARDED_BY(lock_).mutable Mutex lock_; std::vector<std::string> keys_ GUARDED_BY(lock_);
std::vector<std::string> keys_;
DISALLOW_COPY_AND_ASSIGN(CryptoSecretBoxer); DISALLOW_COPY_AND_ASSIGN(CryptoSecretBoxer);
}; };
......
...@@ -24,7 +24,7 @@ LocalStrikeRegisterClient::LocalStrikeRegisterClient( ...@@ -24,7 +24,7 @@ LocalStrikeRegisterClient::LocalStrikeRegisterClient(
startup) {} startup) {}
bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const { bool LocalStrikeRegisterClient::IsKnownOrbit(StringPiece orbit) const {
base::AutoLock lock(m_); QuicWriterMutexLock lock(&m_);
if (orbit.length() != kOrbitSize) { if (orbit.length() != kOrbitSize) {
return false; return false;
} }
...@@ -39,7 +39,7 @@ void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique( ...@@ -39,7 +39,7 @@ void LocalStrikeRegisterClient::VerifyNonceIsValidAndUnique(
if (nonce.length() != kNonceSize) { if (nonce.length() != kNonceSize) {
nonce_error = NONCE_INVALID_FAILURE; nonce_error = NONCE_INVALID_FAILURE;
} else { } else {
base::AutoLock lock(m_); QuicWriterMutexLock lock(&m_);
nonce_error = nonce_error =
strike_register_.Insert(reinterpret_cast<const uint8_t*>(nonce.data()), strike_register_.Insert(reinterpret_cast<const uint8_t*>(nonce.data()),
static_cast<uint32_t>(now.ToUNIXSeconds())); static_cast<uint32_t>(now.ToUNIXSeconds()));
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "net/quic/core/crypto/strike_register.h" #include "net/quic/core/crypto/strike_register.h"
#include "net/quic/core/crypto/strike_register_client.h" #include "net/quic/core/crypto/strike_register_client.h"
#include "net/quic/core/quic_time.h" #include "net/quic/core/quic_time.h"
#include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_mutex.h"
namespace net { namespace net {
...@@ -34,8 +34,8 @@ class QUIC_EXPORT_PRIVATE LocalStrikeRegisterClient ...@@ -34,8 +34,8 @@ class QUIC_EXPORT_PRIVATE LocalStrikeRegisterClient
ResultCallback* cb) override; ResultCallback* cb) override;
private: private:
mutable base::Lock m_; mutable QuicMutex m_;
StrikeRegister strike_register_; StrikeRegister strike_register_ GUARDED_BY(m_);
DISALLOW_COPY_AND_ASSIGN(LocalStrikeRegisterClient); DISALLOW_COPY_AND_ASSIGN(LocalStrikeRegisterClient);
}; };
......
...@@ -311,7 +311,7 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( ...@@ -311,7 +311,7 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
} }
{ {
base::AutoLock locked(configs_lock_); QuicWriterMutexLock locked(&configs_lock_);
if (configs_.find(config->id) != configs_.end()) { if (configs_.find(config->id) != configs_.end()) {
LOG(WARNING) << "Failed to add config because another with the same " LOG(WARNING) << "Failed to add config because another with the same "
"server config id already exists: " "server config id already exists: "
...@@ -361,7 +361,7 @@ bool QuicCryptoServerConfig::SetConfigs( ...@@ -361,7 +361,7 @@ bool QuicCryptoServerConfig::SetConfigs(
} else { } else {
VLOG(1) << "Updating configs:"; VLOG(1) << "Updating configs:";
base::AutoLock locked(configs_lock_); QuicWriterMutexLock locked(&configs_lock_);
ConfigMap new_configs; ConfigMap new_configs;
for (std::vector<scoped_refptr<Config>>::const_iterator i = for (std::vector<scoped_refptr<Config>>::const_iterator i =
...@@ -409,7 +409,7 @@ void QuicCryptoServerConfig::SetSourceAddressTokenKeys( ...@@ -409,7 +409,7 @@ void QuicCryptoServerConfig::SetSourceAddressTokenKeys(
} }
void QuicCryptoServerConfig::GetConfigIds(std::vector<string>* scids) const { void QuicCryptoServerConfig::GetConfigIds(std::vector<string>* scids) const {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end(); for (ConfigMap::const_iterator it = configs_.begin(); it != configs_.end();
++it) { ++it) {
scids->push_back(it->first); scids->push_back(it->first);
...@@ -436,7 +436,7 @@ void QuicCryptoServerConfig::ValidateClientHello( ...@@ -436,7 +436,7 @@ void QuicCryptoServerConfig::ValidateClientHello(
scoped_refptr<Config> requested_config; scoped_refptr<Config> requested_config;
scoped_refptr<Config> primary_config; scoped_refptr<Config> primary_config;
{ {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
if (!primary_config_.get()) { if (!primary_config_.get()) {
result->error_code = QUIC_CRYPTO_INTERNAL_ERROR; result->error_code = QUIC_CRYPTO_INTERNAL_ERROR;
...@@ -444,9 +444,13 @@ void QuicCryptoServerConfig::ValidateClientHello( ...@@ -444,9 +444,13 @@ void QuicCryptoServerConfig::ValidateClientHello(
} else { } else {
if (!next_config_promotion_time_.IsZero() && if (!next_config_promotion_time_.IsZero() &&
next_config_promotion_time_.IsAfter(now)) { next_config_promotion_time_.IsAfter(now)) {
configs_lock_.ReaderUnlock();
configs_lock_.WriterLock();
SelectNewPrimaryConfig(now); SelectNewPrimaryConfig(now);
DCHECK(primary_config_.get()); DCHECK(primary_config_.get());
DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
configs_lock_.WriterUnlock();
configs_lock_.ReaderLock();
} }
} }
...@@ -629,16 +633,20 @@ void QuicCryptoServerConfig::ProcessClientHello( ...@@ -629,16 +633,20 @@ void QuicCryptoServerConfig::ProcessClientHello(
scoped_refptr<Config> primary_config; scoped_refptr<Config> primary_config;
bool no_primary_config = false; bool no_primary_config = false;
{ {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
if (!primary_config_) { if (!primary_config_) {
no_primary_config = true; no_primary_config = true;
} else { } else {
if (!next_config_promotion_time_.IsZero() && if (!next_config_promotion_time_.IsZero() &&
next_config_promotion_time_.IsAfter(now)) { next_config_promotion_time_.IsAfter(now)) {
configs_lock_.ReaderUnlock();
configs_lock_.WriterLock();
SelectNewPrimaryConfig(now); SelectNewPrimaryConfig(now);
DCHECK(primary_config_.get()); DCHECK(primary_config_.get());
DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_); DCHECK_EQ(configs_.find(primary_config_->id)->second, primary_config_);
configs_lock_.WriterUnlock();
configs_lock_.ReaderLock();
} }
// Use the config that the client requested in order to do key-agreement. // Use the config that the client requested in order to do key-agreement.
...@@ -995,9 +1003,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( ...@@ -995,9 +1003,7 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof(
scoped_refptr<QuicCryptoServerConfig::Config> scoped_refptr<QuicCryptoServerConfig::Config>
QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const { QuicCryptoServerConfig::GetConfigWithScid(StringPiece requested_scid) const {
// In Chromium, we will dead lock if the lock is held by the current thread. configs_lock_.AssertReaderHeld();
// Chromium doesn't have AssertReaderHeld API call.
// configs_lock_.AssertReaderHeld();
if (!requested_scid.empty()) { if (!requested_scid.empty()) {
ConfigMap::const_iterator it = configs_.find(requested_scid.as_string()); ConfigMap::const_iterator it = configs_.find(requested_scid.as_string());
...@@ -1346,7 +1352,7 @@ bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage( ...@@ -1346,7 +1352,7 @@ bool QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
QuicWallTime expiry_time = QuicWallTime::Zero(); QuicWallTime expiry_time = QuicWallTime::Zero();
const CommonCertSets* common_cert_sets; const CommonCertSets* common_cert_sets;
{ {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
serialized = primary_config_->serialized; serialized = primary_config_->serialized;
common_cert_sets = primary_config_->common_cert_sets; common_cert_sets = primary_config_->common_cert_sets;
expiry_time = primary_config_->expiry_time; expiry_time = primary_config_->expiry_time;
...@@ -1403,7 +1409,7 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( ...@@ -1403,7 +1409,7 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessage(
string source_address_token; string source_address_token;
const CommonCertSets* common_cert_sets; const CommonCertSets* common_cert_sets;
{ {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
serialized = primary_config_->serialized; serialized = primary_config_->serialized;
common_cert_sets = primary_config_->common_cert_sets; common_cert_sets = primary_config_->common_cert_sets;
source_address_token = NewSourceAddressToken( source_address_token = NewSourceAddressToken(
...@@ -1815,7 +1821,7 @@ void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) { ...@@ -1815,7 +1821,7 @@ void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) {
void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb(
std::unique_ptr<PrimaryConfigChangedCallback> cb) { std::unique_ptr<PrimaryConfigChangedCallback> cb) {
base::AutoLock locked(configs_lock_); QuicWriterMutexLock locked(&configs_lock_);
primary_config_changed_cb_ = std::move(cb); primary_config_changed_cb_ = std::move(cb);
} }
...@@ -1858,7 +1864,7 @@ string QuicCryptoServerConfig::NewSourceAddressToken( ...@@ -1858,7 +1864,7 @@ string QuicCryptoServerConfig::NewSourceAddressToken(
} }
int QuicCryptoServerConfig::NumberOfConfigs() const { int QuicCryptoServerConfig::NumberOfConfigs() const {
base::AutoLock locked(configs_lock_); QuicReaderMutexLock locked(&configs_lock_);
return configs_.size(); return configs_.size();
} }
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "net/base/ip_address.h" #include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h" #include "net/base/ip_endpoint.h"
#include "net/quic/core/crypto/crypto_handshake.h" #include "net/quic/core/crypto/crypto_handshake.h"
...@@ -30,6 +29,7 @@ ...@@ -30,6 +29,7 @@
#include "net/quic/core/proto/source_address_token.pb.h" #include "net/quic/core/proto/source_address_token.pb.h"
#include "net/quic/core/quic_time.h" #include "net/quic/core/quic_time.h"
#include "net/quic/platform/api/quic_export.h" #include "net/quic/platform/api/quic_export.h"
#include "net/quic/platform/api/quic_mutex.h"
#include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_socket_address.h"
namespace net { namespace net {
...@@ -739,18 +739,19 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { ...@@ -739,18 +739,19 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
// 1) configs_.empty() <-> primary_config_ == nullptr // 1) configs_.empty() <-> primary_config_ == nullptr
// 2) primary_config_ != nullptr -> primary_config_->is_primary // 2) primary_config_ != nullptr -> primary_config_->is_primary
// 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_ // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_
mutable base::Lock configs_lock_; mutable QuicMutex configs_lock_;
// configs_ contains all active server configs. It's expected that there are // configs_ contains all active server configs. It's expected that there are
// about half-a-dozen configs active at any one time. // about half-a-dozen configs active at any one time.
ConfigMap configs_; ConfigMap configs_ GUARDED_BY(configs_lock_);
// primary_config_ points to a Config (which is also in |configs_|) which is // primary_config_ points to a Config (which is also in |configs_|) which is
// the primary config - i.e. the one that we'll give out to new clients. // the primary config - i.e. the one that we'll give out to new clients.
mutable scoped_refptr<Config> primary_config_; mutable scoped_refptr<Config> primary_config_ GUARDED_BY(configs_lock_);
// next_config_promotion_time_ contains the nearest, future time when an // next_config_promotion_time_ contains the nearest, future time when an
// active config will be promoted to primary. // active config will be promoted to primary.
mutable QuicWallTime next_config_promotion_time_; mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_);
// Callback to invoke when the primary config changes. // Callback to invoke when the primary config changes.
std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_; std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_
GUARDED_BY(configs_lock_);
// Used to protect the source-address tokens that are given to clients. // Used to protect the source-address tokens that are given to clients.
CryptoSecretBoxer source_address_token_boxer_; CryptoSecretBoxer source_address_token_boxer_;
......
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/platform/api/quic_mutex.h"
namespace net {
void QuicMutex::WriterLock() {
impl_.WriterLock();
}
void QuicMutex::WriterUnlock() {
impl_.WriterUnlock();
}
void QuicMutex::ReaderLock() {
impl_.ReaderLock();
}
void QuicMutex::ReaderUnlock() {
impl_.ReaderUnlock();
}
void QuicMutex::AssertReaderHeld() const {
impl_.AssertReaderHeld();
}
QuicReaderMutexLock::QuicReaderMutexLock(QuicMutex* lock) : lock_(lock) {
lock->ReaderLock();
}
QuicReaderMutexLock::~QuicReaderMutexLock() {
lock_->ReaderUnlock();
}
QuicWriterMutexLock::QuicWriterMutexLock(QuicMutex* lock) : lock_(lock) {
lock->WriterLock();
}
QuicWriterMutexLock::~QuicWriterMutexLock() {
lock_->WriterUnlock();
}
} // namespace net
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
#define NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
#include "net/quic/platform/impl/quic_mutex_impl.h"
namespace net {
// A class representing a non-reentrant mutex in QUIC.
class QUIC_EXPORT_PRIVATE LOCKABLE QuicMutex {
public:
QuicMutex() = default;
// Block until this Mutex is free, then acquire it exclusively.
void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
// Release this Mutex. Caller must hold it exclusively.
void WriterUnlock() UNLOCK_FUNCTION();
// Block until this Mutex is free or shared, then acquire a share of it.
void ReaderLock() SHARED_LOCK_FUNCTION();
// Release this Mutex. Caller could hold it in shared mode.
void ReaderUnlock() UNLOCK_FUNCTION();
// Returns immediately if current thread holds the Mutex in at least shared
// mode. Otherwise, may report an error (typically by crashing with a
// diagnostic), or may return immediately.
void AssertReaderHeld() const ASSERT_SHARED_LOCK();
private:
QuicLockImpl impl_;
DISALLOW_COPY_AND_ASSIGN(QuicMutex);
};
// A helper class that acquires the given QuicMutex shared lock while the
// QuicReaderMutexLock is in scope.
class QUIC_EXPORT_PRIVATE SCOPED_LOCKABLE QuicReaderMutexLock {
public:
explicit QuicReaderMutexLock(QuicMutex* lock) SHARED_LOCK_FUNCTION(lock);
~QuicReaderMutexLock() UNLOCK_FUNCTION();
private:
QuicMutex* const lock_;
DISALLOW_COPY_AND_ASSIGN(QuicReaderMutexLock);
};
// A helper class that acquires the given QuicMutex exclusive lock while the
// QuicWriterMutexLock is in scope.
class QUIC_EXPORT_PRIVATE SCOPED_LOCKABLE QuicWriterMutexLock {
public:
explicit QuicWriterMutexLock(QuicMutex* lock) EXCLUSIVE_LOCK_FUNCTION(lock);
~QuicWriterMutexLock() UNLOCK_FUNCTION();
private:
QuicMutex* const lock_;
DISALLOW_COPY_AND_ASSIGN(QuicWriterMutexLock);
};
} // namespace net
#endif // NET_QUIC_PLATFORM_API_QUIC_MUTEX_H_
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/platform/impl/quic_mutex_impl.h"
namespace net {
void QuicLockImpl::WriterLock() {
lock_.Acquire();
}
void QuicLockImpl::WriterUnlock() {
lock_.Release();
}
void QuicLockImpl::ReaderLock() {
lock_.Acquire();
}
void QuicLockImpl::ReaderUnlock() {
lock_.Release();
}
} // namespace net
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
#define NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
#include "base/synchronization/lock.h"
#include "net/quic/platform/api/quic_export.h"
#ifndef EXCLUSIVE_LOCK_FUNCTION
#define EXCLUSIVE_LOCK_FUNCTION(...)
#endif
#ifndef UNLOCK_FUNCTION
#define UNLOCK_FUNCTION(...)
#endif
#ifndef SHARED_LOCK_FUNCTION
#define SHARED_LOCK_FUNCTION(...)
#endif
#ifndef ASSERT_SHARED_LOCK
#define ASSERT_SHARED_LOCK(...)
#endif
#ifndef LOCKABLE
#define LOCKABLE
#endif
#ifndef SCOPED_LOCKABLE
#define SCOPED_LOCKABLE
#endif
#ifndef GUARDED_BY
#define GUARDED_BY(x)
#endif
namespace net {
// A class wrapping a non-reentrant mutex.
class QUIC_EXPORT_PRIVATE QuicLockImpl {
public:
QuicLockImpl() = default;
// Block until lock_ is free, then acquire it exclusively.
void WriterLock() EXCLUSIVE_LOCK_FUNCTION();
// Release lock_. Caller must hold it exclusively.
void WriterUnlock() UNLOCK_FUNCTION();
// Block until lock_ is free or shared, then acquire a share of it.
void ReaderLock() SHARED_LOCK_FUNCTION();
// Release lock_. Caller could hold it in shared mode.
void ReaderUnlock() UNLOCK_FUNCTION();
// Not implemented.
void AssertReaderHeld() const ASSERT_SHARED_LOCK() {}
private:
base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(QuicLockImpl);
};
} // namespace net
#endif // NET_QUIC_PLATFORM_IMPL_QUIC_MUTEX_IMPL_H_
...@@ -22,14 +22,14 @@ ProofSource* QuicCryptoServerConfigPeer::GetProofSource() { ...@@ -22,14 +22,14 @@ ProofSource* QuicCryptoServerConfigPeer::GetProofSource() {
scoped_refptr<QuicCryptoServerConfig::Config> scoped_refptr<QuicCryptoServerConfig::Config>
QuicCryptoServerConfigPeer::GetPrimaryConfig() { QuicCryptoServerConfigPeer::GetPrimaryConfig() {
base::AutoLock locked(server_config_->configs_lock_); QuicReaderMutexLock locked(&server_config_->configs_lock_);
return scoped_refptr<QuicCryptoServerConfig::Config>( return scoped_refptr<QuicCryptoServerConfig::Config>(
server_config_->primary_config_); server_config_->primary_config_);
} }
scoped_refptr<QuicCryptoServerConfig::Config> scoped_refptr<QuicCryptoServerConfig::Config>
QuicCryptoServerConfigPeer::GetConfig(string config_id) { QuicCryptoServerConfigPeer::GetConfig(string config_id) {
base::AutoLock locked(server_config_->configs_lock_); QuicReaderMutexLock locked(&server_config_->configs_lock_);
if (config_id == "<primary>") { if (config_id == "<primary>") {
return scoped_refptr<QuicCryptoServerConfig::Config>( return scoped_refptr<QuicCryptoServerConfig::Config>(
server_config_->primary_config_); server_config_->primary_config_);
...@@ -120,7 +120,7 @@ void QuicCryptoServerConfigPeer::CheckConfigs(const char* server_config_id1, ...@@ -120,7 +120,7 @@ void QuicCryptoServerConfigPeer::CheckConfigs(const char* server_config_id1,
va_end(ap); va_end(ap);
base::AutoLock locked(server_config_->configs_lock_); QuicReaderMutexLock locked(&server_config_->configs_lock_);
ASSERT_EQ(expected.size(), server_config_->configs_.size()) << ConfigsDebug(); ASSERT_EQ(expected.size(), server_config_->configs_.size()) << ConfigsDebug();
...@@ -166,7 +166,7 @@ string QuicCryptoServerConfigPeer::ConfigsDebug() { ...@@ -166,7 +166,7 @@ string QuicCryptoServerConfigPeer::ConfigsDebug() {
} }
void QuicCryptoServerConfigPeer::SelectNewPrimaryConfig(int seconds) { void QuicCryptoServerConfigPeer::SelectNewPrimaryConfig(int seconds) {
base::AutoLock locked(server_config_->configs_lock_); QuicWriterMutexLock locked(&server_config_->configs_lock_);
server_config_->SelectNewPrimaryConfig( server_config_->SelectNewPrimaryConfig(
QuicWallTime::FromUNIXSeconds(seconds)); QuicWallTime::FromUNIXSeconds(seconds));
} }
......
...@@ -163,7 +163,7 @@ void QuicHttpResponseCache::ResourceFile::HandleXOriginalUrl() { ...@@ -163,7 +163,7 @@ void QuicHttpResponseCache::ResourceFile::HandleXOriginalUrl() {
const QuicHttpResponseCache::Response* QuicHttpResponseCache::GetResponse( const QuicHttpResponseCache::Response* QuicHttpResponseCache::GetResponse(
StringPiece host, StringPiece host,
StringPiece path) const { StringPiece path) const {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
auto it = responses_.find(GetKey(host, path)); auto it = responses_.find(GetKey(host, path));
if (it == responses_.end()) { if (it == responses_.end()) {
...@@ -201,7 +201,7 @@ void QuicHttpResponseCache::AddSimpleResponseWithServerPushResources( ...@@ -201,7 +201,7 @@ void QuicHttpResponseCache::AddSimpleResponseWithServerPushResources(
} }
void QuicHttpResponseCache::AddDefaultResponse(Response* response) { void QuicHttpResponseCache::AddDefaultResponse(Response* response) {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
default_response_.reset(response); default_response_.reset(response);
} }
...@@ -288,7 +288,7 @@ void QuicHttpResponseCache::InitializeFromDirectory( ...@@ -288,7 +288,7 @@ void QuicHttpResponseCache::InitializeFromDirectory(
std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources( std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources(
string request_url) { string request_url) {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
std::list<ServerPushInfo> resources; std::list<ServerPushInfo> resources;
auto resource_range = server_push_resources_.equal_range(request_url); auto resource_range = server_push_resources_.equal_range(request_url);
...@@ -302,7 +302,7 @@ std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources( ...@@ -302,7 +302,7 @@ std::list<ServerPushInfo> QuicHttpResponseCache::GetServerPushResources(
QuicHttpResponseCache::~QuicHttpResponseCache() { QuicHttpResponseCache::~QuicHttpResponseCache() {
{ {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
responses_.clear(); responses_.clear();
} }
} }
...@@ -313,7 +313,7 @@ void QuicHttpResponseCache::AddResponseImpl(StringPiece host, ...@@ -313,7 +313,7 @@ void QuicHttpResponseCache::AddResponseImpl(StringPiece host,
SpdyHeaderBlock response_headers, SpdyHeaderBlock response_headers,
StringPiece response_body, StringPiece response_body,
SpdyHeaderBlock response_trailers) { SpdyHeaderBlock response_trailers) {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\""; DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\"";
string key = GetKey(host, path); string key = GetKey(host, path);
...@@ -349,7 +349,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources( ...@@ -349,7 +349,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources(
<< " push url " << push_resource.request_url << " push url " << push_resource.request_url
<< " response headers " << push_resource.headers.DebugString(); << " response headers " << push_resource.headers.DebugString();
{ {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
server_push_resources_.insert(std::make_pair(request_url, push_resource)); server_push_resources_.insert(std::make_pair(request_url, push_resource));
} }
string host = push_resource.request_url.host(); string host = push_resource.request_url.host();
...@@ -359,7 +359,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources( ...@@ -359,7 +359,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources(
string path = push_resource.request_url.path(); string path = push_resource.request_url.path();
bool found_existing_response = false; bool found_existing_response = false;
{ {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
found_existing_response = found_existing_response =
base::ContainsKey(responses_, GetKey(host, path)); base::ContainsKey(responses_, GetKey(host, path));
} }
...@@ -376,7 +376,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources( ...@@ -376,7 +376,7 @@ void QuicHttpResponseCache::MaybeAddServerPushResources(
bool QuicHttpResponseCache::PushResourceExistsInCache( bool QuicHttpResponseCache::PushResourceExistsInCache(
string original_request_url, string original_request_url,
ServerPushInfo resource) { ServerPushInfo resource) {
base::AutoLock lock(response_mutex_); QuicWriterMutexLock lock(&response_mutex_);
auto resource_range = auto resource_range =
server_push_resources_.equal_range(original_request_url); server_push_resources_.equal_range(original_request_url);
for (auto it = resource_range.first; it != resource_range.second; ++it) { for (auto it = resource_range.first; it != resource_range.second; ++it) {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
#include "net/quic/core/spdy_utils.h" #include "net/quic/core/spdy_utils.h"
#include "net/quic/platform/api/quic_mutex.h"
#include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_framer.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -201,17 +202,19 @@ class QuicHttpResponseCache { ...@@ -201,17 +202,19 @@ class QuicHttpResponseCache {
ServerPushInfo resource); ServerPushInfo resource);
// Cached responses. // Cached responses.
std::unordered_map<std::string, std::unique_ptr<Response>> responses_; std::unordered_map<std::string, std::unique_ptr<Response>> responses_
GUARDED_BY(response_mutex_);
// The default response for cache misses, if set. // The default response for cache misses, if set.
std::unique_ptr<Response> default_response_; std::unique_ptr<Response> default_response_ GUARDED_BY(response_mutex_);
// A map from request URL to associated server push responses (if any). // A map from request URL to associated server push responses (if any).
std::multimap<std::string, ServerPushInfo> server_push_resources_; std::multimap<std::string, ServerPushInfo> server_push_resources_
GUARDED_BY(response_mutex_);
// Protects against concurrent access from test threads setting responses, and // Protects against concurrent access from test threads setting responses, and
// server threads accessing those responses. // server threads accessing those responses.
mutable base::Lock response_mutex_; mutable QuicMutex response_mutex_;
DISALLOW_COPY_AND_ASSIGN(QuicHttpResponseCache); DISALLOW_COPY_AND_ASSIGN(QuicHttpResponseCache);
}; };
......
...@@ -84,7 +84,7 @@ WriteResult PacketDroppingTestWriter::WritePacket( ...@@ -84,7 +84,7 @@ WriteResult PacketDroppingTestWriter::WritePacket(
++num_calls_to_write_; ++num_calls_to_write_;
ReleaseOldPackets(); ReleaseOldPackets();
base::AutoLock locked(config_mutex_); QuicReaderMutexLock lock(&config_mutex_);
if (fake_drop_first_n_packets_ > 0 && if (fake_drop_first_n_packets_ > 0 &&
num_calls_to_write_ <= num_calls_to_write_ <=
static_cast<uint64_t>(fake_drop_first_n_packets_)) { static_cast<uint64_t>(fake_drop_first_n_packets_)) {
...@@ -168,7 +168,7 @@ QuicTime PacketDroppingTestWriter::ReleaseNextPacket() { ...@@ -168,7 +168,7 @@ QuicTime PacketDroppingTestWriter::ReleaseNextPacket() {
if (delayed_packets_.empty()) { if (delayed_packets_.empty()) {
return QuicTime::Zero(); return QuicTime::Zero();
} }
base::AutoLock locked(config_mutex_); QuicReaderMutexLock lock(&config_mutex_);
DelayedPacketList::iterator iter = delayed_packets_.begin(); DelayedPacketList::iterator iter = delayed_packets_.begin();
// Determine if we should re-order. // Determine if we should re-order.
if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 && if (delayed_packets_.size() > 1 && fake_packet_reorder_percentage_ > 0 &&
......
...@@ -71,14 +71,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { ...@@ -71,14 +71,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
// The percent of time a packet is simulated as being lost. // The percent of time a packet is simulated as being lost.
void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) { void set_fake_packet_loss_percentage(int32_t fake_packet_loss_percentage) {
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
fake_packet_loss_percentage_ = fake_packet_loss_percentage; fake_packet_loss_percentage_ = fake_packet_loss_percentage;
} }
// Simulate dropping the first n packets unconditionally. // Simulate dropping the first n packets unconditionally.
// Subsequent packets will be lost at fake_packet_loss_percentage_ if set. // Subsequent packets will be lost at fake_packet_loss_percentage_ if set.
void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) { void set_fake_drop_first_n_packets(int32_t fake_drop_first_n_packets) {
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
fake_drop_first_n_packets_ = fake_drop_first_n_packets; fake_drop_first_n_packets_ = fake_drop_first_n_packets;
} }
...@@ -87,14 +87,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { ...@@ -87,14 +87,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
void set_fake_blocked_socket_percentage( void set_fake_blocked_socket_percentage(
int32_t fake_blocked_socket_percentage) { int32_t fake_blocked_socket_percentage) {
DCHECK(clock_); DCHECK(clock_);
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
fake_blocked_socket_percentage_ = fake_blocked_socket_percentage; fake_blocked_socket_percentage_ = fake_blocked_socket_percentage;
} }
// The percent of time a packet is simulated as being reordered. // The percent of time a packet is simulated as being reordered.
void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) { void set_fake_reorder_percentage(int32_t fake_packet_reorder_percentage) {
DCHECK(clock_); DCHECK(clock_);
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
DCHECK(!fake_packet_delay_.IsZero()); DCHECK(!fake_packet_delay_.IsZero());
fake_packet_reorder_percentage_ = fake_packet_reorder_percentage; fake_packet_reorder_percentage_ = fake_packet_reorder_percentage;
} }
...@@ -102,7 +102,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { ...@@ -102,7 +102,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
// The delay before writing this packet. // The delay before writing this packet.
void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) { void set_fake_packet_delay(QuicTime::Delta fake_packet_delay) {
DCHECK(clock_); DCHECK(clock_);
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
fake_packet_delay_ = fake_packet_delay; fake_packet_delay_ = fake_packet_delay;
} }
...@@ -113,7 +113,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { ...@@ -113,7 +113,7 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth, void set_max_bandwidth_and_buffer_size(QuicBandwidth fake_bandwidth,
QuicByteCount buffer_size) { QuicByteCount buffer_size) {
DCHECK(clock_); DCHECK(clock_);
base::AutoLock locked(config_mutex_); QuicWriterMutexLock lock(&config_mutex_);
fake_bandwidth_ = fake_bandwidth; fake_bandwidth_ = fake_bandwidth;
buffer_size_ = buffer_size; buffer_size_ = buffer_size;
} }
...@@ -163,14 +163,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper { ...@@ -163,14 +163,14 @@ class PacketDroppingTestWriter : public QuicPacketWriterWrapper {
QuicByteCount cur_buffer_size_; QuicByteCount cur_buffer_size_;
uint64_t num_calls_to_write_; uint64_t num_calls_to_write_;
base::Lock config_mutex_; QuicMutex config_mutex_;
int32_t fake_packet_loss_percentage_; int32_t fake_packet_loss_percentage_ GUARDED_BY(config_mutex_);
int32_t fake_drop_first_n_packets_; int32_t fake_drop_first_n_packets_ GUARDED_BY(config_mutex_);
int32_t fake_blocked_socket_percentage_; int32_t fake_blocked_socket_percentage_ GUARDED_BY(config_mutex_);
int32_t fake_packet_reorder_percentage_; int32_t fake_packet_reorder_percentage_ GUARDED_BY(config_mutex_);
QuicTime::Delta fake_packet_delay_; QuicTime::Delta fake_packet_delay_ GUARDED_BY(config_mutex_);
QuicBandwidth fake_bandwidth_; QuicBandwidth fake_bandwidth_ GUARDED_BY(config_mutex_);
QuicByteCount buffer_size_; QuicByteCount buffer_size_ GUARDED_BY(config_mutex_);
DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter); DISALLOW_COPY_AND_ASSIGN(PacketDroppingTestWriter);
}; };
......
...@@ -102,7 +102,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { ...@@ -102,7 +102,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher {
QuicServerSessionBase* CreateQuicSession( QuicServerSessionBase* CreateQuicSession(
QuicConnectionId id, QuicConnectionId id,
const QuicSocketAddress& client) override { const QuicSocketAddress& client) override {
base::AutoLock lock(factory_lock_); QuicReaderMutexLock lock(&factory_lock_);
if (session_factory_ == nullptr && stream_factory_ == nullptr && if (session_factory_ == nullptr && stream_factory_ == nullptr &&
crypto_stream_factory_ == nullptr) { crypto_stream_factory_ == nullptr) {
return QuicSimpleDispatcher::CreateQuicSession(id, client); return QuicSimpleDispatcher::CreateQuicSession(id, client);
...@@ -128,7 +128,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { ...@@ -128,7 +128,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher {
} }
void SetSessionFactory(QuicTestServer::SessionFactory* factory) { void SetSessionFactory(QuicTestServer::SessionFactory* factory) {
base::AutoLock lock(factory_lock_); QuicWriterMutexLock lock(&factory_lock_);
DCHECK(session_factory_ == nullptr); DCHECK(session_factory_ == nullptr);
DCHECK(stream_factory_ == nullptr); DCHECK(stream_factory_ == nullptr);
DCHECK(crypto_stream_factory_ == nullptr); DCHECK(crypto_stream_factory_ == nullptr);
...@@ -136,21 +136,21 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { ...@@ -136,21 +136,21 @@ class QuicTestDispatcher : public QuicSimpleDispatcher {
} }
void SetStreamFactory(QuicTestServer::StreamFactory* factory) { void SetStreamFactory(QuicTestServer::StreamFactory* factory) {
base::AutoLock lock(factory_lock_); QuicWriterMutexLock lock(&factory_lock_);
DCHECK(session_factory_ == nullptr); DCHECK(session_factory_ == nullptr);
DCHECK(stream_factory_ == nullptr); DCHECK(stream_factory_ == nullptr);
stream_factory_ = factory; stream_factory_ = factory;
} }
void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) { void SetCryptoStreamFactory(QuicTestServer::CryptoStreamFactory* factory) {
base::AutoLock lock(factory_lock_); QuicWriterMutexLock lock(&factory_lock_);
DCHECK(session_factory_ == nullptr); DCHECK(session_factory_ == nullptr);
DCHECK(crypto_stream_factory_ == nullptr); DCHECK(crypto_stream_factory_ == nullptr);
crypto_stream_factory_ = factory; crypto_stream_factory_ = factory;
} }
private: private:
base::Lock factory_lock_; QuicMutex factory_lock_;
QuicTestServer::SessionFactory* session_factory_; // Not owned. QuicTestServer::SessionFactory* session_factory_; // Not owned.
QuicTestServer::StreamFactory* stream_factory_; // Not owned. QuicTestServer::StreamFactory* stream_factory_; // Not owned.
QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned. QuicTestServer::CryptoStreamFactory* crypto_stream_factory_; // Not owned.
......
...@@ -71,7 +71,7 @@ int ServerThread::GetPort() { ...@@ -71,7 +71,7 @@ int ServerThread::GetPort() {
void ServerThread::Schedule(std::function<void()> action) { void ServerThread::Schedule(std::function<void()> action) {
DCHECK(!quit_.IsSignaled()); DCHECK(!quit_.IsSignaled());
base::AutoLock lock(scheduled_actions_lock_); QuicWriterMutexLock lock(&scheduled_actions_lock_);
scheduled_actions_.push_back(std::move(action)); scheduled_actions_.push_back(std::move(action));
} }
...@@ -117,7 +117,7 @@ void ServerThread::MaybeNotifyOfHandshakeConfirmation() { ...@@ -117,7 +117,7 @@ void ServerThread::MaybeNotifyOfHandshakeConfirmation() {
void ServerThread::ExecuteScheduledActions() { void ServerThread::ExecuteScheduledActions() {
std::deque<std::function<void()>> actions; std::deque<std::function<void()>> actions;
{ {
base::AutoLock lock(scheduled_actions_lock_); QuicWriterMutexLock lock(&scheduled_actions_lock_);
actions.swap(scheduled_actions_); actions.swap(scheduled_actions_);
} }
while (!actions.empty()) { while (!actions.empty()) {
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/simple_thread.h" #include "base/threading/simple_thread.h"
#include "net/quic/core/quic_config.h" #include "net/quic/core/quic_config.h"
#include "net/quic/platform/api/quic_mutex.h"
#include "net/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/api/quic_socket_address.h"
#include "net/tools/quic/quic_server.h" #include "net/tools/quic/quic_server.h"
...@@ -75,8 +75,9 @@ class ServerThread : public base::SimpleThread { ...@@ -75,8 +75,9 @@ class ServerThread : public base::SimpleThread {
bool initialized_; bool initialized_;
base::Lock scheduled_actions_lock_; QuicMutex scheduled_actions_lock_;
std::deque<std::function<void()>> scheduled_actions_; std::deque<std::function<void()>> scheduled_actions_
GUARDED_BY(scheduled_actions_lock_);
DISALLOW_COPY_AND_ASSIGN(ServerThread); DISALLOW_COPY_AND_ASSIGN(ServerThread);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment