Fix autorelease problem (issue #62)

This commit is contained in:
Marco Antognini 2011-07-03 19:56:26 +02:00
parent de70f691e1
commit edf82be16b
7 changed files with 184 additions and 20 deletions

View File

@ -74,6 +74,8 @@ else() # MACOSX
${SRCROOT}/OSX/WindowImplCocoa.hpp ${SRCROOT}/OSX/WindowImplCocoa.hpp
${SRCROOT}/OSX/WindowImplCocoa.mm ${SRCROOT}/OSX/WindowImplCocoa.mm
${SRCROOT}/OSX/WindowImplDelegateProtocol.h ${SRCROOT}/OSX/WindowImplDelegateProtocol.h
${SRCROOT}/OSX/AutoreleasePoolWrapper.h
${SRCROOT}/OSX/AutoreleasePoolWrapper.mm
) )
endif() endif()

View File

@ -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);

View File

@ -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 <SFML/System/ThreadLocalPtr.hpp>
#include <SFML/System/Err.hpp>
#import "AutoreleasePoolWrapper.h"
#import <Foundation/Foundation.h>
// 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<PoolWrapper> 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
}

View File

@ -39,9 +39,6 @@
@class NSOpenGLContext; @class NSOpenGLContext;
typedef NSOpenGLContext* NSOpenGLContextRef; typedef NSOpenGLContext* NSOpenGLContextRef;
@class NSAutoreleasePool;
typedef NSAutoreleasePool* NSAutoreleasePoolRef;
@class NSOpenGLView; @class NSOpenGLView;
typedef NSOpenGLView* NSOpenGLViewRef; typedef NSOpenGLView* NSOpenGLViewRef;
@ -51,7 +48,6 @@ typedef NSWindow* NSWindowRef;
#else // If C++ #else // If C++
typedef void* NSOpenGLContextRef; typedef void* NSOpenGLContextRef;
typedef void* NSAutoreleasePoolRef;
typedef void* NSOpenGLViewRef; typedef void* NSOpenGLViewRef;
typedef void* NSWindowRef; typedef void* NSWindowRef;
@ -154,7 +150,6 @@ private:
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
NSOpenGLContextRef myContext; ///< OpenGL context. NSOpenGLContextRef myContext; ///< OpenGL context.
NSAutoreleasePoolRef myPool; ///< Memory manager for this class.
NSOpenGLViewRef myView; ///< Only for offscreen context. NSOpenGLViewRef myView; ///< Only for offscreen context.
NSWindowRef myWindow; ///< Only for offscreen context. NSWindowRef myWindow; ///< Only for offscreen context.
}; };

View File

@ -30,6 +30,8 @@
#include <SFML/Window/OSX/WindowImplCocoa.hpp> #include <SFML/Window/OSX/WindowImplCocoa.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
/* /*
* DISCUSSION : * DISCUSSION :
* ============ * ============
@ -53,7 +55,8 @@ namespace priv
SFContext::SFContext(SFContext* shared) SFContext::SFContext(SFContext* shared)
: myView(0), myWindow(0) : myView(0), myWindow(0)
{ {
myPool = [[NSAutoreleasePool alloc] init]; // Ask for a pool.
RetainPool();
// Create the context // Create the context
CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, ContextSettings(0, 0, 0)); 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) const WindowImpl* owner, unsigned int bitsPerPixel)
: myView(0), myWindow(0) : myView(0), myWindow(0)
{ {
myPool = [[NSAutoreleasePool alloc] init]; // Ask for a pool.
RetainPool();
// Create the context. // Create the context.
CreateContext(shared, bitsPerPixel, settings); 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. // Ensure the process is setup in order to create a valid window.
WindowImplCocoa::SetUpProcess(); WindowImplCocoa::SetUpProcess();
myPool = [[NSAutoreleasePool alloc] init]; // Ask for a pool.
RetainPool();
// Create the context. // Create the context.
CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, settings); CreateContext(shared, VideoMode::GetDesktopMode().BitsPerPixel, settings);
@ -109,8 +114,7 @@ SFContext::~SFContext()
[myView release]; // Might be nil but we don't care. [myView release]; // Might be nil but we don't care.
[myWindow release]; // Idem. [myWindow release]; // Idem.
[myPool drain]; // Produce sometimes "*** attempt to pop an unknown autorelease pool" ReleasePool();
// This is not a real issue : http://stackoverflow.com/questions/3484888/nsautoreleasepool-question
} }

View File

@ -40,9 +40,6 @@
#import <SFML/Window/OSX/WindowImplDelegateProtocol.h> #import <SFML/Window/OSX/WindowImplDelegateProtocol.h>
typedef id<WindowImplDelegateProtocol,NSObject> WindowImplDelegateRef; typedef id<WindowImplDelegateProtocol,NSObject> WindowImplDelegateRef;
@class NSAutoreleasePool;
typedef NSAutoreleasePool* NSAutoreleasePoolRef;
@class NSOpenGLContext; @class NSOpenGLContext;
typedef NSOpenGLContext* NSOpenGLContextRef; typedef NSOpenGLContext* NSOpenGLContextRef;
@ -51,7 +48,6 @@ typedef NSOpenGLContext* NSOpenGLContextRef;
typedef unsigned short unichar; // See NSString.h typedef unsigned short unichar; // See NSString.h
typedef void* WindowImplDelegateRef; typedef void* WindowImplDelegateRef;
typedef void* NSAutoreleasePoolRef;
typedef void* NSOpenGLContextRef; typedef void* NSOpenGLContextRef;
#endif #endif
@ -326,7 +322,6 @@ private:
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
WindowImplDelegateRef myDelegate; ///< Implementation in Obj-C. WindowImplDelegateRef myDelegate; ///< Implementation in Obj-C.
NSAutoreleasePoolRef myPool; ///< Memory manager for this class.
}; };
} // namespace priv } // namespace priv

View File

@ -32,6 +32,7 @@
#import <SFML/Window/OSX/SFWindowController.h> #import <SFML/Window/OSX/SFWindowController.h>
#import <SFML/Window/OSX/SFViewController.h> #import <SFML/Window/OSX/SFViewController.h>
#import <SFML/Window/OSX/cpp_objc_conversion.h> #import <SFML/Window/OSX/cpp_objc_conversion.h>
#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
namespace sf namespace sf
{ {
@ -44,8 +45,8 @@ namespace priv
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
WindowImplCocoa::WindowImplCocoa(WindowHandle handle) WindowImplCocoa::WindowImplCocoa(WindowHandle handle)
{ {
// Create the pool. // Ask for a pool.
myPool = [[NSAutoreleasePool alloc] init]; RetainPool();
// Treat the handle as it real type // Treat the handle as it real type
id nsHandle = (id)handle; id nsHandle = (id)handle;
@ -94,8 +95,8 @@ WindowImplCocoa::WindowImplCocoa(VideoMode mode,
// Transform the app process. // Transform the app process.
SetUpProcess(); SetUpProcess();
// Create the pool. // Ask for a pool.
myPool = [[NSAutoreleasePool alloc] init]; RetainPool();
// Don't forget to update our parent (that is, WindowImpl) size : // Don't forget to update our parent (that is, WindowImpl) size :
myWidth = mode.Width; myWidth = mode.Width;
@ -113,7 +114,8 @@ WindowImplCocoa::~WindowImplCocoa()
[myDelegate closeWindow]; [myDelegate closeWindow];
[myDelegate release]; [myDelegate release];
[myPool drain];
ReleasePool();
} }