From 1b73af1a4f59e2c85127a70d537712f130329462 Mon Sep 17 00:00:00 2001 From: Ben Craig Date: Tue, 7 Jul 2015 20:54:50 -0500 Subject: [PATCH 1/4] Fixing double pipe close --- lib/cpp/src/thrift/transport/TPipe.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/cpp/src/thrift/transport/TPipe.cpp b/lib/cpp/src/thrift/transport/TPipe.cpp index 8939d50c266..84e55f56be6 100644 --- a/lib/cpp/src/thrift/transport/TPipe.cpp +++ b/lib/cpp/src/thrift/transport/TPipe.cpp @@ -99,13 +99,14 @@ class TAnonPipeImpl : public TPipeImpl { class TWaitableNamedPipeImpl : public TPipeImpl { public: explicit TWaitableNamedPipeImpl(HANDLE pipehandle) - : Pipe_(pipehandle), begin_unread_idx_(0), end_unread_idx_(0) { + : begin_unread_idx_(0), end_unread_idx_(0) { readOverlap_.action = TOverlappedWorkItem::READ; - readOverlap_.h = Pipe_.h; + readOverlap_.h = pipehandle; cancelOverlap_.action = TOverlappedWorkItem::CANCELIO; - cancelOverlap_.h = Pipe_.h; + cancelOverlap_.h = pipehandle; buffer_.resize(1024 /*arbitrary buffer size*/, '\0'); beginAsyncRead(&buffer_[0], static_cast(buffer_.size())); + Pipe_.reset(pipehandle); } virtual ~TWaitableNamedPipeImpl() { // see if there is an outstanding read request From f6f096938ecd6d6bb3faa918d8689218fc402ef1 Mon Sep 17 00:00:00 2001 From: Ben Craig Date: Thu, 9 Jul 2015 21:17:25 -0500 Subject: [PATCH 2/4] Using TAutoHandle more frequently, still needs testing though --- lib/cpp/src/thrift/transport/TPipe.cpp | 17 +++++++++++------ lib/cpp/src/thrift/transport/TPipe.h | 4 ++++ lib/cpp/src/thrift/transport/TPipeServer.cpp | 9 +++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/cpp/src/thrift/transport/TPipe.cpp b/lib/cpp/src/thrift/transport/TPipe.cpp index 84e55f56be6..75843122fe4 100644 --- a/lib/cpp/src/thrift/transport/TPipe.cpp +++ b/lib/cpp/src/thrift/transport/TPipe.cpp @@ -98,15 +98,14 @@ class TAnonPipeImpl : public TPipeImpl { // than using the regular named pipe implementation class TWaitableNamedPipeImpl : public TPipeImpl { public: - explicit TWaitableNamedPipeImpl(HANDLE pipehandle) - : begin_unread_idx_(0), end_unread_idx_(0) { + explicit TWaitableNamedPipeImpl(TAutoHandle &pipehandle) + : Pipe_(pipehandle.release()), begin_unread_idx_(0), end_unread_idx_(0) { readOverlap_.action = TOverlappedWorkItem::READ; - readOverlap_.h = pipehandle; + readOverlap_.h = Pipe_.h; cancelOverlap_.action = TOverlappedWorkItem::CANCELIO; - cancelOverlap_.h = pipehandle; + cancelOverlap_.h = Pipe_.h; buffer_.resize(1024 /*arbitrary buffer size*/, '\0'); beginAsyncRead(&buffer_[0], static_cast(buffer_.size())); - Pipe_.reset(pipehandle); } virtual ~TWaitableNamedPipeImpl() { // see if there is an outstanding read request @@ -223,10 +222,16 @@ uint32_t pseudo_sync_read(HANDLE pipe, HANDLE event, uint8_t* buf, uint32_t len) } //---- Constructors ---- -TPipe::TPipe(HANDLE Pipe) +TPipe::TPipe(TAutoHandle &Pipe) : impl_(new TWaitableNamedPipeImpl(Pipe)), TimeoutSeconds_(3), isAnonymous_(false) { } +TPipe::TPipe(HANDLE Pipe) + : TimeoutSeconds_(3), isAnonymous_(false) { + TAutoHandle autoObj(Pipe); + impl_.reset(new TWaitableNamedPipeImpl(autoObj)); +} + TPipe::TPipe(const char* pipename) : TimeoutSeconds_(3), isAnonymous_(false) { setPipename(pipename); } diff --git a/lib/cpp/src/thrift/transport/TPipe.h b/lib/cpp/src/thrift/transport/TPipe.h index ef957c66118..2e5fbd63cb5 100644 --- a/lib/cpp/src/thrift/transport/TPipe.h +++ b/lib/cpp/src/thrift/transport/TPipe.h @@ -26,6 +26,9 @@ #include #endif #include +#ifdef _WIN32 +#include +#endif namespace apache { namespace thrift { @@ -45,6 +48,7 @@ class TPipe : public TVirtualTransport { // Constructs a new pipe object. TPipe(); // Named pipe constructors - + explicit TPipe(TAutoHandle &Pipe); // The Pipe will be pseudo-moved from in here explicit TPipe(HANDLE Pipe); // HANDLE is a void* // need a const char * overload so string literals don't go to the HANDLE overload explicit TPipe(const char* pipename); diff --git a/lib/cpp/src/thrift/transport/TPipeServer.cpp b/lib/cpp/src/thrift/transport/TPipeServer.cpp index 3779d7fa4aa..0d515df426a 100644 --- a/lib/cpp/src/thrift/transport/TPipeServer.cpp +++ b/lib/cpp/src/thrift/transport/TPipeServer.cpp @@ -236,8 +236,7 @@ void TNamedPipeServer::initiateNamedConnect() { // zero, GetLastError should return ERROR_PIPE_CONNECTED. if (connectOverlap_.success) { GlobalOutput.printf("Client connected."); - cached_client_.reset(new TPipe(Pipe_.h)); - Pipe_.release(); + cached_client_.reset(new TPipe(Pipe_)); // make sure people know that a connection is ready SetEvent(listen_event_.h); return; @@ -247,8 +246,7 @@ void TNamedPipeServer::initiateNamedConnect() { switch (dwErr) { case ERROR_PIPE_CONNECTED: GlobalOutput.printf("Client connected."); - cached_client_.reset(new TPipe(Pipe_.h)); - Pipe_.release(); + cached_client_.reset(new TPipe(Pipe_)); // make sure people know that a connection is ready SetEvent(listen_event_.h); return; @@ -284,8 +282,7 @@ shared_ptr TNamedPipeServer::acceptImpl() { if (GetOverlappedResult(Pipe_.h, &connectOverlap_.overlap, &dwDummy, TRUE)) { TAutoCrit lock(pipe_protect_); GlobalOutput.printf("Client connected."); - shared_ptr client(new TPipe(Pipe_.h)); - Pipe_.release(); + shared_ptr client(new TPipe(Pipe_)); // kick off the next connection before returning initiateNamedConnect(); return client; // success! From 649ab3d5d13124be615c1f3f010948177fef8b31 Mon Sep 17 00:00:00 2001 From: ben-craig Date: Mon, 13 Jul 2015 09:12:15 -0500 Subject: [PATCH 3/4] Changing exe name --- lib/cpp/test/CMakeLists.txt | 10 +++++----- lib/cpp/test/Makefile.am | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt index 365db8fabc9..548cd105d09 100644 --- a/lib/cpp/test/CMakeLists.txt +++ b/lib/cpp/test/CMakeLists.txt @@ -83,16 +83,16 @@ target_link_libraries(UnitTests testgencpp ${Boost_LIBRARIES}) LINK_AGAINST_THRIFT_LIBRARY(UnitTests thrift) add_test(NAME UnitTests COMMAND UnitTests) -add_executable(TSocketInterruptTest TSocketInterruptTest.cpp) -target_link_libraries(TSocketInterruptTest +add_executable(TInterruptTest TSocketInterruptTest.cpp) +target_link_libraries(TInterruptTest testgencpp ${Boost_LIBRARIES} ) -LINK_AGAINST_THRIFT_LIBRARY(TSocketInterruptTest thrift) +LINK_AGAINST_THRIFT_LIBRARY(TInterruptTest thrift) if (NOT MSVC AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") -target_link_libraries(TSocketInterruptTest -lrt) +target_link_libraries(TInterruptTest -lrt) endif () -add_test(NAME TSocketInterruptTest COMMAND TSocketInterruptTest) +add_test(NAME TInterruptTest COMMAND TInterruptTest) add_executable(TServerIntegrationTest TServerIntegrationTest.cpp) target_link_libraries(TServerIntegrationTest diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am index 18b46546b97..5c32eba2cab 100755 --- a/lib/cpp/test/Makefile.am +++ b/lib/cpp/test/Makefile.am @@ -82,7 +82,7 @@ check_PROGRAMS = \ SpecializationTest \ AllProtocolsTest \ TransportTest \ - TSocketInterruptTest \ + TInterruptTest \ TServerIntegrationTest \ ZlibTest \ TFileTransportTest \ @@ -125,10 +125,10 @@ UnitTests_LDADD = \ libtestgencpp.la \ $(BOOST_TEST_LDADD) -TSocketInterruptTest_SOURCES = \ +TInterruptTest_SOURCES = \ TSocketInterruptTest.cpp -TSocketInterruptTest_LDADD = \ +TInterruptTest_LDADD = \ libtestgencpp.la \ $(BOOST_TEST_LDADD) \ $(BOOST_CHRONO_LDADD) \ @@ -214,7 +214,7 @@ AllProtocolsTest_LDADD = \ # DebugProtoTest # DebugProtoTest_SOURCES = \ - DebugProtoTest.cpp + DebugProtoTest.cpp DebugProtoTest_LDADD = \ libtestgencpp.la \ From 0327433e9af7f62148be5e17c828d449af67c70d Mon Sep 17 00:00:00 2001 From: ben-craig Date: Tue, 14 Jul 2015 14:41:12 -0500 Subject: [PATCH 4/4] New pipe interruption test, and pipe interruption now works --- lib/cpp/src/thrift/transport/TPipe.cpp | 28 +++++-- lib/cpp/src/thrift/transport/TPipe.h | 4 + lib/cpp/src/thrift/transport/TPipeServer.cpp | 60 +++++++------- lib/cpp/test/CMakeLists.txt | 9 +- lib/cpp/test/TPipeInterruptTest.cpp | 86 ++++++++++++++++++++ 5 files changed, 148 insertions(+), 39 deletions(-) create mode 100644 lib/cpp/test/TPipeInterruptTest.cpp diff --git a/lib/cpp/src/thrift/transport/TPipe.cpp b/lib/cpp/src/thrift/transport/TPipe.cpp index 8939d50c266..cd114c2b115 100644 --- a/lib/cpp/src/thrift/transport/TPipe.cpp +++ b/lib/cpp/src/thrift/transport/TPipe.cpp @@ -58,7 +58,7 @@ class TPipeImpl : boost::noncopyable { class TNamedPipeImpl : public TPipeImpl { public: - explicit TNamedPipeImpl(HANDLE pipehandle) : Pipe_(pipehandle) {} + explicit TNamedPipeImpl(TAutoHandle &pipehandle) : Pipe_(pipehandle.release()) {} virtual ~TNamedPipeImpl() {} virtual uint32_t read(uint8_t* buf, uint32_t len) { return pseudo_sync_read(Pipe_.h, read_event_.h, buf, len); @@ -98,14 +98,15 @@ class TAnonPipeImpl : public TPipeImpl { // than using the regular named pipe implementation class TWaitableNamedPipeImpl : public TPipeImpl { public: - explicit TWaitableNamedPipeImpl(HANDLE pipehandle) - : Pipe_(pipehandle), begin_unread_idx_(0), end_unread_idx_(0) { + explicit TWaitableNamedPipeImpl(TAutoHandle &pipehandle) + : begin_unread_idx_(0), end_unread_idx_(0) { readOverlap_.action = TOverlappedWorkItem::READ; - readOverlap_.h = Pipe_.h; + readOverlap_.h = pipehandle.h; cancelOverlap_.action = TOverlappedWorkItem::CANCELIO; - cancelOverlap_.h = Pipe_.h; + cancelOverlap_.h = pipehandle.h; buffer_.resize(1024 /*arbitrary buffer size*/, '\0'); beginAsyncRead(&buffer_[0], static_cast(buffer_.size())); + Pipe_.reset(pipehandle.release()); } virtual ~TWaitableNamedPipeImpl() { // see if there is an outstanding read request @@ -222,10 +223,17 @@ uint32_t pseudo_sync_read(HANDLE pipe, HANDLE event, uint8_t* buf, uint32_t len) } //---- Constructors ---- -TPipe::TPipe(HANDLE Pipe) +TPipe::TPipe(TAutoHandle &Pipe) : impl_(new TWaitableNamedPipeImpl(Pipe)), TimeoutSeconds_(3), isAnonymous_(false) { } +TPipe::TPipe(HANDLE Pipe) + : TimeoutSeconds_(3), isAnonymous_(false) +{ + TAutoHandle pipeHandle(Pipe); + impl_.reset(new TWaitableNamedPipeImpl(pipeHandle)); +} + TPipe::TPipe(const char* pipename) : TimeoutSeconds_(3), isAnonymous_(false) { setPipename(pipename); } @@ -284,8 +292,7 @@ void TPipe::open() { throw TTransportException(TTransportException::NOT_OPEN, "Unable to open pipe"); } - impl_.reset(new TNamedPipeImpl(hPipe.h)); - hPipe.release(); + impl_.reset(new TNamedPipeImpl(hPipe)); } void TPipe::close() { @@ -355,7 +362,10 @@ void TPipe::setPipeHandle(HANDLE pipehandle) { if (isAnonymous_) impl_->setPipeHandle(pipehandle); else - impl_.reset(new TNamedPipeImpl(pipehandle)); + { + TAutoHandle pipe(pipehandle); + impl_.reset(new TNamedPipeImpl(pipe)); + } } HANDLE TPipe::getWrtPipeHandle() { diff --git a/lib/cpp/src/thrift/transport/TPipe.h b/lib/cpp/src/thrift/transport/TPipe.h index ef957c66118..97bd200d595 100644 --- a/lib/cpp/src/thrift/transport/TPipe.h +++ b/lib/cpp/src/thrift/transport/TPipe.h @@ -25,6 +25,9 @@ #ifndef _WIN32 #include #endif +#ifdef _WIN32 +#include +#endif #include namespace apache { @@ -46,6 +49,7 @@ class TPipe : public TVirtualTransport { TPipe(); // Named pipe constructors - explicit TPipe(HANDLE Pipe); // HANDLE is a void* + explicit TPipe(TAutoHandle &Pipe); // this ctor will clear out / move from Pipe // need a const char * overload so string literals don't go to the HANDLE overload explicit TPipe(const char* pipename); explicit TPipe(const std::string& pipename); diff --git a/lib/cpp/src/thrift/transport/TPipeServer.cpp b/lib/cpp/src/thrift/transport/TPipeServer.cpp index 3779d7fa4aa..baa260343d8 100644 --- a/lib/cpp/src/thrift/transport/TPipeServer.cpp +++ b/lib/cpp/src/thrift/transport/TPipeServer.cpp @@ -45,7 +45,6 @@ class TPipeServerImpl : boost::noncopyable { TPipeServerImpl() {} virtual ~TPipeServerImpl() = 0 {} virtual void interrupt() = 0; - virtual void close() = 0; virtual boost::shared_ptr acceptImpl() = 0; virtual HANDLE getPipeHandle() = 0; @@ -68,16 +67,15 @@ class TAnonPipeServer : public TPipeServerImpl { } } - virtual ~TAnonPipeServer() {} - - virtual void interrupt() {} // not currently implemented - virtual void close() { + virtual ~TAnonPipeServer() { PipeR_.reset(); PipeW_.reset(); ClientAnonRead_.reset(); ClientAnonWrite_.reset(); } + virtual void interrupt() {} // not currently implemented + virtual boost::shared_ptr acceptImpl(); virtual HANDLE getPipeHandle() { return PipeR_.h; } @@ -100,10 +98,12 @@ class TAnonPipeServer : public TPipeServerImpl { class TNamedPipeServer : public TPipeServerImpl { public: TNamedPipeServer(const std::string& pipename, uint32_t bufsize, uint32_t maxconnections) - : stopping_(false), pipename_(pipename), bufsize_(bufsize), maxconns_(maxconnections) { + : stopping_(false), pipename_(pipename), bufsize_(bufsize), maxconns_(maxconnections) + { connectOverlap_.action = TOverlappedWorkItem::CONNECT; cancelOverlap_.action = TOverlappedWorkItem::CANCELIO; - initiateNamedConnect(); + TAutoCrit lock(pipe_protect_); + initiateNamedConnect(lock); } virtual ~TNamedPipeServer() {} @@ -115,12 +115,9 @@ class TNamedPipeServer : public TPipeServerImpl { cancelOverlap_.h = Pipe_.h; // This should wake up GetOverlappedResult thread_->addWorkItem(&cancelOverlap_); - close(); } } - virtual void close() { Pipe_.reset(); } - virtual boost::shared_ptr acceptImpl(); virtual HANDLE getPipeHandle() { return Pipe_.h; } @@ -130,8 +127,8 @@ class TNamedPipeServer : public TPipeServerImpl { virtual HANDLE getNativeWaitHandle() { return listen_event_.h; } private: - bool createNamedPipe(); - void initiateNamedConnect(); + bool createNamedPipe(const TAutoCrit &lockProof); + void initiateNamedConnect(const TAutoCrit &lockProof); TAutoOverlapThread thread_; TOverlappedWorkItem connectOverlap_; @@ -142,9 +139,11 @@ class TNamedPipeServer : public TPipeServerImpl { uint32_t bufsize_; uint32_t maxconns_; TManualResetEvent listen_event_; + + TCriticalSection pipe_protect_; + // only read or write these variables underneath a locked pipe_protect_ boost::shared_ptr cached_client_; TAutoHandle Pipe_; - TCriticalSection pipe_protect_; }; HANDLE TPipeServer::getNativeWaitHandle() { @@ -182,8 +181,7 @@ TPipeServer::TPipeServer() : bufsize_(1024), isAnonymous_(true) { } //---- Destructor ---- -TPipeServer::~TPipeServer() { -} +TPipeServer::~TPipeServer() {} //--------------------------------------------------------- // Transport callbacks @@ -217,10 +215,10 @@ shared_ptr TAnonPipeServer::acceptImpl() { return client; } -void TNamedPipeServer::initiateNamedConnect() { +void TNamedPipeServer::initiateNamedConnect(const TAutoCrit &lockProof) { if (stopping_) return; - if (!createNamedPipe()) { + if (!createNamedPipe(lockProof)) { GlobalOutput.perror("TPipeServer CreateNamedPipe failed, GLE=", GetLastError()); throw TTransportException(TTransportException::NOT_OPEN, " TPipeServer CreateNamedPipe failed"); } @@ -236,8 +234,7 @@ void TNamedPipeServer::initiateNamedConnect() { // zero, GetLastError should return ERROR_PIPE_CONNECTED. if (connectOverlap_.success) { GlobalOutput.printf("Client connected."); - cached_client_.reset(new TPipe(Pipe_.h)); - Pipe_.release(); + cached_client_.reset(new TPipe(Pipe_)); // make sure people know that a connection is ready SetEvent(listen_event_.h); return; @@ -247,8 +244,7 @@ void TNamedPipeServer::initiateNamedConnect() { switch (dwErr) { case ERROR_PIPE_CONNECTED: GlobalOutput.printf("Client connected."); - cached_client_.reset(new TPipe(Pipe_.h)); - Pipe_.release(); + cached_client_.reset(new TPipe(Pipe_)); // make sure people know that a connection is ready SetEvent(listen_event_.h); return; @@ -270,7 +266,7 @@ shared_ptr TNamedPipeServer::acceptImpl() { client.swap(cached_client_); // kick off the next connection before returning - initiateNamedConnect(); + initiateNamedConnect(lock); return client; // success! } } @@ -281,18 +277,25 @@ shared_ptr TNamedPipeServer::acceptImpl() { } DWORD dwDummy = 0; + + // For the most part, Pipe_ should be protected with pipe_protect_. We can't + // reasonably do that here though without breaking interruptability. However, + // this should be safe, though I'm not happy about it. We only need to ensure + // that no one writes / modifies Pipe_.h while we are reading it. Well, the + // only two things that should be modifying Pipe_ are acceptImpl, the + // functions it calls, and the destructor. Those things shouldn't be run + // concurrently anyway. So this call is 'really' just a read that may happen + // concurrently with interrupt, and that should be fine. if (GetOverlappedResult(Pipe_.h, &connectOverlap_.overlap, &dwDummy, TRUE)) { TAutoCrit lock(pipe_protect_); GlobalOutput.printf("Client connected."); - shared_ptr client(new TPipe(Pipe_.h)); - Pipe_.release(); + shared_ptr client(new TPipe(Pipe_)); // kick off the next connection before returning - initiateNamedConnect(); + initiateNamedConnect(lock); return client; // success! } // if we got here, then we are in an error / shutdown case DWORD gle = GetLastError(); // save error before doing cleanup - close(); GlobalOutput.perror("TPipeServer ConnectNamedPipe GLE=", gle); throw TTransportException(TTransportException::NOT_OPEN, "TPipeServer: client connection failed"); } @@ -303,11 +306,10 @@ void TPipeServer::interrupt() { } void TPipeServer::close() { - if (impl_) - impl_->close(); + impl_.reset(); } -bool TNamedPipeServer::createNamedPipe() { +bool TNamedPipeServer::createNamedPipe(const TAutoCrit & /*lockProof*/) { // Windows - set security to allow non-elevated apps // to access pipes created by elevated apps. diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt index 548cd105d09..dec6732b972 100644 --- a/lib/cpp/test/CMakeLists.txt +++ b/lib/cpp/test/CMakeLists.txt @@ -83,7 +83,14 @@ target_link_libraries(UnitTests testgencpp ${Boost_LIBRARIES}) LINK_AGAINST_THRIFT_LIBRARY(UnitTests thrift) add_test(NAME UnitTests COMMAND UnitTests) -add_executable(TInterruptTest TSocketInterruptTest.cpp) + +set( TInterruptTest_SOURCES TSocketInterruptTest.cpp ) +if (WIN32) + list(APPEND TInterruptTest_SOURCES + TPipeInterruptTest.cpp + ) +endif() +add_executable(TInterruptTest ${TInterruptTest_SOURCES}) target_link_libraries(TInterruptTest testgencpp ${Boost_LIBRARIES} diff --git a/lib/cpp/test/TPipeInterruptTest.cpp b/lib/cpp/test/TPipeInterruptTest.cpp new file mode 100644 index 00000000000..b0e246db160 --- /dev/null +++ b/lib/cpp/test/TPipeInterruptTest.cpp @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +using apache::thrift::transport::TPipeServer; +using apache::thrift::transport::TPipe; +using apache::thrift::transport::TTransport; +using apache::thrift::transport::TTransportException; + +BOOST_AUTO_TEST_SUITE(TPipeInterruptTest) + +// TODO: duplicate the test cases in TSocketInterruptTest for pipes, +// once pipes implement interruptChildren + +BOOST_AUTO_TEST_CASE(test_interrupt_before_accept) { + TPipeServer pipe1("TPipeInterruptTest"); + pipe1.listen(); + pipe1.interrupt(); + BOOST_CHECK_THROW(pipe1.accept(), TTransportException); +} + +static void acceptWorker(TPipeServer *pipe) { + try + { + for (;;) + { + boost::shared_ptr temp = pipe->accept(); + } + } + catch (...) {/*just want to make sure nothing crashes*/ } +} + +static void interruptWorker(TPipeServer *pipe) { + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + pipe->interrupt(); +} + +BOOST_AUTO_TEST_CASE(stress_pipe_accept_interruption) { + int interruptIters = 100; + + for (int i = 0; i < interruptIters; ++i) + { + TPipeServer pipeServer("TPipeInterruptTest"); + pipeServer.listen(); + boost::thread acceptThread(boost::bind(acceptWorker, &pipeServer)); + boost::thread interruptThread(boost::bind(interruptWorker, &pipeServer)); + try + { + for (;;) + { + TPipe client("TPipeInterruptTest"); + client.setConnectTimeout(1); + client.open(); + } + } catch (...) { /*just testing for crashes*/ } + interruptThread.join(); + acceptThread.join(); + } +} + +BOOST_AUTO_TEST_SUITE_END()