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