1 #ifndef BOOST_STATECHART_FIFO_SCHEDULER_HPP_INCLUDED
2 #define BOOST_STATECHART_FIFO_SCHEDULER_HPP_INCLUDED
3 //////////////////////////////////////////////////////////////////////////////
4 // Copyright 2002-2006 Andreas Huber Doenni
5 // Distributed under the Boost Software License, Version 1.0. (See accompany-
6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //////////////////////////////////////////////////////////////////////////////
8 
9 
10 
11 #include <boost/statechart/event_base.hpp>
12 #include <boost/statechart/fifo_worker.hpp>
13 #include <boost/statechart/processor_container.hpp>
14 
15 #include <boost/intrusive_ptr.hpp>
16 #include <boost/noncopyable.hpp>
17 #include <boost/config.hpp> // BOOST_HAS_THREADS
18 
19 
20 
21 namespace boost
22 {
23 namespace statechart
24 {
25 
26 
27 
28 //////////////////////////////////////////////////////////////////////////////
29 template<
30   class FifoWorker = fifo_worker<>,
31   class Allocator = std::allocator< void > >
32 class fifo_scheduler : noncopyable
33 {
34   typedef processor_container<
35     fifo_scheduler, typename FifoWorker::work_item, Allocator > container;
36   public:
37     //////////////////////////////////////////////////////////////////////////
38     #ifdef BOOST_HAS_THREADS
fifo_scheduler(bool waitOnEmptyQueue=false)39     fifo_scheduler( bool waitOnEmptyQueue = false ) :
40       worker_( waitOnEmptyQueue )
41     {
42     }
43     #endif
44 
45     typedef typename container::processor_handle processor_handle;
46     typedef typename container::processor_context processor_context;
47 
48     template< class Processor >
create_processor()49     processor_handle create_processor()
50     {
51       processor_handle result;
52       work_item item =
53         container_.template create_processor< Processor >( result, *this );
54       worker_.queue_work_item( item );
55       return result;
56     }
57 
58     template< class Processor, typename Arg1 >
create_processor(Arg1 arg1)59     processor_handle create_processor( Arg1 arg1 )
60     {
61       processor_handle result;
62       work_item item = container_.template create_processor< Processor >(
63         result, *this, arg1 );
64       worker_.queue_work_item( item );
65       return result;
66     }
67 
68     template< class Processor, typename Arg1, typename Arg2 >
create_processor(Arg1 arg1,Arg2 arg2)69     processor_handle create_processor( Arg1 arg1, Arg2 arg2 )
70     {
71       processor_handle result;
72       work_item item = container_.template create_processor< Processor >(
73         result, *this, arg1, arg2 );
74       worker_.queue_work_item( item );
75       return result;
76     }
77 
78     template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
create_processor(Arg1 arg1,Arg2 arg2,Arg3 arg3)79     processor_handle create_processor( Arg1 arg1, Arg2 arg2, Arg3 arg3 )
80     {
81       processor_handle result;
82       work_item item = container_.template create_processor< Processor >(
83         result, *this, arg1, arg2, arg3 );
84       worker_.queue_work_item( item );
85       return result;
86     }
87 
88     template<
89       class Processor, typename Arg1, typename Arg2,
90       typename Arg3, typename Arg4 >
create_processor(Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4)91     processor_handle create_processor(
92       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
93     {
94       processor_handle result;
95       work_item item = container_.template create_processor< Processor >(
96         result, *this, arg1, arg2, arg3, arg4 );
97       worker_.queue_work_item( item );
98       return result;
99     }
100 
101     template<
102       class Processor, typename Arg1, typename Arg2,
103       typename Arg3, typename Arg4, typename Arg5 >
create_processor(Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5)104     processor_handle create_processor(
105       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
106     {
107       processor_handle result;
108       work_item item = container_.template create_processor< Processor >(
109         result, *this, arg1, arg2, arg3, arg4, arg5 );
110       worker_.queue_work_item( item );
111       return result;
112     }
113 
114     template<
115       class Processor, typename Arg1, typename Arg2,
116       typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
create_processor(Arg1 arg1,Arg2 arg2,Arg3 arg3,Arg4 arg4,Arg5 arg5,Arg6 arg6)117     processor_handle create_processor(
118       Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
119     {
120       processor_handle result;
121       work_item item = container_.template create_processor< Processor >(
122         result, *this, arg1, arg2, arg3, arg4, arg5, arg6 );
123       worker_.queue_work_item( item );
124       return result;
125     }
126 
destroy_processor(const processor_handle & processor)127     void destroy_processor( const processor_handle & processor )
128     {
129       work_item item = container_.destroy_processor( processor );
130       worker_.queue_work_item( item );
131     }
132 
initiate_processor(const processor_handle & processor)133     void initiate_processor( const processor_handle & processor )
134     {
135       work_item item = container_.initiate_processor( processor );
136       worker_.queue_work_item( item );
137     }
138 
terminate_processor(const processor_handle & processor)139     void terminate_processor( const processor_handle & processor )
140     {
141       work_item item = container_.terminate_processor( processor );
142       worker_.queue_work_item( item );
143     }
144 
145     typedef intrusive_ptr< const event_base > event_ptr_type;
146 
queue_event(const processor_handle & processor,const event_ptr_type & pEvent)147     void queue_event(
148       const processor_handle & processor, const event_ptr_type & pEvent )
149     {
150       work_item item = container_.queue_event( processor, pEvent );
151       worker_.queue_work_item( item );
152     }
153 
154     typedef typename FifoWorker::work_item work_item;
155 
156     // We take a non-const reference so that we can move (i.e. swap) the item
157     // into the queue, what avoids copying the (possibly heap-allocated)
158     // implementation object inside work_item.
queue_work_item(work_item & item)159     void queue_work_item( work_item & item )
160     {
161       worker_.queue_work_item( item );
162     }
163 
164     // Convenience overload so that temporary objects can be passed directly
165     // instead of having to create a work_item object first. Under most
166     // circumstances, this will lead to one unnecessary copy of the
167     // function implementation object.
queue_work_item(const work_item & item)168     void queue_work_item( const work_item & item )
169     {
170       worker_.queue_work_item( item );
171     }
172 
terminate()173     void terminate()
174     {
175       worker_.terminate();
176     }
177 
178     // Is not mutex-protected! Must only be called from the thread that also
179     // calls operator().
terminated() const180     bool terminated() const
181     {
182       return worker_.terminated();
183     }
184 
operator ()(unsigned long maxEventCount=0)185     unsigned long operator()( unsigned long maxEventCount = 0 )
186     {
187       return worker_( maxEventCount );
188     }
189 
190   private:
191     //////////////////////////////////////////////////////////////////////////
192     container container_;
193     FifoWorker worker_;
194 };
195 
196 
197 
198 } // namespace statechart
199 } // namespace boost
200 
201 
202 
203 #endif
204