* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
/** Control of executable units within a shared virtual memory space
|
2010-03-25 22:53:21 +00:00
|
|
|
|
Copyright (C) 1996-2010 Free Software Foundation, Inc.
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
Original Author: David Chisnall <csdavec@swan.ac.uk>
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1996-02-13 15:40:05 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
1996-02-13 15:40:05 +00:00
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Lesser General Public License for more details.
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1999-12-10 00:59:40 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-10-20 10:56:27 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Boston, MA 02110 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSLock class reference</title>
|
2009-11-23 09:42:18 +00:00
|
|
|
|
<ignore> All autogsdoc markup is in the header
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
2010-06-12 07:19:26 +00:00
|
|
|
|
#import "common.h"
|
2018-03-26 14:20:48 +00:00
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#define EXPOSE_NSLock_IVARS 1
|
|
|
|
|
#define EXPOSE_NSRecursiveLock_IVARS 1
|
|
|
|
|
#define EXPOSE_NSCondition_IVARS 1
|
|
|
|
|
#define EXPOSE_NSConditionLock_IVARS 1
|
2010-02-19 08:12:46 +00:00
|
|
|
|
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#define gs_cond_public_t gs_cond_t
|
|
|
|
|
#define gs_cond_mutex_public_t gs_cond_mutex_t
|
|
|
|
|
#define gs_mutex_public_t gs_mutex_t
|
|
|
|
|
|
|
|
|
|
#import "GSPrivate.h"
|
|
|
|
|
#import "GSPThread.h"
|
|
|
|
|
#include <math.h>
|
2023-09-11 15:02:14 +00:00
|
|
|
|
#include <stdlib.h>
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
|
|
|
|
|
2009-09-06 11:02:57 +00:00
|
|
|
|
#import "Foundation/NSLock.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
2018-03-26 14:20:48 +00:00
|
|
|
|
#import "Foundation/NSThread.h"
|
|
|
|
|
|
2018-04-12 20:41:15 +00:00
|
|
|
|
#define class_createInstance(C,E) NSAllocateObject(C,E,NSDefaultMallocZone())
|
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
static Class baseConditionClass = Nil;
|
|
|
|
|
static Class baseConditionLockClass = Nil;
|
|
|
|
|
static Class baseLockClass = Nil;
|
|
|
|
|
static Class baseRecursiveLockClass = Nil;
|
|
|
|
|
|
|
|
|
|
static Class tracedConditionClass = Nil;
|
|
|
|
|
static Class tracedConditionLockClass = Nil;
|
|
|
|
|
static Class tracedLockClass = Nil;
|
|
|
|
|
static Class tracedRecursiveLockClass = Nil;
|
|
|
|
|
|
|
|
|
|
static Class untracedConditionClass = Nil;
|
|
|
|
|
static Class untracedConditionLockClass = Nil;
|
|
|
|
|
static Class untracedLockClass = Nil;
|
|
|
|
|
static Class untracedRecursiveLockClass = Nil;
|
|
|
|
|
|
2018-03-26 14:20:48 +00:00
|
|
|
|
static BOOL traceLocks = NO;
|
|
|
|
|
|
2018-04-04 13:42:20 +00:00
|
|
|
|
@implementation NSObject (GSTraceLocks)
|
|
|
|
|
|
|
|
|
|
+ (BOOL) shouldCreateTraceableLocks: (BOOL)shouldTrace
|
|
|
|
|
{
|
|
|
|
|
BOOL old = traceLocks;
|
|
|
|
|
|
|
|
|
|
traceLocks = shouldTrace ? YES : NO;
|
|
|
|
|
return old;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSCondition*) tracedCondition
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([GSTracedCondition new]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSConditionLock*) tracedConditionLockWithCondition: (NSInteger)value
|
2018-03-26 14:20:48 +00:00
|
|
|
|
{
|
2018-04-04 13:42:20 +00:00
|
|
|
|
return AUTORELEASE([[GSTracedConditionLock alloc] initWithCondition: value]);
|
2018-03-26 14:20:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-04 13:42:20 +00:00
|
|
|
|
+ (NSLock*) tracedLock
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([GSTracedLock new]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSRecursiveLock*) tracedRecursiveLock
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([GSTracedRecursiveLock new]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
/* In untraced operations these macros do nothing.
|
|
|
|
|
* When tracing they are defined to perform the trace methods of the thread.
|
|
|
|
|
*/
|
|
|
|
|
#define CHKT(T,X)
|
|
|
|
|
#define CHK(X)
|
2003-07-20 06:37:25 +00:00
|
|
|
|
|
2009-11-23 09:42:18 +00:00
|
|
|
|
/*
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
* Methods shared between NSLock, NSRecursiveLock, and NSCondition
|
|
|
|
|
*
|
|
|
|
|
* Note: These methods currently throw exceptions when locks are incorrectly
|
|
|
|
|
* acquired. This is compatible with earlier GNUstep behaviour. In OS X 10.5
|
|
|
|
|
* and later, these will just NSLog a warning instead. Throwing an exception
|
|
|
|
|
* is probably better behaviour, because it encourages developer to fix their
|
2010-02-03 22:13:48 +00:00
|
|
|
|
* code.
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
*/
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
|
|
|
|
#define MDEALLOC \
|
|
|
|
|
- (void) dealloc\
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
{\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
[self finalize];\
|
|
|
|
|
[_name release];\
|
|
|
|
|
[super dealloc];\
|
|
|
|
|
}
|
2015-06-30 10:49:19 +00:00
|
|
|
|
|
|
|
|
|
#if defined(HAVE_PTHREAD_MUTEX_OWNER)
|
2015-07-08 12:54:15 +00:00
|
|
|
|
|
2015-06-30 10:49:19 +00:00
|
|
|
|
#define MDESCRIPTION \
|
|
|
|
|
- (NSString*) description\
|
|
|
|
|
{\
|
|
|
|
|
if (_mutex.__data.__owner)\
|
|
|
|
|
{\
|
|
|
|
|
if (_name == nil)\
|
|
|
|
|
{\
|
2015-07-08 12:54:15 +00:00
|
|
|
|
return [NSString stringWithFormat: @"%@ (locked by %llu)",\
|
2015-08-16 10:42:48 +00:00
|
|
|
|
[super description], (unsigned long long)_mutex.__data.__owner];\
|
2015-06-30 10:49:19 +00:00
|
|
|
|
}\
|
2015-07-08 12:54:15 +00:00
|
|
|
|
return [NSString stringWithFormat: @"%@ '%@' (locked by %llu)",\
|
2015-08-16 10:42:48 +00:00
|
|
|
|
[super description], _name, (unsigned long long)_mutex.__data.__owner];\
|
2015-06-30 10:49:19 +00:00
|
|
|
|
}\
|
|
|
|
|
else\
|
|
|
|
|
{\
|
|
|
|
|
if (_name == nil)\
|
|
|
|
|
{\
|
|
|
|
|
return [super description];\
|
|
|
|
|
}\
|
|
|
|
|
return [NSString stringWithFormat: @"%@ '%@'",\
|
|
|
|
|
[super description], _name];\
|
|
|
|
|
}\
|
|
|
|
|
}
|
2015-07-08 12:54:15 +00:00
|
|
|
|
|
|
|
|
|
#define MISLOCKED \
|
|
|
|
|
- (BOOL) isLockedByCurrentThread\
|
|
|
|
|
{\
|
|
|
|
|
if (GSPrivateThreadID() == (NSUInteger)_mutex.__data.__owner)\
|
|
|
|
|
return YES;\
|
|
|
|
|
else\
|
|
|
|
|
return NO; \
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-30 10:49:19 +00:00
|
|
|
|
#else
|
2015-07-08 12:54:15 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
#define MDESCRIPTION \
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
- (NSString*) description\
|
|
|
|
|
{\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
if (_name == nil)\
|
|
|
|
|
{\
|
|
|
|
|
return [super description];\
|
|
|
|
|
}\
|
|
|
|
|
return [NSString stringWithFormat: @"%@ '%@'",\
|
|
|
|
|
[super description], _name];\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2015-07-08 12:54:15 +00:00
|
|
|
|
|
|
|
|
|
#define MISLOCKED \
|
|
|
|
|
- (BOOL) isLockedByCurrentThread\
|
|
|
|
|
{\
|
|
|
|
|
[NSException raise: NSGenericException format: @"Not supported"];\
|
|
|
|
|
return NO;\
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-30 10:49:19 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
#define MFINALIZE \
|
|
|
|
|
- (void) finalize\
|
|
|
|
|
{\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_MUTEX_DESTROY(_mutex);\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2015-06-30 10:49:19 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
#define MLOCK \
|
|
|
|
|
- (void) lock\
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
{\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int err = GS_MUTEX_LOCK(_mutex);\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
if (EDEADLK == err)\
|
|
|
|
|
{\
|
2018-03-26 14:20:48 +00:00
|
|
|
|
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
|
|
|
|
|
}\
|
|
|
|
|
else if (err != 0)\
|
|
|
|
|
{\
|
2018-04-04 11:58:06 +00:00
|
|
|
|
[NSException raise: NSLockException format: @"failed to lock mutex"];\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
}\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2015-06-30 10:49:19 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
#define MLOCKBEFOREDATE \
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
- (BOOL) lockBeforeDate: (NSDate*)limit\
|
|
|
|
|
{\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
do\
|
|
|
|
|
{\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int err = GS_MUTEX_TRYLOCK(_mutex);\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
if (0 == err)\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{\
|
2018-03-26 14:20:48 +00:00
|
|
|
|
CHK(Hold) \
|
2021-07-28 14:17:47 +00:00
|
|
|
|
return YES;\
|
|
|
|
|
}\
|
|
|
|
|
GS_YIELD();\
|
2011-08-27 16:46:26 +00:00
|
|
|
|
} while ([limit timeIntervalSinceNow] > 0);\
|
2009-09-03 09:45:23 +00:00
|
|
|
|
return NO;\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2015-06-30 10:49:19 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
#define MNAME \
|
|
|
|
|
- (void) setName: (NSString*)newName\
|
|
|
|
|
{\
|
|
|
|
|
ASSIGNCOPY(_name, newName);\
|
|
|
|
|
}\
|
|
|
|
|
- (NSString*) name\
|
|
|
|
|
{\
|
|
|
|
|
return _name;\
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MSTACK \
|
|
|
|
|
- (GSStackTrace*) stack \
|
|
|
|
|
{ \
|
|
|
|
|
return nil; \
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
#define MTRYLOCK \
|
|
|
|
|
- (BOOL) tryLock\
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
{\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int err = GS_MUTEX_TRYLOCK(_mutex);\
|
2018-03-26 14:20:48 +00:00
|
|
|
|
if (0 == err) \
|
|
|
|
|
{ \
|
|
|
|
|
CHK(Hold) \
|
|
|
|
|
return YES; \
|
|
|
|
|
} \
|
|
|
|
|
else \
|
|
|
|
|
{ \
|
|
|
|
|
return NO;\
|
|
|
|
|
} \
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2015-06-30 10:49:19 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
#define MUNLOCK \
|
|
|
|
|
- (void) unlock\
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
{\
|
2021-07-28 14:17:47 +00:00
|
|
|
|
if (0 != GS_MUTEX_UNLOCK(_mutex))\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
{\
|
2023-09-11 16:25:57 +00:00
|
|
|
|
if (GSPrivateDefaultsFlag(GSMacOSXCompatible))\
|
|
|
|
|
{\
|
|
|
|
|
NSLog(@"Failed to unlock mutex %@ at %@",\
|
|
|
|
|
self, [NSThread callStackSymbols]);\
|
|
|
|
|
}\
|
|
|
|
|
else \
|
2023-09-09 16:53:42 +00:00
|
|
|
|
{\
|
|
|
|
|
[NSException raise: NSLockException\
|
2023-09-11 16:25:57 +00:00
|
|
|
|
format: @"failed to unlock mutex %@", self];\
|
2023-09-09 16:53:42 +00:00
|
|
|
|
}\
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}\
|
2018-03-26 14:20:48 +00:00
|
|
|
|
CHK(Drop) \
|
2003-07-20 06:37:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-28 14:17:47 +00:00
|
|
|
|
static gs_mutex_t deadlock;
|
|
|
|
|
#if !GS_USE_WIN32_THREADS_AND_LOCKS
|
2009-09-06 14:37:07 +00:00
|
|
|
|
static pthread_mutexattr_t attr_normal;
|
|
|
|
|
static pthread_mutexattr_t attr_reporting;
|
|
|
|
|
static pthread_mutexattr_t attr_recursive;
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
2009-11-23 09:42:18 +00:00
|
|
|
|
/*
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
* OS X 10.5 compatibility function to allow debugging deadlock conditions.
|
2003-07-20 06:37:25 +00:00
|
|
|
|
*/
|
2018-03-26 14:20:48 +00:00
|
|
|
|
void _NSLockError(id obj, SEL _cmd, BOOL stop, NSString *msg)
|
2003-07-20 06:37:25 +00:00
|
|
|
|
{
|
2018-03-26 14:20:48 +00:00
|
|
|
|
NSLog(@"*** -[%@ %@]: %@ (%@)", [obj class], NSStringFromSelector(_cmd),
|
|
|
|
|
msg, obj);
|
2009-09-03 09:45:23 +00:00
|
|
|
|
NSLog(@"*** Break on _NSLockError() to debug.");
|
2010-02-14 10:48:10 +00:00
|
|
|
|
if (YES == stop)
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_MUTEX_LOCK(deadlock);
|
2003-07-20 06:37:25 +00:00
|
|
|
|
}
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
2018-03-16 15:11:02 +00:00
|
|
|
|
NSLock_error_handler *_NSLock_error_handler = _NSLockError;
|
|
|
|
|
|
1998-04-20 14:13:19 +00:00
|
|
|
|
// Exceptions
|
|
|
|
|
|
|
|
|
|
NSString *NSLockException = @"NSLockException";
|
|
|
|
|
|
1996-05-28 13:37:17 +00:00
|
|
|
|
@implementation NSLock
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == baseLockClass && YES == traceLocks)
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
return class_createInstance(self, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
static BOOL beenHere = NO;
|
|
|
|
|
|
|
|
|
|
if (beenHere == NO)
|
|
|
|
|
{
|
|
|
|
|
beenHere = YES;
|
|
|
|
|
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if !GS_USE_WIN32_THREADS_AND_LOCKS
|
2009-09-06 14:37:07 +00:00
|
|
|
|
/* Initialise attributes for the different types of mutex.
|
|
|
|
|
* We do it once, since attributes can be shared between multiple
|
|
|
|
|
* mutexes.
|
|
|
|
|
* If we had a pthread_mutexattr_t instance for each mutex, we would
|
|
|
|
|
* either have to store it as an ivar of our NSLock (or similar), or
|
|
|
|
|
* we would potentially leak instances as we couldn't destroy them
|
|
|
|
|
* when destroying the NSLock. I don't know if any implementation
|
|
|
|
|
* of pthreads actually allocates memory when you call the
|
|
|
|
|
* pthread_mutexattr_init function, but they are allowed to do so
|
|
|
|
|
* (and deallocate the memory in pthread_mutexattr_destroy).
|
|
|
|
|
*/
|
|
|
|
|
pthread_mutexattr_init(&attr_normal);
|
|
|
|
|
pthread_mutexattr_settype(&attr_normal, PTHREAD_MUTEX_NORMAL);
|
|
|
|
|
pthread_mutexattr_init(&attr_reporting);
|
|
|
|
|
pthread_mutexattr_settype(&attr_reporting, PTHREAD_MUTEX_ERRORCHECK);
|
|
|
|
|
pthread_mutexattr_init(&attr_recursive);
|
|
|
|
|
pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
|
|
|
|
/* To emulate OSX behavior, we need to be able both to detect deadlocks
|
|
|
|
|
* (so we can log them), and also hang the thread when one occurs.
|
|
|
|
|
* the simple way to do that is to set up a locked mutex we can
|
|
|
|
|
* force a deadlock on.
|
|
|
|
|
*/
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
gs_mutex_init(&deadlock, gs_mutex_attr_normal);
|
|
|
|
|
#else
|
2009-09-06 14:37:07 +00:00
|
|
|
|
pthread_mutex_init(&deadlock, &attr_normal);
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif
|
|
|
|
|
GS_MUTEX_LOCK(deadlock);
|
2018-04-04 11:58:06 +00:00
|
|
|
|
|
|
|
|
|
baseConditionClass = [NSCondition class];
|
|
|
|
|
baseConditionLockClass = [NSConditionLock class];
|
|
|
|
|
baseLockClass = [NSLock class];
|
|
|
|
|
baseRecursiveLockClass = [NSRecursiveLock class];
|
|
|
|
|
|
|
|
|
|
tracedConditionClass = [GSTracedCondition class];
|
|
|
|
|
tracedConditionLockClass = [GSTracedConditionLock class];
|
|
|
|
|
tracedLockClass = [GSTracedLock class];
|
|
|
|
|
tracedRecursiveLockClass = [GSTracedRecursiveLock class];
|
|
|
|
|
|
|
|
|
|
untracedConditionClass = [GSUntracedCondition class];
|
|
|
|
|
untracedConditionLockClass = [GSUntracedConditionLock class];
|
|
|
|
|
untracedLockClass = [GSUntracedLock class];
|
|
|
|
|
untracedRecursiveLockClass = [GSUntracedRecursiveLock class];
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MDEALLOC
|
|
|
|
|
MDESCRIPTION
|
|
|
|
|
MFINALIZE
|
|
|
|
|
|
|
|
|
|
/* Use an error-checking lock. This is marginally slower, but lets us throw
|
|
|
|
|
* exceptions when incorrect locking occurs.
|
|
|
|
|
*/
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
if (nil != (self = [super init]))
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
gs_mutex_init(&_mutex, gs_mutex_attr_errorcheck);
|
|
|
|
|
#else
|
2009-09-06 14:37:07 +00:00
|
|
|
|
if (0 != pthread_mutex_init(&_mutex, &attr_reporting))
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 12:54:15 +00:00
|
|
|
|
MISLOCKED
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MLOCK
|
2010-02-14 10:48:10 +00:00
|
|
|
|
|
|
|
|
|
- (BOOL) lockBeforeDate: (NSDate*)limit
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int err = GS_MUTEX_TRYLOCK(_mutex);
|
2010-02-14 10:48:10 +00:00
|
|
|
|
if (0 == err)
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
2018-04-04 11:58:06 +00:00
|
|
|
|
CHK(Hold)
|
2021-07-28 14:17:47 +00:00
|
|
|
|
return YES;
|
|
|
|
|
}
|
2010-02-14 10:48:10 +00:00
|
|
|
|
if (EDEADLK == err)
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
(*_NSLock_error_handler)(self, _cmd, NO, @"deadlock");
|
|
|
|
|
}
|
|
|
|
|
GS_YIELD();
|
2011-08-27 16:46:26 +00:00
|
|
|
|
} while ([limit timeIntervalSinceNow] > 0);
|
2010-02-14 10:48:10 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MNAME
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MTRYLOCK
|
|
|
|
|
MUNLOCK
|
2018-04-04 11:58:06 +00:00
|
|
|
|
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
@end
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
@implementation NSRecursiveLock
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == baseRecursiveLockClass && YES == traceLocks)
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedRecursiveLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
return class_createInstance(self, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
[NSLock class]; // Ensure mutex attributes are set up.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MDEALLOC
|
|
|
|
|
MDESCRIPTION
|
|
|
|
|
MFINALIZE
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
if (nil != (self = [super init]))
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
gs_mutex_init(&_mutex, gs_mutex_attr_recursive);
|
|
|
|
|
#else
|
2009-09-06 14:37:07 +00:00
|
|
|
|
if (0 != pthread_mutex_init(&_mutex, &attr_recursive))
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 12:54:15 +00:00
|
|
|
|
MISLOCKED
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MLOCK
|
|
|
|
|
MLOCKBEFOREDATE
|
|
|
|
|
MNAME
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MTRYLOCK
|
|
|
|
|
MUNLOCK
|
* Source/NSLock.m
* Headers/Foundation/NSLock.h
Completely rewritten implementations of NSLock.h classes. These are now
faster, more complete, OS X-compatible, and most importantly actually
work. The old ones, for example, called functions that were not
implemented on Windows.
* Source/NSThread.m
Call pthread functions directly in NSThread instead of via the libobjc
abstraction layer. Also fixed a few issues, such as GC not being
initialized properly for NSThread subclasses that override -main (Javaism
supported by OS X) and tidies up the code in several places, removing
premature optimizations, especially those that introduce a test for an
unlikely case at the start of a method and thus slow everything down.
As a result of this change, GNUstep now depends on an implementation of
POSIX threads. This is included as standard on all modern UNIX systems,
and as an option on less-modern UNIX systems and non-UNIX systems,
including Windows. If you are building GNUstep on Windows, please install
the pthreads-win32 package, available from:
http://sourceware.org/pthreads-win32/
PLEASE TEST THIS! There may be some code that depended on the old
behaviour. I have been running the new NSLock implementation on FreeBSD
for a few weeks without issue; please report to me any problems that you
have on your platform.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28598 72102866-910b-0410-8b05-ffd578937521
2009-09-02 13:03:13 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSCondition
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == baseConditionClass && YES == traceLocks)
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedConditionClass, 0);
|
|
|
|
|
}
|
|
|
|
|
return class_createInstance(self, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
+ (void) initialize
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
[NSLock class]; // Ensure mutex attributes are set up.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) broadcast
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_COND_BROADCAST(_condition);
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MDEALLOC
|
|
|
|
|
MDESCRIPTION
|
|
|
|
|
|
|
|
|
|
- (void) finalize
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if !GS_USE_WIN32_THREADS_AND_LOCKS
|
2009-09-06 14:37:07 +00:00
|
|
|
|
pthread_cond_destroy(&_condition);
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif
|
|
|
|
|
GS_MUTEX_DESTROY(_mutex);
|
2009-09-06 14:37:07 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (id) init
|
|
|
|
|
{
|
2010-02-26 08:39:47 +00:00
|
|
|
|
if (nil != (self = [super init]))
|
2009-09-03 09:45:23 +00:00
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
InitializeConditionVariable(&_condition);
|
|
|
|
|
gs_mutex_init(&_mutex, gs_mutex_attr_errorcheck);
|
|
|
|
|
#else
|
2010-02-26 08:39:47 +00:00
|
|
|
|
if (0 != pthread_cond_init(&_condition, NULL))
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
2010-02-26 08:39:47 +00:00
|
|
|
|
else if (0 != pthread_mutex_init(&_mutex, &attr_reporting))
|
2021-07-28 14:17:47 +00:00
|
|
|
|
{
|
|
|
|
|
pthread_cond_destroy(&_condition);
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2009-09-03 09:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
2008-06-06 13:57:06 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2015-07-08 12:54:15 +00:00
|
|
|
|
MISLOCKED
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MLOCK
|
|
|
|
|
MLOCKBEFOREDATE
|
|
|
|
|
MNAME
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (void) signal
|
2008-06-06 13:57:06 +00:00
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_COND_SIGNAL(_condition);
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MTRYLOCK
|
|
|
|
|
MUNLOCK
|
|
|
|
|
|
2009-09-03 09:45:23 +00:00
|
|
|
|
- (void) wait
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_COND_WAIT(&_condition, &_mutex);
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
|
|
|
|
- (BOOL) waitUntilDate: (NSDate*)limit
|
1998-11-16 19:36:51 +00:00
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int retVal = 0;
|
|
|
|
|
|
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
NSTimeInterval ti = [limit timeIntervalSinceNow];
|
|
|
|
|
if (ti < 0) {
|
|
|
|
|
ti = 0.0; // handle timeout in the past
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retVal = gs_cond_timedwait(&_condition, &_mutex, ti * 1000.0);
|
|
|
|
|
#else
|
2018-03-26 14:20:48 +00:00
|
|
|
|
NSTimeInterval ti = [limit timeIntervalSince1970];
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|
2009-09-03 09:45:23 +00:00
|
|
|
|
double secs, subsecs;
|
|
|
|
|
struct timespec timeout;
|
|
|
|
|
|
|
|
|
|
// Split the float into seconds and fractions of a second
|
2018-03-26 14:20:48 +00:00
|
|
|
|
subsecs = modf(ti, &secs);
|
2009-09-03 09:45:23 +00:00
|
|
|
|
timeout.tv_sec = secs;
|
|
|
|
|
// Convert fractions of a second to nanoseconds
|
|
|
|
|
timeout.tv_nsec = subsecs * 1e9;
|
2010-02-03 22:13:48 +00:00
|
|
|
|
|
2018-03-26 14:20:48 +00:00
|
|
|
|
/* NB. On timeout the lock is still held even through condition is not met
|
|
|
|
|
*/
|
2010-02-03 22:13:48 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */
|
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
if (retVal == 0)
|
2009-09-30 20:12:14 +00:00
|
|
|
|
{
|
2018-04-04 11:58:06 +00:00
|
|
|
|
return YES;
|
2009-09-30 20:12:14 +00:00
|
|
|
|
}
|
2018-04-04 11:58:06 +00:00
|
|
|
|
if (retVal == ETIMEDOUT)
|
2009-09-30 20:12:14 +00:00
|
|
|
|
{
|
2018-04-04 11:58:06 +00:00
|
|
|
|
return NO;
|
2010-02-03 22:13:48 +00:00
|
|
|
|
}
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|
|
|
|
|
NSLog(@"Error calling pthread_cond_timedwait: %d", retVal);
|
2010-02-03 22:13:48 +00:00
|
|
|
|
return NO;
|
1998-11-16 19:36:51 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSConditionLock
|
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == baseConditionLockClass && YES == traceLocks)
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedConditionLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
return class_createInstance(self, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
+ (void) initialize
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
[NSLock class]; // Ensure mutex attributes are set up.
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (NSInteger) condition
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
return _condition_value;
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[_name release];
|
|
|
|
|
[_condition release];
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
1996-02-13 15:40:05 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
- (id) init
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
1996-05-28 13:37:17 +00:00
|
|
|
|
return [self initWithCondition: 0];
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (id) initWithCondition: (NSInteger)value
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2010-02-26 08:39:47 +00:00
|
|
|
|
if (nil != (self = [super init]))
|
2009-09-03 09:45:23 +00:00
|
|
|
|
{
|
2010-02-26 08:39:47 +00:00
|
|
|
|
if (nil == (_condition = [NSCondition new]))
|
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_condition_value = value;
|
2018-03-26 14:20:48 +00:00
|
|
|
|
[_condition setName:
|
|
|
|
|
[NSString stringWithFormat: @"condition-for-lock-%p", self]];
|
2010-02-26 08:39:47 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 12:54:15 +00:00
|
|
|
|
- (BOOL) isLockedByCurrentThread
|
|
|
|
|
{
|
|
|
|
|
return [_condition isLockedByCurrentThread];
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (void) lock
|
2000-09-14 08:48:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
[_condition lock];
|
2000-09-14 08:48:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (BOOL) lockBeforeDate: (NSDate*)limit
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
return [_condition lockBeforeDate: limit];
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (void) lockWhenCondition: (NSInteger)value
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-03 09:45:23 +00:00
|
|
|
|
[_condition lock];
|
|
|
|
|
while (value != _condition_value)
|
|
|
|
|
{
|
|
|
|
|
[_condition wait];
|
|
|
|
|
}
|
2008-06-06 13:57:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (BOOL) lockWhenCondition: (NSInteger)condition_to_meet
|
1999-09-16 07:21:34 +00:00
|
|
|
|
beforeDate: (NSDate*)limitDate
|
1998-11-16 19:36:51 +00:00
|
|
|
|
{
|
2013-05-31 09:28:14 +00:00
|
|
|
|
if (NO == [_condition lockBeforeDate: limitDate])
|
|
|
|
|
{
|
2018-03-26 14:20:48 +00:00
|
|
|
|
return NO; // Not locked
|
2013-05-31 09:28:14 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
if (condition_to_meet == _condition_value)
|
|
|
|
|
{
|
2018-03-26 14:20:48 +00:00
|
|
|
|
return YES; // Keeping the lock
|
2009-09-03 09:45:23 +00:00
|
|
|
|
}
|
2010-02-03 22:13:48 +00:00
|
|
|
|
while ([_condition waitUntilDate: limitDate])
|
|
|
|
|
{
|
|
|
|
|
if (condition_to_meet == _condition_value)
|
|
|
|
|
{
|
2018-03-26 14:20:48 +00:00
|
|
|
|
return YES; // Keeping the lock
|
2010-02-03 22:13:48 +00:00
|
|
|
|
}
|
2009-09-30 20:12:14 +00:00
|
|
|
|
}
|
2010-02-04 08:15:09 +00:00
|
|
|
|
[_condition unlock];
|
2018-03-26 14:20:48 +00:00
|
|
|
|
return NO; // Not locked
|
1998-11-16 19:36:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
MNAME
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2009-09-06 14:37:07 +00:00
|
|
|
|
|
|
|
|
|
- (BOOL) tryLock
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
return [_condition tryLock];
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 21:15:03 +00:00
|
|
|
|
- (BOOL) tryLockWhenCondition: (NSInteger)condition_to_meet
|
2009-09-06 14:37:07 +00:00
|
|
|
|
{
|
2010-02-03 22:13:48 +00:00
|
|
|
|
if ([_condition tryLock])
|
|
|
|
|
{
|
|
|
|
|
if (condition_to_meet == _condition_value)
|
|
|
|
|
{
|
|
|
|
|
return YES; // KEEP THE LOCK
|
2010-02-03 21:15:03 +00:00
|
|
|
|
}
|
2010-02-03 22:13:48 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[_condition unlock];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
- (void) unlock
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-03 09:45:23 +00:00
|
|
|
|
[_condition unlock];
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-06 14:37:07 +00:00
|
|
|
|
- (void) unlockWithCondition: (NSInteger)value
|
1996-02-13 15:40:05 +00:00
|
|
|
|
{
|
2009-09-06 14:37:07 +00:00
|
|
|
|
_condition_value = value;
|
|
|
|
|
[_condition broadcast];
|
|
|
|
|
[_condition unlock];
|
1996-02-13 15:40:05 +00:00
|
|
|
|
}
|
2009-09-03 09:45:23 +00:00
|
|
|
|
|
1996-02-13 15:40:05 +00:00
|
|
|
|
@end
|
2018-03-26 14:20:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Versions of the lock classes where the locking is unconditionally traced
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#undef CHKT
|
|
|
|
|
#define CHKT(T,X) \
|
|
|
|
|
{ \
|
|
|
|
|
NSString *msg = [T mutex ## X: self]; \
|
|
|
|
|
if (nil != msg) \
|
|
|
|
|
{ \
|
|
|
|
|
(*_NSLock_error_handler)(self, _cmd, YES, msg); \
|
|
|
|
|
} \
|
|
|
|
|
}
|
2018-04-04 11:58:06 +00:00
|
|
|
|
#undef CHK
|
|
|
|
|
#define CHK(X) CHKT(GSCurrentThread(), X)
|
|
|
|
|
|
|
|
|
|
#undef MDEALLOC
|
|
|
|
|
#define MDEALLOC \
|
|
|
|
|
- (void) dealloc \
|
|
|
|
|
{ \
|
|
|
|
|
DESTROY(stack); \
|
|
|
|
|
[super dealloc]; \
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-26 14:20:48 +00:00
|
|
|
|
#undef MLOCK
|
|
|
|
|
#define MLOCK \
|
|
|
|
|
- (void) lock\
|
2018-04-04 11:58:06 +00:00
|
|
|
|
{ \
|
|
|
|
|
NSThread *t = GSCurrentThread(); \
|
2018-04-13 09:55:12 +00:00
|
|
|
|
int err; \
|
2018-04-04 11:58:06 +00:00
|
|
|
|
CHKT(t,Wait) \
|
2021-07-28 14:17:47 +00:00
|
|
|
|
err = GS_MUTEX_LOCK(_mutex);\
|
2018-04-04 11:58:06 +00:00
|
|
|
|
if (EDEADLK == err)\
|
|
|
|
|
{\
|
|
|
|
|
CHKT(t,Drop) \
|
|
|
|
|
(*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\
|
|
|
|
|
}\
|
|
|
|
|
else if (err != 0)\
|
|
|
|
|
{\
|
|
|
|
|
CHKT(t,Drop) \
|
|
|
|
|
[NSException raise: NSLockException format: @"failed to lock mutex"];\
|
|
|
|
|
}\
|
|
|
|
|
CHKT(t,Hold) \
|
|
|
|
|
}
|
2018-03-26 14:20:48 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
#undef MSTACK
|
|
|
|
|
#define MSTACK \
|
|
|
|
|
- (GSStackTrace*) stack \
|
|
|
|
|
{ \
|
|
|
|
|
if (nil == stack) \
|
|
|
|
|
{ \
|
|
|
|
|
stack = [GSStackTrace new]; \
|
|
|
|
|
} \
|
|
|
|
|
return stack; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@implementation GSTracedCondition
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedConditionClass, 0);
|
|
|
|
|
}
|
|
|
|
|
MDEALLOC
|
|
|
|
|
MLOCK
|
|
|
|
|
MLOCKBEFOREDATE
|
|
|
|
|
MSTACK
|
|
|
|
|
MTRYLOCK
|
|
|
|
|
|
|
|
|
|
- (void) wait
|
|
|
|
|
{
|
|
|
|
|
NSThread *t = GSCurrentThread();
|
|
|
|
|
CHKT(t,Drop)
|
|
|
|
|
CHKT(t,Wait)
|
2021-07-28 14:17:47 +00:00
|
|
|
|
GS_COND_WAIT(&_condition, &_mutex);
|
2018-04-04 11:58:06 +00:00
|
|
|
|
CHKT(t,Hold)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) waitUntilDate: (NSDate*)limit
|
|
|
|
|
{
|
2021-07-28 14:17:47 +00:00
|
|
|
|
int retVal = 0;
|
|
|
|
|
NSThread *t = GSCurrentThread();
|
|
|
|
|
|
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
NSTimeInterval ti = [limit timeIntervalSinceNow];
|
|
|
|
|
if (ti < 0) {
|
|
|
|
|
ti = 0.0; // handle timeout in the past
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CHKT(t,Drop)
|
|
|
|
|
retVal = gs_cond_timedwait(&_condition, &_mutex, ti * 1000.0);
|
|
|
|
|
#else
|
2018-04-04 11:58:06 +00:00
|
|
|
|
NSTimeInterval ti = [limit timeIntervalSince1970];
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
double secs, subsecs;
|
|
|
|
|
struct timespec timeout;
|
|
|
|
|
|
|
|
|
|
// Split the float into seconds and fractions of a second
|
|
|
|
|
subsecs = modf(ti, &secs);
|
|
|
|
|
timeout.tv_sec = secs;
|
|
|
|
|
// Convert fractions of a second to nanoseconds
|
|
|
|
|
timeout.tv_nsec = subsecs * 1e9;
|
|
|
|
|
|
|
|
|
|
/* NB. On timeout the lock is still held even through condition is not met
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
CHKT(t,Drop)
|
|
|
|
|
retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout);
|
2021-07-28 14:17:47 +00:00
|
|
|
|
#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */
|
|
|
|
|
|
2018-04-04 11:58:06 +00:00
|
|
|
|
if (retVal == 0)
|
|
|
|
|
{
|
|
|
|
|
CHKT(t,Hold)
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
if (retVal == ETIMEDOUT)
|
|
|
|
|
{
|
|
|
|
|
CHKT(t,Hold)
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-28 14:17:47 +00:00
|
|
|
|
NSLog(@"Error calling pthread_cond_timedwait: %d", retVal);
|
2018-04-04 11:58:06 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MUNLOCK
|
|
|
|
|
@end
|
|
|
|
|
@implementation GSTracedConditionLock
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedConditionLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
- (id) initWithCondition: (NSInteger)value
|
|
|
|
|
{
|
|
|
|
|
if (nil != (self = [super init]))
|
|
|
|
|
{
|
|
|
|
|
if (nil == (_condition = [GSTracedCondition new]))
|
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_condition_value = value;
|
|
|
|
|
[_condition setName:
|
|
|
|
|
[NSString stringWithFormat: @"condition-for-lock-%p", self]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
@end
|
2018-03-26 14:20:48 +00:00
|
|
|
|
@implementation GSTracedLock
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
MDEALLOC
|
2018-03-26 14:20:48 +00:00
|
|
|
|
MLOCK
|
|
|
|
|
MLOCKBEFOREDATE
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2018-03-26 14:20:48 +00:00
|
|
|
|
MTRYLOCK
|
|
|
|
|
MUNLOCK
|
|
|
|
|
@end
|
|
|
|
|
@implementation GSTracedRecursiveLock
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(tracedRecursiveLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
MDEALLOC
|
2018-03-26 14:20:48 +00:00
|
|
|
|
MLOCK
|
|
|
|
|
MLOCKBEFOREDATE
|
2018-04-04 11:58:06 +00:00
|
|
|
|
MSTACK
|
2018-03-26 14:20:48 +00:00
|
|
|
|
MTRYLOCK
|
|
|
|
|
MUNLOCK
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Versions of the lock classes where the locking is never traced
|
|
|
|
|
*/
|
2018-04-04 11:58:06 +00:00
|
|
|
|
@implementation GSUntracedCondition
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(baseConditionClass, 0);
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
@implementation GSUntracedConditionLock
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(baseConditionLockClass, 0);
|
|
|
|
|
}
|
|
|
|
|
@end
|
2018-03-26 14:20:48 +00:00
|
|
|
|
@implementation GSUntracedLock
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(baseRecursiveLockClass, 0);
|
|
|
|
|
}
|
2018-03-26 14:20:48 +00:00
|
|
|
|
@end
|
|
|
|
|
@implementation GSUntracedRecursiveLock
|
2018-04-04 11:58:06 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
return class_createInstance(baseRecursiveLockClass, 0);
|
|
|
|
|
}
|
2018-03-26 14:20:48 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2024-04-29 12:11:35 +00:00
|
|
|
|
/* Return a global recursive lock
|
|
|
|
|
*/
|
|
|
|
|
NSRecursiveLock *
|
|
|
|
|
GSPrivateGlobalLock()
|
|
|
|
|
{
|
|
|
|
|
static NSRecursiveLock *lock = nil;
|
|
|
|
|
|
|
|
|
|
if (nil == lock)
|
|
|
|
|
{
|
|
|
|
|
static gs_mutex_t lockLock = GS_MUTEX_INIT_STATIC;
|
|
|
|
|
|
|
|
|
|
GS_MUTEX_LOCK(lockLock);
|
|
|
|
|
if (nil == lock)
|
|
|
|
|
{
|
|
|
|
|
lock = [GSUntracedRecursiveLock new];
|
|
|
|
|
}
|
|
|
|
|
GS_MUTEX_UNLOCK(lockLock);
|
|
|
|
|
}
|
|
|
|
|
return lock;
|
|
|
|
|
}
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Pthread-like locking primitives using Windows SRWLock. Provides
|
|
|
|
|
* normal, recursive, and error-checked locks.
|
|
|
|
|
*/
|
|
|
|
|
#if GS_USE_WIN32_THREADS_AND_LOCKS
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gs_mutex_init(gs_mutex_t *mutex, gs_mutex_attr_t attr)
|
|
|
|
|
{
|
|
|
|
|
memset(mutex, 0, sizeof(gs_mutex_t));
|
|
|
|
|
InitializeSRWLock(&mutex->lock);
|
|
|
|
|
mutex->attr = attr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
gs_mutex_lock(gs_mutex_t *mutex)
|
|
|
|
|
{
|
|
|
|
|
DWORD thisThread = GetCurrentThreadId();
|
|
|
|
|
DWORD ownerThread;
|
|
|
|
|
|
|
|
|
|
// fast path if lock is not taken
|
|
|
|
|
if (TryAcquireSRWLockExclusive(&mutex->lock))
|
|
|
|
|
{
|
|
|
|
|
assert(mutex->depth == 0);
|
|
|
|
|
mutex->depth = 1;
|
|
|
|
|
atomic_store(&mutex->owner, thisThread);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// needs to be atomic because another thread can concurrently set it
|
|
|
|
|
ownerThread = atomic_load(&mutex->owner);
|
|
|
|
|
if (ownerThread == thisThread)
|
|
|
|
|
{
|
|
|
|
|
// this thread already owns this lock
|
|
|
|
|
switch (mutex->attr)
|
|
|
|
|
{
|
|
|
|
|
case gs_mutex_attr_normal:
|
|
|
|
|
// deadlock
|
|
|
|
|
assert(mutex->depth == 1);
|
|
|
|
|
AcquireSRWLockExclusive(&mutex->lock);
|
|
|
|
|
assert(false); // not reached
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case gs_mutex_attr_errorcheck:
|
|
|
|
|
// return deadlock error
|
|
|
|
|
assert(mutex->depth == 1);
|
|
|
|
|
return EDEADLK;
|
|
|
|
|
|
|
|
|
|
case gs_mutex_attr_recursive:
|
|
|
|
|
// recursive lock
|
|
|
|
|
mutex->depth++;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// wait for another thread to release the lock
|
|
|
|
|
AcquireSRWLockExclusive(&mutex->lock);
|
|
|
|
|
assert(mutex->depth == 0);
|
|
|
|
|
mutex->depth = 1;
|
|
|
|
|
atomic_store(&mutex->owner, thisThread);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
gs_mutex_trylock(gs_mutex_t *mutex)
|
|
|
|
|
{
|
|
|
|
|
DWORD thisThread = GetCurrentThreadId();
|
|
|
|
|
DWORD ownerThread;
|
|
|
|
|
|
|
|
|
|
if (TryAcquireSRWLockExclusive(&mutex->lock))
|
|
|
|
|
{
|
|
|
|
|
assert(mutex->depth == 0);
|
|
|
|
|
mutex->depth = 1;
|
|
|
|
|
atomic_store(&mutex->owner, thisThread);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// needs to be atomic because another thread can concurrently set it
|
|
|
|
|
ownerThread = atomic_load(&mutex->owner);
|
|
|
|
|
if (ownerThread == thisThread && mutex->attr == gs_mutex_attr_recursive)
|
|
|
|
|
{
|
|
|
|
|
// this thread already owns this lock and it's recursive
|
|
|
|
|
assert(mutex->depth > 0);
|
|
|
|
|
mutex->depth++;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// lock is taken
|
|
|
|
|
return EBUSY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
gs_mutex_unlock(gs_mutex_t *mutex)
|
|
|
|
|
{
|
|
|
|
|
switch (mutex->attr)
|
|
|
|
|
{
|
|
|
|
|
case gs_mutex_attr_normal:
|
|
|
|
|
break;
|
|
|
|
|
case gs_mutex_attr_errorcheck:
|
|
|
|
|
case gs_mutex_attr_recursive: {
|
|
|
|
|
// return error if lock is not held by this thread
|
|
|
|
|
DWORD thisThread = GetCurrentThreadId();
|
|
|
|
|
DWORD ownerThread = atomic_load(&mutex->owner);
|
|
|
|
|
if (ownerThread != thisThread) {
|
|
|
|
|
return EPERM;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mutex->attr == gs_mutex_attr_recursive && mutex->depth > 1)
|
|
|
|
|
{
|
|
|
|
|
// recursive lock releasing inner lock
|
|
|
|
|
mutex->depth--;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
assert(mutex->depth == 1);
|
|
|
|
|
mutex->depth = 0;
|
|
|
|
|
atomic_store(&mutex->owner, 0);
|
|
|
|
|
ReleaseSRWLockExclusive(&mutex->lock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NB: timeout specified in milliseconds relative to now
|
|
|
|
|
int
|
|
|
|
|
gs_cond_timedwait(gs_cond_t *cond, gs_mutex_t *mutex, DWORD millisecs)
|
|
|
|
|
{
|
|
|
|
|
int retVal = 0;
|
|
|
|
|
|
|
|
|
|
assert(mutex->depth == 1);
|
|
|
|
|
mutex->depth = 0;
|
|
|
|
|
atomic_store(&mutex->owner, 0);
|
|
|
|
|
|
|
|
|
|
if (!SleepConditionVariableSRW(cond, &mutex->lock, millisecs, 0))
|
|
|
|
|
{
|
|
|
|
|
DWORD lastError = GetLastError();
|
|
|
|
|
if (lastError == ERROR_TIMEOUT) {
|
|
|
|
|
retVal = ETIMEDOUT;
|
|
|
|
|
} else {
|
|
|
|
|
retVal = lastError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(mutex->depth == 0);
|
|
|
|
|
mutex->depth = 1;
|
|
|
|
|
atomic_store(&mutex->owner, GetCurrentThreadId());
|
|
|
|
|
|
|
|
|
|
return retVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline int
|
|
|
|
|
gs_cond_wait(gs_cond_t *cond, gs_mutex_t *mutex)
|
|
|
|
|
{
|
|
|
|
|
return gs_cond_timedwait(cond, mutex, INFINITE);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-21 20:20:52 +00:00
|
|
|
|
#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */
|
|
|
|
|
|
2023-12-12 20:45:06 +00:00
|
|
|
|
/** </ignore>
|
|
|
|
|
*/
|
2021-07-28 14:17:47 +00:00
|
|
|
|
|