Fixes in experimental code

This commit is contained in:
Richard Frith-Macdonald 2018-03-27 09:55:29 +01:00
parent ebfe915619
commit d6612ef880
3 changed files with 66 additions and 59 deletions

View file

@ -4,9 +4,10 @@
* Source/NSDebug.m:
* Source/NSException.m:
* Source/NSThread.m:
* Headers/Foundation/NSThread.h:
Move stack info code from NSDebug to NSException so its all in one
place and. Make thread call stack addresses method use windows code
as well as libbacktrace.
as well as libbacktrace. Remove unused method.
2018-03-26 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -37,7 +37,6 @@
@class NSArray;
@class NSDate;
@class NSMutableArray;
@class NSMutableDictionary;
#if defined(__cplusplus)
@ -379,11 +378,6 @@ GS_EXPORT void GSUnregisterCurrentThread (void);
*/
+ (void) setTraceLocks: (BOOL)aFlag;
/** Returns an array containing a snapshot of threads which are active and
* waiting for a mutex.
*/
+ (NSMutableArray *) waitingThreads;
/* Removes the mutex (either as the one we are waiting for or as a held mutex.
* For internal use only ... do not call this method.<br />
*/

View file

@ -1355,41 +1355,12 @@ lockInfoErr(NSString *str)
{
if (traceLocks)
{
traceLocks = NO;
return str;
}
return nil;
}
+ (NSMutableArray *) waitingThreads
{
NSMutableArray *a;
pthread_mutex_lock(&_activeLock);
{
NSHashEnumerator enumerator;
NSUInteger count = [_activeThreads count];
NSUInteger index;
GS_BEGINITEMBUF(objects, count, NSThread*);
enumerator = NSEnumerateHashTable(_activeThreads);
index = 0;
while (index < count
&& (objects[index] = NSNextHashEnumeratorItem(&enumerator)) != nil)
{
if (YES == objects[index]->_active
&& nil != GSIVar(objects[index], _lockInfo.wait))
{
index++; // Currently active and waiting
}
}
NSEndHashTableEnumeration(&enumerator);
a = [[NSMutableArray alloc] initWithObjects: objects count: index];
GS_ENDITEMBUF();
}
pthread_mutex_unlock(&_activeLock);
return AUTORELEASE(a);
}
- (NSString *) mutexDrop: (id)mutex
{
if (GS_EXISTS_INTERNAL && traceLocks)
@ -1511,17 +1482,23 @@ lockInfoErr(NSString *str)
return nil; // We can't deadlock on a recursive lock we own
}
pthread_mutex_lock(&_activeLock);
/* While checking for deadlocks we don't want threads created/destroyed
* So we hold the lock to prevent thread activity changes.
* This also ensures that no more than one thread can be checking for
* deadlocks at a time (no interference between checks).
*/
pthread_mutex_lock(&_activeLock);
/* As we isolate dependencies (a thread holding the lock another thread
* is waiting for) we disable locking in each thread and record the
* thread in a hash table. Once we have determined all the dependencies
* we can re-enable locking in each of the threads.
*/
if (nil == _activeBlocked)
{
_activeBlocked = NSCreateHashTable(
NSNonRetainedObjectHashCallBacks, 100);
}
else
{
NSResetHashTable(_activeBlocked);
}
NSMutableArray *dependencies = nil;
id want = mutex;
@ -1531,8 +1508,14 @@ pthread_mutex_lock(&_activeLock);
{
NSHashEnumerator enumerator;
NSThread *found = nil;
BOOL foundWasLocked = NO;
NSThread *th;
/* Look for a thread which is holding the mutex we are currently
* interested in. We are only interested in thread which are
* themselves waiting for a lock (if they aren't waiting then
* they can't be part of a deadlock dependency list).
*/
enumerator = NSEnumerateHashTable(_activeThreads);
while ((th = NSNextHashEnumeratorItem(&enumerator)) != nil)
{
@ -1540,13 +1523,33 @@ pthread_mutex_lock(&_activeLock);
if (YES == th->_active && nil != info->wait)
{
BOOL wasLocked;
GSStackTrace *stck;
pthread_spin_lock(&info->spin);
if (th == self
|| NULL != NSHashGet(_activeBlocked, (const void*)th))
{
/* Don't lock ... this is the current thread or is
* already in the set of blocked threads.
*/
wasLocked = YES;
}
else
{
pthread_spin_lock(&info->spin);
wasLocked = NO;
}
if (nil != info->wait
&& nil != (stck = NSMapGet(info->held, (const void*)want)))
{
/* This thread holds the lock we are interested in and
* is waiting for another lock.
* We therefore record the details in the dependency list
* and will go on to look for the thread this found one
* depends on.
*/
found = th;
foundWasLocked = wasLocked;
want = info->wait;
if (nil == dependencies)
{
@ -1563,7 +1566,13 @@ pthread_mutex_lock(&_activeLock);
*/
break;
}
pthread_spin_unlock(&info->spin);
/* This thread did not hold the lock we are interested in,
* so we can unlock it (if necessary) and check another.
*/
if (NO == wasLocked)
{
pthread_spin_unlock(&info->spin);
}
}
}
NSEndHashTableEnumeration(&enumerator);
@ -1575,22 +1584,19 @@ pthread_mutex_lock(&_activeLock);
DESTROY(dependencies);
done = YES;
}
else if (foundWasLocked)
{
/* The found thread is the current one or in the blocked set
* so we have a deadlock.
*/
done = YES;
}
else
{
if (found == self
|| NULL != NSHashGet(_activeBlocked,(const void*)found))
{
/* The found thread is the current one or in the blocked set
* so we have a deadlock.
*/
done = YES;
}
else
{
NSHashInsert(_activeBlocked, (const void*)found);
/* Continue to find the next dependency.
*/
}
/* Record the found (and locked) thread and continue
* to find the next dependency.
*/
NSHashInsert(_activeBlocked, (const void*)found);
}
}
@ -1609,8 +1615,14 @@ pthread_mutex_lock(&_activeLock);
pthread_spin_unlock(&info->spin);
}
NSEndHashTableEnumeration(&enumerator);
NSResetHashTable(_activeBlocked);
}
pthread_mutex_unlock(&_activeLock);
/* Finished check ... re-enable thread activity changes.
*/
pthread_mutex_unlock(&_activeLock);
if (nil != dependencies)
{
NSUInteger count;