diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h index 6921533e..eb5bb57d 100644 --- a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h @@ -24,26 +24,14 @@ //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// -/// \brief Ensure at least one autorelease pool is available on this thread -/// -/// Increment a retain count for *this* thread. +/// \brief Ensure one autorelease pool is available on this thread /// //////////////////////////////////////////////////////////// -void retainPool(void); +void ensureThreadHasPool(void); + //////////////////////////////////////////////////////////// -/// \brief Drain the pool -/// -/// The pool retain count should be absolutely positive before calling this function on this thread. +/// \brief Drain the thread's pool but keep it alive /// //////////////////////////////////////////////////////////// -void drainCurrentPool(void); - -//////////////////////////////////////////////////////////// -/// \brief Release the pool. -/// -/// Decrease the retain count for *this* thread. -/// -//////////////////////////////////////////////////////////// -void releasePool(void); - +void drainThreadPool(void); diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm index 2afd8abb..f88982a2 100644 --- a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm @@ -26,11 +26,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include -#include - #include +#include #import #import @@ -41,165 +38,68 @@ /// pool and making other pools invalid which can lead to a crash on 10.5 and an /// annoying message on 10.6 (*** attempt to pop an unknown autorelease pool). /// -/// Because NSAutoreleasePool cannot be retain we have to do it ourself. -/// We use an sf::ThreadLocalPtr to have one PoolWrapper in each thread. -/// -/// SPECIAL CONSIDERATION: -/// ====================== -/// This implies that if retainPool is called X times in a thread Y then -/// releasePool must be called X times too in the same thread Y. -/// //////////////////////////////////////////////////////////// -namespace sf -{ -namespace priv -{ -//////////////////////////////////////////////////////////// -/// \brief C++ Wrapper of Obj-C Autorelease Pool -/// -//////////////////////////////////////////////////////////// -class PoolWrapper : NonCopyable -{ -public: - - //////////////////////////////////////////////////////////// - /// \brief Default constructor - /// - //////////////////////////////////////////////////////////// - PoolWrapper(); - - //////////////////////////////////////////////////////////// - /// \brief Default destructor - /// - /// Make sure the pool is drained (if appropriate) - /// - //////////////////////////////////////////////////////////// - ~PoolWrapper(); - - //////////////////////////////////////////////////////////// - /// \brief Increment retain count and allocate memory if needed - /// - //////////////////////////////////////////////////////////// - void retain(); - - //////////////////////////////////////////////////////////// - /// \brief Decrement retain count and releasing memory if needed - /// - /// \return true if the pool wrapper can be released - /// - //////////////////////////////////////////////////////////// - bool release(); - - //////////////////////////////////////////////////////////// - /// \brief Drain the pool - /// - //////////////////////////////////////////////////////////// - void drain(); - -private: - - //////////////////////////////////////////////////////////// - // Member data - //////////////////////////////////////////////////////////// - int m_count; ///< How many times was the pool retained? - NSAutoreleasePool* m_pool; ///< Our dedicated pool -}; - - -//////////////////////////////////////////////////////////// -PoolWrapper::PoolWrapper() : -m_count(0), -m_pool(nil) -{ - /* Nothing else */ -} - - -//////////////////////////////////////////////////////////// -PoolWrapper::~PoolWrapper() -{ - // Make sure everything is drained - m_count = 0; - drain(); -} - - -//////////////////////////////////////////////////////////// -void PoolWrapper::retain() -{ - // Increase counter - ++m_count; - - // Allocate pool if required - if (m_pool == nil) - m_pool = [[NSAutoreleasePool alloc] init]; -} - - -//////////////////////////////////////////////////////////// -bool PoolWrapper::release() -{ - // Decrease counter - --m_count; - - return m_count == 0; -} - -void PoolWrapper::drain() -{ - [m_pool drain]; - m_pool = nil; - - if (m_count != 0) - m_pool = [[NSAutoreleasePool alloc] init]; -} - - -} // namespace priv - -} // namespace sf //////////////////////////////////////////////////////////// // Private data //////////////////////////////////////////////////////////// -namespace +static pthread_key_t poolKey; +static pthread_once_t initOnceToken = PTHREAD_ONCE_INIT; + + +//////////////////////////////////////////////////////////// +/// \brief (local function) Drain one more time the pool +/// but this time don't create a new one. +/// +//////////////////////////////////////////////////////////// +static void destroyPool(void* data) { - // This per-thread variable holds the current autorelease pool for each thread - sf::ThreadLocalPtr localPool; + NSAutoreleasePool* pool = (NSAutoreleasePool*)data; + [pool drain]; } //////////////////////////////////////////////////////////// -void retainPool(void) +/// \brief (local function) Init the pthread key for the pool +/// +//////////////////////////////////////////////////////////// +static void createPoolKey(void) { - // First, Check that we have a valid PoolWrapper object in our local pool. - if (localPool == NULL) - localPool = new sf::priv::PoolWrapper(); - - // Then retains! - localPool->retain(); + pthread_key_create(&poolKey, destroyPool); } //////////////////////////////////////////////////////////// -void drainCurrentPool(void) +/// \brief (local function) Store a new pool for this thread +/// +//////////////////////////////////////////////////////////// +static void createNewPool(void) { - assert(localPool != NULL); - localPool->drain(); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + pthread_setspecific(poolKey, pool); } //////////////////////////////////////////////////////////// -void releasePool(void) +void ensureThreadHasPool(void) { - assert(localPool != NULL); - - // If we're done with the pool, let's release the memory - if (localPool->release()) + pthread_once(&initOnceToken, createPoolKey); + if (pthread_getspecific(poolKey) == NULL) { - delete localPool; - localPool = NULL; + createNewPool(); } } + +//////////////////////////////////////////////////////////// +void drainThreadPool(void) +{ + void* data = pthread_getspecific(poolKey); + assert(data != NULL); + + // Drain the pool but keep it alive by creating a new one + destroyPool(data); + createNewPool(); +} + diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 810bcb48..4c24d030 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -46,7 +46,7 @@ m_view(0), m_window(0) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context createContext(shared, @@ -62,7 +62,7 @@ m_view(0), m_window(0) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context. createContext(shared, bitsPerPixel, settings); @@ -83,7 +83,7 @@ m_window(0) WindowImplCocoa::setUpProcess(); // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Create the context. createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); @@ -108,8 +108,6 @@ SFContext::~SFContext() [m_view release]; // Might be nil but we don't care. [m_window release]; // Idem. - - releasePool(); } diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm index 927d5b42..24765ee0 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.mm +++ b/src/SFML/Window/OSX/WindowImplCocoa.mm @@ -155,7 +155,7 @@ WindowImplCocoa::WindowImplCocoa(WindowHandle handle) : m_showCursor(true) { // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Treat the handle as it real type id nsHandle = (id)handle; @@ -200,7 +200,7 @@ m_showCursor(true) setUpProcess(); // Ask for a pool. - retainPool(); + ensureThreadHasPool(); // Use backing size scaleInWidthHeight(mode, nil); @@ -226,11 +226,9 @@ WindowImplCocoa::~WindowImplCocoa() if ([windows count] > 0) [[windows objectAtIndex:0] makeKeyAndOrderFront:nil]; - drainCurrentPool(); // Make sure everything was freed + drainThreadPool(); // Make sure everything was freed // This solve some issue when sf::Window::Create is called for the // second time (nothing was render until the function was called again) - - releasePool(); } @@ -467,7 +465,7 @@ void WindowImplCocoa::textEntered(unichar charcode) void WindowImplCocoa::processEvents() { [m_delegate processEvent]; - drainCurrentPool(); // Reduce memory footprint + drainThreadPool(); // Reduce memory footprint } #pragma mark