/* Mac OS X 10.2.x gcc (and earlier) uses atexit() to clean up for static constructors located at function scope. This can cause the destructor for a class defined in a bundle to get called after the bundle is unloaded (causing a crash). Instead, what we want (and what Win32 does) is call the destructors when the bundle is unloaded. We might need to be careful about 'normal' calls to atexit() from a bundle, but our new solution to this problem (which deprecates OGPInitGuard) is to define our own atexit() function in this file and link it into each bundle). */ #include #include #include #include class OGPBundleAtUnload { private: typedef void (*callback)(void); pthread_mutex_t _lock; callback *_callbacks; unsigned int _callbacksCount, _callbacksSize; public: OGPBundleAtUnload(); ~OGPBundleAtUnload(); void addCallback(callback c); }; OGPBundleAtUnload::OGPBundleAtUnload() { pthread_mutex_init(&_lock, NULL); _callbacks = NULL; _callbacksCount = 0; _callbacksSize = 0; } OGPBundleAtUnload::~OGPBundleAtUnload() { #if 0 && defined(DEBUG) fprintf(stderr, "Running callbacks for OGPBundleAtUnload:0x%08x\n", this); #endif // Try to protect against terrible code that, from a destructor called by us, ends up calling a function that statically constructs an object. while (_callbacks) { callback *callbacks = _callbacks; unsigned int callbacksIndex = _callbacksCount; _callbacks = NULL; _callbacksCount = _callbacksSize = 0; // Call in reverse order while (callbacksIndex--) callbacks[callbacksIndex](); free(callbacks); // We'd like to detect such bogus cases and fix them. assert(_callbacks == NULL); } pthread_mutex_destroy(&_lock); #if 0 && defined(DEBUG) fprintf(stderr, "Done running callbacks for OGPBundleAtUnload:0x%08x\n", this); #endif } void OGPBundleAtUnload::addCallback(callback c) { #if 0 && defined(DEBUG) fprintf(stderr, "Registering callback:0x%08x in OGPBundleAtUnload:0x%08x\n", c, this); #endif // We don't expect this to be called very often, so a pthread mutex should be fast enough pthread_mutex_lock(&_lock); { if (_callbacksCount == _callbacksSize) { _callbacksSize = (_callbacksSize + 1) * 2; _callbacks = (callback *)realloc(_callbacks, sizeof(*_callbacks) * _callbacksSize); } _callbacks[_callbacksCount++] = c; } pthread_mutex_unlock(&_lock); } static OGPBundleAtUnload unloader; int atexit(void (*func)(void)) { unloader.addCallback(func); return 0; }