proccontrol: Fix Coverity UNINIT_CTOR errors
[dyninst.git] / proccontrol / src / generator.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30 #include "proccontrol/h/Generator.h"
31 #include "proccontrol/h/Event.h"
32 #include "proccontrol/h/Mailbox.h"
33 #include "proccontrol/h/PCProcess.h"
34 #include "proccontrol/src/int_process.h"
35 #include "proccontrol/src/procpool.h"
36
37 #include "common/src/dthread.h"
38
39 #include <assert.h>
40 #include <iostream>
41
42 using namespace std;
43
44 std::set<Generator::gen_cb_func_t> Generator::CBs;
45 Mutex *Generator::cb_lock;
46
47 bool Generator::startedAnyGenerator = false;
48
49 /*
50  * Library deinitialization
51  *
52  * Note: it is crucial that this variable is located here because it guarantees
53  * that the threads will be stopped before destructing the CBs collection and
54  * therefore avoiding a problem where the generator will continue to run but
55  * the CBs collection has already been destructed
56  */
57 static int_cleanup cleanup;
58
59 int_cleanup::~int_cleanup() {
60     // First, stop the handler thread if necessary
61     MTManager *tmpMt = mt();
62     if( tmpMt ) tmpMt->stop();
63
64     // Second, stop the generator
65     Generator::stopDefaultGenerator();
66 }
67
68 Generator::Generator(std::string name_) :
69    state(none),
70    m_Event(NULL),
71    name(name_),
72    eventBlock_(false)
73 {
74    if (!cb_lock) cb_lock = new Mutex();
75    startedAnyGenerator = true;
76 }
77
78 Generator::~Generator()
79 {
80    setState(exiting);
81 }
82
83 void Generator::forceEventBlock() {
84    pthrd_printf("Forcing generator to block in waitpid\n");
85    eventBlock_ = true;
86    ProcPool()->condvar()->broadcast();
87 }
88
89 void Generator::stopDefaultGenerator() {
90    if (!startedAnyGenerator)
91       return;
92
93    Generator *gen = Generator::getDefaultGenerator();
94    if (gen) delete gen;
95 }
96
97 void Generator::registerNewEventCB(void (*func)())
98 {
99    if (!cb_lock) cb_lock = new Mutex();
100    Generator::cb_lock->lock();
101    CBs.insert(func);
102    Generator::cb_lock->unlock();
103 }
104
105 void Generator::removeNewEventCB(void (*func)())
106 {
107    if (!cb_lock) cb_lock = new Mutex();
108    Generator::cb_lock->lock();
109    std::set<gen_cb_func_t>::iterator i = CBs.find(func);
110    if (i != CBs.end())
111       CBs.erase(i);
112    Generator::cb_lock->unlock();
113 }
114
115 bool Generator::isExitingState()
116 {
117    return (state == error || state == exiting);
118 }
119
120 #if defined(STR_CASE)
121 #undef STR_CASE
122 #endif
123 #define STR_CASE(X) case Generator::X: return #X
124
125 static const char *generatorStateStr(Generator::state_t s) {
126    switch (s) {
127       STR_CASE(none);
128       STR_CASE(initializing);
129       STR_CASE(process_blocked);
130       STR_CASE(system_blocked);
131       STR_CASE(decoding);
132       STR_CASE(statesync);
133       STR_CASE(handling);
134       STR_CASE(queueing);
135       STR_CASE(error);
136       STR_CASE(exiting);
137    }
138    assert(0);
139    return NULL;
140 }
141
142 void Generator::setState(Generator::state_t new_state)
143 {
144    pthrd_printf("Setting generator state to %s\n", generatorStateStr(new_state));
145    if (isExitingState())
146       return;
147    state = new_state;
148 }
149
150 ArchEvent* Generator::getCachedEvent() 
151 {
152         return m_Event;
153 }
154
155 void Generator::setCachedEvent(ArchEvent* ae)
156 {
157         m_Event = ae;
158 }
159
160 bool Generator::getMultiEvent(bool block, vector<ArchEvent *> &events)
161 {
162    //This function can be optionally overloaded by a platform
163    // that may return multiple events.  Otherwise, it just 
164    // uses the single-event interface and always returns a 
165    // set of size 1 or 0.
166    ArchEvent *ev = getEvent(block);
167    if (!ev)
168       return false;
169    events.push_back(ev);
170    eventBlock_ = false;
171    return true;
172 }
173
174 bool Generator::getAndQueueEventInt(bool block)
175 {
176    bool result = true;
177    //static ArchEvent *arch_event = NULL;
178    ArchEvent* arch_event = getCachedEvent();
179    vector<Event::ptr> events;
180    vector<ArchEvent *> archEvents;
181
182    if (isExitingState()) {
183       pthrd_printf("Generator exiting before processWait\n");
184       result = false;
185       goto done;
186    }
187    setState(process_blocked);
188    result = processWait(block);
189    if (isExitingState()) {
190       pthrd_printf("Generator exiting after processWait\n");
191       result = false;
192       goto done;
193    }
194    if (!result) {
195            pthrd_printf("Generator exiting after processWait returned false\n");
196            result = false;
197       goto done;
198    }
199    result = plat_continue(arch_event);
200    if(!result) {
201            pthrd_printf("Generator exiting after plat_continue returned false\n");
202            result = false;
203            goto done;
204    }
205    setState(system_blocked);
206
207    pthrd_printf("About to getEvent()\n");
208    result = getMultiEvent(block, archEvents);
209    pthrd_printf("Got event\n");
210    if (isExitingState()) {
211       pthrd_printf("Generator exiting after getEvent\n");
212       result = false;
213       goto done;
214    }
215    if (!result) {
216       pthrd_printf("Error. Unable to recieve event\n");
217       result = false;
218       goto done;
219    }
220
221    setState(decoding);
222    //mbox()->lock_queue();
223    ProcPool()->condvar()->lock();
224
225    for (vector<ArchEvent *>::iterator i = archEvents.begin(); i != archEvents.end(); i++) {
226            arch_event = *i;
227       for (decoder_set_t::iterator j = decoders.begin(); j != decoders.end(); j++) {
228          Decoder *decoder = *j;
229          bool result = decoder->decode(arch_event, events);
230          if (result)
231             break;
232       }
233    }
234
235    setState(statesync);
236    for (vector<Event::ptr>::iterator i = events.begin(); i != events.end(); i++) {
237       Event::ptr event = *i;
238           if(event) {
239               event->getProcess()->llproc()->updateSyncState(event, true);
240           }
241    }
242
243    ProcPool()->condvar()->unlock();
244
245    setState(queueing);
246    for (vector<Event::ptr>::iterator i = events.begin(); i != events.end(); ++i) {
247       mbox()->enqueue(*i);
248       Generator::cb_lock->lock();
249       for (set<gen_cb_func_t>::iterator j = CBs.begin(); j != CBs.end(); ++j) {
250          (*j)();
251       }
252       Generator::cb_lock->unlock(); 
253    }
254    //mbox()->unlock_queue();
255
256
257    result = true;
258  done:
259    setState(none);
260    setCachedEvent(arch_event);
261    return result;
262 }
263
264 bool Generator::plat_skipGeneratorBlock()
265 {
266    //Default, do nothing.  May be over-written
267    return false;
268 }
269
270 Generator::state_t Generator::getState()
271 {
272         return state;
273 }
274
275 // TODO: override this in Windows generator so that we use local counters
276 bool Generator::hasLiveProc()
277 {
278    pthrd_printf("Entry to generator::hasLiveProc()\n");
279    if (plat_skipGeneratorBlock()) {
280       return true;
281    }
282
283    int num_running_threads = Counter::globalCount(Counter::GeneratorRunningThreads);
284    int num_non_exited_threads = Counter::globalCount(Counter::GeneratorNonExitedThreads);
285    int num_force_generator_blocking = Counter::globalCount(Counter::ForceGeneratorBlock);
286
287    if (num_running_threads) {
288       pthrd_printf("Generator has running threads, returning true from hasLiveProc\n");
289       return true;
290    }
291    if (!num_non_exited_threads) {
292       pthrd_printf("Generator has all exited threads, returning false from hasLiveProc\n");
293       return false;
294    }
295    if (num_force_generator_blocking) {
296       bool override = true;
297 #if defined(os_linux)
298       // We only want to block if the mailbox is empty; otherwise we double up events
299       if (mbox()->size() > 0) override = false;
300 #endif
301       if (override) {
302          pthrd_printf("Forcing generator blocking\n");
303          return true;
304       }
305    }
306
307
308    pthrd_printf("No live processes, ret false\n");
309    return false;
310 }
311
312
313 struct GeneratorMTInternals
314 {
315    GeneratorMTInternals() {}
316
317    //Start-up synchronization
318    CondVar init_cond;
319
320    DThread thrd;
321 };
322 void GeneratorInternalJoin(GeneratorMTInternals *gen_int)
323 {
324   gen_int->thrd.join();
325 }
326
327 #if defined(os_windows)
328 static unsigned long WINAPI start_generator(void *g)
329 #else
330 static void start_generator(void *g)
331 #endif
332 {
333    GeneratorMT *gen = (GeneratorMT *) g;
334    gen->start();
335 #if defined(os_windows)
336    return 0;
337 #else
338    return;
339 #endif
340 }
341
342 GeneratorMT::GeneratorMT(std::string name_) :
343    Generator(name_)
344 {
345    //Make sure these structures exist before any generators run.
346    mbox();
347    ProcPool();
348
349    sync = new GeneratorMTInternals();
350 }
351
352 void GeneratorMT::lock()
353 {
354    sync->init_cond.lock();
355 }
356 void GeneratorMT::unlock()
357 {
358    sync->init_cond.unlock();
359 }
360 void GeneratorMT::launch()
361 {
362    sync->init_cond.lock();
363    setState(initializing);
364    sync->thrd.spawn(start_generator, this);
365    while (getState() == initializing)
366       sync->init_cond.wait();
367    sync->init_cond.unlock();
368
369    if (getState() == error) {
370       pthrd_printf("Error creating generator\n");
371    }
372 }
373
374 GeneratorMT::~GeneratorMT()
375 {
376    setState(exiting);
377
378    // Wake up the generator thread if it is waiting for processes
379    ProcPool()->condvar()->lock();
380    ProcPool()->condvar()->signal();
381    ProcPool()->condvar()->unlock();
382
383    sync->thrd.join();
384    delete sync;
385    sync = NULL;
386 }
387
388 void GeneratorMT::start() 
389 {
390    setGeneratorThread(DThread::self());
391    pthrd_printf("Generator started on thread %lx\n", DThread::self());
392    bool result;
393
394    sync->init_cond.lock();
395    result = initialize();
396    if (!result) {
397       pthrd_printf("Error initializing Generator\n");
398       setState(error);
399    }
400    else {
401       setState(none);
402    }
403    plat_start();
404    if(getState() == error) result = false;
405    sync->init_cond.signal();
406    sync->init_cond.unlock();
407
408    if (result) {
409       pthrd_printf("Starting main loop of generator thread\n");
410       main();
411    }
412    pthrd_printf("Generator thread exiting\n");
413 }
414
415 void GeneratorMT::main()
416 {
417    while (!isExitingState()) {
418       bool result = getAndQueueEventInt(true);
419       if (!result && !isExitingState()) {
420          pthrd_printf("Error return in getAndQueueEventInt\n");
421       }
422    }
423 }
424
425 bool GeneratorMT::processWait(bool block)
426 {
427    ProcessPool *pp = ProcPool();
428    pp->condvar()->lock();
429    pthrd_printf("Checking for live processes\n");
430    while (!hasLiveProc() && !isExitingState()) {
431       pthrd_printf("Checked and found no live processes\n");
432       if (!block) {
433          pthrd_printf("Returning from non-blocking processWait\n");
434          pp->condvar()->broadcast();
435          pp->condvar()->unlock();
436          return false;
437       }
438       pp->condvar()->wait();
439    }
440    pp->condvar()->broadcast();
441    pp->condvar()->unlock();
442    pthrd_printf("processWait returning true\n");
443    return true;
444 }
445
446 bool GeneratorMT::getAndQueueEvent(bool)
447 {
448    //Doesn't really make sense to be calling this for a MT
449    // generator--part of the point is that you don't have
450    // to call it.
451    return true;
452 }
453
454 GeneratorMTInternals *GeneratorMT::getInternals()
455 {
456   return sync;
457 }