mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 16:30:41 +00:00
Add automatic unregistration of threads that have not been
been explicitly unregistered. This works by keeping around a map table with all threads currently undergoing cleanup, and using that as a fallback if pthread_getspecific would not return the NSThread object from TLS. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@39318 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
478e376882
commit
b0afa17bed
3 changed files with 360 additions and 32 deletions
129
Tests/base/NSThread/late_unregister.m
Normal file
129
Tests/base/NSThread/late_unregister.m
Normal file
|
@ -0,0 +1,129 @@
|
|||
#import "ObjectTesting.h"
|
||||
#import <Foundation/NSThread.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSNotification.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
|
||||
|
||||
@interface ThreadExpectation : NSObject <NSLocking>
|
||||
{
|
||||
NSCondition *condition;
|
||||
NSThread *origThread;
|
||||
BOOL done;
|
||||
BOOL deallocated;
|
||||
}
|
||||
|
||||
- (void)onThreadExit: (NSNotification*)n;
|
||||
- (BOOL)isDone;
|
||||
@end
|
||||
|
||||
@implementation ThreadExpectation
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (nil == (self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
condition = [NSCondition new];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)inThread: (NSThread*)thread
|
||||
{
|
||||
/* We explicitly don't retain this so that we can check that it actually says
|
||||
* alive until the notification is sent. That check is implicit since
|
||||
* PASS_EQUAL in the -onThreadExit method will throw or crash if that isn't
|
||||
* the case.
|
||||
*/
|
||||
origThread = thread;
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(onThreadExit:)
|
||||
name: NSThreadWillExitNotification
|
||||
object: thread];
|
||||
}
|
||||
|
||||
- (void)onThreadExit: (NSNotification*)thr
|
||||
{
|
||||
NSThread *current = [NSThread currentThread];
|
||||
|
||||
PASS_EQUAL(origThread,current,
|
||||
"Correct thread reference can be obtained on exit");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
origThread = nil;
|
||||
[condition lock];
|
||||
done = YES;
|
||||
[condition broadcast];
|
||||
[condition unlock];
|
||||
}
|
||||
|
||||
- (BOOL)isDone
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
- (void)waitUntilDate: (NSDate*)date
|
||||
{
|
||||
[condition waitUntilDate: date];
|
||||
}
|
||||
|
||||
- (void)lock
|
||||
{
|
||||
[condition lock];
|
||||
}
|
||||
|
||||
- (void)unlock
|
||||
{
|
||||
[condition unlock];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
DESTROY(condition);
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
void *thread(void *expectation)
|
||||
{
|
||||
[(ThreadExpectation*)expectation inThread: [NSThread currentThread]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This test checks whether we can still obtain a reference to the NSThread
|
||||
* object of a thread that is in the process of exiting without an explicit
|
||||
* call to [NSThread exit]. To do this, we pass an expectation object to
|
||||
* a thread created purely using the pthreads API. We then wait on a condition
|
||||
* until the thread exits and posts the NSThreadWillExitNotification. If that
|
||||
* does not happen within 5 seconds, we flag the test as failed.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
pthread_t thr;
|
||||
pthread_attr_t attr;
|
||||
void *ret;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
ThreadExpectation *expectation = [ThreadExpectation new];
|
||||
pthread_create(&thr, &attr, thread, expectation);
|
||||
|
||||
NSDate *start = [NSDate date];
|
||||
[expectation lock];
|
||||
while (![expectation isDone] && [start timeIntervalSinceNow] > -5.0f)
|
||||
{
|
||||
[expectation waitUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.5f]];
|
||||
}
|
||||
PASS([expectation isDone], "Notification for thread exit was sent");
|
||||
[expectation unlock];
|
||||
DESTROY(expectation);
|
||||
DESTROY(arp);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue