First take at making the lot thread-safe.
[beacon-ss.git] / beacon / event_loop.hpp
blob821a2119fcb51b760860271084ca09e19822b040
1 /**
2 * beacon
3 * Author: Lukas Krejci <krejci.l@centrum.cz>, (C) 2008
4 * Copyright: See COPYING file that comes with this distribution
5 */
7 #ifndef BEACON_EVENT_LOOP_H
8 #define BEACON_EVENT_LOOP_H
10 #include <beacon/invokable.hpp>
11 #include <beacon/detail/in_loop_invoke.hpp>
12 #include <beacon/detail/quick_wait.hpp>
13 #include <boost/thread.hpp>
14 #include <boost/bind.hpp>
15 #include <boost/type_traits/add_pointer.hpp>
16 #include <deque>
18 extern "C" {
19 #include <atomic_ops.h>
22 namespace beacon {
24 /**
25 * Event loop is a thread that invokes slots for signals.
26 * When connecting a slot to signal::signal
27 * one can specify an event loop that the slot will be invoked
28 * in.
29 * This is to support thread-safe signals&slots mechanism.
30 * The invocations are thread safe as long as all the signals
31 * are connected to a slot with the same event loop and
32 * all the arguments of the signal are copy-constructible (with deep
33 * copying semantics). Care must be taken when the arguments are
34 * references or pointers as it is not guaranteed when the slots
35 * will actually be invoked after the signal has been emitted.
37 class event_loop {
38 public:
39 typedef invokable * ev_type;
41 /**
42 * A new thread is started to handle this event loop.
44 event_loop() :
45 _queue_guard(AO_TS_INITIALIZER),
46 _running(true),
47 _finished(false)
50 /**
51 * This call does NOT block until the underlying thread finishes.
52 * It just destroys the event_loop object without stopping
53 * the underlying thread. Be sure to call @link join method before
54 * the event_loop is destroyed.
56 ~event_loop() {
57 if (_thread) delete _thread;
60 /**
61 * Enqueues given invokable to be executed in the event loop thread at some
62 * point in the future.
63 * <p>
64 * The event loop takes over the ownership of the invokable once it is passed
65 * to this method. Therefore the invokable must not be destroyed by the user code
66 * once passed to this method.
68 * @param invokable the invokable object to put into the event loop queue.
70 void enqueue(ev_type invokable);
72 /**
73 * Removes invokables identified by given token from the event loop queue.
75 * @param token the token of the invokable to remove from the queue.
77 * @return how many invokables have been removed from the queue.
79 unsigned dequeue(invokable::token_type token);
81 /**
82 * Starts the event loop. The events can be enqueued and dequeued before
83 * the event loop is started but they won't be processed until it is.
85 void start() {
86 _thread = new boost::thread(boost::bind(&event_loop::run, this));
89 /**
90 * Joins the event loop thread. If the thread is started using the {@link start} method
91 * while another thread is executing this method, the result is undefined.
93 void join();
94 private:
95 //list of events to process
96 std::deque<ev_type> _events;
98 //list of recently dequeued events that need destroyed
99 std::deque<ev_type> _dequeued;
101 //the thread we're executing the events in
102 boost::thread * _thread;
104 //the queue modification guard
105 volatile AO_TS_t _queue_guard;
107 //controlling the thread alive-state
108 bool _running;
109 bool _finished;
111 //main loop
112 void run();
116 * A helper class to enqueue function calls in the event loop.
118 template<typename Signature>
119 struct enqueue {
122 * A helper structure to represent the return type of the enqueue::invoke method
123 * more easily.
125 template<typename F>
126 struct invokable {
127 typedef typename detail::in_loop_wrapper_future_pointer<F, typename boost::add_pointer<Signature>::type> type;
131 * A helper structure to represent the return type of the enqueue::call method
132 * more easily.
134 template<typename F>
135 struct callable {
136 typedef typename detail::in_loop_wrapper_no_future<F, typename boost::add_pointer<Signature>::type> type;
140 * Using this function one can obtain a function object that
141 * when invoked enqueues the actual computation in the provided
142 * event loop and returns a pointer to a future object that can be used
143 * to obtain the return value. The receiver is responsible for destroying
144 * that future object afterwards.
145 * @param el the event_loop to be used
146 * @param f the function to be called in event_loop
147 * @param token a token uniquely identifying the function. This token is
148 * then used in event_loop disconnect method.
149 * @return a function object with operator () defined as:
150 * \c beacon::future<R> * operator()(ARGS)
151 * \endcode, where R is the
152 * return type of the supplied function and ARGS are its argument types.
154 template<typename F>
155 static typename invokable<F>::type invoke(event_loop & el, F const & f, beacon::invokable::token_type token) {
156 return typename invokable<F>::type(el, &f, token);
160 * Using this function one can obtain a function object that
161 * when invoked enqueues the actual computation in the provided
162 * event loop and is not able to query the result in any manner.
163 * Note that this is by far the fastest method and should be used
164 * preferably.
165 * @param el the event_loop to be used
166 * @param f the function to be called in event_loop
167 * @param token a token uniquely identifying the function. This token is
168 * then used in event_loop disconnect method.
169 * @return a function object with operator () defined as:
170 * \c void * operator()(ARGS)
171 * \endcode, where ARGS are argument types of the supplied function f.
173 template<typename F>
174 static typename callable<F>::type call(event_loop & el, F const & f, beacon::invokable::token_type token) {
175 return typename callable<F>::type(el, &f, token);
179 } //namespage
181 #endif