Initial commit for ProcControlAPI on BG/Q
[dyninst.git] / proccontrol / src / generator.C
1 /*
2  * Copyright (c) 1996-2011 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 #include "proccontrol/h/Generator.h"
32 #include "proccontrol/h/Event.h"
33 #include "proccontrol/h/Mailbox.h"
34 #include "proccontrol/h/Process.h"
35 #include "proccontrol/src/int_process.h"
36 #include "proccontrol/src/procpool.h"
37
38 #include "common/h/dthread.h"
39
40 #include <assert.h>
41
42 using namespace std;
43
44 std::set<Generator::gen_cb_func_t> Generator::CBs;
45 Mutex *Generator::cb_lock;
46
47 /*
48  * Library deinitialization
49  *
50  * Note: it is crucial that this variable is located here because it guarantees
51  * that the threads will be stopped before destructing the CBs collection and
52  * therefore avoiding a problem where the generator will continue to run but
53  * the CBs collection has already been destructed
54  */
55 static int_cleanup cleanup;
56
57 int_cleanup::~int_cleanup() {
58     // First, stop the handler thread if necessary
59     MTManager *tmpMt = mt();
60     if( tmpMt ) tmpMt->stop();
61
62     // Second, stop the generator
63     Generator::stopDefaultGenerator();
64 }
65
66 Generator::Generator(std::string name_) :
67    state(none),
68    name(name_)
69 {
70    if (!cb_lock) cb_lock = new Mutex();
71 }
72
73 Generator::~Generator()
74 {
75    setState(exiting);
76 }
77
78 void Generator::stopDefaultGenerator() {
79    Generator *gen = Generator::getDefaultGenerator();
80    if (gen) delete gen;
81 }
82
83 void Generator::registerNewEventCB(void (*func)())
84 {
85    if (!cb_lock) cb_lock = new Mutex();
86    Generator::cb_lock->lock();
87    CBs.insert(func);
88    Generator::cb_lock->unlock();
89 }
90
91 void Generator::removeNewEventCB(void (*func)())
92 {
93    if (!cb_lock) cb_lock = new Mutex();
94    Generator::cb_lock->lock();
95    std::set<gen_cb_func_t>::iterator i = CBs.find(func);
96    if (i != CBs.end())
97       CBs.erase(i);
98    Generator::cb_lock->unlock();
99 }
100
101 bool Generator::isExitingState()
102 {
103    return (state == error || state == exiting);
104 }
105
106 void Generator::setState(Generator::state_t new_state)
107 {
108    if (isExitingState())
109       return;
110    state = new_state;
111 }
112
113 bool Generator::getEvent(bool block, vector<ArchEvent *> &events)
114 {
115    //This function can be optionally overloaded by a platform
116    // that may return multiple events.  Otherwise, it just 
117    // uses the single-event interface and always returns a 
118    // set of size 1 or 0.
119    ArchEvent *ev = getEvent(block);
120    if (!ev)
121       return false;
122    events.push_back(ev);
123    return true;
124 }
125
126 bool Generator::getAndQueueEventInt(bool block)
127 {
128    bool result = true;
129    vector<Event::ptr> events;
130    vector<ArchEvent *> archEvents;
131
132    setState(process_blocked);
133    result = processWait(block);
134    if (isExitingState()) {
135       pthrd_printf("Generator exiting after processWait\n");
136       result = false;
137       goto done;
138    }
139    if (!result) {
140       pthrd_printf("getAndQueueEventInt returning due to processWait call\n");
141       goto done;
142    }
143
144    setState(system_blocked);
145    result = getEvent(block, archEvents);
146    if (isExitingState()) {
147       pthrd_printf("Generator exiting after getEvent\n");
148       result = false;
149       goto done;
150    }
151    if (!result) {
152       pthrd_printf("Error. Unable to recieve event\n");
153       result = false;
154       goto done;
155    }
156
157    setState(decoding);
158    ProcPool()->condvar()->lock();
159
160    for (vector<ArchEvent *>::iterator i = archEvents.begin(); i != archEvents.end(); i++) {
161       ArchEvent *arch_event = *i;
162       for (decoder_set_t::iterator j = decoders.begin(); j != decoders.end(); j++) {
163          Decoder *decoder = *j;
164          bool result = decoder->decode(arch_event, events);
165          if (result)
166             break;
167       }
168    }
169
170    setState(statesync);
171    for (vector<Event::ptr>::iterator i = events.begin(); i != events.end(); i++) {
172       Event::ptr event = *i;
173       event->getProcess()->llproc()->updateSyncState(event, true);
174    }
175
176    ProcPool()->condvar()->unlock();
177
178    setState(queueing);
179    for (vector<Event::ptr>::iterator i = events.begin(); i != events.end(); i++) {
180       mbox()->enqueue(*i);
181       Generator::cb_lock->lock();
182       for (set<gen_cb_func_t>::iterator j = CBs.begin(); j != CBs.end(); j++) {
183          (*j)();
184       }
185       Generator::cb_lock->unlock(); 
186    }
187
188    result = true;
189  done:
190    setState(none);
191    return result;
192 }
193
194 bool Generator::plat_skipGeneratorBlock()
195 {
196    //Default, do nothing.  May be over-written
197    return false;
198 }
199
200 bool Generator::hasLiveProc()
201 {
202    if (plat_skipGeneratorBlock()) {
203       return true;
204    }
205
206    int num_running_threads = Counter::globalCount(Counter::GeneratorRunningThreads);
207    int num_non_exited_threads = Counter::globalCount(Counter::GeneratorNonExitedThreads);
208    int num_force_generator_blocking = Counter::globalCount(Counter::ForceGeneratorBlock);
209
210    if (num_running_threads) {
211       pthrd_printf("Generator has running threads, returning true from hasLiveProc\n");
212       return true;
213    }
214    if (!num_non_exited_threads) {
215       pthrd_printf("Generator has all exited threads, returning false from hasLiveProc\n");
216       return false;
217    }
218    if (num_force_generator_blocking) {
219       pthrd_printf("Generator is forced into blocking state, returning true from hasLiveProc\n");
220       return true;
221    }
222    pthrd_printf("All threads stopped, returing false from hasLiveProc\n");
223    return false;
224 }
225
226 struct GeneratorMTInternals
227 {
228    GeneratorMTInternals() {}
229
230    //Start-up synchronization
231    CondVar init_cond;
232
233    DThread thrd;
234 };
235
236 static void start_generator(void *g)
237 {
238    GeneratorMT *gen = (GeneratorMT *) g;
239    gen->start();
240 }
241
242 GeneratorMT::GeneratorMT(std::string name_) :
243    Generator(name_)
244 {
245    //Make sure these structures exist before any generators run.
246    mbox();
247    ProcPool();
248
249    sync = new GeneratorMTInternals();
250 }
251
252 void GeneratorMT::launch()
253 {
254    sync->init_cond.lock();
255    state = initializing;
256    sync->thrd.spawn(start_generator, this);
257    while (state == initializing)
258       sync->init_cond.wait();
259    sync->init_cond.unlock();
260
261    if (state == error) {
262       pthrd_printf("Error creating generator\n");
263    }
264 }
265
266 GeneratorMT::~GeneratorMT()
267 {
268    setState(exiting);
269
270    // Wake up the generator thread if it is waiting for processes
271    ProcPool()->condvar()->lock();
272    ProcPool()->condvar()->signal();
273    ProcPool()->condvar()->unlock();
274
275    sync->thrd.join();
276    delete sync;
277    sync = NULL;
278 }
279
280 void GeneratorMT::start() 
281 {
282    setGeneratorThread(DThread::self());
283    pthrd_printf("Generator started on thread %lx\n", DThread::self());
284    bool result;
285
286    sync->init_cond.lock();
287    result = initialize();
288    if (!result) {
289       pthrd_printf("Error initializing Generator\n");
290       setState(error);
291    }
292    else {
293       setState(none);
294    }
295    sync->init_cond.signal();
296    sync->init_cond.unlock();
297
298    if (result) {
299       pthrd_printf("Starting main loop of generator thread\n");
300       main();
301    }
302    pthrd_printf("Generator thread exiting\n");
303 }
304
305 void GeneratorMT::main()
306 {
307    while (!isExitingState()) {
308       bool result = getAndQueueEventInt(true);
309       if (!result && !isExitingState()) {
310          pthrd_printf("Error return in getAndQueueEventInt\n");
311       }
312    }
313 }
314
315 bool GeneratorMT::processWait(bool block)
316 {
317    ProcessPool *pp = ProcPool();
318    pp->condvar()->lock();
319    pthrd_printf("Checking for live processes\n");
320    while (!hasLiveProc() && !isExitingState()) {
321       pthrd_printf("Checked and found no live processes\n");
322       if (!block) {
323          pthrd_printf("Returning from non-blocking processWait\n");
324          return false;
325       }
326       pp->condvar()->wait();
327    }
328    pp->condvar()->unlock();
329    return true;
330 }
331
332 bool GeneratorMT::getAndQueueEvent(bool)
333 {
334    //Doesn't really make sense to be calling this for a MT
335    // generator--part of the point is that you don't have
336    // to call it.
337    return true;
338 }