Problem 1:
[dyninst.git] / dyninstAPI / src / mailbox.C
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  *
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  *
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  *
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  *
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include "dyninstAPI/src/mailbox.h"
43 #include "dyninstAPI/src/util.h"
44 #include "dyninstAPI/src/showerror.h"
45 #include "common/h/headers.h"
46 #include "dyninstAPI/src/os.h"
47 #if defined (os_windows)
48 #include <windows.h>
49 #endif
50 ThreadMailbox *eventmb = NULL;
51 ThreadMailbox *getMailbox()
52 {
53   if (eventmb == NULL) {
54     eventmb = new ThreadMailbox();
55   }
56   return eventmb;
57 }
58
59 extern eventLock *global_mutex;
60 eventLock::eventLock()
61 {
62 #if defined(os_windows)
63 #if 0
64 //HANDLE CreateMutex(
65 //  LPSECURITY_ATTRIBUTES lpMutexAttributes,
66 //  BOOL bInitialOwner,
67 //  LPCTSTR lpName )
68   mutex = CreateMutex(NULL, false /*no initial owner*/, NULL);
69   assert(mutex);
70 #endif
71   InitializeCriticalSection(&mutex);
72   InitializeCriticalSection(&waiter_lock);
73   num_waiters = 0;
74 //HANDLE CreateEvent(
75 //  LPSECURITY_ATTRIBUTES lpEventAttributes,
76 //  BOOL bManualReset,
77 //  BOOL bInitialState,
78 //  LPCTSTR lpName )
79
80   cond = CreateEvent(NULL, true /*true is manual reset, false for auto*/,
81                     false /*initially not in signalled state */,
82                     NULL /*name*/);
83   assert (cond);
84 #else
85   int err = 0;
86   pthread_mutexattr_t mutex_type;
87   if (0 != pthread_mutexattr_init(&mutex_type)) {
88    abort();
89   }
90   if (0 != pthread_mutexattr_settype(&mutex_type, PTHREAD_MUTEX_TYPE)) {
91     abort();
92   }
93   if (0 != pthread_mutex_init(&mutex, &mutex_type)) {
94    ERROR_BUFFER;
95     fprintf(stderr, "%s[%d]:  failed to init mutex: %s[%d]\n",
96             FILE__, __LINE__, STRERROR(err, buf), err);
97     abort();
98   }
99   pthread_cond_init(&cond, NULL);
100 #endif // !Windows
101   lock_depth = 0;
102 }
103
104 eventLock::~eventLock()
105 {
106 #if defined(os_windows)
107   DeleteCriticalSection(&mutex);  
108   DeleteCriticalSection(&waiter_lock);
109   CloseHandle(cond);
110 #else
111   pthread_mutex_destroy(&mutex);
112   pthread_cond_destroy(&cond);
113 #endif
114 }
115
116 int eventLock::_Lock(const char *__file__, unsigned int __line__)
117 {
118   int err = 0;
119   //fprintf(stderr, "%s[%d]: about to lock %p: from %s[%d]\n", FILE__, __LINE__, &mutex, __file__, __line__);
120
121 #if defined(os_windows)
122   EnterCriticalSection(&mutex);
123 #if 0
124   DWORD res = WaitForSingleObject(mutex, INFINITE);
125   assert(res == WAIT_OBJECT_0);
126   //  Other possible results for res are WAIT_TIMEOUT and WAIT_ABANDONED
127 #endif
128
129 #else
130   if(0 != (err = pthread_mutex_lock(&mutex))){
131     ERROR_BUFFER;
132     fprintf(stderr, "%s[%d]:  failed to lock mutex: %s[%d]\n",
133             __file__, __line__, STRERROR(err, buf), err);
134     return err;
135   }
136 #endif
137
138     if (lock_depth) {
139       if ((owner_id != getExecThreadID()) && (owner_id != -1UL)) {
140         fprintf(stderr, "%s[%d]:  FATAL MUTEX ERROR, lock obtained by 2 threads,\n",
141                 FILE__, __LINE__); 
142         const char *old_owner_name = getThreadStr(owner_id);
143         if (!old_owner_name) old_owner_name = "no-name";
144         fprintf(stderr, "\tnow: %s[%lu], previous: %s[%lu]\n", getThreadStr(getExecThreadID()),
145                 getExecThreadID(), old_owner_name, owner_id);
146         assert(0);
147       }
148     }
149     owner_id = getExecThreadID();
150     lock_depth++;
151     lock_stack_elem el;
152     el.file  = __file__;
153     el.line = __line__;
154     lock_stack.push_back(el);
155     
156
157   mutex_printf("%s[%d]:  lock obtained from %s[%d], depth = %d\n", FILE__, __LINE__, __file__, __line__, lock_depth);
158
159   return err;
160 }
161
162
163 int eventLock::_Trylock(const char *__file__, unsigned int __line__)
164 {
165   int err = 0;
166 #if defined(os_windows)
167   assert(0); 
168   lock_depth++;
169    //  need to look at result of tryEnter to see if we should increment lock_depth
170 #else
171   if(0 != (err = pthread_mutex_trylock(&mutex))){
172     if (EBUSY != err) {
173       ERROR_BUFFER;
174       //  trylock returns EBUSY immediately when lock cannot be obtained
175       fprintf(stderr, "%s[%d]:  failed to trylock mutex: %s[%d]\n",
176               __file__, __line__, STRERROR(err, buf), err);
177     }
178   }
179   else {
180     if (lock_depth) {
181       assert(owner_id == getExecThreadID());
182     }
183     owner_id = getExecThreadID();
184     lock_depth++;
185     lock_stack_elem el;
186     el.file = __file__;
187     el.line = __line__;
188     lock_stack.push_back(el);
189   }
190
191 #endif
192   return err;
193 }
194
195 int eventLock::_Unlock(const char *__file__, unsigned int __line__)
196 {
197   unsigned long old_owner_id = owner_id;
198   if (!lock_depth) {
199     fprintf(stderr, "%s[%d]:  MUTEX ERROR, attempt to unlock nonlocked mutex, at %s[%d]\n",
200             FILE__, __LINE__, __file__, __line__);
201     assert(0);
202   }
203   lock_depth--;
204   lock_stack_elem el = lock_stack[lock_stack.size() -1];
205   lock_stack.pop_back();
206   if (!lock_depth)
207     owner_id = -1UL;
208
209   mutex_printf("%s[%d]:  unlock issued from %s[%d], depth = %d\n", FILE__, __LINE__, __file__, __line__, lock_depth);
210
211 #if defined(os_windows)
212   LeaveCriticalSection(&mutex);
213 #if 0
214   assert(ReleaseMutex(mutex));
215 #endif
216 #else
217   int err = 0;
218   if(0 != (err = pthread_mutex_unlock(&mutex))){
219     ERROR_BUFFER;
220     fprintf(stderr, "%s[%d]:  failed to unlock mutex: %s[%d]\n",
221             __file__, __line__, STRERROR(err, buf), err);
222     lock_depth++;
223     lock_stack.push_back(el);
224     owner_id = old_owner_id;
225   }
226 #endif
227
228   return err;
229 }
230
231 int eventLock::_Broadcast(const char *__file__, unsigned int __line__)
232 {
233 #if defined(os_windows)
234   EnterCriticalSection(&waiter_lock);
235
236   if (num_waiters > 0) {
237     int ret = SetEvent(cond);
238     assert (ret);
239     release_num = num_waiters;
240     generation_num++;
241   }
242
243   LeaveCriticalSection(&waiter_lock);
244   //ret = SetEvent(mutex);
245   //assert (ret);
246 #else
247   if (!this) {
248     fprintf(stderr, "%s[%d]:  lock is broken:\n", FILE__, __LINE__);
249     //  most likely the lock stack will crash here...  but this is pretty fatal anyways.
250     printLockStack();
251     return 1;
252   }
253   int err = 0;
254   if(0 != (err = pthread_cond_broadcast(&cond))){
255     ERROR_BUFFER;
256     fprintf(stderr, "From: %s[%d]:  failed to broadcast cond: %s[%d]\n",
257             __file__, __line__, STRERROR(err, buf), err);
258     return 1;
259   }
260
261 #endif
262   return 0;
263 }
264
265 int eventLock::_WaitForSignal(const char *__file__, unsigned int __line__)
266 {
267   int err = 0;
268   if (!lock_depth) {
269     fprintf(stderr, "%s[%d][%s]: cannot call wait until lock is obtained, see %s[%d]\n", FILE__, __LINE__, getThreadStr(getExecThreadID()), __file__, __line__);
270     abort();
271   }
272   lock_depth--;
273
274   if (lock_depth) {
275     const char *thread_name = getThreadStr(getExecThreadID());
276     if (!thread_name) thread_name = "unnamed thread";
277     assert(__file__);
278     assert (FILE__);
279     fprintf(stderr, "%s[%d][%s]:  FATAL, cannot wait while recursively locked to depth %d, called from %s[%d]\n",
280             FILE__, __LINE__, thread_name, lock_depth +1, __file__, __line__);
281     printLockStack();
282     abort();
283   }
284
285   lock_stack_elem el = lock_stack[lock_stack.size() -1];
286   lock_stack.pop_back();
287   owner_id = 0;
288
289   assert(lock_stack.size() == 0);
290 #if defined(os_windows)
291   EnterCriticalSection(&waiter_lock);
292   num_waiters++;
293   int my_generation = generation_num;
294   LeaveCriticalSection(&waiter_lock);
295
296   LeaveCriticalSection(&mutex);
297  
298   while (1) {
299     DWORD res = WaitForSingleObject(cond, INFINITE);
300
301     if (res != WAIT_OBJECT_0) {
302       switch(res) {
303         case WAIT_ABANDONED:  fprintf(stderr, "%s[%d]:  WAIT_ABANDONED\n", FILE__, __LINE__); break;
304         case WAIT_TIMEOUT:  fprintf(stderr, "%s[%d]:  WAIT_TIMEOUT\n", FILE__, __LINE__); break;
305         case WAIT_FAILED:  fprintf(stderr, "%s[%d]:  WAIT_FAILED\n", FILE__, __LINE__); 
306         default:
307           DWORD err = GetLastError();
308           extern void printSysError(unsigned errNo);
309           printSysError(err);
310        };
311      }
312      EnterCriticalSection(&waiter_lock);
313      bool wait_done = (release_num > 0) && (generation_num != my_generation);
314      LeaveCriticalSection(&waiter_lock);
315      if (wait_done) break;
316    }  
317
318    EnterCriticalSection(&mutex);
319    EnterCriticalSection(&waiter_lock);
320    num_waiters--;
321    release_num--;
322    if (num_waiters < 0) {
323       fprintf(stderr, "FIXME!\n", FILE__, __LINE__);
324       num_waiters = 0;
325    }
326    if (release_num < 0) {
327       fprintf(stderr, "FIXME!\n", FILE__, __LINE__);
328       num_waiters = 0;
329    }
330
331    bool do_reset  = (release_num == 0);
332    LeaveCriticalSection(&waiter_lock);
333
334    if (do_reset)
335       ResetEvent(cond);
336
337 #else
338   mutex_printf("%s[%d]:  unlock/wait issued from %s[%d], depth = %d\n", FILE__, __LINE__, __file__, __line__, lock_depth);
339   if(0 != (err = pthread_cond_wait(&cond, &mutex))){
340     ERROR_BUFFER;
341     fprintf(stderr, "%s[%d]:  failed to broadcast cond: %s[%d]\n",
342             __file__, __line__, STRERROR(err, buf), err);
343     return 1;
344   }
345 #endif
346
347   lock_depth++;
348   lock_stack.push_back(el);
349   owner_id = getExecThreadID();
350   mutex_printf("%s[%d]:  wait/re-loc issued from %s[%d], depth = %d\n", FILE__, __LINE__, __file__, __line__, lock_depth);
351   return 0;
352 }
353
354 void eventLock::printLockStack()
355 {
356     fprintf(stderr, "%s[%d]:  Lock stack:\n", FILE__, __LINE__);
357     for (unsigned int i = 0; i < lock_stack.size(); ++i) {
358       fprintf(stderr, "\t[%s][%d]\n", lock_stack[i].file, lock_stack[i].line);
359     }
360 }
361
362 ThreadMailbox::~ThreadMailbox() 
363 {
364   for (unsigned int i = 0; i < cbs.size(); ++i) {
365     delete &(cbs[i]);
366   }
367   cbs.clear();
368 }
369
370 void ThreadMailbox::executeOrRegisterCallback(CallbackBase *cb) 
371 {
372   //assert(global_mutex->depth());
373   CallbackBase *called_cb = executeCallback(cb);
374   mb_lock._Lock(FILE__, __LINE__);
375   cleanUpCalled();
376   if (called_cb) {
377     called.push_back(cb);
378   } else {
379     //  cannot execute now, save for later.
380     cbs.push_back(cb);
381   }
382   mb_lock._Unlock(FILE__, __LINE__);
383 }
384
385 void ThreadMailbox::executeCallbacks(const char *file, unsigned int line) 
386 {
387   if (!global_mutex->depth()) {
388     mailbox_printf("%s[%d][%s]: no lock before exec cbs from %s[%d], bad??\n",
389             FILE__, __LINE__, getThreadStr(getExecThreadID()), file, line);
390   }
391
392   //assert(global_mutex->depth());
393   mb_lock._Lock(FILE__, __LINE__);
394   mailbox_printf("%s[%d][%s]:  executeCallbacks...  %d in pile\n", FILE__, __LINE__, getThreadStr(getExecThreadID()), cbs.size());
395   cleanUpCalled();
396
397   pdvector<CallbackBase *> deferred;
398
399   while (cbs.size())
400   {
401     CallbackBase *cb = cbs[0], *called_cb;
402     cbs.erase(0,0);
403
404     mb_lock._Unlock(FILE__, __LINE__);
405     called_cb = executeCallback(cb);
406     mb_lock._Lock(FILE__, __LINE__);
407
408     if (called_cb) {
409        called.push_back(called_cb);
410        mailbox_printf("%s[%d]:  callback executed\n", FILE__, __LINE__);
411     }
412     else {
413       deferred.push_back(cb);
414     }
415   }
416   for (unsigned int i = 0; i < deferred.size(); ++i) {
417     cbs.push_back(deferred[i]);
418   }
419   deferred.clear(); 
420   mb_lock._Unlock(FILE__, __LINE__);
421 }
422
423 CallbackBase *ThreadMailbox::executeCallback(CallbackBase *cb)
424 {
425   if (cb->isExecuting()) {
426     //  per-callback recursion guard
427     mailbox_printf("%s[%d]:  callback is already executing!\n", FILE__, __LINE__);
428     return NULL;
429   }
430   if ((cb->targetThread() != getExecThreadID())
431       && (cb->targetThread()  != (unsigned long) -1L)) {
432     //  not the right thread for this callback, cannot execute
433     mailbox_printf("%s[%d]:  wrong thread for callback: target = %lu(%s), cur = %lu(%s)\n", 
434            FILE__, __LINE__, cb->targetThread(), getThreadStr(cb->targetThread()),
435             getExecThreadID(), getThreadStr(getExecThreadID()));
436     return NULL;
437   }
438   else {
439     mailbox_printf("%s[%d]:  got callback for thread %lu(%s), current: %lu\n",FILE__, __LINE__,
440            cb->targetThread(), getThreadStr(cb->targetThread()), getExecThreadID());
441   }
442
443   cb->setExecuting(true, getExecThreadID());
444   running.push_back(cb);
445   cb->execute(); 
446
447   //  remove callback from the running pile
448   bool erased_from_running_pile = false;
449   for (unsigned int i = 0; i < running.size(); ++i) {
450     if (running[i] == cb) {
451        running.erase(i,i);
452        erased_from_running_pile = true;
453        break;
454     }
455   }
456   assert(erased_from_running_pile);
457   cb->setExecuting(false);
458
459  mailbox_printf("%s[%d]:  after executing callback for thread %lu(%s)\n",FILE__, __LINE__,
460         getExecThreadID(), getThreadStr(getExecThreadID()));
461
462   CallbackCompletionCallback cleanup_cb = cb->getCleanupCallback();
463  mailbox_printf("%s[%d]:  before cleanup for thread %lu(%s), cb is %p\n",FILE__, __LINE__,
464         getExecThreadID(), getThreadStr(getExecThreadID()), cleanup_cb);
465   if (cleanup_cb) {
466     (cleanup_cb)(cb);
467   }
468
469  mailbox_printf("%s[%d]:  after executing cleanup for thread %lu(%s)\n",FILE__, __LINE__,
470         getExecThreadID(), getThreadStr(getExecThreadID()));
471   return cb;
472 }
473
474 CallbackBase *ThreadMailbox::runningInsideCallback()
475 {
476   //  if there is a callback executing on the current thread, then caller 
477   //  must be, by extension, running as a result being inside that callback.
478   for (unsigned int i = 0; i < running.size(); ++i) {
479     assert(running[i]->isExecuting());
480     if (running[i]->execThread() == getExecThreadID())
481       return running[i];
482   }
483   return NULL;
484 }
485
486 void ThreadMailbox::cleanUpCalled()
487 {
488   int startsz = called.size();
489   for (int i = startsz -1; i >= 0; i--) {
490     if (called[i]->deleteEnabled()) {
491       CallbackBase *cb = called[i];
492       called.erase(i,i);
493       delete (cb);
494     }
495   }
496 }
497