Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -93,10 +93,14 @@ if ([delegate respondsToSelector: @selector(applicationWillTerminate)]) [delegate applicationWillTerminate]; [delegate release]; + +#if defined(OF_HAVE_THREADS) && defined(OF_HAVE_SOCKETS) && defined(OF_AMIGAOS) + of_socket_deinit(); +#endif } #define SIGNAL_HANDLER(signal) \ static void \ handle##signal(int sig) \ Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -53,14 +53,11 @@ # define interface struct # include # undef interface #endif -#ifdef OF_AMIGAOS -# include -# include -#endif +#import "socket_helpers.h" #ifdef OF_NINTENDO_3DS # include <3ds.h> #endif Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -910,10 +910,11 @@ [OFMutableArray arrayWithCapacity: _numberOfThreads - 1]; for (size_t i = 1; i < _numberOfThreads; i++) { OFHTTPServerThread *thread = [OFHTTPServerThread thread]; + thread.supportsSockets = true; [thread start]; [threads addObject: thread]; } Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -48,10 +48,15 @@ * * @brief A class which provides portable threads. * * To use it, you should create a new class derived from it and reimplement * main. + * + * @warning Some operating systems such as AmigaOS need special per-thread + * initialization of sockets. If you intend to use sockets in the + * thread, set the @ref usesSockets property to true before starting + * it. * * @warning Even though the OFCopying protocol is implemented, it does *not* * return an independent copy of the thread, but instead retains it. * This is so that the thread can be used as a key for a dictionary, * so context can be associated with a thread. @@ -74,10 +79,12 @@ # ifdef OF_HAVE_BLOCKS of_thread_block_t _Nullable _threadBlock; # endif jmp_buf _exitEnv; id _returnValue; +@protected + bool _supportsSockets; OFRunLoop *_Nullable _runLoop; OFMutableDictionary *_threadDictionary; @private OFString *_Nullable _name; # ifdef OF_HAVE_SOCKETS @@ -139,10 +146,19 @@ * * @note This has to be set before the thread is started! */ @property (nonatomic) size_t stackSize; +/*! + * @brief Whether the thread supports sockets. + * + * Some operating systems such as AmigaOS need special per-thread + * initialization of sockets. If you intend to use sockets in the thread, set + * this property to true before starting the thread. + */ +@property (nonatomic) bool supportsSockets; + /*! * @brief Creates a new thread. * * @return A new, autoreleased thread */ Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -88,10 +88,13 @@ # define lrint(x) rint(x) #endif #if defined(OF_HAVE_THREADS) # import "tlskey.h" +# if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) +# import "socket.h" +# endif static of_tlskey_t threadSelfKey; static OFThread *mainThread; static void @@ -111,10 +114,17 @@ of_thread_set_name( [name cStringWithEncoding: [OFLocale encoding]]); else of_thread_set_name(object_getClassName(thread)); +#if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) + if (thread.supportsSockets) + if (!of_socket_init()) + @throw [OFInitializationFailedException + exceptionWithClass: thread.class]; +#endif + /* * Nasty workaround for thread implementations which can't return a * pointer on join, or don't have a way to exit a thread. */ if (setjmp(thread->_exitEnv) == 0) { @@ -128,10 +138,15 @@ [thread handleTermination]; objc_autoreleasePoolPop(thread->_pool); [OFAutoreleasePool of_handleThreadTermination]; + +#if defined(OF_AMIGAOS) && defined(OF_HAVE_SOCKETS) + if (thread.supportsSockets) + of_socket_deinit(); +#endif thread->_running = OF_THREAD_WAITING_FOR_JOIN; [thread release]; } @@ -463,10 +478,24 @@ @throw [OFThreadStillRunningException exceptionWithThread: self]; _attr.stackSize = stackSize; } + +- (bool)supportsSockets +{ + return _supportsSockets; +} + +- (void)setSupportsSockets: (bool)supportsSockets +{ + if (_running == OF_THREAD_RUNNING) + @throw [OFThreadStillRunningException + exceptionWithThread: self]; + + _supportsSockets = supportsSockets; +} - (void)dealloc { if (_running == OF_THREAD_RUNNING) @throw [OFThreadStillRunningException Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -51,10 +51,13 @@ #ifdef OF_PSP # include #endif #import "macros.h" +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +# import "tlskey.h" +#endif OF_ASSUME_NONNULL_BEGIN #ifndef OF_WINDOWS typedef int of_socket_t; @@ -125,17 +128,10 @@ } of_socket_address_t; #ifdef __cplusplus extern "C" { #endif -extern bool of_socket_init(void); -extern int of_socket_errno(void); -# if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) -extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr, - socklen_t *restrict addrLen); -# endif - /*! * @brief Parses the specified IP and port into an of_socket_address_t. * * @param IP The IP to parse * @param port The port to use @@ -214,10 +210,27 @@ * @param address The address on which to get the port * @return The port of the address */ extern uint16_t of_socket_address_get_port( const of_socket_address_t *_Nonnull address); + +extern bool of_socket_init(void); +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +extern void of_socket_deinit(void); +#endif +extern int of_socket_errno(void); +#if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) +extern int of_getsockname(of_socket_t sock, struct sockaddr *restrict addr, + socklen_t *restrict addrLen); +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +extern of_tlskey_t of_socket_base_key; +# ifdef OF_AMIGAOS4 +extern of_tlskey_t of_socket_interface_key; +# endif +#endif #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -27,19 +27,24 @@ #import "OFCharacterSet.h" #import "OFLocale.h" #import "OFString.h" #import "OFException.h" /* For some E* -> WSAE* defines */ +#import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" #import "socket.h" #import "socket_helpers.h" #ifdef OF_HAVE_THREADS -# include "mutex.h" +# ifndef OF_AMIGAOS +# import "mutex.h" +# else +# import "tlskey.h" +# endif #endif #include "once.h" #ifdef OF_AMIGAOS # include @@ -48,90 +53,172 @@ #ifdef OF_NINTENDO_3DS # include <3ds/types.h> # include <3ds/services/soc.h> #endif -#ifdef OF_HAVE_THREADS +#if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) static of_mutex_t mutex; #endif -#ifdef OF_AMIGAOS -/* TODO: Support multiple threads */ +#ifndef OF_AMIGAOS +static bool initSuccessful = false; +#else +# ifdef OF_HAVE_THREADS +of_tlskey_t of_socket_base_key; +# ifdef OF_AMIGAOS4 +of_tlskey_t of_socket_interface_key; +# endif +# else struct Library *SocketBase; -# ifdef OF_AMIGAOS4 +# ifdef OF_AMIGAOS4 struct SocketIFace *ISocket = NULL; +# endif +# endif +#endif + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +OF_CONSTRUCTOR() +{ + if (!of_tlskey_new(&of_socket_base_key)) + @throw [OFInitializationFailedException exception]; + +# ifdef OF_AMIGAOS4 + if (!of_tlskey_new(&of_socket_interface_key)) + @throw [OFInitializationFailedException exception]; # endif +} #endif -static bool initSuccessful = false; +#if !defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) static void init(void) { -#if defined(OF_WINDOWS) +# if defined(OF_WINDOWS) WSADATA wsa; if (WSAStartup(MAKEWORD(2, 0), &wsa)) return; -#elif defined(OF_AMIGAOS) +# elif defined(OF_AMIGAOS) if ((SocketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) return; -# ifdef OF_AMIGAOS4 +# ifdef OF_AMIGAOS4 if ((ISocket = (struct SocketIFace *) GetInterface(SocketBase, "main", 1, NULL)) == NULL) { CloseLibrary(SocketBase); return; } -# endif -#elif defined(OF_WII) +# endif +# elif defined(OF_WII) if (net_init() < 0) return; -#elif defined(OF_NINTENDO_3DS) +# elif defined(OF_NINTENDO_3DS) void *ctx; if ((ctx = memalign(0x1000, 0x100000)) == NULL) return; if (socInit(ctx, 0x100000) != 0) return; atexit((void (*)(void))socExit); -#endif +# endif -#ifdef OF_HAVE_THREADS +# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) if (!of_mutex_new(&mutex)) return; -# ifdef OF_WII +# ifdef OF_WII if (!of_spinlock_new(&spinlock)) return; +# endif # endif -#endif initSuccessful = true; } -#ifdef OF_AMIGAOS +# ifdef OF_AMIGAOS OF_DESTRUCTOR() { -# ifdef OF_AMIGAOS4 +# ifdef OF_AMIGAOS4 if (ISocket != NULL) DropInterface((struct Interface *)ISocket); -# endif +# endif if (SocketBase != NULL) CloseLibrary(SocketBase); } +# endif #endif bool -of_socket_init() +of_socket_init(void) { +#if !defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) static of_once_t onceControl = OF_ONCE_INIT; of_once(&onceControl, init); return initSuccessful; +#else + struct Library *socketBase; +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface; +# endif + +# ifdef OF_AMIGAOS4 + if ((socketInterface = of_tlskey_get(of_socket_interface_key)) != NULL) +# else + if ((socketBase = of_tlskey_get(of_socket_base_key)) != NULL) +# endif + return true; + + if ((socketBase = OpenLibrary("bsdsocket.library", 4)) == NULL) + return false; + +# ifdef OF_AMIGAOS4 + if ((socketInterface = (struct SocketIFace *) + GetInterface(socketBase, "main", 1, NULL)) == NULL) { + CloseLibrary(socketBase); + return false; + } +# endif + + if (!of_tlskey_set(of_socket_base_key, socketBase)) { + CloseLibrary(socketBase); +# ifdef OF_AMIGAOS4 + DropInterface((struct Interface *)socketInterface); +# endif + return false; + } + +# ifdef OF_AMIGAOS4 + if (!of_tlskey_set(of_socket_interface_key, socketInterface)) { + CloseLibrary(socketBase); + DropInterface((struct Interface *)socketInterface); + return false; + } +# endif + + return true; +#endif +} + +#if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) +void +of_socket_deinit(void) +{ + struct Library *socketBase = of_tlskey_get(of_socket_base_key); +# ifdef OF_AMIGAOS4 + struct SocketIFace *socketInterface = + of_tlskey_get(of_socket_interface_key); + + if (socketInterface != NULL) + DropInterface((struct Interface *)socketInterface); +# endif + if (socketBase != NULL) + CloseLibrary(socketBase); } +#endif int of_socket_errno() { #if defined(OF_WINDOWS) @@ -237,19 +324,19 @@ of_getsockname(of_socket_t sock, struct sockaddr *restrict addr, socklen_t *restrict addrLen) { int ret; -# ifdef OF_HAVE_THREADS +# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) if (!of_mutex_lock(&mutex)) @throw [OFLockFailedException exception]; # endif ret = getsockname(sock, addr, addrLen); -# ifdef OF_HAVE_THREADS +# if defined(OF_HAVE_THREADS) && !defined(OF_AMIGAOS) if (!of_mutex_unlock(&mutex)) @throw [OFUnlockFailedException exception]; # endif return ret; Index: src/socket_helpers.h ================================================================== --- src/socket_helpers.h +++ src/socket_helpers.h @@ -53,10 +53,17 @@ # include # define closesocket(sock) CloseSocket(sock) # define ioctlsocket(fd, req, arg) IoctlSocket(fd, req, arg) # define hstrerror(err) "unknown (no hstrerror)" # define SOCKET_ERROR -1 +# ifdef OF_HAVE_THREADS +# define SocketBase ((struct Library *)of_tlskey_get(of_socket_base_key)) +# ifdef OF_AMIGAOS4 +# define ISocket \ + ((struct SocketIFace *)of_tlskey_get(of_socket_interface_key)) +# endif +# endif # ifdef OF_MORPHOS typedef uint32_t in_addr_t; # endif #elif !defined(OF_WINDOWS) && !defined(OF_WII) # define closesocket(sock) close(sock) Index: tests/OFHTTPClientTests.m ================================================================== --- tests/OFHTTPClientTests.m +++ tests/OFHTTPClientTests.m @@ -118,10 +118,11 @@ cond = [OFCondition condition]; [cond lock]; server = [[[HTTPClientTestsServer alloc] init] autorelease]; + server.supportsSockets = true; [server start]; [cond wait]; [cond unlock];