Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -77,16 +77,10 @@ size_max="SIZE_T_MAX"], [ AC_MSG_RESULT(no) size_max="((size_t)-1)"]) AC_DEFINE_UNQUOTED(SIZE_MAX, $size_max, [Maximum value for size_t])]) -AC_CHECK_FUNC(objc_sync_enter,, [ - AC_SUBST(OBJC_SYNC, "objc_sync") - AC_SUBST(OBJC_SYNC_M, "objc_sync.m") - AC_DEFINE(NEED_OBJC_SYNC_INIT, 1, - [Whether objc_sync_init needs to be called])]) - AC_CHECK_FUNC(asprintf, [ have_asprintf="yes" AC_DEFINE(OF_HAVE_ASPRINTF, 1, [Whether we have asprintf]) AC_SUBST(ASPRINTF_DEF, "-DOF_HAVE_ASPRINTF") ], [ @@ -110,23 +104,37 @@ test x"$have_asprintf" != x"yes" -a x"$ac_cv_snprintf_useful_ret" != x"yes" && \ AC_MSG_ERROR(No asprintf and no snprintf returning required space!) AC_CHECK_LIB(dl, dlopen, LIBS="$LIBS -ldl") -case "$host" in - *-*-mingw*) - AC_MSG_CHECKING(for threads) - AC_MSG_RESULT(win32) - ;; - *) - ACX_PTHREAD([ - CPPLAGS="$CPPFLAGS $PTHREAD_CFLAGS" - LIBS="$LIBS $PTHREAD_LIBS" - ], [ - AC_MSG_ERROR(No pthreads or other supported threads!)]) - ;; -esac +AC_ARG_ENABLE(threads, + AS_HELP_STRING([--disable-threads], [disable thread support])) +if test x"$enable_threads" != x"no"; then + case "$host_os" in + mingw*) + AC_MSG_CHECKING(for threads) + AC_MSG_RESULT(win32) + ;; + *) + ACX_PTHREAD([ + CPPLAGS="$CPPFLAGS $PTHREAD_CFLAGS" + LIBS="$LIBS $PTHREAD_LIBS" + ], [ + AC_MSG_ERROR(No supported threads found!)]) + ;; + esac + + AC_DEFINE(OF_THREADS, 1, [Whether we have threads]) + AC_SUBST(OFTHREAD_M, "OFThread.m") + AC_SUBST(THREADING_H, "threading.h") + + AC_CHECK_FUNC(objc_sync_enter,, [ + AC_SUBST(OBJC_SYNC, "objc_sync") + AC_SUBST(OBJC_SYNC_M, "objc_sync.m") + AC_DEFINE(NEED_OBJC_SYNC_INIT, 1, + [Whether objc_sync_init needs to be called])]) +fi AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") AC_CHECK_LIB(ws2_32, main, LIBS="$LIBS -lws2_32") AC_MSG_CHECKING(for getaddrinfo) @@ -144,36 +152,38 @@ getaddrinfo(NULL, NULL, NULL, NULL); ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether we have getaddrinfo]) - AC_MSG_CHECKING(whether getaddrinfo is thread-safe) - case "$host_os" in - darwin[[12345]].*) - have_threadsafe_getaddrinfo="no" - ;; - darwin*) - have_threadsafe_getaddrinfo="yes" - ;; - freebsd[[1234]].* | freebsd5.[[1234]]*) - have_threadsafe_getaddrinfo="no" - ;; - freebsd*) - have_threadsafe_getaddrinfo="yes" - ;; - netbsd[[123]].*) - have_threadsafe_getaddrinfo="no" - ;; - netbsd*) - have_threadsafe_getaddrinfo="yes" - ;; - solaris*) - have_threadsafe_getaddrinfo="yes" - ;; - *) - have_threadsafe_getaddrinfo="unknown" - ;; + if test x"$enable_threads" != x"no"; then + AC_MSG_CHECKING(whether getaddrinfo is thread-safe) + + case "$host_os" in + darwin[[12345]].*) + have_threadsafe_getaddrinfo="no" + ;; + darwin*) + have_threadsafe_getaddrinfo="yes" + ;; + freebsd[[1234]].* | freebsd5.[[1234]]*) + have_threadsafe_getaddrinfo="no" + ;; + freebsd*) + have_threadsafe_getaddrinfo="yes" + ;; + netbsd[[123]].*) + have_threadsafe_getaddrinfo="no" + ;; + netbsd*) + have_threadsafe_getaddrinfo="yes" + ;; + solaris*) + have_threadsafe_getaddrinfo="yes" + ;; + *) + have_threadsafe_getaddrinfo="unknown" + ;; esac if test x"$have_threadsafe_getaddrinfo" = x"unknown"; then AC_EGREP_CPP(yes, [ #include @@ -188,10 +198,11 @@ test x"$have_threadsafe_getaddrinfo" = x"yes" && \ AC_DEFINE(HAVE_THREADSAFE_GETADDRINFO, 1, [Whether getaddrinfo is thread-safe]) AC_MSG_RESULT($have_threadsafe_getaddrinfo) + fi ], [ AC_MSG_RESULT(no)]) AC_CHECK_FUNC(madvise, [AC_DEFINE(HAVE_MADVISE, 1, [Whether we have madvise])]) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -1,8 +1,10 @@ ASPRINTF_M = @ASPRINTF_M@ OBJC_SYNC = @OBJC_SYNC@ OBJC_SYNC_M = @OBJC_SYNC_M@ OFPLUGIN_M = @OFPLUGIN_M@ +OFTHREAD_M = @OFTHREAD_M@ TESTPLUGIN = @TESTPLUGIN@ WS2_LIBS = @WS2_LIBS@ TESTS = @TESTS@ TEST_LAUNCHER = @TEST_LAUNCHER@ +THREADING_H = @THREADING_H@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -22,11 +22,11 @@ ${OFPLUGIN_M} \ OFSocket.m \ OFStream.m \ OFString.m \ OFTCPSocket.m \ - OFThread.m \ + ${OFTHREAD_M} \ OFURLEncoding.m \ OFXMLElement.m \ OFXMLParser.m \ unicode.m @@ -33,11 +33,11 @@ INCLUDES := ${SRCS:.m=.h} \ OFMacros.h \ ObjFW.h \ asprintf.h \ objfw-defs.h \ - threading.h + ${THREADING_H} SRCS += ${OBJC_SYNC_M} \ ${ASPRINTF_M} \ iso_8859_15.m \ windows_1252.m Index: src/OFAutoreleasePool.m ================================================================== --- src/OFAutoreleasePool.m +++ src/OFAutoreleasePool.m @@ -13,40 +13,49 @@ #include #import "OFAutoreleasePool.h" #import "OFList.h" -#import "OFThread.h" #import "OFExceptions.h" +#ifdef OF_THREADS #import "threading.h" static of_tlskey_t first_key, last_key; +#else +static OFAutoreleasePool *first = nil, *last = nil; +#endif @implementation OFAutoreleasePool +#ifdef OF_THREADS + (void)initialize { if (self != [OFAutoreleasePool class]) return; if (!of_tlskey_new(&first_key) || !of_tlskey_new(&last_key)) @throw [OFInitializationFailedException newWithClass: self]; } +#endif + (void)addObjectToTopmostPool: (OFObject*)obj { +#ifdef OF_THREADS id last = of_tlskey_get(last_key); +#endif if (last == nil) { @try { [[self alloc] init]; } @catch (OFException *e) { [obj release]; @throw e; } +#ifdef OF_THREADS last = of_tlskey_get(last_key); +#endif } if (last == nil) { [obj release]; @throw [OFInitializationFailedException newWithClass: self]; @@ -60,38 +69,53 @@ } } + (void)releaseAll { +#ifdef OF_THREADS [of_tlskey_get(first_key) release]; +#else + [first release]; +#endif } - init { +#ifdef OF_THREADS id first; +#endif self = [super init]; +#ifdef OF_THREADS first = of_tlskey_get(first_key); prev = of_tlskey_get(last_key); if (!of_tlskey_set(last_key, self)) { Class c = isa; [super dealloc]; @throw [OFInitializationFailedException newWithClass: c]; } +#else + prev = last; + last = self; +#endif if (first == nil) { +#ifdef OF_THREADS if (!of_tlskey_set(first_key, self)) { Class c = isa; of_tlskey_set(last_key, prev); [super dealloc]; @throw [OFInitializationFailedException newWithClass: c]; } +#else + first = self; +#endif } if (prev != nil) prev->next = self; @@ -109,23 +133,32 @@ * deallocation. This way, new objects will be added to the current * pool, but released when the pool below gets released - and maybe * the pool itself will be released as well then, because maybe * of_tlskey_set will work this time. */ +#ifdef OF_THREADS if (!of_tlskey_set(last_key, prev)) return; +#else + last = prev; +#endif if (prev != nil) prev->next = nil; /* * If of_tlskey_set fails here, this is even worse, as this will * definitely be a memory leak. But this should never happen anyway. */ +#ifdef OF_THREADS if (of_tlskey_get(first_key) == self) if (!of_tlskey_set(first_key, nil)) return; +#else + if (first == self) + first = nil; +#endif [super dealloc]; } - addObject: (OFObject*)obj Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -22,23 +22,24 @@ # endif #endif #import "OFTCPSocket.h" #import "OFExceptions.h" +#import "OFMacros.h" #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif -#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_THREADSAFE_GETADDRINFO) +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) #import "OFThread.h" static OFMutex *mutex = nil; #endif @implementation OFTCPSocket -#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_THREADSAFE_GETADDRINFO) +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) + (void)initialize { if (self == [OFTCPSocket class]) mutex = [[OFMutex alloc] init]; } @@ -67,16 +68,16 @@ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; -#ifndef HAVE_THREADSAFE_GETADDRINFO +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) [mutex lock]; #endif if (getaddrinfo([node cString], [service cString], &hints, &res0)) { -#ifndef HAVE_THREADSAFE_GETADDRINFO +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) [mutex unlock]; #endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node @@ -97,11 +98,11 @@ break; } freeaddrinfo(res0); -#ifndef HAVE_THREADSAFE_GETADDRINFO +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) [mutex unlock]; #endif #else BOOL connected = NO; struct hostent *he; @@ -108,24 +109,30 @@ struct servent *se; struct sockaddr_in addr; uint16_t port; char **ip; +#ifdef OF_THREADS [mutex lock]; +#endif if ((he = gethostbyname([node cString])) == NULL) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; } if ((se = getservbyname([service cString], "TCP")) != NULL) port = se->s_port; else if ((port = OF_BSWAP16_IF_LE(atoi([service cString]))) == 0) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; } @@ -134,11 +141,13 @@ addr.sin_family = AF_INET; addr.sin_port = port; if (he->h_addrtype != AF_INET || (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFConnectionFailedException newWithClass: isa node: node service: service]; } @@ -151,11 +160,13 @@ connected = YES; break; } +#ifdef OF_THREADS [mutex unlock]; +#endif if (!connected) { close(sock); sock = INVALID_SOCKET; } @@ -187,25 +198,40 @@ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo([node cString], [service cString], &hints, &res)) +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) + [mutex lock]; +#endif + + if (getaddrinfo([node cString], [service cString], &hints, &res)) { +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) + [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; + } if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) { freeaddrinfo(res); +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) + [mutex unlock]; +#endif @throw [OFBindFailedException newWithClass: isa node: node service: service family: family]; } freeaddrinfo(res); + +#if defined(OF_THREADS) && !defined(HAVE_THREADSAFE_GETADDRINFO) + [mutex unlock]; +#endif #else struct hostent *he; struct servent *se; struct sockaddr_in addr; uint16_t port; @@ -214,24 +240,30 @@ @throw [OFBindFailedException newWithClass: isa node: node service: service family: family]; +#ifdef OF_THREADS [mutex lock]; +#endif if ((he = gethostbyname([node cString])) == NULL) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; } if ((se = getservbyname([service cString], "TCP")) != NULL) port = se->s_port; else if ((port = OF_BSWAP16_IF_LE(atoi([service cString]))) == 0) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; } @@ -239,20 +271,24 @@ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = port; if (he->h_addrtype != AF_INET || he->h_addr_list[0] == NULL) { +#ifdef OF_THREADS [mutex unlock]; +#endif @throw [OFAddressTranslationFailedException newWithClass: isa node: node service: service]; } memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); +#ifdef OF_THREADS [mutex unlock]; +#endif if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) @throw [OFBindFailedException newWithClass: isa node: node service: service Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -31,14 +31,17 @@ #import "OFSocket.h" #import "OFTCPSocket.h" #import "OFHashes.h" -#import "OFThread.h" #import "OFXMLElement.h" #ifdef OF_PLUGINS #import "OFPlugin.h" #endif + +#ifdef OF_THREADS +#import "OFThread.h" +#endif #import "OFMacros.h" #import "asprintf.h" Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,6 +1,7 @@ #undef OF_APPLE_RUNTIME #undef OF_BIG_ENDIAN #undef OF_GNU_RUNTIME #undef OF_HAVE_ASPRINTF #undef OF_PLUGINS +#undef OF_THREADS #undef SIZE_MAX Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -10,11 +10,11 @@ OFList.m \ OFObject.m \ ${OFPLUGIN_M} \ OFString.m \ OFTCPSocket.m \ - OFThread.m \ + ${OFTHREAD_M} \ OFXMLElement.m \ OFXMLParser.m \ main.m IPHONE_USER = mobile Index: tests/main.m ================================================================== --- tests/main.m +++ tests/main.m @@ -28,11 +28,13 @@ #ifdef OF_PLUGINS extern void plugin_tests(); #endif extern void string_tests(); extern void tcpsocket_tests(); +#ifdef OF_THREADS extern void thread_tests(); +#endif extern void xmlelement_tests(); extern void xmlparser_tests(); static int fails = 0; @@ -103,14 +105,16 @@ dataarray_tests(); array_tests(); dictionary_tests(); list_tests(); tcpsocket_tests(); +#ifdef OF_THREADS thread_tests(); +#endif xmlelement_tests(); xmlparser_tests(); #ifdef OF_PLUGINS plugin_tests(); #endif return fails; }