summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/sys
diff options
context:
space:
mode:
authorAlan Conway <aconway@apache.org>2008-06-06 20:23:28 +0000
committerAlan Conway <aconway@apache.org>2008-06-06 20:23:28 +0000
commitfb1f5c770c551fe526adf5b860dd72cf5eb07311 (patch)
tree79a0d3ccb278e51b9ec5213b038b903d768c2727 /cpp/src/qpid/sys
parent76c922baf182bb367feed2ec014e7cab9db7f79d (diff)
downloadqpid-python-fb1f5c770c551fe526adf5b860dd72cf5eb07311.tar.gz
Added exceptions to sys::Waitable.
Fixed client side deadlock involving client::Bounds. Fixed incorrect exception messages during connection shutdown. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@664114 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/qpid/sys')
-rw-r--r--cpp/src/qpid/sys/ExceptionHolder.h75
-rw-r--r--cpp/src/qpid/sys/Waitable.h55
2 files changed, 121 insertions, 9 deletions
diff --git a/cpp/src/qpid/sys/ExceptionHolder.h b/cpp/src/qpid/sys/ExceptionHolder.h
new file mode 100644
index 0000000000..cfb971411e
--- /dev/null
+++ b/cpp/src/qpid/sys/ExceptionHolder.h
@@ -0,0 +1,75 @@
+#ifndef QPID_EXCEPTIONHOLDER_H
+#define QPID_EXCEPTIONHOLDER_H
+
+/*
+ *
+ * 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 "qpid/memory.h"
+#include <boost/shared_ptr.hpp>
+
+
+namespace qpid {
+namespace sys {
+
+struct Raisable {
+ virtual ~Raisable() {};
+ virtual void raise() const=0;
+ virtual std::string what() const=0;
+};
+
+/**
+ * Holder for exceptions. Allows the thread that notices an error condition to
+ * create an exception and store it to be thrown by another thread.
+ */
+class ExceptionHolder : public Raisable {
+ public:
+ ExceptionHolder() {}
+ // Use default copy & assign.
+
+ /** Take ownership of ex */
+ template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); }
+ template <class Ex> ExceptionHolder(const boost::shared_ptr<Ex>& ex) { wrap(ex.release()); }
+
+ template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; }
+ template <class Ex> ExceptionHolder& operator=(boost::shared_ptr<Ex> ex) { wrap(ex.release()); return *this; }
+
+ void raise() const { if (wrapper.get()) wrapper->raise() ; }
+ std::string what() const { return wrapper->what(); }
+ bool empty() const { return !wrapper.get(); }
+ operator bool() const { return !empty(); }
+ void reset() { wrapper.reset(); }
+
+ private:
+ template <class Ex> struct Wrapper : public Raisable {
+ Wrapper(Ex* ptr) : exception(ptr) {}
+ void raise() const { throw *exception; }
+ std::string what() const { return exception->what(); }
+ boost::shared_ptr<Ex> exception;
+ };
+ template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); }
+ boost::shared_ptr<Raisable> wrapper;
+};
+
+
+}} // namespace qpid::sys
+
+
+#endif /*!QPID_EXCEPTIONHOLDER_H*/
diff --git a/cpp/src/qpid/sys/Waitable.h b/cpp/src/qpid/sys/Waitable.h
index 37392ed761..61b7e7d82b 100644
--- a/cpp/src/qpid/sys/Waitable.h
+++ b/cpp/src/qpid/sys/Waitable.h
@@ -21,8 +21,8 @@
*
*/
-#include "Monitor.h"
-
+#include "qpid/sys/Monitor.h"
+#include "qpid/sys/ExceptionHolder.h"
#include <assert.h>
namespace qpid {
@@ -31,14 +31,18 @@ namespace sys {
/**
* A monitor that keeps track of waiting threads. Threads declare a
* ScopedWait around wait() inside a ScopedLock to be considered
- * waiters.
+ * waiters.
+ *
+ * Allows waiting threads to be interrupted by an exception.
*/
class Waitable : public Monitor {
public:
Waitable() : waiters(0) {}
+ ~Waitable() { assert(waiters == 0); }
+
/** Use this inside a scoped lock around the
- * call to Monitor::wait to be counted as a waiter
+ * call to wait() to be counted as a waiter.
*/
struct ScopedWait {
Waitable& w;
@@ -46,22 +50,55 @@ class Waitable : public Monitor {
~ScopedWait() { if (--w.waiters==0) w.notifyAll(); }
};
- /** Block till there are no more ScopedWaits.
+ /** Block till there are no more waiters in ScopedWaits.
+ * waitWaiters() does not raise an exception even if waiters
+ * were interrupted by one.
*@pre Must be called inside a ScopedLock but NOT a ScopedWait.
*/
void waitWaiters() {
while (waiters != 0)
- wait();
+ Monitor::wait();
}
/** Returns the number of outstanding ScopedWaits.
* Must be called with the lock held.
*/
- size_t hasWaiters() { return waiters; }
-
+ size_t hasWaiters() const {
+ return waiters;
+ }
+
+ /** Set an execption to interrupt waiters in ScopedWait.
+ * Must be called with the lock held.
+ */
+ void setException(const ExceptionHolder& e) {
+ exception = e;
+ notifyAll();
+
+ }
+
+ /** Throws an exception if one is set before or during the wait. */
+ void wait() {
+ ExCheck e(exception);
+ Monitor::wait();
+ }
+
+ /** Throws an exception if one is set before or during the wait. */
+ bool wait(const AbsTime& absoluteTime) {
+ ExCheck e(exception);
+ return Monitor::wait(absoluteTime);
+ }
+
+ ExceptionHolder exception;
+
private:
- friend struct ScopedWait;
+ struct ExCheck {
+ const ExceptionHolder& exception;
+ ExCheck(const ExceptionHolder& e) : exception(e) { e.raise(); }
+ ~ExCheck() { exception.raise(); }
+ };
+
size_t waiters;
+ friend struct ScopedWait;
};
}} // namespace qpid::sys