Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / runtime / gr_top_block_impl.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gr_top_block.h>
28 #include <gr_top_block_impl.h>
29 #include <gr_flat_flowgraph.h>
30 #include <gr_scheduler_sts.h>
31 #include <gr_scheduler_tpb.h>
32
33 #include <stdexcept>
34 #include <iostream>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38
39 #define GR_TOP_BLOCK_IMPL_DEBUG 0
40
41
42 typedef gr_scheduler_sptr (*scheduler_maker)(gr_flat_flowgraph_sptr ffg);
43
44 static struct scheduler_table {
45   const char           *name;
46   scheduler_maker       f;
47 } scheduler_table[] = {
48   { "TPB",      gr_scheduler_tpb::make },       // first entry is default
49   { "STS",      gr_scheduler_sts::make }
50 };
51
52 static gr_scheduler_sptr
53 make_scheduler(gr_flat_flowgraph_sptr ffg)
54 {
55   static scheduler_maker  factory = 0;
56
57   if (factory == 0){
58     char *v = getenv("GR_SCHEDULER");
59     if (!v)
60       factory = scheduler_table[0].f;   // use default
61     else {
62       for (size_t i = 0; i < sizeof(scheduler_table)/sizeof(scheduler_table[0]); i++){
63         if (strcmp(v, scheduler_table[i].name) == 0){
64           factory = scheduler_table[i].f;
65           break;
66         }
67       }
68       if (factory == 0){
69         std::cerr << "warning: Invalid GR_SCHEDULER environment variable value \""
70                   << v << "\".  Using \"" << scheduler_table[0].name << "\"\n";
71         factory = scheduler_table[0].f;
72       }
73     }
74   }
75   return factory(ffg);
76 }
77
78
79 gr_top_block_impl::gr_top_block_impl(gr_top_block *owner) 
80   : d_owner(owner), d_ffg(),
81     d_state(IDLE), d_lock_count(0)
82 {
83 }
84
85 gr_top_block_impl::~gr_top_block_impl()
86 {
87   d_owner = 0;
88 }
89
90 void
91 gr_top_block_impl::start()
92 {
93   gr_lock_guard l(d_mutex);
94
95   if (d_state != IDLE)
96     throw std::runtime_error("top_block::start: top block already running or wait() not called after previous stop()");
97
98   if (d_lock_count > 0)
99     throw std::runtime_error("top_block::start: can't start with flow graph locked");
100
101   // Create new flat flow graph by flattening hierarchy
102   d_ffg = d_owner->flatten();
103
104   // Validate new simple flow graph and wire it up
105   d_ffg->validate();
106   d_ffg->setup_connections();
107
108   d_scheduler = make_scheduler(d_ffg);
109   d_state = RUNNING;
110 }
111
112 void 
113 gr_top_block_impl::stop()
114 {
115   if (d_scheduler)
116     d_scheduler->stop();
117 }
118
119
120 void
121 gr_top_block_impl::wait()
122 {
123   if (d_scheduler)
124     d_scheduler->wait();
125
126   d_state = IDLE;
127 }
128
129 // N.B. lock() and unlock() cannot be called from a flow graph thread or
130 // deadlock will occur when reconfiguration happens
131 void
132 gr_top_block_impl::lock()
133 {
134   gr_lock_guard lock(d_mutex);
135   d_lock_count++;
136 }
137
138 void
139 gr_top_block_impl::unlock()
140 {
141   gr_lock_guard lock(d_mutex);
142
143   if (d_lock_count <= 0){
144     d_lock_count = 0;           // fix it, then complain
145     throw std::runtime_error("unpaired unlock() call");
146   }
147
148   d_lock_count--;
149   if (d_lock_count > 0 || d_state == IDLE) // nothing to do
150     return;
151
152   restart();
153 }
154
155 /*
156  * restart is called with d_mutex held
157  */
158 void
159 gr_top_block_impl::restart()
160 {
161   stop();                    // Stop scheduler and wait for completion
162   wait();
163
164   // Create new simple flow graph
165   gr_flat_flowgraph_sptr new_ffg = d_owner->flatten();        
166   new_ffg->validate();                 // check consistency, sanity, etc
167   new_ffg->merge_connections(d_ffg);   // reuse buffers, etc
168   d_ffg = new_ffg;
169
170   // Create a new scheduler to execute it
171   d_scheduler = make_scheduler(d_ffg);
172   d_state = RUNNING;
173 }
174
175 void
176 gr_top_block_impl::dump()
177 {
178   if (d_ffg)
179     d_ffg->dump();
180 }