2001-12-17 14:31:42 +00:00
/ * * Control of executable units within a shared virtual memory space
2018-04-23 18:37:28 +00:00
Copyright ( C ) 1996 -2018 Free Software Foundation , Inc .
1996-02-13 15:40:05 +00:00
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
Original Author : Scott Christley < scottc @ net - community . com >
Rewritten by : Andrew Kachites McCallum < mccallum @ gnu . ai . mit . edu >
Created : 1996
1999-05-10 06:45:36 +00:00
Rewritten by : Richard Frith - Macdonald < richard @ brainstorm . co . uk >
to add optimisations features for faster thread access .
2000-11-12 07:41:24 +00:00
Modified by : Nicola Pero < n . pero @ mi . flashnet . it >
2005-02-22 11:22:44 +00:00
to add GNUstep extensions allowing to interact with threads created
2000-11-12 07:41:24 +00:00
by external libraries / code ( eg , a Java Virtual Machine ) .
2005-02-22 11:22:44 +00:00
1996-02-13 15:40:05 +00:00
This file is part of the GNUstep Objective - C Library .
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
1996-02-13 15:40:05 +00:00
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
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
1996-02-13 15:40:05 +00:00
License along with this library ; if not , write to the Free
2024-11-07 13:37:59 +00:00
Software Foundation , Inc . , 31 Milk Street #960789 Boston , MA 02196 USA .
2001-12-18 16:54:15 +00:00
< title > NSThread class reference < / title >
2005-02-22 11:22:44 +00:00
* /
1996-02-13 15:40:05 +00:00
2010-02-19 08:12:46 +00:00
# import "common.h"
2018-03-26 14:20:48 +00:00
# import "GSPThread.h"
2024-04-19 04:21:35 +00:00
# ifdef _WIN32
# import < processthreadsapi . h >
# endif
2018-04-23 18:37:28 +00:00
// Dummy implementatation
// cleaner than IFDEF ' ing the code everywhere
2021-07-28 14:17:47 +00:00
# ifndef HAVE_PTHREAD _SPIN _LOCK
2019-05-07 15:38:54 +00:00
typedef volatile int pthread_spinlock _t ;
2018-05-29 22:40:34 +00:00
int pthread_spin _init ( pthread_spinlock _t * lock , int pshared )
2018-04-23 18:37:28 +00:00
{
2019-05-07 15:38:54 +00:00
# if DEBUG && ! __has _builtin ( __sync _bool _compare _and _swap )
2018-08-07 14:50:33 +00:00
fprintf ( stderr , "NSThread.m: Warning this platform does not support spin locks - init.\n" ) ;
2018-08-07 11:01:45 +00:00
# endif
2018-04-23 18:37:28 +00:00
return 0 ;
}
int pthread_spin _lock ( pthread_spinlock _t * lock )
{
2019-05-07 15:38:54 +00:00
# if __has _builtin ( __sync _bool _compare _and _swap )
int count = 0 ;
// Set the spin lock value to 1 if it is 0.
while ( ! __sync _bool _compare _and _swap ( lock , 0 , 1 ) )
{
count + + ;
if ( 0 = = count % 10 )
{
// If it is already 1 , let another thread play with the CPU for a
// bit then try again .
2021-07-28 14:17:47 +00:00
# if defined ( _WIN32 )
Sleep ( 0 ) ;
# else
2019-05-07 15:38:54 +00:00
sleep ( 0 ) ;
2021-07-28 14:17:47 +00:00
# endif
2019-05-07 15:38:54 +00:00
}
}
# else
# warning no spin_locks , using dummy versions
# endif
2018-04-23 18:37:28 +00:00
return 0 ;
}
int pthread_spin _unlock ( pthread_spinlock _t * lock )
{
2019-05-07 15:38:54 +00:00
# if __has _builtin ( __sync _bool _compare _and _swap )
__sync _synchronize ( ) ;
* lock = 0 ;
# endif
2018-05-20 11:40:24 +00:00
return 0 ;
2018-04-23 18:37:28 +00:00
}
int pthread_spin _destroy ( pthread_spinlock _t * lock )
{
return 0 ;
}
2021-07-28 14:17:47 +00:00
# endif / * HAVE_PTHREAD _SPIN _LOCK * /
2018-04-23 18:37:28 +00:00
2018-03-26 14:20:48 +00:00
/ * * Structure for holding lock information for a thread .
* /
typedef struct {
pthread_spinlock _t spin ; / * protect access to struct members * /
2018-04-04 13:42:20 +00:00
NSHashTable * held ; / * all locks / conditions held by thread * /
2018-03-26 14:20:48 +00:00
id wait ; / * the lock / condition we are waiting for * /
} GSLockInfo ;
2010-02-14 10:48:10 +00:00
# define EXPOSE_NSThread _IVARS 1
2018-03-26 14:20:48 +00:00
# define GS_NSThread _IVARS \
2025-01-27 11:13:18 +00:00
id _stringCollatorCache ; \
BOOL _targetIsBlock ; \
2021-07-28 14:17:47 +00:00
gs_thread _id _t _pthreadID ; \
2018-03-26 14:20:48 +00:00
NSUInteger _threadID ; \
GSLockInfo _lockInfo
2003-07-17 09:00:31 +00:00
# ifdef HAVE_NANOSLEEP
2015-03-31 09:14:01 +00:00
# include < time . h >
2003-07-17 09:00:31 +00:00
# endif
2007-12-27 07:02:27 +00:00
# ifdef HAVE_SYS _TIME _H
2015-03-31 09:14:01 +00:00
# include < sys / time . h >
2007-12-27 07:02:27 +00:00
# endif
# ifdef HAVE_SYS _RESOURCE _H
2015-03-31 09:14:01 +00:00
# include < sys / resource . h >
2007-12-27 07:02:27 +00:00
# endif
2011-12-15 09:42:39 +00:00
# if defined ( HAVE_SYS _FILE _H )
2015-03-31 09:14:01 +00:00
# include < sys / file . h >
2008-09-23 08:10:59 +00:00
# endif
2011-12-15 09:42:39 +00:00
2024-08-13 17:59:56 +00:00
# if defined ( __ANDROID __ )
# include < string . h > // For strerror
# include < sys / resource . h > // For getpriority and setpriority
# endif
2011-12-15 09:42:39 +00:00
# if defined ( HAVE_SYS _FCNTL _H )
# include < sys / fcntl . h >
# elif defined ( HAVE_FCNTL _H )
# include < fcntl . h >
2008-09-23 08:10:59 +00:00
# endif
2012-10-30 13:35:00 +00:00
# if defined ( __POSIX _SOURCE ) \
|| defined ( __EXT _POSIX1 _198808 ) \
|| defined ( O_NONBLOCK )
2008-09-18 08:22:53 +00:00
# define NBLK_OPT O_NONBLOCK
# else
# define NBLK_OPT FNDELAY
# endif
2005-02-23 16:05:09 +00:00
2010-02-17 11:47:06 +00:00
# import "Foundation/NSException.h"
2018-03-26 14:20:48 +00:00
# import "Foundation/NSHashTable.h"
2010-02-17 11:47:06 +00:00
# import "Foundation/NSThread.h"
# import "Foundation/NSLock.h"
2018-03-26 14:20:48 +00:00
# import "Foundation/NSMapTable.h"
2010-02-17 11:47:06 +00:00
# import "Foundation/NSNotification.h"
# import "Foundation/NSNotificationQueue.h"
# import "Foundation/NSRunLoop.h"
# import "Foundation/NSConnection.h"
# import "Foundation/NSInvocation.h"
2011-03-16 12:17:02 +00:00
# import "Foundation/NSUserDefaults.h"
2016-01-29 13:42:07 +00:00
# import "Foundation/NSValue.h"
1996-02-13 15:40:05 +00:00
2010-02-17 11:47:06 +00:00
# import "GSPrivate.h"
# import "GSRunLoopCtxt.h"
2002-11-03 18:56:46 +00:00
2015-03-31 09:14:01 +00:00
# if defined ( HAVE_PTHREAD _NP _H )
2011-07-11 14:31:36 +00:00
# include < pthread_np . h >
2015-03-31 09:14:01 +00:00
# endif
# if defined ( HAVE_GETTID )
# include < unistd . h >
# include < sys / syscall . h >
# include < sys / types . h >
# endif
2018-03-26 14:20:48 +00:00
# define GSInternal NSThreadInternal
# include "GSInternal.h"
GS_PRIVATE _INTERNAL ( NSThread )
# define pthreadID ( internal -> _pthreadID )
# define threadID ( internal -> _threadID )
# define lockInfo ( internal -> _lockInfo )
2025-01-27 18:16:07 +00:00
# define targetIsBlock ( internal -> _targetIsBlock )
# define stringCollatorCache ( internal -> _stringCollatorCache )
2018-03-26 14:20:48 +00:00
2015-03-31 09:45:40 +00:00
# if defined ( HAVE_PTHREAD _MAIN _NP )
# define IS_MAIN _PTHREAD ( pthread_main _np ( ) = = 1 )
# elif defined ( HAVE_GETTID )
# define IS_MAIN _PTHREAD ( getpid ( ) = = ( pid_t ) syscall ( SYS_gettid ) )
# else
# define IS_MAIN _PTHREAD ( 1 )
# endif
2015-03-31 09:14:01 +00:00
/ * Return the current thread ID as an unsigned long .
* Ideally , we use the operating - system ' s notion of a thread ID so
* that external process monitoring software will be using the same
* value that we log . If we don ' t know the system ' s mechanism , we
* use the address of the current NSThread object so that , even if
* it makes no sense externally , it can still be used to show that
* different threads generated different logs .
* /
2015-07-08 12:54:15 +00:00
NSUInteger
2015-03-31 09:14:01 +00:00
GSPrivateThreadID ( )
{
2016-03-09 13:16:16 +00:00
# if defined ( _WIN32 )
2015-07-08 12:54:15 +00:00
return ( NSUInteger ) GetCurrentThreadId ( ) ;
2015-03-31 09:14:01 +00:00
# elif defined ( HAVE_GETTID )
2015-07-08 12:54:15 +00:00
return ( NSUInteger ) syscall ( SYS_gettid ) ;
2015-03-31 09:14:01 +00:00
# elif defined ( HAVE_PTHREAD _GETTHREADID _NP )
2015-07-14 18:05:55 +00:00
return ( NSUInteger ) pthread_getthreadid _np ( ) ;
2015-03-31 09:14:01 +00:00
# else
2015-07-08 12:54:15 +00:00
return ( NSUInteger ) GSCurrentThread ( ) ;
2015-03-31 09:14:01 +00:00
# endif
}
2014-11-28 18:38:24 +00:00
# ifndef PTHREAD_SETNAME
2014-12-28 13:19:19 +00:00
# define PTHREAD_SETNAME ( a ) -1
2014-11-28 18:38:24 +00:00
# endif
2024-04-19 04:10:45 +00:00
# ifndef PTHREAD_GETNAME
2024-04-19 04:29:09 +00:00
# define PTHREAD_GETNAME ( a , b ) -1
2024-04-19 04:10:45 +00:00
# endif
2011-07-11 14:31:36 +00:00
2018-03-26 14:20:48 +00:00
@ interface NSThread ( Activation )
2018-04-10 08:19:50 +00:00
- ( void ) _makeThreadCurrent ;
2018-03-26 14:20:48 +00:00
@ end
2006-03-08 11:28:59 +00:00
@ interface NSAutoreleasePool ( NSThread )
+ ( void ) _endThread : ( NSThread * ) thread ;
@ end
2018-03-26 14:20:48 +00:00
static Class threadClass = Nil ;
static NSNotificationCenter * nc = nil ;
2018-04-04 13:42:20 +00:00
static BOOL disableTraceLocks = NO ;
2001-03-19 12:20:21 +00:00
2005-07-08 11:48:37 +00:00
/ * *
* This class performs a dual function . . .
* < p >
* As a class , it is responsible for handling incoming events from
* the main runloop on a special inputFd . This consumes any bytes
* written to wake the main runloop . < br / >
* During initialisation , the default runloop is set up to watch
* for data arriving on inputFd .
* < / p >
* < p >
* As instances , each instance retains perform receiver and argument
* values as long as they are needed , and handles locking to support
2008-02-08 13:35:50 +00:00
* methods which want to block until an action has been performed .
2005-07-08 11:48:37 +00:00
* < / p >
* < p >
* The initialize method of this class is called before any new threads
* run .
* < / p >
* /
@ interface GSPerformHolder : NSObject
{
id receiver ;
id argument ;
SEL selector ;
NSConditionLock * lock ; // Not retained .
2008-03-17 15:23:11 +00:00
NSArray * modes ;
2008-03-18 05:45:05 +00:00
BOOL invalidated ;
2015-04-02 15:59:48 +00:00
@ public
NSException * exception ;
2005-07-08 11:48:37 +00:00
}
+ ( GSPerformHolder * ) newForReceiver : ( id ) r
argument : ( id ) a
selector : ( SEL ) s
modes : ( NSArray * ) m
lock : ( NSConditionLock * ) l ;
- ( void ) fire ;
2008-03-18 05:45:05 +00:00
- ( void ) invalidate ;
- ( BOOL ) isInvalidated ;
2008-03-17 15:23:11 +00:00
- ( NSArray * ) modes ;
2005-07-08 11:48:37 +00:00
@ end
2003-07-20 06:37:25 +00:00
/ * *
* Sleep until the current date / time is the specified time interval
* past the reference date / time . < br / >
* Implemented as a function taking an NSTimeInterval argument in order
* to avoid objc messaging and object allocation / deallocation ( NSDate )
* overheads . < br / >
* Used to implement [ NSThread + sleepUntilDate : ]
2009-09-08 17:56:58 +00:00
* If the date is in the past , this function simply allows other threads
* ( if any ) to run .
2003-07-20 06:37:25 +00:00
* /
void
GSSleepUntilIntervalSinceReferenceDate ( NSTimeInterval when )
{
NSTimeInterval delay ;
// delay is always the number of seconds we still need to wait
2010-12-27 07:03:50 +00:00
delay = when - GSPrivateTimeNow ( ) ;
2009-09-09 08:21:51 +00:00
if ( delay <= 0.0 )
2009-09-08 17:56:58 +00:00
{
2015-02-07 11:01:53 +00:00
/ * We don ' t need to wait , but since we are willing to wait at this
* point , we should let other threads have preference over this one .
* /
2021-07-28 14:17:47 +00:00
GS_YIELD ( ) ;
2009-09-08 17:56:58 +00:00
return ;
}
2003-07-20 06:37:25 +00:00
2016-03-09 13:16:16 +00:00
# if defined ( _WIN32 )
2015-02-07 11:01:53 +00:00
/ *
* Avoid integer overflow by breaking up long sleeps .
* /
while ( delay > 30.0 * 60.0 )
2003-07-20 06:37:25 +00:00
{
2015-02-07 11:01:53 +00:00
// sleep 30 minutes
Sleep ( 30 * 60 * 1000 ) ;
delay = when - GSPrivateTimeNow ( ) ;
}
2003-07-20 06:37:25 +00:00
2015-02-07 11:01:53 +00:00
/ * Don ' t use nanosleep ( even if available ) on mingw . . . it ' s reported no
* to work with pthreads .
* Sleeping may return early because of signals , so we need to re - calculate
* the required delay and check to see if we need to sleep again .
* /
while ( delay > 0 )
{
# if defined ( HAVE_USLEEP )
/ * On windows usleep ( ) seems to perform a busy wait . . . so we only
* use it for short delays . . . otherwise use the less accurate Sleep ( )
* /
if ( delay > 0.1 )
{
Sleep ( ( NSInteger ) ( delay * 1000 ) ) ;
}
else
{
usleep ( ( NSInteger ) ( delay * 1000000 ) ) ;
}
# else
Sleep ( ( NSInteger ) ( delay * 1000 ) ) ;
# endif / * HAVE_USLEEP * /
2010-12-27 07:03:50 +00:00
delay = when - GSPrivateTimeNow ( ) ;
2003-07-20 06:37:25 +00:00
}
2015-02-07 11:01:53 +00:00
2016-03-09 13:16:16 +00:00
# else / * _WIN32 * /
2015-02-07 11:01:53 +00:00
/ *
* Avoid integer overflow by breaking up long sleeps .
* /
while ( delay > 30.0 * 60.0 )
{
// sleep 30 minutes
sleep ( 30 * 60 ) ;
delay = when - GSPrivateTimeNow ( ) ;
}
# ifdef HAVE_NANOSLEEP
2003-07-20 06:37:25 +00:00
if ( delay > 0 )
{
struct timespec request ;
struct timespec remainder ;
request . tv_sec = ( time_t ) delay ;
request . tv_nsec = ( long ) ( ( delay - request . tv_sec ) * 1000000000 ) ;
remainder . tv_sec = 0 ;
remainder . tv_nsec = 0 ;
/ *
* With nanosleep , we can restart the sleep after a signal by using
* the remainder information . . . so we can be sure to sleep to the
* desired limit without having to re - generate the delay needed .
* /
while ( nanosleep ( & request , & remainder ) < 0
&& ( remainder . tv_sec > 0 || remainder . tv_nsec > 0 ) )
{
request . tv_sec = remainder . tv_sec ;
request . tv_nsec = remainder . tv_nsec ;
remainder . tv_sec = 0 ;
remainder . tv_nsec = 0 ;
}
}
2015-02-07 11:01:53 +00:00
# else / * HAVE_NANOSLEEP * /
2003-07-20 06:37:25 +00:00
/ *
* sleeping may return early because of signals , so we need to re - calculate
* the required delay and check to see if we need to sleep again .
* /
while ( delay > 0 )
{
2010-02-03 09:45:45 +00:00
# if defined ( HAVE_USLEEP )
2015-02-07 11:01:53 +00:00
usleep ( ( NSInteger ) ( delay * 1000000 ) ) ;
# else / * HAVE_USLEEP * /
sleep ( ( NSInteger ) delay ) ;
# endif / * ! HAVE_USLEEP * /
2010-12-27 07:03:50 +00:00
delay = when - GSPrivateTimeNow ( ) ;
2003-07-20 06:37:25 +00:00
}
2015-02-07 11:01:53 +00:00
# endif / * ! HAVE_NANOSLEEP * /
2016-03-09 13:16:16 +00:00
# endif / * ! _WIN32 * /
2003-07-20 06:37:25 +00:00
}
2002-11-03 18:56:46 +00:00
static NSArray *
2003-12-23 17:41:38 +00:00
commonModes ( void )
2002-11-03 18:56:46 +00:00
{
2024-05-30 09:40:52 +00:00
static gs_mutex _t modesLock = GS_MUTEX _INIT _STATIC ;
2002-11-03 18:56:46 +00:00
static NSArray * modes = nil ;
if ( modes = = nil )
{
2024-05-30 09:40:52 +00:00
GS_MUTEX _LOCK ( modesLock ) ;
2002-11-03 18:56:46 +00:00
if ( modes = = nil )
{
Class c = NSClassFromString ( @ "NSApplication" ) ;
SEL s = @ selector ( allRunLoopModes ) ;
if ( c ! = 0 && [ c respondsToSelector : s ] )
{
modes = RETAIN ( [ c performSelector : s ] ) ;
}
else
{
modes = [ [ NSArray alloc ] initWithObjects :
NSDefaultRunLoopMode , NSConnectionReplyMode , nil ] ;
}
}
2024-05-30 09:40:52 +00:00
GS_MUTEX _UNLOCK ( modesLock ) ;
2002-11-03 18:56:46 +00:00
}
return modes ;
}
2000-04-19 12:29:17 +00:00
/ *
* Flag indicating whether the objc runtime ever went multi - threaded .
* /
static BOOL entered_multi _threaded _state = NO ;
1996-02-13 15:40:05 +00:00
2009-09-08 20:32:52 +00:00
static NSThread * defaultThread ;
1996-02-13 15:40:05 +00:00
2018-04-16 12:18:36 +00:00
static BOOL keyInitialized = NO ;
2021-07-28 14:17:47 +00:00
static gs_thread _key _t thread_object _key ;
2009-09-08 20:32:52 +00:00
2016-01-29 13:42:07 +00:00
2018-03-26 14:20:48 +00:00
static NSHashTable * _activeBlocked = nil ;
static NSHashTable * _activeThreads = nil ;
2021-07-28 14:17:47 +00:00
static gs_mutex _t _activeLock = GS_MUTEX _INIT _STATIC ;
2018-03-26 14:20:48 +00:00
2016-01-29 13:42:07 +00:00
/ * *
* pthread_t is an opaque type . It might be a scalar type or
* some kind of struct depending on the implementation , so we
* need to wrap it up in an NSValue object if we want to pass
* it around .
* This follows the CoreFoundation ' create rule ' and returns an object with
* a reference count of 1.
* /
2021-07-28 14:17:47 +00:00
static inline NSValue * NSValueCreateFromPthread ( gs_thread _id _t thread )
2016-01-29 13:42:07 +00:00
{
return [ [ NSValue alloc ] initWithBytes : & thread
2021-07-28 14:17:47 +00:00
objCType : @ encode ( gs_thread _id _t ) ] ;
2016-01-29 13:42:07 +00:00
}
/ * *
* Conversely , we need to be able to retrieve the pthread_t
* from an NSValue .
* /
2016-02-10 09:15:10 +00:00
static inline void
2021-07-28 14:17:47 +00:00
_getPthreadFromNSValue ( const void * value , gs_thread _id _t * thread_ptr )
2016-01-29 13:42:07 +00:00
{
2016-02-10 09:15:10 +00:00
const char * enc ;
2016-01-29 13:42:07 +00:00
NSCAssert ( thread_ptr , @ "No storage for thread reference" ) ;
# ifndef NS_BLOCK _ASSERTIONS
2016-04-17 15:07:38 +00:00
enc = [ ( NSValue * ) value objCType ] ;
2021-07-28 14:17:47 +00:00
NSCAssert ( enc ! = NULL && ( 0 = = strcmp ( @ encode ( gs_thread _id _t ) , enc ) ) ,
2016-01-29 13:42:07 +00:00
@ "Invalid NSValue container for thread reference" ) ;
# endif
2016-04-17 15:07:38 +00:00
[ ( NSValue * ) value getValue : ( void * ) thread_ptr ] ;
2016-01-29 13:42:07 +00:00
}
/ * *
* This is the comparison function for boxed pthreads , as used by the
* NSMapTable containing them .
* /
static BOOL
_boxedPthreadIsEqual ( NSMapTable * t ,
2016-04-17 15:07:38 +00:00
const void * boxed ,
const void * boxedOther )
2016-01-29 13:42:07 +00:00
{
2021-07-28 14:17:47 +00:00
gs_thread _id _t thread ;
gs_thread _id _t otherThread ;
2016-02-10 09:15:10 +00:00
2016-01-29 13:42:07 +00:00
_getPthreadFromNSValue ( boxed , & thread ) ;
_getPthreadFromNSValue ( boxedOther , & otherThread ) ;
2021-07-28 14:17:47 +00:00
# if GS_USE _WIN32 _THREADS _AND _LOCKS
return thread = = otherThread ;
# else
2016-01-29 13:42:07 +00:00
return pthread_equal ( thread , otherThread ) ;
2021-07-28 14:17:47 +00:00
# endif
2016-01-29 13:42:07 +00:00
}
/ * *
* Since pthread_t is opaque , we cannot make any assumption about how
* to hash it . There are a few problems here :
* 1. Functions to obtain the thread ID of an arbitrary thread
* exist in the in the Win32 and some pthread APIs ( GetThreadId ( ) and
* pthread_getunique _np ( ) , respectively ) , but there is no protable solution
* for this problem .
* 2. Even where pthread_getunique _np ( ) is available , it might have different
* definitions , so it ' s not really robust to use it .
*
* For these reasons , we always return the same hash . That fulfills the API
* contract for NSMapTable ( key - hash equality as a necessary condition for key
* equality ) , but makes things quite inefficient ( linear search over all
* elements ) , so we need to keep the table small .
* /
2016-04-17 15:07:38 +00:00
static NSUInteger _boxedPthreadHash ( NSMapTable * t , const void * value )
2016-01-29 13:42:07 +00:00
{
return 0 ;
}
/ * *
* Retain callback for boxed thread references .
* /
2016-04-17 15:07:38 +00:00
static void _boxedPthreadRetain ( NSMapTable * t , const void * value )
2016-01-29 13:42:07 +00:00
{
2016-02-10 09:15:10 +00:00
RETAIN ( ( NSValue * ) value ) ;
2016-01-29 13:42:07 +00:00
}
/ * *
* Release callback for boxed thread references .
* /
2016-04-17 15:07:38 +00:00
static void _boxedPthreadRelease ( NSMapTable * t , void * value )
2016-01-29 13:42:07 +00:00
{
2016-02-10 09:15:10 +00:00
RELEASE ( ( NSValue * ) value ) ;
2016-01-29 13:42:07 +00:00
}
/ * *
* Description callback for boxed thread references .
* /
2016-04-17 15:07:38 +00:00
static NSString * _boxedPthreadDescribe ( NSMapTable * t , const void * value )
2016-01-29 13:42:07 +00:00
{
return [ ( NSValue * ) value description ] ;
}
static const NSMapTableKeyCallBacks _boxedPthreadKeyCallBacks =
{
_boxedPthreadHash ,
_boxedPthreadIsEqual ,
_boxedPthreadRetain ,
_boxedPthreadRelease ,
_boxedPthreadDescribe ,
NULL
} ;
/ * *
* This map table maintains a list of all threads currently undergoing
* cleanup . This is a required so that + currentThread can still find the
* thred if called from within the late - cleanup function .
* /
2016-02-16 22:28:34 +00:00
static NSMapTable * _exitingThreads = nil ;
2021-07-28 14:17:47 +00:00
static gs_mutex _t _exitingThreadsLock = GS_MUTEX _INIT _STATIC ;
2018-03-26 14:20:48 +00:00
2016-01-29 13:42:07 +00:00
/ * *
* Called before late cleanup is run and inserts the NSThread object into the
* table that is used by GSCurrentThread to find the thread if it is called
* during cleanup . The boxedThread variable contains a boxed reference to
* the result of calling pthread_self ( ) .
* /
static inline void _willLateUnregisterThread ( NSValue * boxedThread ,
NSThread * specific )
{
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _exitingThreadsLock ) ;
2016-03-05 19:09:11 +00:00
/ * The map table is created lazily / late so that the NSThread
2018-03-26 14:20:48 +00:00
* + initialize method can be called without causing other
2016-03-05 19:09:11 +00:00
* classes to be initialized .
* NB this locked section cannot be protected by an exception handler
* because the exception handler stores information in the current
* thread variables . . . which causes recursion .
* /
if ( nil = = _exitingThreads )
2016-01-29 13:42:07 +00:00
{
2016-03-05 19:09:11 +00:00
_exitingThreads = NSCreateMapTable ( _boxedPthreadKeyCallBacks ,
NSObjectMapValueCallBacks , 10 ) ;
2016-01-29 13:42:07 +00:00
}
2016-03-05 19:09:11 +00:00
NSMapInsert ( _exitingThreads , ( const void * ) boxedThread ,
( const void * ) specific ) ;
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _exitingThreadsLock ) ;
2016-01-29 13:42:07 +00:00
}
/ * *
* Called after late cleanup has run . Will remove the current thread from
* the lookup table again . The boxedThread variable contains a boxed reference
* to the result of calling pthread_self ( ) .
* /
static inline void _didLateUnregisterCurrentThread ( NSValue * boxedThread )
{
2016-03-05 19:09:11 +00:00
/ * NB this locked section cannot be protected by an exception handler
* because the exception handler stores information in the current
* thread variables . . . which causes recursion .
* /
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _exitingThreadsLock ) ;
2016-02-16 22:28:34 +00:00
if ( nil ! = _exitingThreads )
2016-01-29 13:42:07 +00:00
{
2016-03-05 19:09:11 +00:00
NSMapRemove ( _exitingThreads , ( const void * ) boxedThread ) ;
2016-01-29 13:42:07 +00:00
}
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _exitingThreadsLock ) ;
2016-01-29 13:42:07 +00:00
}
/ *
* Forward declaration of the thread unregistration function
* /
static void
unregisterActiveThread ( NSThread * thread ) ;
2002-05-03 08:17:04 +00:00
/ * *
2009-09-08 20:32:52 +00:00
* Pthread cleanup call .
*
* We should normally not get here . . . because threads should exit properly
* and clean up , so that this function doesn ' t get called . However if a
* thread terminates for some reason without calling the exit method , we
2016-01-29 13:42:07 +00:00
* we add it to a special lookup table that is used by GSCurrentThread ( ) to
* obtain the NSThread object .
* We need to be a bit careful about this regarding object allocation because
* we must not call into NSAutoreleasePool unless the NSThread object can still
* be found using GSCurrentThread ( )
2000-04-19 12:29:17 +00:00
* /
2021-08-07 20:19:09 +00:00
static void GS_WINAPI
exitedThread ( void * thread )
1999-04-19 14:29:52 +00:00
{
2010-02-04 18:04:13 +00:00
if ( thread ! = defaultThread )
2009-09-08 20:32:52 +00:00
{
2016-02-10 09:15:10 +00:00
NSValue * ref ;
2016-06-27 20:21:11 +00:00
if ( 0 = = thread )
{
/ * On some systems this is called with a null thread pointer ,
2018-03-26 14:20:48 +00:00
* so try to get the NSThread object for the current thread .
2016-06-27 20:21:11 +00:00
* /
2021-07-28 14:17:47 +00:00
thread = GS_THREAD _KEY _GET ( thread_object _key ) ;
2016-06-27 20:21:11 +00:00
if ( 0 = = thread )
{
return ; // no thread info
}
}
2016-02-10 09:15:10 +00:00
RETAIN ( ( NSThread * ) thread ) ;
2021-07-28 14:17:47 +00:00
ref = NSValueCreateFromPthread ( GS_THREAD _ID _SELF ( ) ) ;
2016-01-29 13:42:07 +00:00
_willLateUnregisterThread ( ref , ( NSThread * ) thread ) ;
2016-02-15 11:07:44 +00:00
{
CREATE_AUTORELEASE _POOL ( arp ) ;
NS_DURING
{
unregisterActiveThread ( ( NSThread * ) thread ) ;
}
NS_HANDLER
{
DESTROY ( arp ) ;
_didLateUnregisterCurrentThread ( ref ) ;
DESTROY ( ref ) ;
RELEASE ( ( NSThread * ) thread ) ;
}
NS_ENDHANDLER
DESTROY ( arp ) ;
}
2015-07-14 18:05:55 +00:00
2016-01-29 13:42:07 +00:00
/ * At this point threre shouldn ' t be any autoreleased objects lingering
* around anymore . So we may remove the thread from the lookup table .
* /
_didLateUnregisterCurrentThread ( ref ) ;
DESTROY ( ref ) ;
2016-02-10 09:15:10 +00:00
RELEASE ( ( NSThread * ) thread ) ;
2009-09-08 20:32:52 +00:00
}
1999-04-19 14:29:52 +00:00
}
2002-05-03 08:17:04 +00:00
/ * *
2009-09-08 20:32:52 +00:00
* These functions needed because sending messages to classes is a seriously
* slow process with gcc and the gnu runtime .
2000-04-19 12:29:17 +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
inline NSThread *
GSCurrentThread ( void )
{
2018-04-16 12:18:36 +00:00
NSThread * thr ;
2016-02-10 10:22:43 +00:00
2018-04-16 12:18:36 +00:00
if ( NO = = keyInitialized )
{
2021-07-28 14:17:47 +00:00
if ( ! GS_THREAD _KEY _INIT ( thread_object _key , exitedThread ) )
2018-04-16 12:18:36 +00:00
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Unable to create thread key!" ] ;
}
keyInitialized = YES ;
}
2021-07-28 14:17:47 +00:00
thr = GS_THREAD _KEY _GET ( thread_object _key ) ;
2016-01-29 13:42:07 +00:00
if ( nil = = thr )
{
2021-07-28 14:17:47 +00:00
NSValue * selfThread = NSValueCreateFromPthread ( GS_THREAD _ID _SELF ( ) ) ;
2016-02-10 10:22:43 +00:00
/ * NB this locked section cannot be protected by an exception handler
* because the exception handler stores information in the current
* thread variables . . . which causes recursion .
* /
2016-02-16 22:28:34 +00:00
if ( nil ! = _exitingThreads )
{
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _exitingThreadsLock ) ;
2016-02-16 22:28:34 +00:00
thr = NSMapGet ( _exitingThreads , ( const void * ) selfThread ) ;
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _exitingThreadsLock ) ;
2016-02-16 22:28:34 +00:00
}
2016-01-29 13:42:07 +00:00
DESTROY ( selfThread ) ;
2018-03-26 14:20:48 +00:00
if ( nil = = thr )
2011-07-11 14:31:36 +00:00
{
2018-03-26 14:20:48 +00:00
GSRegisterCurrentThread ( ) ;
2021-07-28 14:17:47 +00:00
thr = GS_THREAD _KEY _GET ( thread_object _key ) ;
2018-03-26 14:20:48 +00:00
if ( ( nil = = defaultThread ) && IS_MAIN _PTHREAD )
{
defaultThread = RETAIN ( thr ) ;
}
2011-07-11 14:31:36 +00:00
}
2018-03-26 14:20:48 +00:00
assert ( nil ! = thr && "No main thread" ) ;
2009-09-08 20:32:52 +00:00
}
2011-07-11 14:31:36 +00:00
return thr ;
* 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-08 20:32:52 +00:00
1999-04-19 14:29:52 +00:00
NSMutableDictionary *
2002-10-30 07:45:59 +00:00
GSDictionaryForThread ( NSThread * t )
1999-04-19 14:29:52 +00:00
{
2009-09-08 20:32:52 +00:00
if ( nil = = t )
{
t = GSCurrentThread ( ) ;
}
return [ t threadDictionary ] ;
1999-04-19 14:29:52 +00:00
}
2002-10-30 07:45:59 +00:00
/ * *
* Fast access function for thread dictionary of current thread .
* /
NSMutableDictionary *
2003-12-23 17:41:38 +00:00
GSCurrentThreadDictionary ( void )
2002-10-30 07:45:59 +00:00
{
return GSDictionaryForThread ( nil ) ;
}
2000-04-19 12:29:17 +00:00
/ *
2016-06-25 07:12:41 +00:00
* Callback function to send notifications on becoming multi - threaded .
2000-04-19 12:29:17 +00:00
* /
static void
2003-12-23 17:41:38 +00:00
gnustep_base _thread _callback ( void )
1998-05-29 15:25:41 +00:00
{
2021-07-28 14:17:47 +00:00
static gs_mutex _t threadLock = GS_MUTEX _INIT _STATIC ;
1999-06-22 15:06:21 +00:00
/ *
2003-09-30 18:19:03 +00:00
* Protect this function with locking . . . to avoid any possibility
* of multiple threads registering with the system simultaneously ,
* and so that all NSWillBecomeMultiThreadedNotifications are sent
* out before any second thread can interfere with anything .
1999-06-22 15:06:21 +00:00
* /
2000-04-19 12:29:17 +00:00
if ( entered_multi _threaded _state = = NO )
1998-05-29 15:25:41 +00:00
{
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( threadLock ) ;
2003-09-30 18:19:03 +00:00
if ( entered_multi _threaded _state = = NO )
2002-08-07 13:29:31 +00:00
{
2004-03-12 16:51:30 +00:00
/ *
* For apple compatibility . . . and to make things easier for
* code called indirectly within a will - become - multi - threaded
* notification handler , we set the flag to say we are multi
* threaded BEFORE sending the notifications .
* /
entered_multi _threaded _state = YES ;
2020-07-06 19:33:06 +00:00
/ *
* Enter pool after setting flag , because - [ NSAutoreleasePool
* allocWithZone : ] calls GSCurrentThread ( ) , which may end up
* calling this function , which would cause a deadlock .
* /
ENTER_POOL
2003-09-30 18:19:03 +00:00
NS_DURING
{
[ GSPerformHolder class ] ; // Force initialization
/ *
* Post a notification if this is the first new thread
* to be created .
* Won ' t work properly if threads are not all created
* by this class , but it ' s better than nothing .
* /
if ( nc = = nil )
{
2004-11-10 11:45:08 +00:00
nc = RETAIN ( [ NSNotificationCenter defaultCenter ] ) ;
2003-09-30 18:19:03 +00:00
}
2011-03-05 13:11:47 +00:00
# if ! defined ( HAVE_INITIALIZE )
2011-03-16 12:17:02 +00:00
if ( NO = = [ [ NSUserDefaults standardUserDefaults ]
boolForKey : @ "GSSilenceInitializeWarning" ] )
{
2011-09-29 17:04:13 +00:00
NSLog ( @ "WARNING your program is becoming multi-threaded, but you are using an ObjectiveC runtime library which does not have a thread-safe implementation of the +initialize method. Please see README.initialize for more information." ) ;
2011-03-16 12:17:02 +00:00
}
2011-03-05 13:11:47 +00:00
# endif
2003-09-30 18:19:03 +00:00
[ nc postNotificationName : NSWillBecomeMultiThreadedNotification
object : nil
userInfo : nil ] ;
}
NS_HANDLER
{
2003-09-30 18:57:49 +00:00
fprintf ( stderr ,
2003-12-23 17:41:38 +00:00
"ALERT ... exception while becoming multi-threaded ... system may not be\n"
"properly initialised.\n" ) ;
2003-09-30 18:57:49 +00:00
fflush ( stderr ) ;
2003-09-30 18:19:03 +00:00
}
NS_ENDHANDLER
2020-05-29 15:25:52 +00:00
LEAVE_POOL
2002-08-07 13:29:31 +00:00
}
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( threadLock ) ;
1998-05-29 15:25:41 +00:00
}
}
2018-03-26 14:20:48 +00:00
@ implementation NSThread ( Activation )
2018-04-10 13:29:57 +00:00
- ( void ) _makeThreadCurrent
2018-03-26 14:20:48 +00:00
{
2018-04-10 08:19:50 +00:00
/ * NB . We must set up the pointer to the new NSThread instance from
* pthread specific memory before we do anything which might need to
* check what the current thread is ( like getting the ID ) !
* /
2021-07-28 14:17:47 +00:00
GS_THREAD _KEY _SET ( thread_object _key , self ) ;
2018-03-26 14:20:48 +00:00
threadID = GSPrivateThreadID ( ) ;
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _activeLock ) ;
2018-03-26 14:20:48 +00:00
/ * The hash table is created lazily / late so that the NSThread
* + initialize method can be called without causing other
* classes to be initialized .
* NB this locked section cannot be protected by an exception handler
* because the exception handler stores information in the current
* thread variables . . . which causes recursion .
* /
if ( nil = = _activeThreads )
{
_activeThreads = NSCreateHashTable (
NSNonRetainedObjectHashCallBacks , 100 ) ;
}
NSHashInsert ( _activeThreads , ( const void * ) self ) ;
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _activeLock ) ;
2018-03-26 14:20:48 +00:00
}
@ end
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
@ implementation NSThread
1996-02-13 15:40:05 +00:00
2010-04-16 18:18:43 +00:00
static void
setThreadForCurrentThread ( NSThread * t )
* 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
{
2018-04-10 08:19:50 +00:00
[ t _makeThreadCurrent ] ;
* 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
gnustep_base _thread _callback ( ) ;
}
2010-04-16 18:18:43 +00:00
static void
unregisterActiveThread ( NSThread * thread )
{
if ( thread -> _active = = YES )
{
2020-05-26 15:30:15 +00:00
/ * Let observers know this thread is exiting .
2010-04-16 18:18:43 +00:00
* /
2020-05-29 15:25:52 +00:00
ENTER_POOL
2010-04-16 18:18:43 +00:00
if ( nc = = nil )
{
nc = RETAIN ( [ NSNotificationCenter defaultCenter ] ) ;
}
[ nc postNotificationName : NSThreadWillExitNotification
object : thread
userInfo : nil ] ;
2020-05-26 15:30:15 +00:00
/ * Set the thread to be finished * after * notification it will exit .
* This is the order OSX 10.15 .4 does it ( May 2020 ) .
* /
thread -> _active = NO ;
thread -> _finished = YES ;
2010-04-16 18:18:43 +00:00
[ ( GSRunLoopThreadInfo * ) thread -> _runLoopInfo invalidate ] ;
2020-05-29 15:25:52 +00:00
LEAVE_POOL
2016-02-10 09:15:10 +00:00
RELEASE ( thread ) ;
2021-07-28 14:17:47 +00:00
GS_THREAD _KEY _SET ( thread_object _key , nil ) ;
2010-04-16 18:18:43 +00:00
}
}
2007-11-25 14:25:26 +00:00
+ ( NSArray * ) callStackReturnAddresses
{
2018-04-04 13:42:20 +00:00
GSStackTrace * stack ;
NSArray * addrs ;
stack = [ GSStackTrace new ] ;
[ stack trace ] ;
addrs = RETAIN ( [ stack addresses ] ) ;
2018-03-27 06:06:17 +00:00
RELEASE ( stack ) ;
return AUTORELEASE ( addrs ) ;
2007-11-25 14:25:26 +00:00
}
2009-09-08 20:32:52 +00:00
+ ( BOOL ) _createThreadForCurrentPthread
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
{
2021-07-28 14:17:47 +00:00
NSThread * t = GS_THREAD _KEY _GET ( thread_object _key ) ;
2009-09-08 20:32:52 +00:00
2003-07-25 09:27:44 +00:00
if ( t = = nil )
2000-08-07 22:00:31 +00:00
{
2011-02-11 19:08:32 +00:00
t = [ self new ] ;
t -> _active = YES ;
2018-04-10 08:19:50 +00:00
[ t _makeThreadCurrent ] ;
2011-02-12 09:00:18 +00:00
GS_CONSUMED ( t ) ;
2016-07-18 10:50:28 +00:00
if ( defaultThread ! = nil && t ! = defaultThread )
{
gnustep_base _thread _callback ( ) ;
}
2011-02-11 19:08:32 +00:00
return YES ;
2000-08-07 22:00:31 +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
return NO ;
}
+ ( NSThread * ) currentThread
{
2011-07-11 14:31:36 +00:00
return GSCurrentThread ( ) ;
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
}
1996-03-19 01:45:25 +00:00
1999-05-10 06:45:36 +00:00
+ ( void ) detachNewThreadSelector : ( SEL ) aSelector
toTarget : ( id ) aTarget
withObject : ( id ) anArgument
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
{
2000-04-19 12:29:17 +00:00
NSThread * thread ;
1999-06-22 15:06:21 +00:00
/ *
2000-04-19 12:29:17 +00:00
* Create the new thread .
1999-06-22 15:06:21 +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
thread = [ [ NSThread alloc ] initWithTarget : aTarget
selector : aSelector
object : anArgument ] ;
1999-07-14 16:28:43 +00:00
2007-12-24 17:31:52 +00:00
[ thread start ] ;
RELEASE ( thread ) ;
2000-04-19 12:29:17 +00:00
}
+ ( void ) exit
{
2009-09-08 20:32:52 +00:00
NSThread * t ;
2000-04-19 12:29:17 +00:00
t = GSCurrentThread ( ) ;
if ( t -> _active = = YES )
{
2016-06-27 20:21:11 +00:00
unregisterActiveThread ( t ) ;
2000-04-19 12:29:17 +00:00
2010-02-02 14:25:58 +00:00
if ( t = = defaultThread || defaultThread = = nil )
{
/ * For the default thread , we exit the process .
* /
exit ( 0 ) ;
}
else
{
2021-07-28 14:17:47 +00:00
# if GS_USE _WIN32 _THREADS _AND _LOCKS
_endthread ( ) ;
# else
2010-02-02 14:25:58 +00:00
pthread_exit ( NULL ) ;
2021-07-28 14:17:47 +00:00
# endif
2010-02-02 14:25:58 +00:00
}
2000-04-19 12:29:17 +00:00
}
1996-02-13 15:40:05 +00:00
}
2000-04-19 12:29:17 +00:00
/ *
* Class initialization
* /
+ ( void ) initialize
{
if ( self = = [ NSThread class ] )
{
2018-04-16 12:18:36 +00:00
if ( NO = = keyInitialized )
{
2021-07-28 14:17:47 +00:00
if ( ! GS_THREAD _KEY _INIT ( thread_object _key , exitedThread ) )
2018-04-16 12:18:36 +00:00
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Unable to create thread key!" ] ;
}
keyInitialized = YES ;
}
2016-02-16 22:28:34 +00:00
/ * Ensure that the default thread exists .
* It ' s safe to create a lock here ( since [ NSObject + initialize ]
* creates locks , and locks don ' t depend on any other class ) ,
* but we want to avoid initialising other classes while we are
* initialising NSThread .
2000-04-19 12:29:17 +00:00
* /
2001-03-19 12:20:21 +00:00
threadClass = self ;
2011-07-11 14:31:36 +00:00
GSCurrentThread ( ) ;
2000-04-19 12:29:17 +00:00
}
}
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
2008-03-18 05:45:05 +00:00
+ ( BOOL ) isMainThread
{
return ( GSCurrentThread ( ) = = defaultThread ? YES : NO ) ;
}
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
+ ( BOOL ) isMultiThreaded
1996-02-13 15:40:05 +00:00
{
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
return entered_multi _threaded _state ;
1996-02-13 15:40:05 +00:00
}
2007-11-25 14:25:26 +00:00
+ ( NSThread * ) mainThread
{
return defaultThread ;
}
2002-08-27 17:02:05 +00:00
/ * *
* Set the priority of the current thread . This is a value in the
* range 0.0 ( lowest ) to 1.0 ( highest ) which is mapped to the underlying
2012-08-26 08:55:49 +00:00
* system priorities .
2002-08-27 17:02:05 +00:00
* /
2021-07-28 14:17:47 +00:00
+ ( BOOL ) setThreadPriority : ( double ) pri
2002-08-27 17:02:05 +00:00
{
2021-07-28 14:17:47 +00:00
# if GS_USE _WIN32 _THREADS _AND _LOCKS
// convert [ 0.0 , 1.0 ] priority to Windows defines
int winPri ;
if ( pri <= 0.0 ) {
winPri = THREAD_PRIORITY _IDLE ;
} else if ( pri <= 0.25 ) {
winPri = THREAD_PRIORITY _LOWEST ;
} else if ( pri < 0.5 ) {
winPri = THREAD_PRIORITY _BELOW _NORMAL ;
} else if ( pri >= 1.0 ) {
winPri = THREAD_PRIORITY _TIME _CRITICAL ;
} else if ( pri >= 0.75 ) {
winPri = THREAD_PRIORITY _HIGHEST ;
} else if ( pri > 0.5 ) {
winPri = THREAD_PRIORITY _ABOVE _NORMAL ;
} else {
winPri = THREAD_PRIORITY _NORMAL ;
}
if ( ! SetThreadPriority ( GetCurrentThread ( ) , winPri ) ) {
NSLog ( @ "Failed to set thread priority %d: %@" , winPri , [ NSError _last ] ) ;
return NO ;
}
return YES ;
2024-08-13 17:59:56 +00:00
# elif defined ( __ANDROID __ )
/ * Android ' s pthread_setschedparam is currently broken , as it checks
* if the priority is in the range of the system ' s min and max
* priorities . The interval bounds are queried with ` sched_get _priority _min ` ,
* and ` sched_get _priority _max ` which just return 0 , regardless of the
* specified scheduling policy .
*
* The solution is to use ` setpriority` to set the thread
* priority . This is possible because on Linux , it is not a per - process setting
* as specified by POSIX but a per - thread setting ( See the ` Bugs` section in ` setpriority` ) .
*
* Android ' s internal implementation also relies on this behavior , so it
* is safe to use it here .
* /
// Clamp pri into the required range .
if ( pri > 1 ) { pri = 1 ; }
if ( pri < 0 ) { pri = 0 ; }
// Convert [ 0.0 , 1.0 ] to [ -20 , 19 ] range where -20 is the highest
// and 19 the lowest priority .
int priority = ( int ) ( -20 + ( 1 - pri ) * 39 ) ;
if ( setpriority ( PRIO_PROCESS , 0 , priority ) = = -1 )
{
NSLog ( @ "Failed to set thread priority %d: %s" , priority , strerror ( errno ) ) ;
return NO ;
}
return YES ;
2021-07-28 14:17:47 +00:00
# elif defined ( _POSIX _THREAD _PRIORITY _SCHEDULING ) && ( _POSIX _THREAD _PRIORITY _SCHEDULING > 0 )
int res ;
* 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
int policy ;
struct sched_param param ;
2002-08-27 17:02: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
// Clamp pri into the required range .
if ( pri > 1 ) { pri = 1 ; }
if ( pri < 0 ) { pri = 0 ; }
2021-07-28 14:17:47 +00:00
res = pthread_getschedparam ( pthread_self ( ) , & policy , & param ) ;
2021-07-28 11:30:01 +00:00
if ( res = = 0 )
{
int min = sched_get _priority _min ( policy ) ;
int max = sched_get _priority _max ( policy ) ;
if ( min = = max ) {
// priority not settable = > fail silently
return NO ;
}
// Scale pri based on the range of the host system .
pri = min + pri * ( max - min ) ;
param . sched_priority = pri ;
res = pthread_setschedparam ( pthread_self ( ) , policy , & param ) ;
}
2021-07-28 14:17:47 +00:00
if ( res ! = 0 ) {
NSLog ( @ "Failed to set thread priority %f: %d" , pri , res ) ;
return NO ;
}
2021-07-28 11:30:01 +00:00
2021-07-28 14:17:47 +00:00
return YES ;
# else
return NO ;
* 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
# endif
2002-08-27 17:02:05 +00:00
}
2007-11-25 14:25:26 +00:00
+ ( void ) sleepForTimeInterval : ( NSTimeInterval ) ti
{
2010-12-27 07:03:50 +00:00
GSSleepUntilIntervalSinceReferenceDate ( GSPrivateTimeNow ( ) + ti ) ;
2007-11-25 14:25:26 +00:00
}
2002-08-27 17:02:05 +00:00
/ * *
* Delaying a thread . . . pause until the specified date .
1997-09-01 21:59:51 +00:00
* /
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
+ ( void ) sleepUntilDate : ( NSDate * ) date
1996-02-13 15:40:05 +00:00
{
2003-07-20 06:37:25 +00:00
GSSleepUntilIntervalSinceReferenceDate ( [ date timeIntervalSinceReferenceDate ] ) ;
1996-02-13 15:40:05 +00:00
}
2003-07-20 06:37:25 +00:00
2002-08-27 17:02:05 +00:00
/ * *
* Return the priority of the current thread .
* /
+ ( double ) threadPriority
{
* 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
double pri = 0 ;
2021-07-28 14:17:47 +00:00
# if GS_USE _WIN32 _THREADS _AND _LOCKS
// convert [ 0.0 , 1.0 ] priority to Windows defines
int winPri = GetThreadPriority ( GetCurrentThread ( ) ) ;
if ( winPri = = THREAD_PRIORITY _ERROR _RETURN ) {
NSLog ( @ "Failed to get thread priority: %@" , [ NSError _last ] ) ;
return pri ;
}
switch ( winPri )
{
case THREAD_PRIORITY _IDLE :
pri = 0.0 ;
break ;
case THREAD_PRIORITY _LOWEST :
pri = 0.2 ;
break ;
case THREAD_PRIORITY _BELOW _NORMAL :
pri = 0.4 ;
break ;
case THREAD_PRIORITY _TIME _CRITICAL :
pri = 1.0 ;
break ;
case THREAD_PRIORITY _HIGHEST :
pri = 0.8 ;
break ;
case THREAD_PRIORITY _ABOVE _NORMAL :
pri = 0.6 ;
break ;
case THREAD_PRIORITY _NORMAL :
pri = 0.5 ;
break ;
default :
NSLog ( @ "Unknown thread priority: %d" , winPri ) ;
break ;
}
2024-08-13 17:59:56 +00:00
# elif defined ( __ANDROID __ )
/ * See notes in setThreadPriority
* /
int priority = getpriority ( PRIO_PROCESS , 0 ) ;
if ( priority = = -1 )
{
NSLog ( @ "Failed to get thread priority: %s" , strerror ( errno ) ) ;
return pri ;
}
// Convert [ -20 , 19 ] to [ 0.0 , 1.0 ] range
pri = 1 - ( priority + 20 ) / 39.0 ;
2021-07-28 14:17:47 +00:00
# elif defined ( _POSIX _THREAD _PRIORITY _SCHEDULING ) && ( _POSIX _THREAD _PRIORITY _SCHEDULING > 0 )
int res ;
* 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
int policy ;
struct sched_param param ;
2021-07-28 14:17:47 +00:00
res = pthread_getschedparam ( pthread_self ( ) , & policy , & param ) ;
2021-07-28 11:30:01 +00:00
if ( res = = 0 )
{
int min = sched_get _priority _min ( policy ) ;
int max = sched_get _priority _max ( policy ) ;
if ( min ! = max ) / * avoid division by zero * /
{
pri = param . sched_priority ;
// Scale pri based on the range of the host system .
pri = ( pri - min ) / ( max - min ) ;
}
}
else
{
NSLog ( @ "Failed to get thread priority: %d" , res ) ;
}
* 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
# else
# warning Your pthread implementation does not support thread priorities
# endif
2021-07-28 14:17:47 +00:00
return pri ;
2002-08-27 17:02:05 +00:00
}
2000-04-19 12:29:17 +00:00
/ *
* Thread instance methods .
* /
2007-11-25 14:25:26 +00:00
- ( void ) cancel
{
_cancelled = YES ;
}
2000-04-19 12:29:17 +00:00
- ( void ) dealloc
1996-02-13 15:40:05 +00:00
{
2015-02-14 05:50:48 +00:00
int retries = 0 ;
2000-04-19 12:29:17 +00:00
if ( _active = = YES )
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Deallocating an active thread without [+exit]!" ] ;
}
2015-02-14 05:50:48 +00:00
DESTROY ( _runLoopInfo ) ;
2000-04-19 12:29:17 +00:00
DESTROY ( _thread _dictionary ) ;
DESTROY ( _target ) ;
DESTROY ( _arg ) ;
2007-11-25 14:25:26 +00:00
DESTROY ( _name ) ;
2025-01-27 18:16:07 +00:00
DESTROY ( stringCollatorCache ) ;
2006-01-19 06:15:27 +00:00
if ( _autorelease _vars . pool_cache ! = 0 )
{
[ NSAutoreleasePool _endThread : self ] ;
}
2000-11-22 08:41:07 +00:00
2015-02-14 05:50:48 +00:00
while ( ( _thread _dictionary ! = nil || _runLoopInfo ! = nil ) && retries + + < 10 )
2001-03-17 10:18:09 +00:00
{
2015-02-14 05:50:48 +00:00
/ * Try again .
2001-03-17 10:18:09 +00:00
* /
2015-02-14 05:50:48 +00:00
DESTROY ( _runLoopInfo ) ;
2001-03-17 10:18:09 +00:00
DESTROY ( _thread _dictionary ) ;
2006-01-19 06:15:27 +00:00
if ( _autorelease _vars . pool_cache ! = 0 )
{
[ NSAutoreleasePool _endThread : self ] ;
}
2015-02-14 05:50:48 +00:00
}
if ( _runLoopInfo ! = nil )
{
NSLog ( @ "Oops - leak - run loop is %@" , _runLoopInfo ) ;
if ( _autorelease _vars . pool_cache ! = 0 )
{
[ NSAutoreleasePool _endThread : self ] ;
}
}
if ( _thread _dictionary ! = nil )
{
NSLog ( @ "Oops - leak - thread dictionary is %@" , _thread _dictionary ) ;
if ( _autorelease _vars . pool_cache ! = 0 )
{
[ NSAutoreleasePool _endThread : self ] ;
}
2001-03-17 10:18:09 +00:00
}
2007-12-25 20:31:24 +00:00
DESTROY ( _gcontext ) ;
2018-03-26 14:20:48 +00:00
if ( _activeThreads )
{
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _activeLock ) ;
2018-03-26 14:20:48 +00:00
NSHashRemove ( _activeThreads , self ) ;
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _activeLock ) ;
2018-03-26 14:20:48 +00:00
}
if ( GS_EXISTS _INTERNAL )
{
pthread_spin _lock ( & lockInfo . spin ) ;
DESTROY ( lockInfo . held ) ;
lockInfo . wait = nil ;
pthread_spin _unlock ( & lockInfo . spin ) ;
pthread_spin _destroy ( & lockInfo . spin ) ;
if ( internal ! = nil )
{
GS_DESTROY _INTERNAL ( NSThread ) ;
}
}
2009-10-10 08:16:17 +00:00
[ super dealloc ] ;
2000-04-19 12:29:17 +00:00
}
1996-03-19 01:45:25 +00:00
2015-03-31 09:14:01 +00:00
- ( NSString * ) description
{
2015-07-14 18:05:55 +00:00
return [ NSString stringWithFormat : @ "%@{name = %@, num = %" PRIuPTR "}" ,
2018-03-26 14:20:48 +00:00
[ super description ] , _name , threadID ] ;
2015-03-31 09:14:01 +00:00
}
2000-04-19 12:29:17 +00:00
- ( id ) init
{
2024-04-19 04:10:45 +00:00
// SetThreadDescription ( ) was added in Windows 10 1607 ( Redstone 1 )
# if defined ( _WIN32 ) && ( NTDDI_VERSION >= NTDDI_WIN10 _RS1 )
HANDLE current ;
HRESULT hr ;
PWSTR name ;
NSString * threadName ;
current = GetCurrentThread ( ) ;
hr = GetThreadDescription ( current , & name ) ;
if ( SUCCEEDED ( hr ) )
{
threadName = [ NSString stringWithCharacters : ( const void * ) name length : wcslen ( name ) ] ;
ASSIGN ( _name , threadName ) ;
LocalFree ( name ) ;
}
# elif defined ( PTHREAD_GETNAME )
NSString * threadName ;
char name [ 16 ] ;
int status ;
status = PTHREAD_GETNAME ( name , 16 ) ;
if ( status = = 0 )
{
threadName = [ NSString stringWithCString : name encoding : NSUTF8StringEncoding ] ;
ASSIGN ( _name , threadName ) ;
}
# endif
2018-03-26 14:20:48 +00:00
GS_CREATE _INTERNAL ( NSThread ) ;
pthread_spin _init ( & lockInfo . spin , 0 ) ;
2018-04-04 13:42:20 +00:00
lockInfo . held = NSCreateHashTable ( NSNonOwnedPointerHashCallBacks , 10 ) ;
2009-09-08 20:32:52 +00:00
init_autorelease _thread _vars ( & _autorelease _vars ) ;
2007-11-25 14:25:26 +00:00
return self ;
2000-04-19 12:29:17 +00:00
}
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
2007-11-25 14:25:26 +00:00
- ( id ) initWithTarget : ( id ) aTarget
selector : ( SEL ) aSelector
object : ( id ) anArgument
2000-04-19 12:29:17 +00:00
{
2018-03-26 14:20:48 +00:00
if ( nil ! = ( self = [ self init ] ) )
{
/ * initialize our ivars . * /
_selector = aSelector ;
_target = RETAIN ( aTarget ) ;
_arg = RETAIN ( anArgument ) ;
}
2000-04-19 12:29:17 +00:00
return self ;
}
(NSBecomingMultiThreaded, NSThreadExiting): Initialize the
notification strings as static strings, not in +initialize.
(thread_id_2_nsthread): Renamed from THREAD_LIST. Keep the collection
of NSThread's as a maptable, not a NSArray that takes linear time to
search!
(thread_lock): Renamed from THREAD_LIST_LOCK.
(entered_multi_threaded_state): Renamed from ENTERED_MULTI-THREADED_STATE.
([NSThread +initialize]): Don't initialize notification strings here.
Don't autorelease the lock!
([NSThread -init]): Initialize _thread_autorelease_pool. Set our
thread data to self, for easy, efficient access to this NSThread
object later. Put ourselves in the thread collection here, not in
+detach...
([NSThread +currentThread]): This will be called often and needs to be
fast. Reimplemented so we don't have to acquire a lock and step
through an NSArray of threads; instead, just look ourselves up with
the objc_thread_get_data(), and furthermore, no lock required.
([NSThread +detachNewThreadSelector:toTarget:withObject:]): Avoid race
condition, don't create new NSThread object here.
([NSThread +sleepUntilDate:]): Call -notImplemented:.
([NSThread +exit]): Properly post NSThreadExiting notification, making
sure not to hold the lock while we do so. Get the NSThread object
efficiently.
([NSThread -threadId]): Removed unnecessary private method.
([NSThread -setThreadId]): Likewise.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1530 72102866-910b-0410-8b05-ffd578937521
1996-05-13 15:53:36 +00:00
2007-11-25 14:25:26 +00:00
- ( BOOL ) isCancelled
{
return _cancelled ;
}
- ( BOOL ) isExecuting
{
return _active ;
}
2008-03-18 05:45:05 +00:00
- ( BOOL ) isFinished
{
return _finished ;
}
2007-11-25 14:25:26 +00:00
- ( BOOL ) isMainThread
{
return ( self = = defaultThread ? YES : NO ) ;
}
2007-11-25 14:49:05 +00:00
- ( void ) main
{
2007-12-24 17:31:52 +00:00
if ( _active = = NO )
{
[ NSException raise : NSInternalInconsistencyException
2013-07-02 15:46:26 +00:00
format : @ "[%@-%@] called on inactive thread" ,
2007-12-24 17:31:52 +00:00
NSStringFromClass ( [ self class ] ) ,
NSStringFromSelector ( _cmd ) ] ;
}
2025-01-27 18:16:07 +00:00
if ( targetIsBlock )
2024-10-30 10:13:28 +00:00
{
GSThreadBlock block = ( GSThreadBlock ) _target ;
CALL_BLOCK _NO _ARGS ( block ) ;
}
else
{
[ _target performSelector : _selector withObject : _arg ] ;
}
* 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 * ) name
{
return _name ;
}
2014-11-28 18:38:24 +00:00
- ( void ) _setName : ( NSString * ) aName
{
2016-05-13 13:19:22 +00:00
if ( [ aName isKindOfClass : [ NSString class ] ] )
2014-11-28 18:38:24 +00:00
{
2024-04-19 04:10:45 +00:00
// SetThreadDescription ( ) was added in Windows 10 1607 ( Redstone 1 )
# if defined ( _WIN32 ) && ( NTDDI_VERSION >= NTDDI_WIN10 _RS1 )
HANDLE current ;
const void * utf16String ;
current = GetCurrentThread ( ) ;
utf16String = [ aName cStringUsingEncoding : NSUnicodeStringEncoding ] ;
SetThreadDescription ( current , utf16String ) ;
# elif defined ( PTHREAD_SETNAME )
2016-05-13 13:19:22 +00:00
int i ;
char buf [ 200 ] ;
if ( YES = = [ aName getCString : buf
2024-04-19 04:10:45 +00:00
maxLength : sizeof ( buf )
2016-05-13 13:19:22 +00:00
encoding : NSUTF8StringEncoding ] )
{
i = strlen ( buf ) ;
}
else
{
/ * Too much for buffer . . . truncate on a character boundary .
2024-04-19 04:10:45 +00:00
* /
2016-05-13 13:19:22 +00:00
i = sizeof ( buf ) - 1 ;
if ( buf [ i ] & 0 x80 )
{
while ( i > 0 && ( buf [ i ] & 0 x80 ) )
{
buf [ i - - ] = ' \ 0 ' ;
}
}
else
{
buf [ i - - ] = ' \ 0 ' ;
}
}
while ( i > 0 )
2014-11-28 18:38:24 +00:00
{
2020-03-17 13:27:06 +00:00
if ( PTHREAD_SETNAME ( buf ) = = ERANGE )
2014-11-28 18:38:24 +00:00
{
2014-12-28 13:19:19 +00:00
/ * Name must be too long . . . gnu / linux uses 15 characters
2024-04-19 04:10:45 +00:00
* /
2016-05-13 13:19:22 +00:00
if ( i > 15 )
2014-11-28 18:38:24 +00:00
{
2024-11-30 19:06:40 +00:00
NSWarnLog ( @ "Truncating thread name '%s' to 15 characters"
@ " due to platform limitations" , buf ) ;
2016-05-13 13:19:22 +00:00
i = 15 ;
2014-11-28 18:38:24 +00:00
}
else
{
2016-05-13 13:19:22 +00:00
i - - ;
}
/ * too long a name . . . truncate on a character boundary .
2024-04-19 04:10:45 +00:00
* /
2016-05-13 13:19:22 +00:00
if ( buf [ i ] & 0 x80 )
{
while ( i > 0 && ( buf [ i ] & 0 x80 ) )
{
buf [ i - - ] = ' \ 0 ' ;
}
}
else
{
buf [ i - - ] = ' \ 0 ' ;
2014-11-28 18:38:24 +00:00
}
}
else
{
2020-03-17 13:27:06 +00:00
break ; // Success or some other error
2014-11-28 18:38:24 +00:00
}
}
2024-04-19 04:10:45 +00:00
# endif
}
2014-11-28 18:38:24 +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
- ( void ) setName : ( NSString * ) aName
{
ASSIGN ( _name , aName ) ;
2024-04-19 04:10:45 +00:00
2014-11-28 18:38:24 +00:00
if ( YES = = _active )
{
[ self performSelector : @ selector ( _setName : )
onThread : self
withObject : aName
waitUntilDone : NO ] ;
}
* 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
}
- ( void ) setStackSize : ( NSUInteger ) stackSize
{
_stackSize = stackSize ;
}
- ( NSUInteger ) stackSize
{
return _stackSize ;
}
/ * *
* Trampoline function called to launch the thread
* /
2021-07-28 14:17:47 +00:00
static
# if GS_USE _WIN32 _THREADS _AND _LOCKS
void __cdecl
# else
void *
# endif
2016-05-13 13:19:22 +00:00
nsthreadLauncher ( void * thread )
* 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
{
2016-05-13 13:19:22 +00:00
NSThread * t = ( NSThread * ) thread ;
setThreadForCurrentThread ( t ) ;
2009-02-10 12:16:40 +00:00
2024-11-30 19:06:40 +00:00
ENTER_POOL
2007-12-24 17:31:52 +00:00
/ *
* Let observers know a new thread is starting .
* /
if ( nc = = nil )
{
nc = RETAIN ( [ NSNotificationCenter defaultCenter ] ) ;
}
[ nc postNotificationName : NSThreadDidStartNotification
* 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
object : t
2007-12-24 17:31:52 +00:00
userInfo : nil ] ;
2014-11-28 18:38:24 +00:00
[ t _setName : [ t name ] ] ;
2024-11-30 19:06:40 +00:00
LEAVE_POOL
2014-11-28 18:38:24 +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
[ t main ] ;
2007-12-24 17:31:52 +00:00
[ NSThread exit ] ;
* 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
// Not reached
2021-07-28 14:17:47 +00:00
# if ! GS_USE _WIN32 _THREADS _AND _LOCKS
* 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
return NULL ;
2021-07-28 14:17:47 +00:00
# endif
2007-11-25 14:25:26 +00:00
}
- ( void ) start
2000-04-19 12:29:17 +00:00
{
2021-07-28 14:17:47 +00:00
# if ! GS_USE _WIN32 _THREADS _AND _LOCKS
2009-09-27 19:31:31 +00:00
pthread_attr _t attr ;
2021-07-28 14:17:47 +00:00
# endif
2009-09-27 19:31:31 +00:00
2007-12-24 20:51:19 +00:00
if ( _active = = YES )
2002-08-07 13:29:31 +00:00
{
2007-12-24 20:51:19 +00:00
[ NSException raise : NSInternalInconsistencyException
2013-07-02 15:46:26 +00:00
format : @ "[%@-%@] called on active thread" ,
2007-12-24 20:51:19 +00:00
NSStringFromClass ( [ self class ] ) ,
NSStringFromSelector ( _cmd ) ] ;
}
if ( _cancelled = = YES )
{
[ NSException raise : NSInternalInconsistencyException
2013-07-02 15:46:26 +00:00
format : @ "[%@-%@] called on cancelled thread" ,
2007-12-24 20:51:19 +00:00
NSStringFromClass ( [ self class ] ) ,
NSStringFromSelector ( _cmd ) ] ;
}
2008-03-18 05:45:05 +00:00
if ( _finished = = YES )
{
[ NSException raise : NSInternalInconsistencyException
2013-07-02 15:46:26 +00:00
format : @ "[%@-%@] called on finished thread" ,
2008-03-18 05:45:05 +00:00
NSStringFromClass ( [ self class ] ) ,
NSStringFromSelector ( _cmd ) ] ;
}
2000-11-12 07:41:24 +00:00
2007-12-24 20:51:19 +00:00
/ * Make sure the notification is posted BEFORE the new thread starts .
* /
gnustep_base _thread _callback ( ) ;
2007-12-24 17:31:52 +00:00
2007-12-24 20:51:19 +00:00
/ * The thread must persist until it finishes executing .
* /
2016-02-10 09:15:10 +00:00
RETAIN ( self ) ;
2007-12-24 17:31:52 +00:00
2018-03-26 14:20:48 +00:00
/ * Mark the thread as active while it ' s running .
2007-12-24 20:51:19 +00:00
* /
_active = YES ;
2008-01-06 08:56:59 +00:00
errno = 0 ;
2021-07-28 14:17:47 +00:00
# if GS_USE _WIN32 _THREADS _AND _LOCKS
if ( _beginthread ( nsthreadLauncher , _stackSize , self ) = = -1 )
{
DESTROY ( self ) ;
[ NSException raise : NSInternalInconsistencyException
format : @ "Unable to detach thread (last error %d)" ,
errno ] ;
}
# else
* 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
pthread_attr _init ( & attr ) ;
2009-09-27 19:31:31 +00:00
/ * Create this thread detached , because we never use the return state from
* threads .
* /
* 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
pthread_attr _setdetachstate ( & attr , PTHREAD_CREATE _DETACHED ) ;
2009-09-27 19:31:31 +00:00
/ * Set the stack size when the thread is created . Unlike the old setrlimit
* code , this actually works .
* /
* 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
if ( _stackSize > 0 )
{
pthread_attr _setstacksize ( & attr , _stackSize ) ;
}
2018-03-26 14:20:48 +00:00
if ( pthread_create ( & pthreadID , & attr , nsthreadLauncher , self ) )
2007-12-24 20:51:19 +00:00
{
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2007-12-24 20:51:19 +00:00
[ NSException raise : NSInternalInconsistencyException
2008-01-06 08:56:59 +00:00
format : @ "Unable to detach thread (last error %@)" ,
2007-12-25 14:13:18 +00:00
[ NSError _last ] ] ;
2007-12-24 17:31:52 +00:00
}
2021-07-28 14:17:47 +00:00
# endif
2000-04-19 12:29:17 +00:00
}
1996-03-19 01:45:25 +00:00
2002-08-27 17:02:05 +00:00
/ * *
* Return the thread dictionary . This dictionary can be used to store
* arbitrary thread specific data . < br / >
2000-04-19 12:29:17 +00:00
* NB . This cannot be autoreleased , since we cannot be sure that the
* autorelease pool for the thread will continue to exist for the entire
* life of the thread !
* /
- ( NSMutableDictionary * ) threadDictionary
{
2001-03-17 10:18:09 +00:00
if ( _thread _dictionary = = nil )
2000-04-19 12:29:17 +00:00
{
_thread _dictionary = [ NSMutableDictionary new ] ;
}
return _thread _dictionary ;
1996-02-13 15:40:05 +00:00
}
2024-09-23 12:32:36 +00:00
- ( id ) _stringCollatorCache
{
2025-01-27 18:16:07 +00:00
return ( id ) stringCollatorCache ;
2024-09-23 12:32:36 +00:00
}
- ( void ) _setStringCollatorCache : ( id ) cache
{
2025-01-27 18:16:07 +00:00
ASSIGN ( stringCollatorCache , cache ) ;
2024-09-23 12:32:36 +00:00
}
1996-03-19 01:45:25 +00:00
@ end
2000-04-19 12:29:17 +00:00
2024-09-23 12:32:36 +00:00
2002-10-30 07:45:59 +00:00
2018-03-26 14:20:48 +00:00
@ implementation NSThread ( GSLockInfo )
static NSString *
lockInfoErr ( NSString * str )
{
2018-04-04 13:42:20 +00:00
if ( disableTraceLocks )
2018-03-26 14:20:48 +00:00
{
2018-04-04 13:42:20 +00:00
return nil ;
2018-03-26 14:20:48 +00:00
}
2018-04-04 13:42:20 +00:00
return str ;
2018-03-26 14:20:48 +00:00
}
- ( NSString * ) mutexDrop : ( id ) mutex
{
2018-04-04 11:58:06 +00:00
if ( GS_EXISTS _INTERNAL )
2018-03-26 14:20:48 +00:00
{
GSLockInfo * li = & lockInfo ;
int err ;
2018-04-04 13:42:20 +00:00
if ( YES = = disableTraceLocks ) return nil ;
2018-03-26 14:20:48 +00:00
err = pthread_spin _lock ( & li -> spin ) ;
if ( EDEADLK = = err ) return lockInfoErr ( @ "thread spin lock deadlocked" ) ;
if ( EINVAL = = err ) return lockInfoErr ( @ "thread spin lock invalid" ) ;
if ( mutex = = li -> wait )
{
/ * The mutex was being waited for . . . simply remove it .
* /
li -> wait = nil ;
}
2018-04-04 13:42:20 +00:00
else if ( NSHashGet ( li -> held , ( void * ) mutex ) = = ( void * ) mutex )
2018-03-26 14:20:48 +00:00
{
2018-04-04 13:42:20 +00:00
GSStackTrace * stck = [ mutex stack ] ;
2018-03-26 14:20:48 +00:00
/ * The mutex was being held . . . if the recursion count was zero
* we remove it ( otherwise the count is decreased ) .
* /
if ( stck -> recursion - - = = 0 )
{
2018-04-04 13:42:20 +00:00
NSHashRemove ( li -> held , ( void * ) mutex ) ;
// fprintf ( stderr , "%lu: Drop %p (final) %lu\n" , ( unsigned long ) _threadID , mutex , [ li -> held count ] ) ;
2018-03-26 14:20:48 +00:00
}
else
{
2018-04-04 13:42:20 +00:00
// fprintf ( stderr , "%lu: Drop %p (%lu) %lu\n" , ( unsigned long ) threadID , mutex , ( unsigned long ) stck -> recursion , [ li -> held count ] ) ;
2018-03-26 14:20:48 +00:00
}
}
else
{
2018-04-04 13:42:20 +00:00
// fprintf ( stderr , "%lu: Drop %p (bad) %lu\n" , ( unsigned long ) threadID , mutex , [ li -> held count ] ) ;
2018-03-26 14:20:48 +00:00
pthread_spin _unlock ( & li -> spin ) ;
return lockInfoErr (
@ "attempt to unlock mutex not locked by this thread" ) ;
}
pthread_spin _unlock ( & li -> spin ) ;
return nil ;
}
return lockInfoErr ( @ "thread not active" ) ;
}
- ( NSString * ) mutexHold : ( id ) mutex
{
2018-04-04 11:58:06 +00:00
if ( GS_EXISTS _INTERNAL )
2018-03-26 14:20:48 +00:00
{
GSLockInfo * li = & lockInfo ;
int err ;
2018-04-04 13:42:20 +00:00
if ( YES = = disableTraceLocks ) return nil ;
2018-03-26 14:20:48 +00:00
err = pthread_spin _lock ( & li -> spin ) ;
if ( EDEADLK = = err ) return lockInfoErr ( @ "thread spin lock deadlocked" ) ;
if ( EINVAL = = err ) return lockInfoErr ( @ "thread spin lock invalid" ) ;
if ( nil = = mutex )
{
mutex = li -> wait ;
if ( nil = = mutex )
{
pthread_spin _unlock ( & li -> spin ) ;
return lockInfoErr ( @ "attempt to hold nil mutex" ) ;
}
}
else if ( nil ! = li -> wait && mutex ! = li -> wait )
{
pthread_spin _unlock ( & li -> spin ) ;
return lockInfoErr ( @ "attempt to hold mutex without waiting for it" ) ;
}
2018-04-04 13:42:20 +00:00
if ( NSHashGet ( li -> held , ( void * ) mutex ) = = NULL )
2018-03-26 14:20:48 +00:00
{
2018-04-04 13:42:20 +00:00
[ [ mutex stack ] trace ] ; // Get current strack trace
NSHashInsert ( li -> held , ( void * ) mutex ) ;
// fprintf ( stderr , "%lu: Hold %p (initial) %lu\n" , ( unsigned long ) threadID , mutex , [ li -> held count ] ) ;
2018-03-26 14:20:48 +00:00
}
else
{
2018-04-04 13:42:20 +00:00
GSStackTrace * stck = [ mutex stack ] ;
2018-03-26 14:20:48 +00:00
stck -> recursion + + ;
2018-04-04 13:42:20 +00:00
// fprintf ( stderr , "%lu: Hold %p (%lu) %lu\n" , ( unsigned long ) threadID , mutex , ( unsigned long ) stck -> recursion , [ li -> held count ] ) ;
2018-03-26 14:20:48 +00:00
}
li -> wait = nil ;
pthread_spin _unlock ( & li -> spin ) ;
return nil ;
}
return lockInfoErr ( @ "thread not active" ) ;
}
- ( NSString * ) mutexWait : ( id ) mutex
{
2018-04-04 11:58:06 +00:00
if ( GS_EXISTS _INTERNAL )
2018-03-26 14:20:48 +00:00
{
2018-04-24 11:24:37 +00:00
NSMutableArray * dependencies ;
id want ;
BOOL done ;
2018-03-26 14:20:48 +00:00
GSLockInfo * li = & lockInfo ;
2018-03-26 15:05:18 +00:00
BOOL owned = NO ;
2018-03-26 14:20:48 +00:00
int err ;
2018-04-04 13:42:20 +00:00
if ( YES = = disableTraceLocks ) return nil ;
2018-03-26 14:20:48 +00:00
err = pthread_spin _lock ( & li -> spin ) ;
if ( EDEADLK = = err ) return lockInfoErr ( @ "thread spin lock deadlocked" ) ;
if ( EINVAL = = err ) return lockInfoErr ( @ "thread spin lock invalid" ) ;
if ( nil ! = li -> wait )
{
NSString * msg = [ NSString stringWithFormat :
2018-03-26 15:05:18 +00:00
@ "trying to lock %@ when already trying to lock %@" ,
2018-03-26 14:20:48 +00:00
mutex , li -> wait ] ;
pthread_spin _unlock ( & li -> spin ) ;
return lockInfoErr ( msg ) ;
}
li -> wait = mutex ;
2018-04-04 13:42:20 +00:00
if ( nil ! = NSHashGet ( li -> held , ( const void * ) mutex ) )
2018-03-26 15:05:18 +00:00
{
owned = YES ;
}
2018-03-26 14:20:48 +00:00
pthread_spin _unlock ( & li -> spin ) ;
2018-04-04 13:42:20 +00:00
// fprintf ( stderr , "%lu: Wait %p\n" , ( unsigned long ) _threadID , mutex ) ;
2018-03-26 15:05:18 +00:00
if ( YES = = owned && [ mutex isKindOfClass : [ NSRecursiveLock class ] ] )
{
return nil ; // We can ' t deadlock on a recursive lock we own
}
2018-03-26 14:20:48 +00:00
2018-03-27 08:55:29 +00:00
/ * 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 ) .
* /
2021-07-28 14:17:47 +00:00
GS_MUTEX _LOCK ( _activeLock ) ;
2018-03-26 14:20:48 +00:00
2018-03-27 08:55:29 +00:00
/ * 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 .
* /
2018-03-26 14:20:48 +00:00
if ( nil = = _activeBlocked )
{
_activeBlocked = NSCreateHashTable (
NSNonRetainedObjectHashCallBacks , 100 ) ;
}
2018-04-24 11:24:37 +00:00
dependencies = nil ;
want = mutex ;
done = NO ;
2018-03-26 14:20:48 +00:00
while ( NO = = done )
{
NSHashEnumerator enumerator ;
NSThread * found = nil ;
2018-03-27 08:55:29 +00:00
BOOL foundWasLocked = NO ;
2018-03-26 14:20:48 +00:00
NSThread * th ;
2018-03-27 08:55:29 +00:00
/ * 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 ) .
* /
2018-03-26 14:20:48 +00:00
enumerator = NSEnumerateHashTable ( _activeThreads ) ;
while ( ( th = NSNextHashEnumeratorItem ( & enumerator ) ) ! = nil )
{
GSLockInfo * info = & GSIVar ( th , _lockInfo ) ;
if ( YES = = th -> _active && nil ! = info -> wait )
{
2018-03-27 08:55:29 +00:00
BOOL wasLocked ;
2018-03-26 14:20:48 +00:00
2018-03-27 08:55:29 +00:00
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 ;
}
2018-03-26 14:20:48 +00:00
if ( nil ! = info -> wait
2024-06-21 14:02:55 +00:00
&& nil ! = ( id ) NSHashGet ( info -> held , ( const void * ) want ) )
2018-03-26 14:20:48 +00:00
{
2018-03-27 08:55:29 +00:00
/ * 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 .
* /
2018-03-26 14:20:48 +00:00
found = th ;
2018-03-27 08:55:29 +00:00
foundWasLocked = wasLocked ;
2018-03-26 14:20:48 +00:00
want = info -> wait ;
if ( nil = = dependencies )
{
dependencies = [ NSMutableArray new ] ;
}
[ dependencies addObject : found ] ; // thread
[ dependencies addObject : want ] ; // mutex
/ * NB . breaking out here holds the spin lock so that
* the lock state of each dependency thread is
* preserved ( if we don ' t have a deadlock , we get a
* consistent snapshot of the threads and their locks ) .
* We therefore have to unlock the threads when done .
* /
break ;
}
2018-03-27 08:55:29 +00:00
/ * 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 ) ;
}
2018-03-26 14:20:48 +00:00
}
}
NSEndHashTableEnumeration ( & enumerator ) ;
if ( nil = = found )
{
/ * There is no thread blocked on the mutex we are checking ,
* so we can ' t have a deadlock .
* /
DESTROY ( dependencies ) ;
done = YES ;
}
2018-03-27 08:55:29 +00:00
else if ( foundWasLocked )
{
/ * The found thread is the current one or in the blocked set
* so we have a deadlock .
* /
done = YES ;
}
2018-03-26 14:20:48 +00:00
else
{
2018-03-27 08:55:29 +00:00
/ * Record the found ( and locked ) thread and continue
* to find the next dependency .
* /
NSHashInsert ( _activeBlocked , ( const void * ) found ) ;
2018-03-26 14:20:48 +00:00
}
}
/ * Ensure any locked threads are unlocked again .
* /
if ( NSCountHashTable ( _activeBlocked ) > 0 )
{
NSHashEnumerator enumerator ;
NSThread * th ;
enumerator = NSEnumerateHashTable ( _activeThreads ) ;
while ( ( th = NSNextHashEnumeratorItem ( & enumerator ) ) ! = nil )
{
GSLockInfo * info = & GSIVar ( th , _lockInfo ) ;
pthread_spin _unlock ( & info -> spin ) ;
}
NSEndHashTableEnumeration ( & enumerator ) ;
2018-03-27 08:55:29 +00:00
NSResetHashTable ( _activeBlocked ) ;
2018-03-26 14:20:48 +00:00
}
2018-03-27 08:55:29 +00:00
/ * Finished check . . . re - enable thread activity changes .
* /
2021-07-28 14:17:47 +00:00
GS_MUTEX _UNLOCK ( _activeLock ) ;
2018-03-27 08:55:29 +00:00
2018-03-26 14:20:48 +00:00
if ( nil ! = dependencies )
{
2018-04-04 13:42:20 +00:00
GSStackTrace * stack ;
2018-03-26 14:20:48 +00:00
NSUInteger count ;
NSUInteger index = 0 ;
NSMutableString * m ;
2018-04-04 13:42:20 +00:00
disableTraceLocks = YES ;
2018-03-26 14:20:48 +00:00
m = [ NSMutableString stringWithCapacity : 1000 ] ;
2018-04-04 13:42:20 +00:00
stack = [ GSStackTrace new ] ;
[ stack trace ] ;
2018-03-27 09:37:53 +00:00
[ m appendFormat : @ "Deadlock on %@ at\n %@\n" ,
mutex , [ stack symbols ] ] ;
RELEASE ( stack ) ;
2018-03-26 14:20:48 +00:00
count = [ dependencies count ] ;
while ( index < count )
{
NSArray * symbols ;
NSThread * thread ;
NSUInteger frameCount ;
thread = [ dependencies objectAtIndex : index + + ] ;
2018-04-04 13:42:20 +00:00
mutex = [ dependencies objectAtIndex : index + + ] ;
symbols = [ [ mutex stack ] symbols ] ;
2018-03-26 14:20:48 +00:00
frameCount = [ symbols count ] ;
if ( frameCount > 0 )
{
NSUInteger i ;
[ m appendFormat : @ " depends on %@\n blocked by %@\n at\n" ,
mutex , thread ] ;
for ( i = 0 ; i < frameCount ; i + + )
{
[ m appendFormat : @ " %@\n" , [ symbols objectAtIndex : i ] ] ;
}
}
else
{
[ m appendFormat : @ " depends on %@\n blocked by %@\n" ,
mutex , thread ] ;
}
}
DESTROY ( dependencies ) ;
/ * NB . Return m directly because we have turned off tracing to
* avoid recursion , and don ' t want lockInfoErr ( ) to stop the
* error being ruturned .
* /
return m ;
}
return nil ;
}
return lockInfoErr ( @ "thread not active" ) ;
}
@ end
2008-03-17 15:23:11 +00:00
@ implementation GSRunLoopThreadInfo
- ( void ) addPerformer : ( id ) performer
2002-11-02 16:53:48 +00:00
{
2014-11-04 09:08:47 +00:00
BOOL signalled = NO ;
2008-03-17 15:23:11 +00:00
[ lock lock ] ;
2016-03-09 13:16:16 +00:00
# if defined ( _WIN32 )
2014-11-04 09:08:47 +00:00
if ( INVALID_HANDLE _VALUE ! = event )
2005-02-23 16:05:09 +00:00
{
2014-11-04 09:08:47 +00:00
if ( SetEvent ( event ) = = 0 )
{
2018-04-04 22:48:41 +00:00
NSLog ( @ "Set event failed - %@" , [ NSError _last ] ) ;
2014-11-04 09:08:47 +00:00
}
else
{
signalled = YES ;
}
2005-02-23 16:05:09 +00:00
}
# else
2017-09-06 08:32:07 +00:00
{
NSTimeInterval start = 0.0 ;
2010-08-30 19:16:30 +00:00
/ * The write could concievably fail if the pipe is full .
2017-09-06 08:32:07 +00:00
* In that case we need to release the lock temporarily to allow the other
2010-08-30 19:16:30 +00:00
* thread to consume data from the pipe . It ' s possible that the thread
* and its runloop might stop during that . . . so we need to check that
* outputFd is still valid .
2010-08-30 17:27:11 +00:00
* /
2014-11-04 09:08:47 +00:00
while ( outputFd >= 0
&& NO = = ( signalled = ( write ( outputFd , "0" , 1 ) = = 1 ) ? YES : NO ) )
2010-08-30 19:16:30 +00:00
{
2017-09-06 08:32:07 +00:00
NSTimeInterval now = [ NSDate timeIntervalSinceReferenceDate ] ;
if ( 0.0 = = start )
{
start = now ;
}
else if ( now - start >= 1.0 )
{
NSLog ( @ "Unable to signal %@ within a second; blocked?" , self ) ;
break ;
}
2010-08-30 19:16:30 +00:00
[ lock unlock ] ;
[ lock lock ] ;
}
2017-09-06 08:32:07 +00:00
}
2005-02-23 16:05:09 +00:00
# endif
2014-11-04 09:08:47 +00:00
if ( YES = = signalled )
{
[ performers addObject : performer ] ;
}
2008-09-18 08:22:53 +00:00
[ lock unlock ] ;
2014-11-04 09:08:47 +00:00
if ( NO = = signalled )
{
/ * We failed to add the performer . . . so we must invalidate it in
* case there is code waiting for it to complete .
* /
[ performer invalidate ] ;
}
2008-03-17 15:23:11 +00:00
}
2005-02-23 16:05:09 +00:00
2008-03-17 15:23:11 +00:00
- ( void ) dealloc
{
2008-03-18 05:45:05 +00:00
[ self invalidate ] ;
2008-03-17 15:23:11 +00:00
DESTROY ( lock ) ;
DESTROY ( loop ) ;
[ super dealloc ] ;
}
2002-11-02 16:53:48 +00:00
2008-03-17 15:23:11 +00:00
- ( id ) init
{
2016-03-09 13:16:16 +00:00
# ifdef _WIN32
2008-03-17 15:23:11 +00:00
if ( ( event = CreateEvent ( NULL , TRUE , FALSE , NULL ) ) = = INVALID_HANDLE _VALUE )
{
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2008-03-17 15:23:11 +00:00
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to create event to handle perform in thread" ] ;
}
# else
int fd [ 2 ] ;
if ( pipe ( fd ) = = 0 )
{
2008-09-18 08:22:53 +00:00
int e ;
2008-03-17 15:23:11 +00:00
inputFd = fd [ 0 ] ;
outputFd = fd [ 1 ] ;
2008-09-18 08:22:53 +00:00
if ( ( e = fcntl ( inputFd , F_GETFL , 0 ) ) >= 0 )
{
e | = NBLK_OPT ;
if ( fcntl ( inputFd , F_SETFL , e ) < 0 )
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to set non block flag for perform in thread" ] ;
}
}
else
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to get non block flag for perform in thread" ] ;
}
2010-08-30 17:27:11 +00:00
if ( ( e = fcntl ( outputFd , F_GETFL , 0 ) ) >= 0 )
{
e | = NBLK_OPT ;
if ( fcntl ( outputFd , F_SETFL , e ) < 0 )
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to set non block flag for perform in thread" ] ;
}
}
else
{
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to get non block flag for perform in thread" ] ;
}
2008-03-17 15:23:11 +00:00
}
else
{
2010-02-25 18:49:31 +00:00
DESTROY ( self ) ;
2008-03-17 15:23:11 +00:00
[ NSException raise : NSInternalInconsistencyException
format : @ "Failed to create pipe to handle perform in thread" ] ;
}
2012-08-26 08:55:49 +00:00
# endif
2008-03-17 15:23:11 +00:00
lock = [ NSLock new ] ;
performers = [ NSMutableArray new ] ;
return self ;
2002-11-02 16:53:48 +00:00
}
2008-03-18 05:45:05 +00:00
- ( void ) invalidate
{
2014-11-04 09:08:47 +00:00
NSArray * p ;
2008-03-18 05:45:05 +00:00
[ lock lock ] ;
2016-02-10 09:15:10 +00:00
p = AUTORELEASE ( performers ) ;
2014-11-04 09:08:47 +00:00
performers = nil ;
2016-03-09 13:16:16 +00:00
# ifdef _WIN32
2008-03-18 05:55:32 +00:00
if ( event ! = INVALID_HANDLE _VALUE )
{
CloseHandle ( event ) ;
2010-03-08 12:36:37 +00:00
event = INVALID_HANDLE _VALUE ;
2008-03-18 05:55:32 +00:00
}
# else
if ( inputFd >= 0 )
{
close ( inputFd ) ;
inputFd = -1 ;
}
if ( outputFd >= 0 )
{
close ( outputFd ) ;
outputFd = -1 ;
}
# endif
2008-09-18 08:22:53 +00:00
[ lock unlock ] ;
2014-11-04 09:08:47 +00:00
[ p makeObjectsPerformSelector : @ selector ( invalidate ) ] ;
2008-03-18 05:45:05 +00:00
}
2008-03-17 15:23:11 +00:00
- ( void ) fire
2002-11-02 16:53:48 +00:00
{
2005-02-23 16:05:09 +00:00
NSArray * toDo ;
2003-04-06 07:14:50 +00:00
unsigned int i ;
unsigned int c ;
2002-11-03 18:56:46 +00:00
2008-09-18 08:22:53 +00:00
[ lock lock ] ;
2016-03-09 13:16:16 +00:00
# if defined ( _WIN32 )
2008-03-18 05:55:32 +00:00
if ( event ! = INVALID_HANDLE _VALUE )
2005-02-23 16:05:09 +00:00
{
2008-03-18 05:55:32 +00:00
if ( ResetEvent ( event ) = = 0 )
{
NSLog ( @ "Reset event failed - %@" , [ NSError _last ] ) ;
}
2005-02-23 16:05:09 +00:00
}
# else
2008-03-18 05:55:32 +00:00
if ( inputFd >= 0 )
2005-02-23 16:05:09 +00:00
{
2010-08-30 17:27:11 +00:00
char buf [ BUFSIZ ] ;
/ * We don ' t care how much we read . If there have been multiple
* performers queued then there will be multiple bytes available ,
* but we always handle all available performers , so we can also
* read all available bytes .
* The descriptor is non - blocking . . . so it ' s safe to ask for more
* bytes than are available .
* /
while ( read ( inputFd , buf , sizeof ( buf ) ) > 0 )
;
2005-02-23 16:05:09 +00:00
}
# endif
2011-02-09 10:10:04 +00:00
c = [ performers count ] ;
if ( 0 = = c )
{
/ * We deal with all available performers each time we fire , so
* it ' s likely that we will fire when we have no performers left .
* In that case we can skip the copying and emptying of the array .
* /
[ lock unlock ] ;
return ;
}
2008-03-17 15:23:11 +00:00
toDo = [ NSArray arrayWithArray : performers ] ;
[ performers removeAllObjects ] ;
[ lock unlock ] ;
2005-02-23 16:05:09 +00:00
2003-04-06 07:14:50 +00:00
for ( i = 0 ; i < c ; i + + )
2002-11-02 16:53:48 +00:00
{
2005-02-23 16:05:09 +00:00
GSPerformHolder * h = [ toDo objectAtIndex : i ] ;
2002-11-03 18:56:46 +00:00
[ loop performSelector : @ selector ( fire )
target : h
argument : nil
order : 0
2008-03-17 15:23:11 +00:00
modes : [ h modes ] ] ;
}
}
@ end
GSRunLoopThreadInfo *
GSRunLoopInfoForThread ( NSThread * aThread )
{
GSRunLoopThreadInfo * info ;
if ( aThread = = nil )
{
aThread = GSCurrentThread ( ) ;
2008-09-23 08:10:59 +00:00
}
2010-02-14 10:48:10 +00:00
if ( aThread -> _runLoopInfo = = nil )
2008-09-23 08:10:59 +00:00
{
2024-05-30 09:40:52 +00:00
static gs_mutex _t infoLock = GS_MUTEX _INIT _STATIC ;
GS_MUTEX _LOCK ( infoLock ) ;
2010-02-14 10:48:10 +00:00
if ( aThread -> _runLoopInfo = = nil )
2009-05-24 04:22:09 +00:00
{
2010-02-14 10:48:10 +00:00
aThread -> _runLoopInfo = [ GSRunLoopThreadInfo new ] ;
2009-05-24 04:22:09 +00:00
}
2024-05-30 09:40:52 +00:00
GS_MUTEX _UNLOCK ( infoLock ) ;
2002-11-02 16:53:48 +00:00
}
2010-02-14 10:48:10 +00:00
info = aThread -> _runLoopInfo ;
2008-03-17 15:23:11 +00:00
return info ;
}
@ implementation GSPerformHolder
+ ( GSPerformHolder * ) newForReceiver : ( id ) r
argument : ( id ) a
selector : ( SEL ) s
modes : ( NSArray * ) m
lock : ( NSConditionLock * ) l
{
GSPerformHolder * h ;
h = ( GSPerformHolder * ) NSAllocateObject ( self , 0 , NSDefaultMallocZone ( ) ) ;
h -> receiver = RETAIN ( r ) ;
h -> argument = RETAIN ( a ) ;
h -> selector = s ;
h -> modes = RETAIN ( m ) ;
h -> lock = l ;
return h ;
2002-11-02 16:53:48 +00:00
}
2002-11-03 18:56:46 +00:00
- ( void ) dealloc
{
2015-04-02 15:59:48 +00:00
DESTROY ( exception ) ;
2002-11-03 18:56:46 +00:00
DESTROY ( receiver ) ;
DESTROY ( argument ) ;
DESTROY ( modes ) ;
if ( lock ! = nil )
{
[ lock lock ] ;
[ lock unlockWithCondition : 1 ] ;
lock = nil ;
}
NSDeallocateObject ( self ) ;
2006-06-04 06:42:10 +00:00
GSNOSUPERDEALLOC ;
2002-11-03 18:56:46 +00:00
}
2019-08-09 10:06:17 +00:00
- ( NSString * ) description
{
return [ [ super description ] stringByAppendingFormat : @ " [%s %s]" ,
class_getName ( object_getClass ( receiver ) ) , sel_getName ( selector ) ] ;
}
2002-11-03 18:56:46 +00:00
- ( void ) fire
{
2008-03-17 15:23:11 +00:00
GSRunLoopThreadInfo * threadInfo ;
2002-11-03 18:56:46 +00:00
if ( receiver = = nil )
{
return ; // Already fired !
}
2008-03-17 15:23:11 +00:00
threadInfo = GSRunLoopInfoForThread ( GSCurrentThread ( ) ) ;
[ threadInfo -> loop cancelPerformSelectorsWithTarget : self ] ;
2015-04-02 15:59:48 +00:00
NS_DURING
{
[ receiver performSelector : selector withObject : argument ] ;
}
NS_HANDLER
{
ASSIGN ( exception , localException ) ;
if ( nil = = lock )
{
NSLog ( @ "*** NSRunLoop ignoring exception '%@' (reason '%@') "
2019-01-16 09:56:08 +00:00
@ "raised during perform in other thread... with receiver %p (%s) "
2015-10-03 17:38:21 +00:00
@ "and selector '%s'" ,
2015-04-02 15:59:48 +00:00
[ localException name ] , [ localException reason ] , receiver ,
2019-01-16 09:56:08 +00:00
class_getName ( object_getClass ( receiver ) ) ,
2015-10-03 17:38:21 +00:00
sel_getName ( selector ) ) ;
2015-04-02 15:59:48 +00:00
}
}
NS_ENDHANDLER
2002-11-03 18:56:46 +00:00
DESTROY ( receiver ) ;
DESTROY ( argument ) ;
DESTROY ( modes ) ;
2008-03-18 05:45:05 +00:00
if ( lock ! = nil )
2002-11-03 18:56:46 +00:00
{
2002-12-08 20:18:34 +00:00
NSConditionLock * l = lock ;
2002-11-03 18:56:46 +00:00
[ lock lock ] ;
lock = nil ;
2002-12-08 20:18:34 +00:00
[ l unlockWithCondition : 1 ] ;
2002-11-03 18:56:46 +00:00
}
}
2008-03-17 15:23:11 +00:00
2008-03-18 05:45:05 +00:00
- ( void ) invalidate
{
if ( invalidated = = NO )
{
invalidated = YES ;
DESTROY ( receiver ) ;
if ( lock ! = nil )
{
NSConditionLock * l = lock ;
[ lock lock ] ;
lock = nil ;
[ l unlockWithCondition : 1 ] ;
}
}
}
- ( BOOL ) isInvalidated
{
return invalidated ;
}
2008-03-17 15:23:11 +00:00
- ( NSArray * ) modes
{
return modes ;
}
2002-11-03 18:56:46 +00:00
@ end
2002-11-02 16:53:48 +00:00
2008-03-17 15:23:11 +00:00
@ implementation NSObject ( NSThreadPerformAdditions )
2002-10-30 07:45:59 +00:00
- ( void ) performSelectorOnMainThread : ( SEL ) aSelector
withObject : ( id ) anObject
waitUntilDone : ( BOOL ) aFlag
2002-11-03 18:56:46 +00:00
modes : ( NSArray * ) anArray
2002-10-30 07:45:59 +00:00
{
2008-09-23 08:10:59 +00:00
/ * It ' s possible that this method could be called before the NSThread
* class is initialised , so we check and make sure it ' s initiailised
* if necessary .
* /
if ( defaultThread = = nil )
{
[ NSThread currentThread ] ;
}
2008-03-17 15:23:11 +00:00
[ self performSelector : aSelector
onThread : defaultThread
withObject : anObject
waitUntilDone : aFlag
modes : anArray ] ;
}
- ( void ) performSelectorOnMainThread : ( SEL ) aSelector
withObject : ( id ) anObject
waitUntilDone : ( BOOL ) aFlag
{
[ self performSelectorOnMainThread : aSelector
withObject : anObject
waitUntilDone : aFlag
modes : commonModes ( ) ] ;
}
- ( void ) performSelector : ( SEL ) aSelector
onThread : ( NSThread * ) aThread
withObject : ( id ) anObject
waitUntilDone : ( BOOL ) aFlag
modes : ( NSArray * ) anArray
{
GSRunLoopThreadInfo * info ;
NSThread * t ;
2002-10-30 07:45:59 +00:00
2002-11-03 18:56:46 +00:00
if ( [ anArray count ] = = 0 )
{
return ;
}
t = GSCurrentThread ( ) ;
2008-03-17 15:23:11 +00:00
if ( aThread = = nil )
2002-10-30 07:45:59 +00:00
{
2008-03-17 15:23:11 +00:00
aThread = t ;
}
info = GSRunLoopInfoForThread ( aThread ) ;
if ( t = = aThread )
{
2008-03-18 05:45:05 +00:00
/ * Perform in current thread .
* /
2008-03-17 15:23:11 +00:00
if ( aFlag = = YES || info -> loop = = nil )
2002-11-02 16:53:48 +00:00
{
2008-03-18 05:45:05 +00:00
/ * Wait until done or no run loop .
* /
2002-11-02 16:53:48 +00:00
[ self performSelector : aSelector withObject : anObject ] ;
}
else
{
2008-03-18 05:45:05 +00:00
/ * Don ' t wait . . . schedule operation in run loop .
* /
2008-03-17 15:23:11 +00:00
[ info -> loop performSelector : aSelector
target : self
argument : anObject
order : 0
modes : anArray ] ;
2002-11-02 16:53:48 +00:00
}
2002-10-30 07:45:59 +00:00
}
else
{
2008-03-17 15:23:11 +00:00
GSPerformHolder * h ;
2002-11-03 18:56:46 +00:00
NSConditionLock * l = nil ;
2002-10-30 07:45:59 +00:00
2013-02-03 06:31:03 +00:00
if ( [ aThread isFinished ] = = YES )
2008-03-18 05:45:05 +00:00
{
[ NSException raise : NSInternalInconsistencyException
2018-01-15 11:42:04 +00:00
format : @ "perform [%@-%@] attempted on finished thread (%@)" ,
2018-01-15 10:08:13 +00:00
NSStringFromClass ( [ self class ] ) ,
2018-01-15 11:42:04 +00:00
NSStringFromSelector ( aSelector ) ,
aThread ] ;
2008-03-18 05:45:05 +00:00
}
2002-10-30 07:45:59 +00:00
if ( aFlag = = YES )
{
2002-11-02 16:53:48 +00:00
l = [ [ NSConditionLock alloc ] init ] ;
2002-10-30 07:45:59 +00:00
}
2005-02-22 11:22:44 +00:00
2002-10-30 07:45:59 +00:00
h = [ GSPerformHolder newForReceiver : self
2002-11-03 18:56:46 +00:00
argument : anObject
selector : aSelector
modes : anArray
lock : l ] ;
2008-03-17 15:23:11 +00:00
[ info addPerformer : h ] ;
if ( l ! = nil )
2002-10-30 07:45:59 +00:00
{
2002-11-03 18:56:46 +00:00
[ l lockWhenCondition : 1 ] ;
2002-10-30 12:37:21 +00:00
[ l unlock ] ;
RELEASE ( l ) ;
2018-01-15 10:08:13 +00:00
if ( [ h isInvalidated ] = = NO )
2008-03-18 05:45:05 +00:00
{
2018-01-15 10:08:13 +00:00
/ * If we have an exception passed back from the remote thread ,
* re - raise it .
* /
if ( nil ! = h -> exception )
{
NSException * e = AUTORELEASE ( RETAIN ( h -> exception ) ) ;
2015-04-02 15:59:48 +00:00
2018-01-15 10:08:13 +00:00
RELEASE ( h ) ;
[ e raise ] ;
}
2008-03-18 05:45:05 +00:00
}
2002-10-30 07:45:59 +00:00
}
2008-03-17 15:23:11 +00:00
RELEASE ( h ) ;
2002-10-30 07:45:59 +00:00
}
}
2008-03-17 15:23:11 +00:00
- ( void ) performSelector : ( SEL ) aSelector
onThread : ( NSThread * ) aThread
withObject : ( id ) anObject
waitUntilDone : ( BOOL ) aFlag
2002-10-30 07:45:59 +00:00
{
2008-03-17 15:23:11 +00:00
[ self performSelector : aSelector
onThread : aThread
withObject : anObject
waitUntilDone : aFlag
modes : commonModes ( ) ] ;
2002-10-30 07:45:59 +00:00
}
2013-08-12 08:56:18 +00:00
2016-01-29 13:42:07 +00:00
- ( void ) performSelectorInBackground : ( SEL ) aSelector
2013-08-12 08:56:18 +00:00
withObject : ( id ) anObject
{
[ NSThread detachNewThreadSelector : aSelector
toTarget : self
withObject : anObject ] ;
}
2002-10-30 07:45:59 +00:00
@ end
2002-11-03 19:09:39 +00:00
2024-10-30 10:13:28 +00:00
@ implementation NSThread ( BlockAdditions )
+ ( void ) detachNewThreadWithBlock : ( GSThreadBlock ) block
{
NSThread * thread ;
thread = [ [ NSThread alloc ] initWithBlock : block ] ;
[ thread start ] ;
RELEASE ( thread ) ;
}
- ( instancetype ) initWithBlock : ( GSThreadBlock ) block
{
if ( nil ! = ( self = [ self init ] ) )
{
2025-01-27 18:16:07 +00:00
targetIsBlock = YES ;
2024-10-30 10:13:28 +00:00
/ * Copy block to heap * /
_target = _Block _copy ( block ) ;
}
return self ;
}
@ end
2002-08-20 10:22:05 +00:00
/ * *
* < p >
* This function is provided to let threads started by some other
* software library register themselves to be used with the
* GNUstep system . All such threads should call this function
* before attempting to use any GNUstep objects .
* < / p >
* < p >
* Returns < code > YES < / code > if the thread can be registered ,
* < code > NO < / code > if it is already registered .
* < / p >
* < p >
* Sends out a < code > NSWillBecomeMultiThreadedNotification < / code >
* if the process was not already multithreaded .
* < / p >
* /
2001-03-19 12:20:21 +00:00
BOOL
2016-06-27 20:21:11 +00:00
GSRegisterCurrentThread ( void )
2000-11-12 07:41:24 +00:00
{
2009-09-08 20:32:52 +00:00
return [ NSThread _createThreadForCurrentPthread ] ;
2000-11-12 07:41:24 +00:00
}
2011-07-15 13:46:51 +00:00
2002-08-20 10:22:05 +00:00
/ * *
* < p >
* This function is provided to let threads started by some other
* software library unregister themselves from the GNUstep threading
2005-02-22 11:22:44 +00:00
* system .
2002-08-20 10:22:05 +00:00
* < / p >
* < p >
* Calling this function causes a
* < code > NSThreadWillExitNotification < / code >
* to be sent out , and destroys the GNUstep NSThread object
2010-04-16 18:18:43 +00:00
* associated with the thread ( like [ NSThread + exit ] ) but does
* not exit the underlying thread .
2002-08-20 10:22:05 +00:00
* < / p >
* /
2001-03-19 12:20:21 +00:00
void
2016-06-27 20:21:11 +00:00
GSUnregisterCurrentThread ( void )
2000-11-12 07:41:24 +00:00
{
2010-04-16 18:18:43 +00:00
unregisterActiveThread ( GSCurrentThread ( ) ) ;
2000-11-12 07:41:24 +00:00
}