diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index d0dd89c66..007a4b789 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -74,6 +74,8 @@ else() # MACOSX ${SRCROOT}/OSX/WindowImplCocoa.hpp ${SRCROOT}/OSX/WindowImplCocoa.mm ${SRCROOT}/OSX/WindowImplDelegateProtocol.h + ${SRCROOT}/OSX/AutoreleasePoolWrapper.h + ${SRCROOT}/OSX/AutoreleasePoolWrapper.mm ) endif() diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h new file mode 100644 index 000000000..2a67f1b76 --- /dev/null +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2011 Marco Antognini (antognini.marco@gmail.com), +// Laurent Gomila (laurent.gom@gmail.com), +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +void RetainPool(void); +void ReleasePool(void); + diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm new file mode 100644 index 000000000..3391562c6 --- /dev/null +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm @@ -0,0 +1,138 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2011 Marco Antognini (antognini.marco@gmail.com), +// Laurent Gomila (laurent.gom@gmail.com), +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#include +#include +#import "AutoreleasePoolWrapper.h" +#import + +// Here we manage one and only one pool by thread. This prevents draining one +// 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. + +// 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. + +class PoolWrapper { +public: + PoolWrapper() + : count(0) + , pool(0) + { + /* Nothing else */ + } + + ~PoolWrapper() + { +#ifdef SFML_DEBUG + if (count < 0) { + sf::Err() << "~PoolWrapper : count is less than zero! " + "You called ReleasePool from a thread too many times." + << std::endl; + } else if (count > 0) { + sf::Err() << "~PoolWrapper : count is greater than zero! " + "You called ReleasePool from a thread to few times." + << std::endl; + } else { // count == 0 + sf::Err() << "~PoolWrapper is HAPPY!" << std::endl; + } +#endif + } + + void Retain() + { + // Increase counter. + ++count; + + // Allocate pool if required. + if (pool == 0) { + pool = [[NSAutoreleasePool alloc] init]; + } + +#ifdef SFML_DEBUG + if (count <= 0) { + sf::Err() << "PoolWrapper::Retain : count <= 0! " << std::endl; + } +#endif + } + + void Release() + { + // Decrease counter. + --count; + + // Drain pool if required. + if (count == 0) { + [pool drain]; + pool = 0; + } + +#ifdef SFML_DEBUG + if (count < 0) { + sf::Err() << "PoolWrapper::Release : count < 0! " << std::endl; + } +#endif + } + + +private: + int count; ///< How many times the pool was retained ? + NSAutoreleasePool* pool; ///< Our pool. +}; + +// Thread shared variable but with local-only shared content. +sf::ThreadLocalPtr localPool; + +void RetainPool(void) +{ + // First, Check that we have a valid PoolWrapper object in our local pool. + if (localPool == NULL) { + localPool = new PoolWrapper(); + } + + // Then retains! + localPool->Retain(); +} + +void ReleasePool(void) +{ +#ifdef SFML_DEBUG + if (localPool == NULL) { + sf::Err() << "ReleasePool : You must call RetainPool at least once " + "in this thread before calling ReleasePool." + << std::endl; + } else { +#endif + + // Releases, that's all. + localPool->Release(); + +#ifdef SFML_DEBUG + } +#endif +} diff --git a/src/SFML/Window/OSX/SFContext.hpp b/src/SFML/Window/OSX/SFContext.hpp index c49e482fa..f3f1f6ec2 100644 --- a/src/SFML/Window/OSX/SFContext.hpp +++ b/src/SFML/Window/OSX/SFContext.hpp @@ -39,9 +39,6 @@ @class NSOpenGLContext; typedef NSOpenGLContext* NSOpenGLContextRef; -@class NSAutoreleasePool; -typedef NSAutoreleasePool* NSAutoreleasePoolRef; - @class NSOpenGLView; typedef NSOpenGLView* NSOpenGLViewRef; @@ -51,7 +48,6 @@ typedef NSWindow* NSWindowRef; #else // If C++ typedef void* NSOpenGLContextRef; -typedef void* NSAutoreleasePoolRef; typedef void* NSOpenGLViewRef; typedef void* NSWindowRef; @@ -154,7 +150,6 @@ private: // Member data //////////////////////////////////////////////////////////// NSOpenGLContextRef myContext; ///< OpenGL context. - NSAutoreleasePoolRef myPool; ///< Memory manager for this class. NSOpenGLViewRef myView; ///< Only for offscreen context. NSWindowRef myWindow; ///< Only for offscreen context. }; diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 4f05b0df9..e542e172a 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -30,6 +30,8 @@ #include #include +#import + /* * DISCUSSION : * ============ @@ -53,7 +55,8 @@ namespace priv SFContext::SFContext(SFContext* shared) : myView(0), myWindow(0) { - myPool = [[NSAutoreleasePool alloc] init]; + // Ask for a pool. + RetainPool(); // Create the context CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, ContextSettings(0, 0, 0)); @@ -65,7 +68,8 @@ SFContext::SFContext(SFContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : myView(0), myWindow(0) { - myPool = [[NSAutoreleasePool alloc] init]; + // Ask for a pool. + RetainPool(); // Create the context. CreateContext(shared, bitsPerPixel, settings); @@ -83,7 +87,8 @@ SFContext::SFContext(SFContext* shared, const ContextSettings& settings, // Ensure the process is setup in order to create a valid window. WindowImplCocoa::SetUpProcess(); - myPool = [[NSAutoreleasePool alloc] init]; + // Ask for a pool. + RetainPool(); // Create the context. CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, settings); @@ -109,8 +114,7 @@ SFContext::~SFContext() [myView release]; // Might be nil but we don't care. [myWindow release]; // Idem. - [myPool drain]; // Produce sometimes "*** attempt to pop an unknown autorelease pool" - // This is not a real issue : http://stackoverflow.com/questions/3484888/nsautoreleasepool-question + ReleasePool(); } diff --git a/src/SFML/Window/OSX/WindowImplCocoa.hpp b/src/SFML/Window/OSX/WindowImplCocoa.hpp index 9ccee81bf..ef2c012b1 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.hpp +++ b/src/SFML/Window/OSX/WindowImplCocoa.hpp @@ -40,9 +40,6 @@ #import typedef id WindowImplDelegateRef; -@class NSAutoreleasePool; -typedef NSAutoreleasePool* NSAutoreleasePoolRef; - @class NSOpenGLContext; typedef NSOpenGLContext* NSOpenGLContextRef; @@ -51,7 +48,6 @@ typedef NSOpenGLContext* NSOpenGLContextRef; typedef unsigned short unichar; // See NSString.h typedef void* WindowImplDelegateRef; -typedef void* NSAutoreleasePoolRef; typedef void* NSOpenGLContextRef; #endif @@ -326,7 +322,6 @@ private: // Member data //////////////////////////////////////////////////////////// WindowImplDelegateRef myDelegate; ///< Implementation in Obj-C. - NSAutoreleasePoolRef myPool; ///< Memory manager for this class. }; } // namespace priv diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm index e6d531ccb..162231e69 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.mm +++ b/src/SFML/Window/OSX/WindowImplCocoa.mm @@ -32,6 +32,7 @@ #import #import #import +#import namespace sf { @@ -44,8 +45,8 @@ namespace priv //////////////////////////////////////////////////////////// WindowImplCocoa::WindowImplCocoa(WindowHandle handle) { - // Create the pool. - myPool = [[NSAutoreleasePool alloc] init]; + // Ask for a pool. + RetainPool(); // Treat the handle as it real type id nsHandle = (id)handle; @@ -94,8 +95,8 @@ WindowImplCocoa::WindowImplCocoa(VideoMode mode, // Transform the app process. SetUpProcess(); - // Create the pool. - myPool = [[NSAutoreleasePool alloc] init]; + // Ask for a pool. + RetainPool(); // Don't forget to update our parent (that is, WindowImpl) size : myWidth = mode.Width; @@ -113,7 +114,8 @@ WindowImplCocoa::~WindowImplCocoa() [myDelegate closeWindow]; [myDelegate release]; - [myPool drain]; + + ReleasePool(); }