diff --git a/ChangeLog b/ChangeLog index 66091f7b5..13be776a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2015-03-31 Richard Frith-Macdonald + + * Source/GSPrivate.h: Internal function to get OS thread ID + * Source/NSThread.m: Report thread name and ID in description + * Source/NSLog.m: Use new function for thread ID + * configure.ac: Detect getaddrinfo and bsd thread id extensions + * Headers/GNUstepBase/config.h.in: regenerate + * configure: regenerate + * Source/NSHost.m: Start of code to use getaddrinfo + 2015-03-13 Richard Frith-Macdonald * Source/NSAutoreleasePool.m: Fix a bug leading to crashes on thread diff --git a/Headers/GNUstepBase/config.h.in b/Headers/GNUstepBase/config.h.in index 77d239c99..e6152e702 100644 --- a/Headers/GNUstepBase/config.h.in +++ b/Headers/GNUstepBase/config.h.in @@ -248,6 +248,9 @@ /* Define if GC_register_my_thread function is available */ #undef HAVE_GC_REGISTER_MY_THREAD +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD @@ -455,9 +458,15 @@ /* Define if your Lib C defines program_invocation_name */ #undef HAVE_PROGRAM_INVOCATION_NAME +/* Define to 1 if you have the `pthread_getthreadid_np' function. */ +#undef HAVE_PTHREAD_GETTHREADID_NP + /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_NP_H + /* Define to 1 if you have the `pthread_set_name_np' function. */ #undef HAVE_PTHREAD_SET_NAME_NP diff --git a/Source/GSPrivate.h b/Source/GSPrivate.h index bada33616..bb920a10c 100644 --- a/Source/GSPrivate.h +++ b/Source/GSPrivate.h @@ -552,5 +552,17 @@ uint32_t GSPrivateFinishHash(uint32_t s0, uint32_t s1, uint32_t totalLength) GS_ATTRIB_PRIVATE; +/* 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. + */ +unsigned long +GSPrivateThreadID() + GS_ATTRIB_PRIVATE; + #endif /* _GSPrivate_h_ */ diff --git a/Source/NSHost.m b/Source/NSHost.m index 7cd58c4f8..201c2c3a8 100644 --- a/Source/NSHost.m +++ b/Source/NSHost.m @@ -63,7 +63,10 @@ static id null = nil; @interface NSHost (Private) - (void) _addName: (NSString*)name; -- (id) _initWithHostEntry: (struct hostent*)entry key: (NSString*)key; +#if defined(HAVE_GETADDRINFO) +- (id) _initWithAddrinfo: (struct addrinfo*)entry key: (NSString*)name; +#endif +- (id) _initWithHostEntry: (struct hostent*)entry key: (NSString*)name; + (NSMutableSet*) _localAddresses; @end @@ -101,6 +104,125 @@ static id null = nil; return self; } +#if defined(HAVE_GETADDRINFO) +- (id) _initWithAddrinfo: (struct addrinfo*)entry key: (NSString*)name +{ + NSMutableSet *names; + NSMutableSet *addresses; + NSMutableSet *extra; + + if ((self = [super init]) == nil) + { + return nil; + } + if ([name isEqualToString: localHostName] == NO + && entry == (struct addrinfo*)NULL) + { + NSLog(@"Host '%@' init failed - perhaps the name/address is wrong or " + @"networking is not set up on your machine", name); + DESTROY(self); + return nil; + } + else if (name == nil && entry != (struct addrinfo*)NULL) + { + NSLog(@"Nil hostname supplied but network database entry is not empty"); + DESTROY(self); + return nil; + } + + names = [NSMutableSet new]; + addresses = [NSMutableSet new]; + + if ([name isEqualToString: localHostName] == YES) + { + extra = [hostClass _localAddresses]; + } + else + { + extra = nil; + } + + for (;;) + { + struct addrinfo *tmp; + + /* + * We remove all the IP addresses that we have added to the host so + * far from the set of extra addresses available on the current host. + * Then we try to find a new network database entry for one of the + * remaining extra addresses, and loop round to add all the names + * and addresses for that entry. + */ + [extra minusSet: addresses]; + while (entry == 0 && [extra count] > 0) + { + NSString *a = [extra anyObject]; + struct addrinfo hints; + + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + getaddrinfo([a UTF8String], 0, &hints, &entry); + if (0 == entry) + { + /* + * Can't find a database entry for this IP address, but since + * we know the address is valid, we add it to the list of + * addresses for this host anyway. + */ + [addresses addObject: a]; + [extra removeObject: a]; + } + } + if (0 == entry) + { + break; + } + + for (tmp = entry; tmp != 0; tmp = tmp->ai_next) + { + if (tmp->ai_canonname && *tmp->ai_canonname) + { + NSString *n; + + n = [[NSString alloc] initWithUTF8String: tmp->ai_canonname]; + [names addObject: n]; + [n release]; + } + + if (tmp->ai_addrlen > 0) + { + char host[NI_MAXHOST]; + char port[NI_MAXSERV]; + + if (0 == getnameinfo(tmp->ai_addr, tmp->ai_addrlen, + host, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICSERV)) + { + NSString *a; + + a = [[NSString alloc] initWithUTF8String: host]; + [addresses addObject: a]; + [a release]; + } + } + } + freeaddrinfo(entry); + entry = 0; + } + + _names = [names copy]; + RELEASE(names); + _addresses = [addresses copy]; + RELEASE(addresses); + + if (YES == _hostCacheEnabled) + { + [_hostCache setObject: self forKey: name]; + } + + return self; +} +#endif + - (id) _initWithHostEntry: (struct hostent*)entry key: (NSString*)name { int i; diff --git a/Source/NSLog.m b/Source/NSLog.m index d961b5ff8..e01269310 100644 --- a/Source/NSLog.m +++ b/Source/NSLog.m @@ -37,32 +37,6 @@ #import "Foundation/NSThread.h" #import "GNUstepBase/NSString+GNUstepBase.h" -#if defined(HAVE_GETTID) -#include -#include -#include -#endif - -/* 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. - */ -static unsigned long -GSThreadID() -{ -#if defined(__MINGW__) - return (unsigned long)GetCurrentThreadId(); -#elif defined(HAVE_GETTID) - return (unsigned long)syscall(SYS_gettid); -#else - return (unsigned long)GSCurrentThread(); -#endif -} - // Some older BSD systems used a non-standard range of thread priorities. #ifdef HAVE_SYSLOG_H #include @@ -394,11 +368,12 @@ NSLogv(NSString* format, va_list args) { if (nil != threadName) { - [prefix appendFormat: @"[thread:%lu,%@] ", GSThreadID(), threadName]; + [prefix appendFormat: @"[thread:%lu,%@] ", + GSPrivateThreadID(), threadName]; } else { - [prefix appendFormat: @"[thread:%lu] ", GSThreadID()]; + [prefix appendFormat: @"[thread:%lu] ", GSPrivateThreadID()]; } } else @@ -423,12 +398,12 @@ NSLogv(NSString* format, va_list args) if (nil == threadName) { [prefix appendFormat: @"[%d:%lu] ", - pid, GSThreadID()]; + pid, GSPrivateThreadID()]; } else { [prefix appendFormat: @"[%d:%lu,%@] ", - pid, GSThreadID(), threadName]; + pid, GSPrivateThreadID(), threadName]; } } diff --git a/Source/NSThread.m b/Source/NSThread.m index 9cd7577db..2b6c13932 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -34,20 +34,20 @@ #import "common.h" #define EXPOSE_NSThread_IVARS 1 #ifdef HAVE_NANOSLEEP -#include +# include #endif #ifdef HAVE_SYS_TIME_H -#include +# include #endif #ifdef HAVE_SYS_RESOURCE_H -#include +# include #endif #ifdef HAVE_PTHREAD_H -#include +# include #endif #if defined(HAVE_SYS_FILE_H) -# include +# include #endif #if defined(HAVE_SYS_FCNTL_H) @@ -79,19 +79,50 @@ #import "GSRunLoopCtxt.h" #if GS_WITH_GC -#include +# include #endif #if __OBJC_GC__ -#include +# include +#endif + +#if defined(HAVE_PTHREAD_NP_H) +# include #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) -# include # define IS_MAIN_PTHREAD (pthread_main_np() == 1) #else # define IS_MAIN_PTHREAD (1) #endif +#if defined(HAVE_GETTID) +# include +# include +# include +#endif + +/* 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. + */ +unsigned long +GSPrivateThreadID() +{ +#if defined(__MINGW__) + return (unsigned long)GetCurrentThreadId(); +#elif defined(HAVE_GETTID) + return (unsigned long)syscall(SYS_gettid); +#elif defined(HAVE_PTHREAD_GETTHREADID_NP) + return pthread_getthreadid_np(); +#else + return (unsigned long)GSCurrentThread(); +#endif +} + #if 0 /* * NSThread setName: method for windows. @@ -759,6 +790,12 @@ unregisterActiveThread(NSThread *thread) [super dealloc]; } +- (NSString*) description +{ + return [NSString stringWithFormat: @"%@{name = %@, num = %lu}", + [super description], _name, GSPrivateThreadID()]; +} + - (id) init { init_autorelease_thread_vars(&_autorelease_vars); diff --git a/configure b/configure index eb3280ca4..3b82edc66 100755 --- a/configure +++ b/configure @@ -11513,11 +11513,114 @@ fi fi + +for ac_func in getaddrinfo +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + #-------------------------------------------------------------------- # Check for pthread.h #-------------------------------------------------------------------- -for ac_header in pthread.h + +for ac_header in pthread.h pthread_np.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -13466,6 +13569,109 @@ $as_echo "$as_me: error: Unable to find pthread library (needed for thread suppo { (exit 1); exit 1; }; } fi +/* See if we have an extension to get a pthread ID + */ + +for ac_func in pthread_getthreadid_np +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + # Typically need librt on Solaris for sched_yield @@ -20776,6 +20982,7 @@ _ACEOF fi done + USE_ZLIB=0 for ac_header in zlib.h diff --git a/configure.ac b/configure.ac index c8c84dcd9..248c3db9a 100644 --- a/configure.ac +++ b/configure.ac @@ -1647,10 +1647,12 @@ if test "$ac_cv_func_gethostbyname" = "no"; then AC_CHECK_LIB(socket, gethostbyname) fi +AC_CHECK_FUNCS(getaddrinfo) + #-------------------------------------------------------------------- # Check for pthread.h #-------------------------------------------------------------------- -AC_CHECK_HEADERS(pthread.h) +AC_CHECK_HEADERS(pthread.h pthread_np.h) if test $ac_cv_header_pthread_h = yes ; then AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT #include ]) @@ -1713,6 +1715,9 @@ if test $pthread_ok = no ; then AC_MSG_ERROR([Unable to find pthread library (needed for thread support).]) fi +/* See if we have an extension to get a pthread ID + */ +AC_CHECK_FUNCS(pthread_getthreadid_np) # Typically need librt on Solaris for sched_yield AC_CHECK_LIB(rt, sched_yield) @@ -2415,6 +2420,7 @@ AC_SUBST(DEFINE_UINTPTR_T) #-------------------------------------------------------------------- AC_SEARCH_LIBS([inet_ntop],[nsl]) AC_CHECK_FUNCS(gethostbyaddr_r inet_aton inet_pton inet_ntop sigaction) + USE_ZLIB=0 AC_CHECK_HEADERS(zlib.h) if test $ac_cv_header_zlib_h = yes; then