mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Github issue #312 ... add thread safety for Apple compatibility
This commit is contained in:
parent
446d168cd3
commit
c1833e1130
3 changed files with 55 additions and 18 deletions
|
@ -1,3 +1,9 @@
|
|||
2023-08-18 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Headers/Foundation/NSCache.h: Add _lock ivar
|
||||
* Source/NSCache.m: Protect cache operations with a lock for
|
||||
thread safety.
|
||||
|
||||
2023-08-10 Frederik Seiffert <frederik@algoriddim.com>
|
||||
|
||||
* Headers/Foundation/NSNumberFormatter.h:
|
||||
|
|
|
@ -36,6 +36,7 @@ extern "C" {
|
|||
|
||||
@class NSString;
|
||||
@class NSMapTable;
|
||||
@class NSRecursiveLock;
|
||||
@class GS_GENERIC_CLASS(NSMutableArray, ElementT);
|
||||
|
||||
GS_EXPORT_CLASS
|
||||
|
@ -61,6 +62,8 @@ GS_EXPORT_CLASS
|
|||
GS_GENERIC_CLASS(NSMutableArray, ValT) *_accesses;
|
||||
/** Total number of accesses to objects */
|
||||
int64_t _totalAccesses;
|
||||
/** locking for thread safety */
|
||||
NSRecursiveLock *_lock;
|
||||
#endif
|
||||
#if GS_NONFRAGILE
|
||||
#else
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#import "Foundation/NSCache.h"
|
||||
#import "Foundation/NSMapTable.h"
|
||||
#import "Foundation/NSEnumerator.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
|
||||
/**
|
||||
* _GSCachedObject is effectively used as a structure containing the various
|
||||
|
@ -60,8 +61,9 @@
|
|||
{
|
||||
return nil;
|
||||
}
|
||||
ASSIGN(_objects,[NSMapTable strongToStrongObjectsMapTable]);
|
||||
ASSIGN(_objects, [NSMapTable strongToStrongObjectsMapTable]);
|
||||
_accesses = [NSMutableArray new];
|
||||
_lock = [NSRecursiveLock new];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -82,15 +84,24 @@
|
|||
|
||||
- (NSString*) name
|
||||
{
|
||||
return _name;
|
||||
NSString *n;
|
||||
|
||||
[_lock lock];
|
||||
n = RETAIN(_name);
|
||||
[_lock unlock];
|
||||
return AUTORELEASE(n);
|
||||
}
|
||||
|
||||
- (id) objectForKey: (id)key
|
||||
{
|
||||
_GSCachedObject *obj = [_objects objectForKey: key];
|
||||
_GSCachedObject *obj;
|
||||
id value;
|
||||
|
||||
[_lock lock];
|
||||
obj = [_objects objectForKey: key];
|
||||
if (nil == obj)
|
||||
{
|
||||
[_lock unlock];
|
||||
return nil;
|
||||
}
|
||||
if (obj->isEvictable)
|
||||
|
@ -101,14 +112,18 @@
|
|||
}
|
||||
obj->accessCount++;
|
||||
_totalAccesses++;
|
||||
return obj->object;
|
||||
value = RETAIN(obj->object);
|
||||
[_lock unlock];
|
||||
return AUTORELEASE(value);
|
||||
}
|
||||
|
||||
- (void) removeAllObjects
|
||||
{
|
||||
NSEnumerator *e = [_objects objectEnumerator];
|
||||
_GSCachedObject *obj;
|
||||
NSEnumerator *e;
|
||||
_GSCachedObject *obj;
|
||||
|
||||
[_lock lock];
|
||||
e = [_objects objectEnumerator];
|
||||
while (nil != (obj = [e nextObject]))
|
||||
{
|
||||
[_delegate cache: self willEvictObject: obj->object];
|
||||
|
@ -116,12 +131,15 @@
|
|||
[_objects removeAllObjects];
|
||||
[_accesses removeAllObjects];
|
||||
_totalAccesses = 0;
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) removeObjectForKey: (id)key
|
||||
{
|
||||
_GSCachedObject *obj = [_objects objectForKey: key];
|
||||
_GSCachedObject *obj;
|
||||
|
||||
[_lock lock];
|
||||
obj = [_objects objectForKey: key];
|
||||
if (nil != obj)
|
||||
{
|
||||
[_delegate cache: self willEvictObject: obj->object];
|
||||
|
@ -129,6 +147,7 @@
|
|||
[_objects removeObjectForKey: key];
|
||||
[_accesses removeObjectIdenticalTo: obj];
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) setCountLimit: (NSUInteger)lim
|
||||
|
@ -148,14 +167,18 @@
|
|||
|
||||
- (void) setName: (NSString*)cacheName
|
||||
{
|
||||
[_lock lock];
|
||||
ASSIGN(_name, cacheName);
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) setObject: (id)obj forKey: (id)key cost: (NSUInteger)num
|
||||
{
|
||||
_GSCachedObject *oldObject = [_objects objectForKey: key];
|
||||
_GSCachedObject *oldObject;
|
||||
_GSCachedObject *newObject;
|
||||
|
||||
[_lock lock];
|
||||
oldObject = [_objects objectForKey: key];
|
||||
if (nil != oldObject)
|
||||
{
|
||||
[self removeObjectForKey: oldObject->key];
|
||||
|
@ -174,6 +197,7 @@
|
|||
[_objects setObject: newObject forKey: key];
|
||||
RELEASE(newObject);
|
||||
_totalCost += num;
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) setObject: (id)obj forKey: (id)key
|
||||
|
@ -198,11 +222,13 @@
|
|||
* could in future have a class cluster with pluggable policies for different
|
||||
* caches or some other mechanism.
|
||||
*/
|
||||
- (void)_evictObjectsToMakeSpaceForObjectWithCost: (NSUInteger)cost
|
||||
- (void) _evictObjectsToMakeSpaceForObjectWithCost: (NSUInteger)cost
|
||||
{
|
||||
NSUInteger spaceNeeded = 0;
|
||||
NSUInteger count = [_objects count];
|
||||
NSUInteger count;
|
||||
|
||||
[_lock lock];
|
||||
count = [_objects count];
|
||||
if (_costLimit > 0 && _totalCost + cost > _costLimit)
|
||||
{
|
||||
spaceNeeded = _totalCost + cost - _costLimit;
|
||||
|
@ -261,24 +287,26 @@
|
|||
[self removeObjectForKey: key];
|
||||
}
|
||||
}
|
||||
[evictedKeys release];
|
||||
RELEASE(evictedKeys);
|
||||
}
|
||||
[_lock unlock];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_name release];
|
||||
[_objects release];
|
||||
[_accesses release];
|
||||
[super dealloc];
|
||||
RELEASE(_lock);
|
||||
RELEASE(_name);
|
||||
RELEASE(_objects);
|
||||
RELEASE(_accesses);
|
||||
DEALLOC
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation _GSCachedObject
|
||||
- (void) dealloc
|
||||
{
|
||||
[object release];
|
||||
[key release];
|
||||
[super dealloc];
|
||||
RELEASE(object);
|
||||
RELEASE(key);
|
||||
DEALLOC
|
||||
}
|
||||
@end
|
||||
|
|
Loading…
Reference in a new issue