Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -146,14 +146,14 @@ thread->_returnValue = [[thread main] retain]; } [thread handleTermination]; - thread->_running = OF_THREAD_WAITING_FOR_JOIN; - objc_autoreleasePoolPop(thread->_pool); [OFAutoreleasePool of_handleThreadTermination]; + + thread->_running = OF_THREAD_WAITING_FOR_JOIN; [thread release]; } #elif defined(OF_HAVE_SOCKETS) static OFDNSResolver *DNSResolver; @@ -331,10 +331,12 @@ OF_ENSURE(thread != nil); thread->_returnValue = [object retain]; longjmp(thread->_exitEnv, 1); + + OF_UNREACHABLE } + (void)setName: (OFString *)name { [OFThread currentThread].name = name; Index: src/mutex_amiga.m ================================================================== --- src/mutex_amiga.m +++ src/mutex_amiga.m @@ -13,11 +13,20 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ +#ifdef OF_AMIGAOS4 +# define __USE_INLINE__ +# define __NOLIBBASE__ +# define __NOGLOBALIFACE__ +#endif #include + +#ifdef OF_AMIGAOS4 +extern struct ExecIFace *IExec; +#endif bool of_mutex_new(of_mutex_t *mutex) { InitSemaphore(mutex); Index: src/thread.h ================================================================== --- src/thread.h +++ src/thread.h @@ -18,11 +18,11 @@ #include "objfw-defs.h" #include "platform.h" #if !defined(OF_HAVE_THREADS) || \ - (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS)) + (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) # error No threads available! #endif #import "macros.h" @@ -30,23 +30,38 @@ # include typedef pthread_t of_thread_t; #elif defined(OF_WINDOWS) # include typedef HANDLE of_thread_t; +#elif defined(OF_AMIGAOS) +# include +# include +typedef struct { + struct Task *task; + void (*function)(id); + id object; + struct SignalSemaphore semaphore; + struct Task *joinTask; + uint8_t joinSigBit; + bool detached, done; +} *of_thread_t; #endif typedef struct of_thread_attr_t { float priority; size_t stackSize; } of_thread_attr_t; #if defined(OF_HAVE_PTHREADS) # define of_thread_is_current(t) pthread_equal(t, pthread_self()) -# define of_thread_current pthread_self +# define of_thread_current() pthread_self() #elif defined(OF_WINDOWS) # define of_thread_is_current(t) (t == GetCurrentThread()) -# define of_thread_current GetCurrentThread +# define of_thread_current() GetCurrentThread() +#elif defined(OF_AMIGAOS) +# define of_thread_is_current(t) (t->thread == FindTask(NULL)) +extern of_thread_t of_thread_current(void); #endif #ifdef __cplusplus extern "C" { #endif Index: src/thread.m ================================================================== --- src/thread.m +++ src/thread.m @@ -21,6 +21,8 @@ #if defined(OF_HAVE_PTHREADS) # include "thread_pthread.m" #elif defined(OF_WINDOWS) # include "thread_winapi.m" +#elif defined(OF_AMIGAOS) +# include "thread_amiga.m" #endif ADDED src/thread_amiga.m Index: src/thread_amiga.m ================================================================== --- src/thread_amiga.m +++ src/thread_amiga.m @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#ifdef OF_AMIGAOS4 +# define __USE_INLINE__ +# define __NOLIBBASE__ +# define __NOGLOBALIFACE__ +#endif +#include +#include +#include + +#import "OFData.h" + +#import "tlskey.h" + +extern void of_tlskey_thread_exited(void); +static of_tlskey_t threadKey; +#ifdef OF_AMIGAOS4 +extern struct ExecIFace *IExec; +static struct Library *DOSBase = NULL; +static struct DOSIFace *IDOS = NULL; + +OF_CONSTRUCTOR() +{ + DOSBase = OpenLibrary("dos.library", 36); + OF_ENSURE(DOSBase != NULL); + + IDOS = (struct DOSIFace *)GetInterface(DOSBase, "main", 1, NULL); + OF_ENSURE(IDOS != NULL); +} + +OF_DESTRUCTOR() +{ + if (IDOS != NULL) + DropInterface((struct Interface *)IDOS); + + if (DOSBase != NULL) + CloseLibrary(DOSBase); +} +#endif + +OF_CONSTRUCTOR() +{ + OF_ENSURE(of_tlskey_new(&threadKey)); +} + +static void +functionWrapper(void) +{ + bool detached = false; + of_thread_t thread = + (of_thread_t)((struct Process *)FindTask(NULL))->pr_ExitData; + OF_ENSURE(of_tlskey_set(threadKey, thread)); + + thread->function(thread->object); + + ObtainSemaphore(&thread->semaphore); + @try { + thread->done = true; + + of_tlskey_thread_exited(); + + if (thread->detached) + detached = true; + else if (thread->joinTask != NULL) + Signal(thread->joinTask, 1 << thread->joinSigBit); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + if (detached) + free(thread); +} + +bool +of_thread_attr_init(of_thread_attr_t *attr) +{ + attr->priority = 0; + attr->stackSize = 0; + + return true; +} + +bool +of_thread_new(of_thread_t *thread, void (*function)(id), id object, + const of_thread_attr_t *attr) +{ + OFMutableData *tags = nil; + + if ((*thread = calloc(1, sizeof(**thread))) == NULL) + return false; + + @try { + (*thread)->function = function; + (*thread)->object = object; + InitSemaphore(&(*thread)->semaphore); + + tags = [[OFMutableData alloc] + initWithItemSize: sizeof(struct TagItem) + capacity: 12]; +#define ADD_TAG(tag, data) \ + { \ + struct TagItem t = { \ + .ti_Tag = tag, \ + .ti_Data = data \ + }; \ + [tags addItem: &t]; \ + } + ADD_TAG(NP_Entry, (ULONG)functionWrapper) + ADD_TAG(NP_ExitData, (ULONG)*thread) +#ifdef OF_AMIGAOS4 + ADD_TAG(NP_Child, TRUE) +#endif +#ifdef OF_MORPHOS + ADD_TAG(NP_CodeType, CODETYPE_PPC); +#endif + + ADD_TAG(NP_Input, ((struct Process *)FindTask(NULL))->pr_CIS) + ADD_TAG(NP_Output, ((struct Process *)FindTask(NULL))->pr_COS) + ADD_TAG(NP_Error, ((struct Process *)FindTask(NULL))->pr_CES) + ADD_TAG(NP_CloseInput, FALSE) + ADD_TAG(NP_CloseOutput, FALSE) + ADD_TAG(NP_CloseError, FALSE) + + if (attr != NULL && attr->priority != 0) { + if (attr->priority < 1 || attr->priority > 1) + return false; + + /* + * -1 should be -128 (lowest possible priority) while + * +1 should be +127 (highest possible priority). + */ + ADD_TAG(NP_Priority, (attr->priority > 0 + ? attr->priority * 127 : attr->priority * 128)) + } + + ADD_TAG(NP_StackSize, (attr != NULL && attr->stackSize != 0 + ? (LONG)attr->stackSize + : ((struct Process *)FindTask(NULL))->pr_StackSize)) + + ADD_TAG(TAG_DONE, 0) +#undef ADD_TAG + + (*thread)->task = (struct Task *)CreateNewProc(tags.items); + if ((*thread)->task == NULL) { + free(*thread); + return false; + } + } @catch (id e) { + free(*thread); + @throw e; + } @finally { + [tags release]; + } + + return true; +} + +of_thread_t +of_thread_current(void) +{ + return of_tlskey_get(threadKey); +} + +bool +of_thread_join(of_thread_t thread) +{ + bool ret; + + ObtainSemaphore(&thread->semaphore); + @try { + if (thread->done) { + free(thread); + return true; + } + + if (thread->detached || thread->joinTask != NULL) + return false; + + if ((thread->joinSigBit = AllocSignal(-1)) == -1) + return false; + + thread->joinTask = FindTask(NULL); + } @finally { + ReleaseSemaphore(&thread->semaphore); + } + + Wait(1 << thread->joinSigBit); + FreeSignal(thread->joinSigBit); + + ret = thread->done; + free(thread); + + return ret; +} + +bool +of_thread_detach(of_thread_t thread) +{ + ObtainSemaphore(&thread->semaphore); + + if (thread->done) + free(thread); + else + thread->detached = true; + + ReleaseSemaphore(&thread->semaphore); + + return true; +} + +void +of_thread_set_name(const char *name) +{ +} Index: src/thread_winapi.m ================================================================== --- src/thread_winapi.m +++ src/thread_winapi.m @@ -13,12 +13,10 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#include "config.h" - #import "macros.h" bool of_thread_attr_init(of_thread_attr_t *attr) { Index: src/tlskey.h ================================================================== --- src/tlskey.h +++ src/tlskey.h @@ -31,14 +31,15 @@ typedef pthread_key_t of_tlskey_t; #elif defined(OF_WINDOWS) # include typedef DWORD of_tlskey_t; #elif defined(OF_AMIGAOS) -# include +# import "OFList.h" @class OFMapTable; typedef struct { OFMapTable *mapTable; + of_list_object_t *listObject; } *of_tlskey_t; #endif #ifdef __cplusplus extern "C" { Index: src/tlskey.m ================================================================== --- src/tlskey.m +++ src/tlskey.m @@ -18,13 +18,32 @@ #include "config.h" #import "tlskey.h" #ifdef OF_AMIGAOS +# ifdef OF_AMIGAOS4 +# define __USE_INLINE__ +# define __NOLIBBASE__ +# define __NOGLOBALIFACE__ +# endif +# include +# include + # import "OFMapTable.h" +# import "OFList.h" +# ifdef OF_AMIGAOS4 +extern struct ExecIFace *IExec; +# endif static const of_map_table_functions_t functions = { NULL }; +static OFList *allKeys = nil; +static struct SignalSemaphore semaphore; + +OF_CONSTRUCTOR() +{ + InitSemaphore(&semaphore); +} #endif bool of_tlskey_new(of_tlskey_t *key) { @@ -31,11 +50,11 @@ #if defined(OF_HAVE_PTHREADS) return (pthread_key_create(key, NULL) == 0); #elif defined(OF_WINDOWS) return ((*key = TlsAlloc()) != TLS_OUT_OF_INDEXES); #elif defined(OF_AMIGAOS) - if ((*key = calloc(1, sizeof(*key))) == NULL) + if ((*key = calloc(1, sizeof(**key))) == NULL) return false; /* * We create the map table lazily, as some TLS are created in * constructors, at which time OFMapTable is not available yet. @@ -51,59 +70,88 @@ #if defined(OF_HAVE_PTHREADS) return (pthread_key_delete(key) == 0); #elif defined(OF_WINDOWS) return TlsFree(key); #elif defined(OF_AMIGAOS) - [key->mapTable release]; - free(key); + ObtainSemaphore(&semaphore); + @try { + [allKeys removeListObject: key->listObject]; + [key->mapTable release]; + free(key); + } @finally { + ReleaseSemaphore(&semaphore); + } return true; #endif } #ifdef OF_AMIGAOS +static void +unsafeCreateMapTable(of_tlskey_t key) +{ + key->mapTable = [[OFMapTable alloc] initWithKeyFunctions: functions + objectFunctions: functions]; + + if (allKeys == nil) + allKeys = [[OFList alloc] init]; + + key->listObject = [allKeys appendObject: key->mapTable]; +} + void * of_tlskey_get(of_tlskey_t key) { void *ret; - Forbid(); + ObtainSemaphore(&semaphore); @try { if (key->mapTable == NULL) - key->mapTable = [[OFMapTable alloc] - initWithKeyFunctions: functions - objectFunctions: functions]; + unsafeCreateMapTable(key); ret = [key->mapTable objectForKey: FindTask(NULL)]; } @finally { - Permit(); + ReleaseSemaphore(&semaphore); } return ret; } bool of_tlskey_set(of_tlskey_t key, void *ptr) { - Forbid(); + ObtainSemaphore(&semaphore); @try { struct Task *task = FindTask(NULL); if (key->mapTable == NULL) - key->mapTable = [[OFMapTable alloc] - initWithKeyFunctions: functions - objectFunctions: functions]; + unsafeCreateMapTable(key); if (ptr == NULL) [key->mapTable removeObjectForKey: task]; else [key->mapTable setObject: ptr forKey: task]; } @catch (id e) { return false; } @finally { - Permit(); + ReleaseSemaphore(&semaphore); } return true; } + +void +of_tlskey_thread_exited(void) +{ + ObtainSemaphore(&semaphore); + @try { + struct Task *task = FindTask(NULL); + + for (of_list_object_t *iter = allKeys.firstListObject; + iter != NULL; iter = iter->next) + [iter->object removeObjectForKey: task]; + } @finally { + ReleaseSemaphore(&semaphore); + } +} #endif