1 //  templated callback system
2 //  Copyright (C) 2008, 2009 Tim Blechmann
3 //
4 //  This program is free software; you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation; either version 2 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; see the file COPYING.  If not, write to
16 //  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 //  Boston, MA 02111-1307, USA.
18 
19 #pragma once
20 
21 #include <memory>
22 #include <exception>
23 #include <iostream>
24 
25 #include <boost/checked_delete.hpp>
26 
27 #include <boost/lockfree/spsc_queue.hpp>
28 #include <boost/lockfree/queue.hpp>
29 
30 
31 namespace nova {
32 
33 /** \brief simple templated callback system, using a lockfree fifo */
34 template <class callback_type, bool mpmc = true, class callback_deleter = boost::checked_deleter<callback_type>>
35 class callback_system : private callback_deleter {
36     typedef typename boost::mpl::if_c<mpmc, boost::lockfree::queue<callback_type*>,
37                                       boost::lockfree::spsc_queue<callback_type*>>::type queue_type;
38 
39 public:
callback_system(size_t element_count=2048)40     callback_system(size_t element_count = 2048): callbacks(element_count) {}
41 
42     /** \brief adds a new Callback to the Scheduler, threadsafe */
add_callback(callback_type * cb)43     inline void add_callback(callback_type* cb) { callbacks.push(cb); }
44 
45     /** \brief run all callbacks */
run_callbacks(void)46     inline void run_callbacks(void) {
47         callbacks.consume_all([this](callback_type* cb) { run_callback(cb); });
48     }
49 
50     /** \brief run one callback
51      *
52      * assumes, that the queue contains at least one callback
53      *
54      * */
run_callback(void)55     void run_callback(void) {
56         callbacks.consume_one([this](callback_type* cb) { run_callback(cb); });
57     }
58 
59 private:
60     /** run a callback, handle exceptions */
run_callback(callback_type * runme)61     bool run_callback(callback_type* runme) {
62         bool ret;
63         try {
64             runme->run();
65             ret = true;
66         } catch (std::exception const& e) {
67             std::cout << "unhandled exception while running callback: " << e.what() << std::endl;
68             ret = false;
69         }
70         callback_deleter::operator()(runme);
71         return ret;
72     }
73 
74 protected:
75     queue_type callbacks; /**< \brief fifo for callbacks */
76 };
77 
78 } /* namespace nova */
79