diff options
author | Andrew Morrow <acm@mongodb.com> | 2017-02-26 15:15:08 -0500 |
---|---|---|
committer | Andrew Morrow <acm@mongodb.com> | 2017-08-02 23:29:55 -0400 |
commit | a8a1ea3b9367adb6d0b65a7da21fed89598ea093 (patch) | |
tree | 8e969ed54b88c2a9c4c2d45a6518d053ac9f4265 /src | |
parent | c02c14e30d75b02894da116f4bb1a71652ead2b4 (diff) | |
download | mongo-a8a1ea3b9367adb6d0b65a7da21fed89598ea093.tar.gz |
SERVER-26538 SERVER-26539 Detach from boost::thread
Also, use thread_local everywhere for our thread specific data needs
and remove the legacy support.
Diffstat (limited to 'src')
26 files changed, 78 insertions, 757 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 67283e703b4..b488158911d 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -244,8 +244,6 @@ if env.TargetOSIs('windows'): config_header_substs = ( ('@mongo_config_byte_order@', 'MONGO_CONFIG_BYTE_ORDER'), ('@mongo_config_debug_build@', 'MONGO_CONFIG_DEBUG_BUILD'), - ('@mongo_config_have___declspec_thread@', 'MONGO_CONFIG_HAVE___DECLSPEC_THREAD'), - ('@mongo_config_have___thread@', 'MONGO_CONFIG_HAVE___THREAD'), ('@mongo_config_have_execinfo_backtrace@', 'MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE'), ('@mongo_config_have_fips_mode_set@', 'MONGO_CONFIG_HAVE_FIPS_MODE_SET'), ('@mongo_config_have_header_unistd_h@', 'MONGO_CONFIG_HAVE_HEADER_UNISTD_H'), @@ -255,7 +253,6 @@ config_header_substs = ( ('@mongo_config_have_std_enable_if_t@', 'MONGO_CONFIG_HAVE_STD_ENABLE_IF_T'), ('@mongo_config_have_std_make_unique@', 'MONGO_CONFIG_HAVE_STD_MAKE_UNIQUE'), ('@mongo_config_have_strnlen@', 'MONGO_CONFIG_HAVE_STRNLEN'), - ('@mongo_config_have_thread_local@', 'MONGO_CONFIG_HAVE_THREAD_LOCAL'), ('@mongo_config_max_extended_alignment@', 'MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT'), ('@mongo_config_optimized_build@', 'MONGO_CONFIG_OPTIMIZED_BUILD'), ('@mongo_config_ssl@', 'MONGO_CONFIG_SSL'), diff --git a/src/mongo/config.h.in b/src/mongo/config.h.in index 02b8d94d566..4b0dc7e710c 100644 --- a/src/mongo/config.h.in +++ b/src/mongo/config.h.in @@ -34,12 +34,6 @@ // Define if building a debug build @mongo_config_debug_build@ -// Defined if __declspec(thread) is available -@mongo_config_have___declspec_thread@ - -// Defined if GCC thread-local storage is available -@mongo_config_have___thread@ - // Defined if execinfo.h and backtrace are available @mongo_config_have_execinfo_backtrace@ @@ -64,9 +58,6 @@ // Defined if strnlen is available @mongo_config_have_strnlen@ -// Defined if thread_local storage class is available -@mongo_config_have_thread_local@ - // A number, if we have some extended alignment ability @mongo_config_max_extended_alignment@ diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp index ac195c79606..24f73349006 100644 --- a/src/mongo/db/client.cpp +++ b/src/mongo/db/client.cpp @@ -50,11 +50,12 @@ namespace mongo { -TSP_DECLARE(ServiceContext::UniqueClient, currentClient) -TSP_DEFINE(ServiceContext::UniqueClient, currentClient) +namespace { +thread_local ServiceContext::UniqueClient currentClient; +} // namespace void Client::initThreadIfNotAlready(StringData desc) { - if (currentClient.getMake()->get()) + if (currentClient) return; initThread(desc); } @@ -82,7 +83,7 @@ void Client::initThread(StringData desc, setThreadName(fullDesc); // Create the client obj, attach to thread - *currentClient.getMake() = service->makeClient(fullDesc, std::move(session)); + currentClient = service->makeClient(fullDesc, std::move(session)); } void Client::destroy() { @@ -149,7 +150,7 @@ std::string Client::clientAddress(bool includePort) const { } Client* Client::getCurrent() { - return currentClient.getMake()->get(); + return currentClient.get(); } Client& cc() { @@ -158,17 +159,17 @@ Client& cc() { } bool haveClient() { - return currentClient.get() && currentClient.get()->get(); + return static_cast<bool>(currentClient); } ServiceContext::UniqueClient Client::releaseCurrent() { invariant(haveClient()); - return ServiceContext::UniqueClient(currentClient.get()->release()); + return std::move(currentClient); } void Client::setCurrent(ServiceContext::UniqueClient client) { invariant(!haveClient()); - *currentClient.getMake() = std::move(client); + currentClient = std::move(client); } } // namespace mongo diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h index 3ceb236c2dc..0126f7ce59b 100644 --- a/src/mongo/db/client.h +++ b/src/mongo/db/client.h @@ -47,7 +47,6 @@ #include "mongo/stdx/thread.h" #include "mongo/transport/session.h" #include "mongo/util/concurrency/spin_lock.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/decorable.h" #include "mongo/util/net/abstract_message_port.h" #include "mongo/util/net/hostandport.h" diff --git a/src/mongo/db/storage/mmap_v1/record_access_tracker.cpp b/src/mongo/db/storage/mmap_v1/record_access_tracker.cpp index f9725f6a104..0bdd9237c52 100644 --- a/src/mongo/db/storage/mmap_v1/record_access_tracker.cpp +++ b/src/mongo/db/storage/mmap_v1/record_access_tracker.cpp @@ -36,8 +36,8 @@ #include "mongo/config.h" #include "mongo/db/storage/mmap_v1/record.h" #include "mongo/platform/bits.h" +#include "mongo/stdx/memory.h" #include "mongo/util/clock_source.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/debug_util.h" #include "mongo/util/net/listen.h" #include "mongo/util/processinfo.h" @@ -268,23 +268,12 @@ void RecordAccessTracker::Rolling::_rotate(ClockSource* cs) { updateLastRotate(cs); } -// These need to be outside the ps namespace due to the way they are defined -#if defined(MONGO_CONFIG_HAVE___THREAD) -__thread PointerTable::Data _pointerTableData; PointerTable::Data* PointerTable::getData() { - return &_pointerTableData; + thread_local std::unique_ptr<PointerTable::Data> data; + if (!data) + data = stdx::make_unique<PointerTable::Data>(); + return data.get(); } -#elif defined(MONGO_CONFIG_HAVE___DECLSPEC_THREAD) -__declspec(thread) PointerTable::Data _pointerTableData; -PointerTable::Data* PointerTable::getData() { - return &_pointerTableData; -} -#else -TSP_DEFINE(PointerTable::Data, _pointerTableData); -PointerTable::Data* PointerTable::getData() { - return _pointerTableData.getMake(); -} -#endif // // RecordAccessTracker diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index 18b9e406ea6..ec3db5a0300 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -80,7 +80,6 @@ dbtest = env.Program( 'namespacetests.cpp', 'oplogstarttests.cpp', 'pdfiletests.cpp', - 'perftests.cpp', 'plan_ranking.cpp', 'query_stage_multiplan.cpp', 'query_plan_executor.cpp', diff --git a/src/mongo/dbtests/perftests.cpp b/src/mongo/dbtests/perftests.cpp deleted file mode 100644 index 042b3629b5d..00000000000 --- a/src/mongo/dbtests/perftests.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/** - * Copyright (C) 2008 10gen Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -/** @file perftests.cpp.cpp : unit tests relating to performance - - The idea herein is tests that run fast and can be part of the normal CI suite. So no - tests herein that take a long time to run. Obviously we need those too, but they will be - separate. - - These tests use DBDirectClient; they are a bit white-boxish. -*/ - -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault - -#include "mongo/platform/basic.h" - -#include <boost/thread/condition.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/thread.hpp> -#include <iomanip> -#include <iostream> -#include <mutex> - -#include "mongo/config.h" -#include "mongo/db/bson/dotted_path_support.h" -#include "mongo/db/client.h" -#include "mongo/db/db.h" -#include "mongo/db/dbdirectclient.h" -#include "mongo/db/lasterror.h" -#include "mongo/db/storage/mmap_v1/dur_stats.h" -#include "mongo/db/storage/mmap_v1/mmap.h" -#include "mongo/db/storage/storage_options.h" -#include "mongo/dbtests/dbtests.h" -#include "mongo/dbtests/framework_options.h" -#include "mongo/stdx/condition_variable.h" -#include "mongo/stdx/thread.h" -#include "mongo/util/log.h" -#include "mongo/util/timer.h" -#include "mongo/util/version.h" - -namespace PerfTests { - -using std::cout; -using std::endl; -using std::fixed; -using std::left; -using std::min; -using std::right; -using std::setprecision; -using std::setw; -using std::string; -using std::vector; - -namespace dps = ::mongo::dotted_path_support; - -const bool profiling = false; - -class ClientBase { -public: - ClientBase() : _client(&_opCtx) { - mongo::LastError::get(_opCtx.getClient()).reset(); - } - virtual ~ClientBase() { - mongo::LastError::get(_opCtx.getClient()).reset(); - } - -protected: - void insert(const char* ns, BSONObj o) { - _client.insert(ns, o); - } - void update(const char* ns, BSONObj q, BSONObj o, bool upsert = 0) { - _client.update(ns, Query(q), o, upsert); - } - bool error() { - return !_client.getPrevError().getField("err").isNull(); - } - - DBClientBase* client() { - return &_client; - } - OperationContext* opCtx() { - return &_opCtx; - } - -private: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - DBDirectClient _client; -}; - -static std::shared_ptr<DBClientConnection> conn; -static string _perfhostname; - -class B : public ClientBase { - string _ns; - -protected: - const char* ns() { - return _ns.c_str(); - } - - // anything you want to do before being timed - virtual void prep() {} - - // anything you want to do before threaded test - virtual void prepThreaded() {} - - virtual void timed() = 0; - - // optional 2nd test phase to be timed separately. You must provide it with a unique - // name in order for it to run by overloading 'name2'. - virtual void timed2(DBClientBase*) {} - - // return name of second test. - virtual string name2() { - return name(); - } - - virtual void post() {} - - virtual string name() = 0; - - // how long to run test. 0 is a sentinel which means just run the timed() method once and time - // it. - virtual int howLongMillis() { - return profiling ? 30000 : 5000; - } - - /* override if your test output doesn't need that */ - virtual bool showDurStats() { - return true; - } - -public: - virtual unsigned batchSize() { - return 50; - } - - void say(unsigned long long n, long long us, string s) { - unsigned long long rps = (n * 1000 * 1000) / (us > 0 ? us : 1); - cout << "stats " << setw(42) << left << s << ' ' << right << setw(9) << rps << ' ' << right - << setw(5) << us / 1000 << "ms "; - if (showDurStats()) { - cout << dur::stats.curr()->_asCSV(); - } - cout << endl; - - if (conn && !conn->isFailed()) { - const char* ns = "perf.pstats"; - if (frameworkGlobalParams.perfHist) { - static bool needver = true; - try { - // try to report rps from last time */ - Query q; - { - BSONObjBuilder b; - b.append("host", _perfhostname); - b.append("test", s); - b.append("dur", storageGlobalParams.dur); - DEV { - b.append("info.DEBUG", true); - } - else b.appendNull("info.DEBUG"); - if (sizeof(int*) == 4) - b.append("info.bits", 32); - else - b.appendNull("info.bits"); - q = Query(b.obj()).sort("when", -1); - } - BSONObj fields = BSON("rps" << 1 << "info" << 1); - vector<BSONObj> v; - conn->findN(v, ns, q, frameworkGlobalParams.perfHist, 0, &fields); - for (vector<BSONObj>::iterator i = v.begin(); i != v.end(); i++) { - BSONObj o = *i; - double lastrps = o["rps"].Number(); - if (0 && lastrps) { - cout << "stats " << setw(42) << right << "new/old:" << ' ' << setw(9); - cout << fixed << setprecision(2) << rps / lastrps; - if (needver) { - cout << " " - << dps::extractElementAtPath(o, "info.git").toString(); - } - cout << '\n'; - } - } - } catch (...) { - } - cout.flush(); - needver = false; - } - { - bob b; - b.append("host", _perfhostname); - b.appendTimeT("when", time(0)); - b.append("test", s); - b.append("rps", (int)rps); - b.append("millis", us / 1000); - b.appendBool("dur", storageGlobalParams.dur); - if (showDurStats() && storageGlobalParams.dur) { - b.append("durStats", dur::stats.asObj()); - } - - { - auto&& vii = VersionInfoInterface::instance(); - bob inf; - inf.append("version", vii.version()); - if (sizeof(int*) == 4) - inf.append("bits", 32); - DEV inf.append("DEBUG", true); -#if defined(_WIN32) - inf.append("os", "win"); -#endif - inf.append("git", vii.gitVersion()); -#ifdef MONGO_CONFIG_SSL - inf.append("OpenSSL", vii.openSSLVersion()); -#endif - inf.append("boost", BOOST_VERSION); - b.append("info", inf.obj()); - } - BSONObj o = b.obj(); - // cout << "inserting " << o.toString() << endl; - try { - conn->insert(ns, o); - } catch (std::exception& e) { - warning() << "couldn't save perf results: " << e.what() << endl; - } - } - } - } - - /** if true runs timed2() again with several threads (8 at time of this writing). - */ - virtual bool testThreaded() { - return false; - } - - int howLong() { - int hlm = howLongMillis(); - DEV { - // don't run very long with in debug mode - not very meaningful anyway on that build - hlm = min(hlm, 500); - } - return hlm; - } - - void run() { - unsigned long long n = 0; - - _ns = string("perftest.") + name(); - client()->dropCollection(ns()); - prep(); - int hlm = howLong(); - mongo::Timer t; - n = 0; - const unsigned int Batch = batchSize(); - - if (hlm == 0) { - // means just do once - timed(); - } else { - do { - unsigned int i; - for (i = 0; i < Batch; i++) - timed(); - n += i; - } while (t.micros() < (hlm * 1000)); - } - - client()->getLastError(); // block until all ops are finished - - say(n, t.micros(), name()); - - post(); - - string test2name = name2(); - { - if (test2name != name()) { - dur::stats.curr()->reset(); - mongo::Timer t; - unsigned long long n = 0; - while (1) { - unsigned int i; - for (i = 0; i < Batch; i++) - timed2(client()); - n += i; - if (t.millis() > hlm) - break; - } - say(n, t.micros(), test2name); - } - } - - if (testThreaded()) { - const int nThreads = 8; - // cout << "testThreaded nThreads:" << nThreads << endl; - mongo::Timer t; - const unsigned long long result = launchThreads(nThreads); - say(result / nThreads, t.micros(), test2name + "-threaded"); - } - } - - bool stop; - - void thread(unsigned long long* counter) { -#if defined(_WIN32) - static int z; - srand(++z ^ (unsigned)time(0)); -#endif - Client::initThreadIfNotAlready("perftestthr"); - const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); - OperationContext& opCtx = *opCtxPtr; - DBDirectClient c(&opCtx); - - const unsigned int Batch = batchSize(); - prepThreaded(); - while (1) { - unsigned int i = 0; - for (i = 0; i < Batch; i++) - timed2(&c); - *counter += i; - if (stop) - break; - } - } - - unsigned long long launchThreads(int remaining) { - stop = false; - if (!remaining) { - int hlm = howLong(); - sleepmillis(hlm); - stop = true; - return 0; - } - unsigned long long counter = 0; - stdx::thread athread(stdx::bind(&B::thread, this, &counter)); - unsigned long long child = launchThreads(remaining - 1); - athread.join(); - unsigned long long accum = child + counter; - return accum; - } -}; - -SimpleMutex m; -boost::mutex mboost; // NOLINT -boost::timed_mutex mboost_timed; // NOLINT -std::mutex mstd; // NOLINT -std::timed_mutex mstd_timed; // NOLINT -SpinLock s; -stdx::condition_variable c; - -class boostmutexspeed : public B { -public: - string name() { - return "boost::mutex"; - } - virtual int howLongMillis() { - return 500; - } - virtual bool showDurStats() { - return false; - } - void timed() { - boost::lock_guard<boost::mutex> lk(mboost); // NOLINT - } -}; -class boosttimed_mutexspeed : public B { -public: - string name() { - return "boost::timed_mutex"; - } - virtual int howLongMillis() { - return 500; - } - virtual bool showDurStats() { - return false; - } - void timed() { - boost::lock_guard<boost::timed_mutex> lk(mboost_timed); // NOLINT - } -}; -class simplemutexspeed : public B { -public: - string name() { - return "simplemutex"; - } - virtual int howLongMillis() { - return 500; - } - virtual bool showDurStats() { - return false; - } - void timed() { - stdx::lock_guard<SimpleMutex> lk(m); - } -}; - -class stdmutexspeed : public B { -public: - string name() { - return "std::mutex"; - } - virtual int howLongMillis() { - return 500; - } - virtual bool showDurStats() { - return false; - } - void timed() { - std::lock_guard<std::mutex> lk(mstd); // NOLINT - } -}; -class stdtimed_mutexspeed : public B { -public: - string name() { - return "std::timed_mutex"; - } - virtual int howLongMillis() { - return 500; - } - virtual bool showDurStats() { - return false; - } - void timed() { - std::lock_guard<std::timed_mutex> lk(mstd_timed); // NOLINT - } -}; - - -class All : public Suite { -public: - All() : Suite("perf") {} - - void setupTests() { - cout << "stats test rps------ time-- " - << dur::stats.curr()->_CSVHeader() << endl; - add<simplemutexspeed>(); - add<boostmutexspeed>(); - add<boosttimed_mutexspeed>(); - add<stdmutexspeed>(); - add<stdtimed_mutexspeed>(); - } -} myall; -} // namespace PerfTests diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp index d73267ce7ce..a890fc7e241 100644 --- a/src/mongo/dbtests/threadedtests.cpp +++ b/src/mongo/dbtests/threadedtests.cpp @@ -33,7 +33,6 @@ #include "mongo/platform/basic.h" -#include <boost/thread/barrier.hpp> #include <boost/version.hpp> #include <iostream> diff --git a/src/mongo/logger/logstream_builder.cpp b/src/mongo/logger/logstream_builder.cpp index f0dfbaeebe9..fcafdfd425f 100644 --- a/src/mongo/logger/logstream_builder.cpp +++ b/src/mongo/logger/logstream_builder.cpp @@ -37,7 +37,6 @@ #include "mongo/logger/tee.h" #include "mongo/stdx/memory.h" #include "mongo/util/assert_util.h" // TODO: remove apple dep for this in threadlocal.h -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/time_support.h" namespace mongo { @@ -54,20 +53,17 @@ MONGO_INITIALIZER(LogstreamBuilder)(InitializerContext*) { return Status::OK(); } -} // namespace - -TSP_DECLARE(std::unique_ptr<std::ostringstream>, threadOstreamCache); -TSP_DEFINE(std::unique_ptr<std::ostringstream>, threadOstreamCache); +thread_local std::unique_ptr<std::ostringstream> threadOstreamCache; -namespace { // During unittests, where we don't use quickExit(), static finalization may destroy the // cache before its last use, so mark it as not initialized in that case. -// This must be after the TSP_DEFINE so that it is destroyed first. +// This must be after the definition of threadOstreamCache so that it is destroyed first. struct ThreadOstreamCacheFinalizer { ~ThreadOstreamCacheFinalizer() { isThreadOstreamCacheInitialized = false; } } threadOstreamCacheFinalizer; + } // namespace namespace logger { @@ -112,9 +108,8 @@ LogstreamBuilder::~LogstreamBuilder() { _tee->write(_os->str()); } _os->str(""); - if (_shouldCache && isThreadOstreamCacheInitialized && - !threadOstreamCache.getMake()->get()) { - *threadOstreamCache.get() = std::move(_os); + if (_shouldCache && isThreadOstreamCacheInitialized && !threadOstreamCache) { + threadOstreamCache = std::move(_os); } } } @@ -127,9 +122,8 @@ void LogstreamBuilder::operator<<(Tee* tee) { void LogstreamBuilder::makeStream() { if (!_os) { - if (_shouldCache && isThreadOstreamCacheInitialized && - threadOstreamCache.getMake()->get()) { - _os = std::move(*threadOstreamCache.get()); + if (_shouldCache && isThreadOstreamCacheInitialized && threadOstreamCache) { + _os = std::move(threadOstreamCache); } else { _os = stdx::make_unique<std::ostringstream>(); } diff --git a/src/mongo/s/client/shard_connection.cpp b/src/mongo/s/client/shard_connection.cpp index 940b88522ae..c0405d45652 100644 --- a/src/mongo/s/client/shard_connection.cpp +++ b/src/mongo/s/client/shard_connection.cpp @@ -364,18 +364,17 @@ public: // ----- - static thread_specific_ptr<ClientConnections> _perThread; + static thread_local std::unique_ptr<ClientConnections> _perThread; static ClientConnections* threadInstance() { - ClientConnections* cc = _perThread.get(); - if (!cc) { - cc = new ClientConnections(); - _perThread.reset(cc); + if (!_perThread) { + _perThread = stdx::make_unique<ClientConnections>(); } - return cc; + return _perThread.get(); } }; +thread_local std::unique_ptr<ClientConnections> ClientConnections::_perThread; void ActiveClientConnections::appendInfo(BSONObjBuilder& b) { BSONArrayBuilder arr(64 * 1024); // There may be quite a few threads @@ -394,8 +393,6 @@ void ActiveClientConnections::appendInfo(BSONObjBuilder& b) { b.appendArray("threads", arr.obj()); } -thread_specific_ptr<ClientConnections> ClientConnections::_perThread; - } // namespace // The global connection pool diff --git a/src/mongo/scripting/mozjs/PosixNSPR.cpp b/src/mongo/scripting/mozjs/PosixNSPR.cpp index ed1a3d5a49d..3469d35038d 100644 --- a/src/mongo/scripting/mozjs/PosixNSPR.cpp +++ b/src/mongo/scripting/mozjs/PosixNSPR.cpp @@ -27,7 +27,6 @@ #include "mongo/stdx/mutex.h" #include "mongo/stdx/thread.h" #include "mongo/util/concurrency/thread_name.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/time_support.h" class nspr::Thread { @@ -48,7 +47,7 @@ public: }; namespace { -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL nspr::Thread* kCurrentThread; +thread_local nspr::Thread* kCurrentThread = nullptr; } // namespace void* nspr::Thread::ThreadRoutine(void* arg) { @@ -136,10 +135,11 @@ PRStatus PR_SetCurrentThreadName(const char* name) { return PR_SUCCESS; } -static const size_t MaxTLSKeyCount = 32; -static size_t gTLSKeyCount; namespace { -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL std::array<void*, MaxTLSKeyCount> gTLSArray; + +const size_t MaxTLSKeyCount = 32; +size_t gTLSKeyCount; +thread_local std::array<void*, MaxTLSKeyCount> gTLSArray; } // namespace diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp index a6b42649d35..4853dfdea47 100644 --- a/src/mongo/scripting/mozjs/implscope.cpp +++ b/src/mongo/scripting/mozjs/implscope.cpp @@ -46,7 +46,6 @@ #include "mongo/scripting/mozjs/valuewriter.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/mutex.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/log.h" #include "mongo/util/scopeguard.h" @@ -100,9 +99,8 @@ bool closeToMaxMemory() { } } // namespace -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL MozJSImplScope::ASANHandles* kCurrentASANHandles = - nullptr; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL MozJSImplScope* kCurrentScope = nullptr; +thread_local MozJSImplScope::ASANHandles* kCurrentASANHandles = nullptr; +thread_local MozJSImplScope* kCurrentScope = nullptr; struct MozJSImplScope::MozJSEntry { MozJSEntry(MozJSImplScope* scope) diff --git a/src/mongo/scripting/mozjs/jscustomallocator.cpp b/src/mongo/scripting/mozjs/jscustomallocator.cpp index 00f5f404fc4..aab9260a9ba 100644 --- a/src/mongo/scripting/mozjs/jscustomallocator.cpp +++ b/src/mongo/scripting/mozjs/jscustomallocator.cpp @@ -34,7 +34,6 @@ #include "mongo/config.h" #include "mongo/scripting/mozjs/implscope.h" -#include "mongo/util/concurrency/threadlocal.h" #ifdef __linux__ #include <malloc.h> @@ -72,8 +71,8 @@ namespace { * maximum number of bytes we will consider handing out. They are set by * MozJSImplScope on start up. */ -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL size_t total_bytes; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL size_t max_bytes; +thread_local size_t total_bytes = 0; +thread_local size_t max_bytes = 0; /** * When we don't have malloc_usable_size, we manage by adjusting our pointer by diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp index d0189a75432..8f42252871f 100644 --- a/src/mongo/shell/shell_utils.cpp +++ b/src/mongo/shell/shell_utils.cpp @@ -43,7 +43,6 @@ #include "mongo/shell/shell_options.h" #include "mongo/shell/shell_utils_extended.h" #include "mongo/shell/shell_utils_launcher.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/log.h" #include "mongo/util/processinfo.h" #include "mongo/util/quick_exit.h" @@ -113,7 +112,7 @@ BSONObj JSGetMemInfo(const BSONObj& args, void* data) { } #if !defined(_WIN32) -ThreadLocalValue<unsigned int> _randomSeed; +thread_local unsigned int _randomSeed = 0; #endif BSONObj JSSrand(const BSONObj& a, void* data) { @@ -127,7 +126,7 @@ BSONObj JSSrand(const BSONObj& a, void* data) { seed = static_cast<unsigned int>(rand->nextInt64()); } #if !defined(_WIN32) - _randomSeed.set(seed); + _randomSeed = seed; #else srand(seed); #endif @@ -138,7 +137,7 @@ BSONObj JSRand(const BSONObj& a, void* data) { uassert(12519, "rand accepts no arguments", a.nFields() == 0); unsigned r; #if !defined(_WIN32) - r = rand_r(&_randomSeed.getRef()); + r = rand_r(&_randomSeed); #else r = rand(); #endif diff --git a/src/mongo/transport/service_executor_adaptive.cpp b/src/mongo/transport/service_executor_adaptive.cpp index 9ef23266c2a..7e4a49b51b7 100644 --- a/src/mongo/transport/service_executor_adaptive.cpp +++ b/src/mongo/transport/service_executor_adaptive.cpp @@ -36,7 +36,6 @@ #include "mongo/db/server_parameters.h" #include "mongo/util/concurrency/thread_name.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/log.h" #include "mongo/util/processinfo.h" #include "mongo/util/scopeguard.h" @@ -71,9 +70,9 @@ MONGO_EXPORT_SERVER_PARAMETER(adaptiveServiceExecutorMaxQueueLatencyMicros, int, // doing actual work. MONGO_EXPORT_SERVER_PARAMETER(adaptiveServiceExecutorIdlePctThreshold, int, 60); -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL TickSource::Tick ticksSpentExecuting = 0; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL TickSource::Tick ticksSpentScheduled = 0; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL int tasksExecuted = 0; +thread_local TickSource::Tick ticksSpentExecuting = 0; +thread_local TickSource::Tick ticksSpentScheduled = 0; +thread_local int tasksExecuted = 0; constexpr auto kTotalScheduled = "totalScheduled"_sd; constexpr auto kTotalExecuted = "totalExecuted"_sd; diff --git a/src/mongo/util/concurrency/idle_thread_block.cpp b/src/mongo/util/concurrency/idle_thread_block.cpp index d81bbdecd7a..d81f920f9cb 100644 --- a/src/mongo/util/concurrency/idle_thread_block.cpp +++ b/src/mongo/util/concurrency/idle_thread_block.cpp @@ -29,12 +29,11 @@ #include "mongo/util/assert_util.h" #include "mongo/util/concurrency/idle_thread_block.h" -#include "mongo/util/concurrency/threadlocal.h" namespace mongo { namespace for_debuggers { // This needs external linkage to ensure that debuggers can use it. -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL const char* idleThreadLocation = nullptr; +thread_local const char* idleThreadLocation = nullptr; } using for_debuggers::idleThreadLocation; diff --git a/src/mongo/util/concurrency/thread_name.cpp b/src/mongo/util/concurrency/thread_name.cpp index 2c2470a5ad5..4bf6aa71f6c 100644 --- a/src/mongo/util/concurrency/thread_name.cpp +++ b/src/mongo/util/concurrency/thread_name.cpp @@ -31,8 +31,6 @@ #include "mongo/util/concurrency/thread_name.h" -#include <boost/thread/tss.hpp> - #if defined(__APPLE__) || defined(__linux__) #include <pthread.h> #endif @@ -52,7 +50,6 @@ #include "mongo/base/init.h" #include "mongo/config.h" #include "mongo/platform/atomic_word.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -110,13 +107,13 @@ MONGO_INITIALIZER(ThreadNameInitializer)(InitializerContext*) { // TODO consider making threadName std::string and removing the size limit once we get real // thread_local. constexpr size_t kMaxThreadNameSize = 63; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL char threadNameStorage[kMaxThreadNameSize + 1]; +thread_local char threadNameStorage[kMaxThreadNameSize + 1]; } // namespace namespace for_debuggers { // This needs external linkage to ensure that debuggers can use it. -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL StringData threadName; +thread_local StringData threadName; } using for_debuggers::threadName; diff --git a/src/mongo/util/concurrency/threadlocal.h b/src/mongo/util/concurrency/threadlocal.h deleted file mode 100644 index d6190bffb0f..00000000000 --- a/src/mongo/util/concurrency/threadlocal.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -/** -* Copyright (C) 2011 10gen Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* 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 Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* As a special exception, the copyright holders give permission to link the -* code of portions of this program with the OpenSSL library under certain -* conditions as described in each individual source file and distribute -* linked combinations including the program with the OpenSSL library. You -* must comply with the GNU Affero General Public License in all respects -* for all of the code used other than as permitted herein. If you modify -* file(s) with this exception, you may extend this exception to your -* version of the file(s), but you are not obligated to do so. If you do not -* wish to do so, delete this exception statement from your version. If you -* delete this exception statement from all source files in the program, -* then also delete it in the license file. -*/ - -#include <boost/thread/tss.hpp> - -#include "mongo/config.h" - -#include "mongo/base/disallow_copying.h" - -#if defined(MONGO_CONFIG_HAVE_THREAD_LOCAL) -#define MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL thread_local -#elif defined(MONGO_CONFIG_HAVE___THREAD) -#define MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL __thread -#elif defined(MONGO_CONFIG_HAVE___DECLSPEC_THREAD) -#define MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL __declspec(thread) -#else -#error "Compiler must support trivially constructible thread local variables" -#endif - -namespace mongo { - -using boost::thread_specific_ptr; - -/** - * DEPRECATED, DO NOT USE. - * - * thread local "value" rather than a pointer - * good for things which have copy constructors (and the copy constructor is fast enough) - * e.g. - * ThreadLocalValue<int> myint; - */ -template <class T> -class ThreadLocalValue { -public: - ThreadLocalValue(T def = 0) : _default(def) {} - - T get() const { - T* val = _val.get(); - if (val) - return *val; - return _default; - } - - void set(const T& i) { - T* v = _val.get(); - if (v) { - *v = i; - return; - } - v = new T(i); - _val.reset(v); - } - - T& getRef() { - T* v = _val.get(); - if (v) { - return *v; - } - v = new T(_default); - _val.reset(v); - return *v; - } - -private: - boost::thread_specific_ptr<T> _val; - const T _default; -}; - -/** - * Emulation of a thread local storage specifier used because not all supported - * compiler toolchains support the C++11 thread_local storage class keyword. - * - * Since all supported toolchains do support a thread local storage class for - * types that are trivially constructible and destructible, we perform the - * emulation using that storage type and the machinery of boost::thread_specific_ptr to - * handle deleting the objects on thread termination. - */ -template <class T> -class TSP { - MONGO_DISALLOW_COPYING(TSP); - -public: - TSP() = default; - T* get() const; - void reset(T* v); - T* getMake() { - T* t = get(); - if (t == nullptr) - reset(t = new T()); - return t; - } - -private: - boost::thread_specific_ptr<T> tsp; -}; - -#define TSP_DECLARE(T, p) extern TSP<T> p; - -#define TSP_DEFINE(T, p) \ - MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL T* _##p; \ - TSP<T> p; \ - template <> \ - T* TSP<T>::get() const { \ - return _##p; \ - } \ - template <> \ - void TSP<T>::reset(T* v) { \ - tsp.reset(v); \ - _##p = v; \ - } -} // namespace mongo diff --git a/src/mongo/util/fail_point.cpp b/src/mongo/util/fail_point.cpp index d4d53e36835..8f85ba18f17 100644 --- a/src/mongo/util/fail_point.cpp +++ b/src/mongo/util/fail_point.cpp @@ -32,8 +32,8 @@ #include "mongo/bson/util/bson_extract.h" #include "mongo/platform/random.h" +#include "mongo/stdx/memory.h" #include "mongo/stdx/thread.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/fail_point_service.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -43,8 +43,7 @@ namespace mongo { namespace { /** - * Type representing the per-thread PRNG used by fail-points. Required because TSP_* macros, - * below, only let you create one thread-specific object per type. + * Type representing the per-thread PRNG used by fail-points. */ class FailPointPRNG { public: @@ -58,26 +57,23 @@ public: return _prng.nextInt32() & ~(1 << 31); } + static FailPointPRNG* current() { + if (!_failPointPrng) + _failPointPrng = stdx::make_unique<FailPointPRNG>(); + return _failPointPrng.get(); + } + private: PseudoRandom _prng; + static thread_local std::unique_ptr<FailPointPRNG> _failPointPrng; }; -} // namespace - - -TSP_DECLARE(FailPointPRNG, failPointPrng); -TSP_DEFINE(FailPointPRNG, failPointPrng); - -namespace { - -int32_t prngNextPositiveInt32() { - return failPointPrng.getMake()->nextPositiveInt32(); -} +thread_local std::unique_ptr<FailPointPRNG> FailPointPRNG::_failPointPrng; } // namespace void FailPoint::setThreadPRNGSeed(int32_t seed) { - failPointPrng.getMake()->resetSeed(seed); + FailPointPRNG::current()->resetSeed(seed); } FailPoint::FailPoint() : _fpInfo(0), _mode(off), _timesOrPeriod(0) {} @@ -158,7 +154,7 @@ FailPoint::RetCode FailPoint::slowShouldFailOpenBlock() { case random: { const AtomicInt32::WordType maxActivationValue = _timesOrPeriod.load(); - if (prngNextPositiveInt32() < maxActivationValue) { + if (FailPointPRNG::current()->nextPositiveInt32() < maxActivationValue) { return slowOn; } return slowOff; diff --git a/src/mongo/util/log.cpp b/src/mongo/util/log.cpp index 76bc1ac8837..7c21dccd079 100644 --- a/src/mongo/util/log.cpp +++ b/src/mongo/util/log.cpp @@ -37,7 +37,6 @@ #include "mongo/logger/rotatable_file_manager.h" #include "mongo/util/assert_util.h" #include "mongo/util/concurrency/thread_name.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/stacktrace.h" #include "mongo/util/time_support.h" diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp index c5b911ca6b2..b5b379ce31a 100644 --- a/src/mongo/util/net/ssl_manager.cpp +++ b/src/mongo/util/net/ssl_manager.cpp @@ -33,8 +33,6 @@ #include <boost/algorithm/string.hpp> #include <boost/date_time/posix_time/posix_time.hpp> -#include <boost/thread/recursive_mutex.hpp> -#include <boost/thread/thread.hpp> #include <iostream> #include <sstream> #include <string> @@ -48,7 +46,6 @@ #include "mongo/stdx/memory.h" #include "mongo/transport/session.h" #include "mongo/util/concurrency/mutex.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/debug_util.h" #include "mongo/util/exit.h" #include "mongo/util/log.h" @@ -189,7 +186,20 @@ const STACK_OF(X509_EXTENSION) * X509_get0_extensions(const X509* peerCert) { class SSLThreadInfo { public: static unsigned long getID() { - enforceCleanupOnShutdown(); + // NOTE: This logic is fully intentional. Because ERR_remove_state (called within + // the destructor of the kRemoveStateFromThread object) re-enters this function, + // we must have a two phase protection, otherwise we would access a thread local + // during its destruction. + static thread_local bool firstCall = false; + if (!firstCall) { + firstCall = true; + + static const thread_local struct CallErrRemoveState { + ~CallErrRemoveState() { + ERR_remove_state(0); + }; + } kRemoveStateFromThread{}; + } #ifdef _WIN32 return GetCurrentThreadId(); @@ -221,15 +231,6 @@ public: private: SSLThreadInfo() = delete; - // When called, ensures that this thread will, on termination, call ERR_remove_state. - static void enforceCleanupOnShutdown() { - static MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL bool firstCall = true; - if (firstCall) { - boost::this_thread::at_thread_exit([] { ERR_remove_state(0); }); - firstCall = false; - } - } - // Note: see SERVER-8734 for why we are using a recursive mutex here. // Once the deadlock fix in OpenSSL is incorporated into most distros of // Linux, this can be changed back to a nonrecursive mutex. diff --git a/src/mongo/util/signal_handlers_synchronous.cpp b/src/mongo/util/signal_handlers_synchronous.cpp index 8107143ef55..2331190fabc 100644 --- a/src/mongo/util/signal_handlers_synchronous.cpp +++ b/src/mongo/util/signal_handlers_synchronous.cpp @@ -48,7 +48,6 @@ #include "mongo/platform/compiler.h" #include "mongo/stdx/thread.h" #include "mongo/util/concurrency/thread_name.h" -#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/debug_util.h" #include "mongo/util/debugger.h" #include "mongo/util/exception_filter_win32.h" @@ -156,12 +155,12 @@ public: private: static stdx::mutex _streamMutex; - static MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL int terminateDepth; + static thread_local int terminateDepth; stdx::unique_lock<stdx::mutex> _lk; }; + stdx::mutex MallocFreeOStreamGuard::_streamMutex; -MONGO_TRIVIALLY_CONSTRUCTIBLE_THREAD_LOCAL -int MallocFreeOStreamGuard::terminateDepth = 0; +thread_local int MallocFreeOStreamGuard::terminateDepth = 0; // must hold MallocFreeOStreamGuard to call void writeMallocFreeStreamToLog() { diff --git a/src/mongo/util/time_support.cpp b/src/mongo/util/time_support.cpp index 7ab7a03215d..eb318a2a6cd 100644 --- a/src/mongo/util/time_support.cpp +++ b/src/mongo/util/time_support.cpp @@ -29,7 +29,6 @@ #include "mongo/util/time_support.h" -#include <boost/thread/tss.hpp> #include <cstdint> #include <cstdio> #include <iostream> @@ -82,7 +81,7 @@ bool Date_t::isFormattable() const { // jsTime_virtual_skew is just for testing. a test command manipulates it. long long jsTime_virtual_skew = 0; -boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew; +thread_local long long jsTime_virtual_thread_skew = 0; using std::string; @@ -770,9 +769,6 @@ int Backoff::getNextSleepMillis(int lastSleepMillis, return lastSleepMillis; } -extern long long jsTime_virtual_skew; -extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew; - // DO NOT TOUCH except for testing void jsTimeVirtualSkew(long long skew) { jsTime_virtual_skew = skew; @@ -782,13 +778,11 @@ long long getJSTimeVirtualSkew() { } void jsTimeVirtualThreadSkew(long long skew) { - jsTime_virtual_thread_skew.reset(new long long(skew)); + jsTime_virtual_thread_skew = skew; } + long long getJSTimeVirtualThreadSkew() { - if (jsTime_virtual_thread_skew.get()) { - return *(jsTime_virtual_thread_skew.get()); - } else - return 0; + return jsTime_virtual_thread_skew; } /** Date_t is milliseconds since epoch */ diff --git a/src/third_party/SConscript b/src/third_party/SConscript index 24192468241..cf20fd7edeb 100644 --- a/src/third_party/SConscript +++ b/src/third_party/SConscript @@ -150,7 +150,6 @@ if use_system_version_of_library("boost"): SYSLIBDEPS=[ env['LIBDEPS_BOOST_PROGRAM_OPTIONS_SYSLIBDEP'], env['LIBDEPS_BOOST_FILESYSTEM_SYSLIBDEP'], - env['LIBDEPS_BOOST_THREAD_SYSLIBDEP'], env['LIBDEPS_BOOST_SYSTEM_SYSLIBDEP'], env['LIBDEPS_BOOST_IOSTREAMS_SYSLIBDEP'], ]) @@ -163,7 +162,6 @@ else: LIBDEPS_INTERFACE=[ boostDirectory + '/boost_program_options', boostDirectory + '/boost_filesystem', - boostDirectory + '/boost_thread', boostDirectory + '/boost_system', boostDirectory + '/boost_iostreams', ]) diff --git a/src/third_party/boost-1.60.0/SConscript b/src/third_party/boost-1.60.0/SConscript index a9c4d2d2ae5..5a4ec8f5519 100644 --- a/src/third_party/boost-1.60.0/SConscript +++ b/src/third_party/boost-1.60.0/SConscript @@ -6,23 +6,6 @@ env = env.Clone() env.Library('boost_system', ['libs/system/src/error_code.cpp']) -boost_thread_source = dict( - posix=['libs/thread/src/pthread/once.cpp', - 'libs/thread/src/pthread/thread.cpp'], - windows=['libs/thread/src/win32/thread.cpp', - 'libs/thread/src/win32/tss_pe.cpp'] - ).get(env['TARGET_OS_FAMILY'], 'UNKNOWN_OS_FAMILY_FOR_BOOST_THREADS__%s' % env['TARGET_OS_FAMILY']) - -threadlib_env = env.Clone() -threadlib_env.Append(CPPDEFINES=['BOOST_THREAD_BUILD_LIB']) -threadlib_env.Library('boost_thread', [ - 'libs/thread/src/future.cpp', - 'libs/thread/src/tss_null.cpp' - ] + boost_thread_source, - LIBDEPS=[ - 'boost_system', - ]) - env.Library('boost_filesystem', [ 'libs/filesystem/src/codecvt_error_category.cpp', 'libs/filesystem/src/operations.cpp', diff --git a/src/third_party/scripts/boost_get_sources.sh b/src/third_party/scripts/boost_get_sources.sh index 225e88546a4..9c74b19ff48 100755 --- a/src/third_party/scripts/boost_get_sources.sh +++ b/src/third_party/scripts/boost_get_sources.sh @@ -43,7 +43,7 @@ cd $SRC ./b2 tools/bcp test -d $DEST_DIR || mkdir $DEST_DIR -$SRC/dist/bin/bcp --boost=$SRC/ algorithm align array asio bind iostreams config container date_time filesystem function integer intrusive multi_index noncopyable optional program_options random smart_ptr static_assert thread unordered utility $DEST_DIR +$SRC/dist/bin/bcp --boost=$SRC/ algorithm align array asio bind iostreams config container date_time filesystem function integer intrusive multi_index noncopyable optional program_options random smart_ptr static_assert unordered utility $DEST_DIR # Trim files cd $DEST_DIR |