Add lazy locking classes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@17979 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2003-10-26 13:45:49 +00:00
parent cd0a17674e
commit cdc7785b67
4 changed files with 369 additions and 0 deletions

View file

@ -1,3 +1,10 @@
Sun Oct 26 14:45:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/GSLock.m: New lazy locking classes as discussed
on the developer list.
* Headers/Additions/GNUstepBase/GSLock.h: Declare new classes.
Please try them out and provide feedback.
Sat Oct 25 18:47:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
* configure.ac: Judicious addition on spaces to fix test arguments.

View file

@ -0,0 +1,48 @@
/** Some extra locking classes
Copyright (C) 2003 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
AutogsdocSource: Additions/GSLock.m
*/
#ifndef INCLUDED_GS_LOCK_H
#define INCLUDED_GS_LOCK_H
#include <Foundation/NSLock.h>
@interface GSLazyLock : NSLock
{
int locked;
}
- (void) _becomeThreaded: (NSNotification*)n;
@end
@interface GSLazyRecursiveLock : NSRecursiveLock
{
int counter;
}
- (void) _becomeThreaded: (NSNotification*)n;
@end
#endif /* INCLUDED_GS_LOCK_H */

View file

@ -35,6 +35,7 @@ Additions_OBJC_FILES =\
GCObject.m \
GCArray.m \
GCDictionary.m \
GSLock.m \
GSMime.m \
GSXML.m \
behavior.m

313
Source/Additions/GSLock.m Normal file
View file

@ -0,0 +1,313 @@
/** Implementation for GSLock
Copyright (C) 2003 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <rfm@gnu.org>
Date: October 2003
This file is part of the GNUstep Base Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
$Date$ $Revision$
*/
#include "config.h"
#include <Foundation/NSException.h>
#include <Foundation/NSLock.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSThread.h>
#include "GNUstepBase/GSLock.h"
/**
* This implements a class which, when used in single-threaded mode,
* acts like a lock while avoiding the overheads of actually using
* a real lock. However, when the programm in which the class is
* used becomes multi-threaded, all instances of this class transform
* themselves into real locks in the correct state (locked/unlocked)
* corresponding to whether the lazy lock was locked or not at the
* point where the program became multi threadeed.<br />
* Use of this class allows you to write thread-safe code which avoids
* locking inefficiencies when used in a single threaded application,
* without having to worry about dealing with the issue yourself.
*/
@implementation GSLazyLock
/**
* Do not use this method ... it is used internally to handle the transition
* from a single threaded system to a multi threaded one.
*/
- (void) _becomeThreaded: (NSNotification*)n
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
isa = [NSLock class];
if (locked == YES)
{
if ([self tryLock] == NO)
{
[NSException raise: NSInternalInconsistencyException
format: @"Failed to lock mutex"];
}
}
/*
* While we have changed 'isa', it's possible someone might have
* cached our old method implementations, so we set the 'locked'
* ivar to a value to tell the old method implementations to use
* the superclass implementatins.
*/
locked = -1;
}
- (void) dealloc
{
[self gcFinalize];
[super dealloc];
}
- (void) gcFinalize
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[super gcFinalize];
}
- (id) init
{
if ([NSThread isMultiThreaded] == YES)
{
RELEASE(self);
self = [NSLock new];
}
else
{
self = [super init];
if (self != nil)
{
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_becomeThreaded:)
name: NSWillBecomeMultiThreadedNotification
object: nil];
}
locked = NO;
}
return self;
}
- (void) lock
{
if (locked == NO)
{
locked = YES;
}
else if (locked == YES)
{
[NSException raise: NSGenericException
format: @"lock: when already locked"];
}
else
{
[super lock];
}
}
- (BOOL) lockBeforeDate: (NSDate*)limit
{
BOOL result;
if (locked == NO)
{
result = YES;
}
else if (locked == YES)
{
result = NO;
[NSException raise: NSGenericException
format: @"lock: when already locked"];
}
else
{
result = [super lockBeforeDate: limit];
}
return result;
}
- (BOOL) tryLock
{
if (locked == NO)
{
locked = YES;
return YES;
}
else if (locked == YES)
{
return NO;
}
else
{
return [super tryLock];
}
}
- (void) unlock
{
if (locked == YES)
{
locked = NO;
}
else if (locked == NO)
{
[NSException raise: NSGenericException
format: @"unlock: when already unlocked"];
}
else
{
[super unlock];
}
}
@end
/**
* This implements a class which, when used in single-threaded mode,
* acts like a recursive lock while avoiding the overheads of using
* a real lock. However, when the programm in which the class is
* used becomes multi-threaded, all instances of this class transform
* themselves into real locks in the correct state (locked/unlocked)
* corresponding to whether the lazy recursive lock was locked or not
* at the point where the program became multi threadeed.<br />
* Use of this class allows you to write thread-safe code which avoids
* locking inefficiencies when used in a single threaded application,
* without having to worry about dealing with the issue yourself.
*/
@implementation GSLazyRecursiveLock
/**
* Do not use this method ... it is used internally to handle the transition
* from a single threaded system to a multi threaded one.
*/
- (void) _becomeThreaded: (NSNotification*)n
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
isa = [NSRecursiveLock class];
while (counter-- > 0)
{
if ([self tryLock] == NO)
{
[NSException raise: NSInternalInconsistencyException
format: @"Failed to lock mutex"];
}
}
/*
* While we have changed 'isa', it's possible someone might have
* cached our old method implementations, so we set the 'locked'
* ivar to a value to tell the old method implementations to use
* the superclass implementatins.
*/
counter = -1;
}
- (void) dealloc
{
[self gcFinalize];
[super dealloc];
}
- (void) gcFinalize
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[super gcFinalize];
}
- (id) init
{
if ([NSThread isMultiThreaded] == YES)
{
RELEASE(self);
self = [NSRecursiveLock new];
}
else
{
self = [super init];
if (self != nil)
{
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_becomeThreaded:)
name: NSWillBecomeMultiThreadedNotification
object: nil];
}
}
return self;
}
- (void) lock
{
if (counter >= 0)
{
counter++;
}
else
{
[super lock];
}
}
- (BOOL) lockBeforeDate: (NSDate*)limit
{
if (counter >= 0)
{
counter++;
return YES;
}
else
{
return [super lockBeforeDate: limit];
}
}
- (BOOL) tryLock
{
if (counter >= 0)
{
counter++;
return YES;
}
else
{
return [super tryLock];
}
}
- (void) unlock
{
if (counter > 0)
{
counter--;
}
else if (counter == 0)
{
[NSException raise: NSGenericException
format: @"unlock: failed to unlock mutex"];
}
else
{
[super unlock];
}
}
@end