/*
* Copyright (c) 2008 - 2009
* Jonathan Schleifer <js@webkeks.org>
*
* All rights reserved.
*
* This file is part of libobjfw. It may be distributed under the terms of the
* Q Public License 1.0, which can be found in the file LICENSE included in
* the packaging of this file.
*/
#include "config.h"
#include <stdlib.h>
#ifndef _WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif
#import "OFAutoreleasePool.h"
#import "OFList.h"
#import "OFThread.h"
#import "OFExceptions.h"
/*
* Pay special attention to NULL and nil in this file, they might be different!
* Use NULL for TLS values and nil for instance variables.
*/
#ifndef _WIN32
static pthread_key_t first_key, last_key;
#else
static DWORD first_key, last_key;
#endif
#ifndef _WIN32 /* Not used on Win32 yet */
static void
release_all(void *list)
{
#ifndef _WIN32
void *first = pthread_getspecific(first_key);
#else
void *first = TlsGetValue(first_key);
#endif
if (first != NULL)
[(OFAutoreleasePool*)first release];
}
#endif
@implementation OFAutoreleasePool
+ (void)initialize
{
if (self != [OFAutoreleasePool class])
return;
#ifndef _WIN32
if (pthread_key_create(&first_key, release_all) ||
pthread_key_create(&last_key, NULL))
#else
/* FIXME: Call destructor */
if ((first_key = TlsAlloc()) == TLS_OUT_OF_INDEXES ||
(last_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
#endif
@throw [OFInitializationFailedException newWithClass: self];
}
+ (void)addObjectToTopmostPool: (OFObject*)obj
{
#ifndef _WIN32
void *last = pthread_getspecific(last_key);
#else
void *last = TlsGetValue(last_key);
#endif
if (last == NULL) {
@try {
[[self alloc] init];
} @catch (OFException *e) {
[obj release];
@throw e;
}
#ifndef _WIN32
last = pthread_getspecific(last_key);
#else
last = TlsGetValue(last_key);
#endif
}
if (last == NULL) {
[obj release];
@throw [OFInitializationFailedException newWithClass: self];
}
@try {
[(OFAutoreleasePool*)last addObject: obj];
} @catch (OFException *e) {
[obj release];
@throw e;
}
}
- init
{
self = [super init];
#ifndef _WIN32
void *first = pthread_getspecific(first_key);
void *last = pthread_getspecific(last_key);
#else
void *first = TlsGetValue(first_key);
void *last = TlsGetValue(last_key);
#endif
#ifndef _WIN32
if (pthread_setspecific(last_key, self)) {
#else
if (!TlsSetValue(last_key, self)) {
#endif
Class c = isa;
[super dealloc];
@throw [OFInitializationFailedException newWithClass: c];
}
if (first == NULL) {
#ifndef _WIN32
if (pthread_setspecific(first_key, self)) {
#else
if (!TlsSetValue(first_key, self)) {
#endif
Class c = isa;
#ifndef _WIN32
pthread_setspecific(last_key, last);
#else
TlsSetValue(last_key, last);
#endif
[super dealloc];
@throw [OFInitializationFailedException
newWithClass: c];
}
}
if (last != NULL) {
prev = (OFAutoreleasePool*)last;
prev->next = self;
}
return self;
}
- (void)dealloc
{
[next dealloc];
if (prev != nil)
prev->next = nil;
#ifndef _WIN32
pthread_setspecific(last_key, (prev != nil ? prev : NULL));
if (pthread_getspecific(first_key) == self)
pthread_setspecific(first_key, NULL);
#else
TlsSetValue(last_key, (prev != nil ? prev : NULL));
if (TlsGetValue(first_key) == self)
TlsSetValue(first_key, NULL);
#endif
[objects release];
[super dealloc];
}
- addObject: (OFObject*)obj
{
if (objects == nil)
objects = [[OFMutableArray alloc] init];
[objects addObject: obj];
[obj release];
return self;
}
- releaseObjects
{
[next releaseObjects];
if (objects == nil)
return self;
[objects release];
objects = nil;
return self;
}
- retain
{
@throw [OFNotImplementedException newWithClass: isa
selector: _cmd];
}
- autorelease
{
@throw [OFNotImplementedException newWithClass: isa
selector: _cmd];
}
@end