diff --git a/aws-cpp-sdk-cognitoidentity-integration-tests/RunTests.cpp b/aws-cpp-sdk-cognitoidentity-integration-tests/RunTests.cpp index 73b7b5dc4e2..3bd087f35d2 100644 --- a/aws-cpp-sdk-cognitoidentity-integration-tests/RunTests.cpp +++ b/aws-cpp-sdk-cognitoidentity-integration-tests/RunTests.cpp @@ -29,11 +29,9 @@ int main(int argc, char** argv) } options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; - Aws::InitAPI(options); + Aws::APIWrapper api(options); ::testing::InitGoogleTest(&argc, argv); int exitCode = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); - Aws::Testing::ShutdownPlatformTest(options); return exitCode; diff --git a/aws-cpp-sdk-core-tests/RunTests.cpp b/aws-cpp-sdk-core-tests/RunTests.cpp index ccbb446f329..6f80e02c11c 100644 --- a/aws-cpp-sdk-core-tests/RunTests.cpp +++ b/aws-cpp-sdk-core-tests/RunTests.cpp @@ -33,14 +33,15 @@ int main(int argc, char** argv) Aws::Testing::InitPlatformTest(options); options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; - - Aws::InitAPI(options); - ::testing::InitGoogleTest(&argc, argv); - int retVal = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); - EXPECT_EQ(memorySystem.GetCurrentOutstandingAllocations(), 0ULL); - EXPECT_EQ(memorySystem.GetCurrentBytesAllocated(), 0ULL); - EXPECT_TRUE(memorySystem.IsClean()); + int retVal = 0; + { + Aws::APIWrapper wrapper(options); + ::testing::InitGoogleTest(&argc, argv); + retVal = RUN_ALL_TESTS(); + } + EXPECT_EQ(memorySystem.GetCurrentOutstandingAllocations(), 0ULL); + EXPECT_EQ(memorySystem.GetCurrentBytesAllocated(), 0ULL); + EXPECT_TRUE(memorySystem.IsClean()); Aws::Testing::ShutdownPlatformTest(options); diff --git a/aws-cpp-sdk-core/include/aws/core/Aws.h b/aws-cpp-sdk-core/include/aws/core/Aws.h index 0dbe04fc7fe..183dba23f52 100644 --- a/aws-cpp-sdk-core/include/aws/core/Aws.h +++ b/aws-cpp-sdk-core/include/aws/core/Aws.h @@ -21,6 +21,9 @@ #include #include +#include +#include + namespace Aws { static const char* DEFAULT_LOG_PREFIX = "aws_sdk_"; @@ -238,5 +241,35 @@ namespace Aws * Do not call any other SDK methods after calling ShutdownAPI. */ AWS_CORE_API void ShutdownAPI(const SDKOptions& options); + + /** + * Ref counted RAII wrapper around SDK Init and Shutdown. The first one created will call InitAPI() and the last one to go out of scope + * will call ShutdownAPI(). This is intended for use cases, such as plugin frameworks where multiple modules depending on the SDK may be loaded + * without being aware of one another. This allows each module to safely init/shutdown the SDK as long as each module uses this wrapper. + * + * Note: whichever instance of SDKOptions is used to init the API, will be used for Shutdown(), and InitAPI will only be called with the first + * call to the Constructor. All other values will be ignored. + */ + class AWS_CORE_API APIWrapper + { + public: + /** + * Initialize the SDK if it hasn't been already. Otherwise just increase the ref count. + */ + APIWrapper(const SDKOptions& options); + /** + * Shutsdown the SDK if no other instances of this class exist. Otherwise just decreases the ref count. + */ + ~APIWrapper(); + + APIWrapper(const APIWrapper&) = delete; + APIWrapper& operator=(const APIWrapper) = delete; + + private: + static std::atomic RefCount; + static std::mutex InitGuard; + + SDKOptions m_sdkOptions; + }; } diff --git a/aws-cpp-sdk-core/source/Aws.cpp b/aws-cpp-sdk-core/source/Aws.cpp index bb6fc18d65f..848c74b52c2 100644 --- a/aws-cpp-sdk-core/source/Aws.cpp +++ b/aws-cpp-sdk-core/source/Aws.cpp @@ -111,4 +111,45 @@ namespace Aws } #endif // USE_AWS_MEMORY_MANAGEMENT } + + std::atomic APIWrapper::RefCount = 0; + std::mutex APIWrapper::InitGuard; + + APIWrapper::APIWrapper(const SDKOptions& options) + { + if (RefCount.load() == 0u) + { + std::lock_guard locker(InitGuard); + + if (RefCount.load() == 0u) + { + m_sdkOptions = options; + Aws::InitAPI(m_sdkOptions); + } + + RefCount++; + } + else + { + RefCount++; + } + } + + APIWrapper::~APIWrapper() + { + if (RefCount.load() == 1u) + { + std::lock_guard locker(InitGuard); + + if (RefCount.load() == 1u) + { + Aws::ShutdownAPI(m_sdkOptions); + } + RefCount--; + } + else + { + RefCount--; + } + } } \ No newline at end of file diff --git a/aws-cpp-sdk-dynamodb-integration-tests/RunTests.cpp b/aws-cpp-sdk-dynamodb-integration-tests/RunTests.cpp index 3db7229adf3..3743eec9e7f 100644 --- a/aws-cpp-sdk-dynamodb-integration-tests/RunTests.cpp +++ b/aws-cpp-sdk-dynamodb-integration-tests/RunTests.cpp @@ -32,10 +32,10 @@ int main(int argc, char** argv) Aws::Testing::SetAwsResourcePrefix(argv[1]); } - Aws::InitAPI(options); + Aws::APIWrapper api(options); + ::testing::InitGoogleTest(&argc, argv); int exitCode = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); Aws::Testing::ShutdownPlatformTest(options); return exitCode; diff --git a/aws-cpp-sdk-s3-integration-tests/RunTests.cpp b/aws-cpp-sdk-s3-integration-tests/RunTests.cpp index 5419384bda3..166c3e4819f 100644 --- a/aws-cpp-sdk-s3-integration-tests/RunTests.cpp +++ b/aws-cpp-sdk-s3-integration-tests/RunTests.cpp @@ -28,10 +28,9 @@ int main(int argc, char** argv) Aws::Testing::SetAwsResourcePrefix(argv[1]); } - Aws::InitAPI(options); + Aws::APIWrapper api(options); ::testing::InitGoogleTest(&argc, argv); int exitCode = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); Aws::Testing::ShutdownPlatformTest(options); return exitCode; diff --git a/aws-cpp-sdk-sqs-integration-tests/RunTests.cpp b/aws-cpp-sdk-sqs-integration-tests/RunTests.cpp index d06e58ca3c2..a37b5e24edb 100644 --- a/aws-cpp-sdk-sqs-integration-tests/RunTests.cpp +++ b/aws-cpp-sdk-sqs-integration-tests/RunTests.cpp @@ -29,10 +29,9 @@ int main(int argc, char** argv) } options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; - Aws::InitAPI(options); + Aws::APIWrapper api(options); ::testing::InitGoogleTest(&argc, argv); int exitCode = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); Aws::Testing::ShutdownPlatformTest(options); return exitCode; diff --git a/aws-cpp-sdk-transfer-tests/RunTests.cpp b/aws-cpp-sdk-transfer-tests/RunTests.cpp index 666d8f9b893..d5655751c0c 100644 --- a/aws-cpp-sdk-transfer-tests/RunTests.cpp +++ b/aws-cpp-sdk-transfer-tests/RunTests.cpp @@ -29,10 +29,9 @@ int main(int argc, char** argv) } options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; - Aws::InitAPI(options); + Aws::APIWrapper api(options); ::testing::InitGoogleTest(&argc, argv); int exitCode = RUN_ALL_TESTS(); - Aws::ShutdownAPI(options); Aws::Testing::ShutdownPlatformTest(options); return exitCode;