corrections
[AROS.git] / compiler / pthread / pthread.c
blob942b9d0803947253541ee3cb3b008025b0357f3b
1 /*
2 Copyright (C) 2014 Szilard Biro
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
21 #ifdef __MORPHOS__
22 #include <sys/time.h>
23 #endif
24 #include <dos/dostags.h>
25 #include <clib/alib_protos.h>
26 #include <proto/exec.h>
27 #include <proto/dos.h>
28 #include <proto/timer.h>
29 #ifdef __AROS__
30 #include <aros/symbolsets.h>
31 #else
32 #include <constructor.h>
33 #define StackSwapArgs PPCStackSwapArgs
34 #define NewStackSwap NewPPCStackSwap
35 #endif
37 #include <setjmp.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <signal.h>
41 #include <stdlib.h>
43 #include "pthread.h"
44 #include "debug.h"
46 #define FALLBACKSIGNAL SIGBREAKB_CTRL_E
47 #define NAMELEN 32
48 #define PTHREAD_INVALID_ID ((pthread_t)-1)
50 typedef struct
52 struct MinNode node;
53 struct Task *task;
54 ULONG sigmask;
55 } CondWaiter;
57 typedef struct
59 void *value;
60 void (*destructor)(void *);
61 BOOL used;
62 } TLSKey;
64 typedef struct
66 struct MinNode node;
67 void (*routine)(void *);
68 void *arg;
69 } CleanupHandler;
72 typedef struct
74 void *(*start)(void *);
75 void *arg;
76 struct MsgPort *msgport;
77 struct Message msg;
78 struct Process *process;
79 //pthread_t id;
80 void *ret;
81 jmp_buf jmp;
82 pthread_attr_t attr;
83 //char name[256];
84 //size_t oldlen;
85 TLSKey tls[PTHREAD_KEYS_MAX];
86 struct MinList cleanup;
87 } ThreadInfo;
89 #define PTHREAD_FIRST_THREAD_ID (1) /* First thread id will be 1 so that it is different than default value of pthread_t */
91 static ThreadInfo threads[PTHREAD_THREADS_MAX];
92 //static volatile pthread_t nextid = 0;
93 static struct SignalSemaphore thread_sem;
96 // Helper functions
99 static int SemaphoreIsInvalid(struct SignalSemaphore *sem)
101 return (!sem || sem->ss_Link.ln_Type != NT_SIGNALSEM || sem->ss_WaitQueue.mlh_Tail != NULL);
104 static ThreadInfo *GetThreadInfo(pthread_t thread)
106 ThreadInfo *inf = NULL;
108 //if (thread < nextid)
109 // TODO: more robust error handling?
110 if (thread < PTHREAD_THREADS_MAX)
111 inf = &threads[thread];
113 return inf;
116 static pthread_t GetThreadId(struct Task *task)
118 pthread_t i;
120 ObtainSemaphore(&thread_sem);
122 for (i = PTHREAD_FIRST_THREAD_ID; i < PTHREAD_THREADS_MAX; i++)
124 if ((struct Task *)threads[i].process == task)
125 break;
128 ReleaseSemaphore(&thread_sem);
130 if (i >= PTHREAD_THREADS_MAX)
131 i = PTHREAD_INVALID_ID;
133 return i;
137 // Thread specific data functions
140 int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
142 pthread_t thread;
143 ThreadInfo *inf;
144 TLSKey *tls;
145 int i;
147 D(bug("%s(%p, %p)\n", __FUNCTION__, key, destructor));
149 if (key == NULL)
150 return EINVAL;
152 thread = pthread_self();
153 inf = GetThreadInfo(thread);
155 for (i = 0; i < PTHREAD_KEYS_MAX; i++)
157 if (inf->tls[i].used == FALSE)
158 break;
161 if (i >= PTHREAD_KEYS_MAX)
162 return EAGAIN;
164 tls = &inf->tls[i];
165 tls->used = TRUE;
166 tls->destructor = destructor;
168 *key = i;
170 return 0;
173 int pthread_key_delete(pthread_key_t key)
175 pthread_t thread;
176 ThreadInfo *inf;
177 TLSKey *tls;
179 D(bug("%s(%u)\n", __FUNCTION__, key));
181 thread = pthread_self();
182 inf = GetThreadInfo(thread);
183 tls = &inf->tls[key];
185 if (tls->used == FALSE)
186 return EINVAL;
188 if (tls->destructor)
189 tls->destructor(tls->value);
191 tls->used = FALSE;
192 tls->destructor = NULL;
194 return 0;
197 int pthread_setspecific(pthread_key_t key, const void *value)
199 pthread_t thread;
200 ThreadInfo *inf;
201 TLSKey *tls;
203 D(bug("%s(%u)\n", __FUNCTION__, key));
205 thread = pthread_self();
206 inf = GetThreadInfo(thread);
207 tls = &inf->tls[key];
209 if (tls->used == FALSE)
210 return EINVAL;
212 tls->value = (void *)value;
214 return 0;
217 void *pthread_getspecific(pthread_key_t key)
219 pthread_t thread;
220 ThreadInfo *inf;
221 TLSKey *tls;
222 void *value = NULL;
224 D(bug("%s(%u)\n", __FUNCTION__, key));
226 thread = pthread_self();
227 inf = GetThreadInfo(thread);
228 tls = &inf->tls[key];
230 if (tls->used == TRUE)
231 value = tls->value;
233 return value;
237 // Mutex attribute functions
240 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
242 D(bug("%s(%p)\n", __FUNCTION__, attr));
244 if (attr == NULL)
245 return EINVAL;
247 memset(attr, 0, sizeof(pthread_mutexattr_t));
249 return 0;
252 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
254 D(bug("%s(%p)\n", __FUNCTION__, attr));
256 if (attr == NULL)
257 return EINVAL;
259 attr->kind = kind;
261 return 0;
265 // Mutex functions
268 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
270 D(bug("%s(%p, %p)\n", __FUNCTION__, mutex, attr));
272 if (mutex == NULL)
273 return EINVAL;
275 InitSemaphore(&mutex->semaphore);
277 return 0;
280 int pthread_mutex_destroy(pthread_mutex_t *mutex)
282 //D(bug("%s(%p)\n", __FUNCTION__, mutex));
284 if (mutex == NULL)
285 return EINVAL;
287 memset(mutex, 0, sizeof(pthread_mutex_t));
289 return 0;
292 int pthread_mutex_lock(pthread_mutex_t *mutex)
294 //D(bug("%s(%p)\n", __FUNCTION__, mutex));
296 if (mutex == NULL)
297 return EINVAL;
299 // initialize static mutexes
300 if (SemaphoreIsInvalid(&mutex->semaphore))
301 pthread_mutex_init(mutex, NULL);
303 ObtainSemaphore(&mutex->semaphore);
305 return 0;
308 int pthread_mutex_trylock(pthread_mutex_t *mutex)
310 ULONG ret;
312 //D(bug("%s(%p)\n", __FUNCTION__, mutex));
314 if (mutex == NULL)
315 return EINVAL;
317 // initialize static mutexes
318 if (SemaphoreIsInvalid(&mutex->semaphore))
319 pthread_mutex_init(mutex, NULL);
321 ret = AttemptSemaphore(&mutex->semaphore);
323 return (ret == TRUE) ? 0 : EBUSY;
326 int pthread_mutex_unlock(pthread_mutex_t *mutex)
328 //D(bug("%s(%p)\n", __FUNCTION__, mutex));
330 if (mutex == NULL)
331 return EINVAL;
333 // initialize static mutexes
334 if (SemaphoreIsInvalid(&mutex->semaphore))
335 pthread_mutex_init(mutex, NULL);
337 ReleaseSemaphore(&mutex->semaphore);
339 return 0;
343 // Condition variable functions
346 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
348 D(bug("%s(%p, %p)\n", __FUNCTION__, cond, attr));
350 if (cond == NULL)
351 return EINVAL;
353 InitSemaphore(&cond->semaphore);
354 NewList((struct List *)&cond->waiters);
355 cond->waiting = 0;
357 return 0;
360 int pthread_cond_destroy(pthread_cond_t *cond)
362 D(bug("%s(%p)\n", __FUNCTION__, cond));
364 if (cond == NULL)
365 return EINVAL;
367 if (cond->waiting > 0)
368 return EBUSY;
370 memset(cond, 0, sizeof(pthread_cond_t));
372 return 0;
375 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
377 CondWaiter waiter;
378 BYTE signal;
379 ULONG sigs = 0;
380 ULONG timermask = 0;
381 struct MsgPort *timermp = NULL;
382 struct timerequest *timerio = NULL;
383 struct Device *TimerBase = NULL;
385 //D(bug("%s(%p, %p, %p)\n", __FUNCTION__, cond, mutex, abstime));
387 if (cond == NULL || mutex == NULL)
388 return EINVAL;
390 // initialize static conditions
391 if (SemaphoreIsInvalid(&cond->semaphore))
392 pthread_cond_init(cond, NULL);
394 if (abstime)
396 if (!(timermp = CreateMsgPort()))
397 return EINVAL;
399 if (!(timerio = (struct timerequest *)CreateIORequest(timermp, sizeof(struct timerequest))))
401 DeleteMsgPort(timermp);
402 return EINVAL;
405 if (OpenDevice(TIMERNAME, UNIT_MICROHZ, &timerio->tr_node, 0) != 0)
407 DeleteMsgPort(timermp);
408 DeleteIORequest((struct IORequest *)timerio);
409 return EINVAL;
412 TimerBase = timerio->tr_node.io_Device;
415 if (TimerBase)
417 struct timeval starttime;
419 gettimeofday(&starttime, NULL);
420 timerio->tr_node.io_Command = TR_ADDREQUEST;
421 timerio->tr_time.tv_secs = abstime->tv_sec;
422 timerio->tr_time.tv_micro = abstime->tv_nsec / 1000;
423 SubTime(&timerio->tr_time, &starttime);
424 timermask = 1 << timermp->mp_SigBit;
425 sigs |= timermask;
426 SendIO((struct IORequest *)timerio);
429 waiter.task = FindTask(NULL);
430 signal = AllocSignal(-1);
431 if (signal == -1)
433 signal = FALLBACKSIGNAL;
434 SetSignal(1 << FALLBACKSIGNAL, 0);
436 waiter.sigmask = 1 << signal;
437 sigs |= waiter.sigmask;
438 ObtainSemaphore(&cond->semaphore);
439 AddTail((struct List *)&cond->waiters, (struct Node *)&waiter);
440 cond->waiting++;
441 ReleaseSemaphore(&cond->semaphore);
443 pthread_mutex_unlock(mutex);
444 sigs = Wait(sigs);
445 pthread_mutex_lock(mutex);
447 ObtainSemaphore(&cond->semaphore);
448 Remove((struct Node *)&waiter);
449 cond->waiting--;
450 ReleaseSemaphore(&cond->semaphore);
452 if (signal != FALLBACKSIGNAL)
453 FreeSignal(signal);
455 if (TimerBase)
457 if (!CheckIO((struct IORequest *)timerio))
459 AbortIO((struct IORequest *)timerio);
460 WaitIO((struct IORequest *)timerio);
462 CloseDevice((struct IORequest *)timerio);
463 DeleteIORequest((struct IORequest *)timerio);
464 DeleteMsgPort(timermp);
466 if (sigs & timermask)
467 return ETIMEDOUT;
470 return 0;
473 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
475 //D(bug("%s(%p)\n", __FUNCTION__, cond));
477 return pthread_cond_timedwait(cond, mutex, NULL);
480 static int _pthread_cond_broadcast(pthread_cond_t *cond, BOOL onlyfirst)
482 CondWaiter *waiter;
484 //D(bug("%s(%p, %d)\n", __FUNCTION__, cond, onlyfirst));
486 if (cond == NULL)
487 return EINVAL;
489 // initialize static conditions
490 if (SemaphoreIsInvalid(&cond->semaphore))
491 pthread_cond_init(cond, NULL);
493 ObtainSemaphore(&cond->semaphore);
494 if (cond->waiting > 0)
496 ForeachNode(&cond->waiters, waiter)
498 Signal(waiter->task, waiter->sigmask);
499 if (onlyfirst) break;
502 ReleaseSemaphore(&cond->semaphore);
504 return 0;
507 int pthread_cond_signal(pthread_cond_t *cond)
509 //D(bug("%s(%p)\n", __FUNCTION__, cond));
511 return _pthread_cond_broadcast(cond, TRUE);
514 int pthread_cond_broadcast(pthread_cond_t *cond)
516 //D(bug("%s(%p)\n", __FUNCTION__, cond));
518 return _pthread_cond_broadcast(cond, FALSE);
522 // Thread attribute functions
525 int pthread_attr_init(pthread_attr_t *attr)
527 struct Task *task = FindTask(NULL);
529 D(bug("%s(%p)\n", __FUNCTION__, attr));
531 if (attr == NULL)
532 return EINVAL;
534 memset(attr, 0, sizeof(pthread_attr_t));
535 // inherit the priority and stack size of the parent thread
536 attr->param.sched_priority = task->tc_Node.ln_Pri;
537 attr->stacksize = (UBYTE *)task->tc_SPUpper - (UBYTE *)task->tc_SPLower;
539 return 0;
542 int pthread_attr_destroy(pthread_attr_t *attr)
544 D(bug("%s(%p)\n", __FUNCTION__, attr));
546 if (attr == NULL)
547 return EINVAL;
549 memset(attr, 0, sizeof(pthread_attr_t));
551 return 0;
554 int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize)
556 D(bug("%s(%p, %p)\n", __FUNCTION__, attr, stackaddr));
558 if (attr == NULL)
559 return EINVAL;
561 if (stackaddr != NULL)
562 *stackaddr = attr->stackaddr;
564 if (stacksize != NULL)
565 *stacksize = attr->stacksize;
567 return 0;
570 int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize)
572 D(bug("%s(%p, %p)\n", __FUNCTION__, attr, stackaddr));
574 if (attr == NULL || (stackaddr != NULL && stacksize == 0))
575 return EINVAL;
577 attr->stackaddr = stackaddr;
578 attr->stacksize = stacksize;
580 return 0;
583 int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
585 D(bug("%s(%p, %p)\n", __FUNCTION__, attr, stacksize));
587 return pthread_attr_getstack(attr, NULL, stacksize);
590 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
592 D(bug("%s(%p, %u)\n", __FUNCTION__, attr, stacksize));
594 return pthread_attr_setstack(attr, NULL, stacksize);
597 int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
599 D(bug("%s(%p, %p)\n", __FUNCTION__, attr, param));
601 if (attr == NULL || param == NULL)
602 return EINVAL;
604 *param = attr->param;
606 return 0;
609 int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
611 D(bug("%s(%p, %p)\n", __FUNCTION__, attr, param));
613 if (attr == NULL || param == NULL)
614 return EINVAL;
616 attr->param = *param;
618 return 0;
622 // Thread functions
625 static void StarterFunc(void)
627 ThreadInfo *inf;
629 D(bug("%s()\n", __FUNCTION__));
631 inf = (ThreadInfo *)FindTask(NULL)->tc_UserData;
632 // trim the name
633 //inf->process->pr_Task.tc_Node.ln_Name[inf->oldlen];
635 // we have to set the priority here to avoid race conditions
636 SetTaskPri((struct Task *)inf->process, inf->attr.param.sched_priority);
638 if (!setjmp(inf->jmp))
640 if (inf->attr.stackaddr != NULL && inf->attr.stacksize > 0)
642 struct StackSwapArgs swapargs;
643 struct StackSwapStruct stack;
645 swapargs.Args[0] = (IPTR)inf->arg;
646 stack.stk_Lower = inf->attr.stackaddr;
647 stack.stk_Upper = (APTR)((IPTR)stack.stk_Lower + inf->attr.stacksize);
648 stack.stk_Pointer = stack.stk_Upper;
650 inf->ret = (void *)NewStackSwap(&stack, inf->start, &swapargs);
652 else
654 inf->ret = inf->start(inf->arg);
658 Forbid();
659 ReplyMsg(&inf->msg);
662 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start)(void *), void *arg)
664 ThreadInfo *inf;
665 char buf[NAMELEN];
666 char name[NAMELEN];
667 size_t oldlen;
668 pthread_t threadnew;
670 D(bug("%s(%p, %p, %p, %p)\n", __FUNCTION__, thread, attr, start, arg));
672 if (thread == NULL || start == NULL)
673 return EINVAL;
675 ObtainSemaphore(&thread_sem);
677 //threadnew = nextid++; //__sync_add_and_fetch(&nextid, 1);
678 threadnew = GetThreadId(NULL);
679 if (threadnew == PTHREAD_INVALID_ID)
681 ReleaseSemaphore(&thread_sem);
682 return EAGAIN;
685 inf = GetThreadInfo(threadnew);
686 memset(inf, 0, sizeof(ThreadInfo));
687 inf->start = start;
688 if (attr)
689 inf->attr = *attr;
690 else
691 pthread_attr_init(&inf->attr);
692 inf->arg = arg;
693 NewList((struct List *)&inf->cleanup);
695 // let's trick CreateNewProc into allocating a larger buffer for the name
696 snprintf(buf, sizeof(buf), "pthread thread #%d", threadnew);
697 oldlen = strlen(buf);
698 memset(name, ' ', sizeof(name));
699 memcpy(name, buf, oldlen);
700 name[sizeof(name) - 1] = '\0';
702 inf->msgport = CreateMsgPort();
703 if (!inf->msgport)
705 ReleaseSemaphore(&thread_sem);
706 return EAGAIN;
709 inf->msg.mn_Node.ln_Type = NT_MESSAGE;
710 inf->msg.mn_ReplyPort = inf->msgport;
711 inf->msg.mn_Length = sizeof(inf->msg);
713 inf->process = CreateNewProcTags(NP_Entry, StarterFunc,
714 #ifdef __MORPHOS__
715 NP_CodeType, CODETYPE_PPC,
716 (inf->attr.stackaddr == NULL && inf->attr.stacksize > 0) ? NP_PPCStackSize : TAG_IGNORE, inf->attr.stacksize,
717 #else
718 (inf->attr.stackaddr == NULL && inf->attr.stacksize > 0) ? NP_StackSize : TAG_IGNORE, inf->attr.stacksize,
719 #endif
720 NP_UserData, inf,
721 NP_Name, name,
722 TAG_DONE);
724 ReleaseSemaphore(&thread_sem);
726 if (!inf->process)
728 DeleteMsgPort(inf->msgport);
729 inf->msgport = NULL;
730 return EAGAIN;
733 *thread = threadnew;
735 return 0;
738 int pthread_detach(pthread_t thread)
740 D(bug("%s(%u) not implemented\n", __FUNCTION__, thread));
742 return ESRCH;
745 int pthread_join(pthread_t thread, void **value_ptr)
747 ThreadInfo *inf;
749 D(bug("%s(%u, %p)\n", __FUNCTION__, thread, value_ptr));
751 inf = GetThreadInfo(thread);
753 if (!inf->msgport)
754 return ESRCH;
756 //while (!GetMsg(inf->msgport))
757 WaitPort(inf->msgport);
759 DeleteMsgPort(inf->msgport);
760 //inf->msgport = NULL;
762 if (value_ptr)
763 *value_ptr = inf->ret;
765 ObtainSemaphore(&thread_sem);
766 memset(inf, 0, sizeof(ThreadInfo));
767 ReleaseSemaphore(&thread_sem);
769 return 0;
772 int pthread_equal(pthread_t t1, pthread_t t2)
774 D(bug("%s(%u, %u)\n", __FUNCTION__, t1, t2));
776 return (t1 == t2);
779 pthread_t pthread_self(void)
781 struct Task *task;
782 pthread_t thread;
784 D(bug("%s()\n", __FUNCTION__));
786 task = FindTask(NULL);
787 thread = GetThreadId(task);
789 // add non-pthread processes to our list, so we can handle the main thread
790 if (thread == PTHREAD_INVALID_ID)
792 ThreadInfo *inf;
794 ObtainSemaphore(&thread_sem);
795 thread = GetThreadId(NULL);
796 //thread = nextid++; //__sync_add_and_fetch(&nextid, 1);
797 inf = GetThreadInfo(thread);
798 memset(inf, 0, sizeof(ThreadInfo));
799 NewList((struct List *)&inf->cleanup);
800 inf->process = (struct Process *)task;
801 ReleaseSemaphore(&thread_sem);
804 return thread;
807 int pthread_cancel(pthread_t thread)
809 D(bug("%s(%u) not implemented\n", __FUNCTION__, thread));
811 // TODO: should I do a pthread_join here?
812 return ESRCH;
815 void pthread_exit(void *value_ptr)
817 ThreadInfo *inf;
818 CleanupHandler *handler;
820 D(bug("%s(%p)\n", __FUNCTION__, value_ptr));
822 inf = GetThreadInfo(pthread_self());
823 inf->ret = value_ptr;
825 while ((handler = (CleanupHandler *)RemTail((struct List *)&inf->cleanup)))
826 if (handler->routine)
827 handler->routine(handler->arg);
829 longjmp(inf->jmp, 1);
832 #if defined __mc68000__
833 /* No CAS instruction on m68k */
834 static int __m68k_sync_val_compare_and_swap(int *v, int o, int n)
836 int ret;
838 Disable();
839 if ((*v) == (o))
840 (*v) = (n);
841 ret = (*v);
842 Enable();
844 return ret;
846 #undef __sync_val_compare_and_swap
847 #define __sync_val_compare_and_swap(v, o, n) __m68k_sync_val_compare_and_swap(v, o, n)
848 #endif
850 int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
852 if (once_control == NULL || init_routine == NULL)
853 return EINVAL;
855 if (__sync_val_compare_and_swap(&once_control->started, FALSE, TRUE))
857 if (!once_control->done)
859 (*init_routine)();
860 once_control->done = TRUE;
864 return 0;
868 // Scheduling functions
871 int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
873 ThreadInfo *inf;
875 D(bug("%s(%u, %d, %p)\n", __FUNCTION__, thread, policy, param));
877 if (param == NULL)
878 return EINVAL;
880 inf = GetThreadInfo(thread);
881 SetTaskPri((struct Task *)inf->process, param->sched_priority);
883 return 0;
887 // NP
889 int pthread_setname_np(pthread_t thread, const char *name)
891 ThreadInfo *inf;
892 char *currentName;
894 D(bug("%s(%u, %s)\n", __FUNCTION__, thread, name));
896 if (name == NULL)
897 return ERANGE;
899 inf = GetThreadInfo(thread);
900 currentName = inf->process->pr_Task.tc_Node.ln_Name;
902 if (strlen(name) + 1 > NAMELEN)
903 return ERANGE;
905 strncpy(currentName, name, NAMELEN);
907 return 0;
910 int pthread_getname_np(pthread_t thread, char *name, size_t len)
912 ThreadInfo *inf;
913 char *currentName;
915 D(bug("%s(%u, %p, %u)\n", __FUNCTION__, thread, name, len));
917 if (name == NULL || len == 0)
918 return ERANGE;
920 inf = GetThreadInfo(thread);
921 currentName = inf->process->pr_Task.tc_Node.ln_Name;
923 if (strlen(currentName) + 1 > len)
924 return ERANGE;
925 // TODO: partially copy the name?
926 strncpy(name, currentName, len);
928 return 0;
932 // Cancellation cleanup
935 // theads can't be cancelled, but they can still call pthread_exit, which
936 // will execute these clean-up handlers
937 void pthread_cleanup_push(void (*routine)(void *), void *arg)
939 pthread_t thread;
940 ThreadInfo *inf;
941 CleanupHandler *handler;
943 D(bug("%s(%p, %p)\n", __FUNCTION__, routine, arg));
945 handler = calloc(1, sizeof(CleanupHandler));
947 if (routine == NULL || handler == NULL)
948 return;
950 thread = pthread_self();
951 inf = GetThreadInfo(thread);
953 AddTail((struct List *)&inf->cleanup, (struct Node *)handler);
956 void pthread_cleanup_pop(int execute)
958 pthread_t thread;
959 ThreadInfo *inf;
960 CleanupHandler *handler;
962 D(bug("%s(%d)\n", __FUNCTION__, execute));
964 thread = pthread_self();
965 inf = GetThreadInfo(thread);
966 handler = (CleanupHandler *)RemTail((struct List *)&inf->cleanup);
968 if (handler && handler->routine && execute)
969 handler->routine(handler->arg);
971 free(handler);
975 // Signalling
978 int pthread_kill(pthread_t thread, int sig)
981 ThreadInfo *inf;
982 struct ETask *et;
984 D(bug("%s(%u, %d)\n", __FUNCTION__, thread, sig));
986 #ifdef __AROS__
987 inf = GetThreadInfo(thread);
988 et = GetETask((struct Task *)inf->process);
990 if (et == NULL)
991 return EINVAL;
993 return kill((pid_t)et->et_UniqueID, sig);
994 #else
995 return EINVAL;
996 #endif
1000 // Constructors, destructors
1003 static int _Init_Func(void)
1005 D(bug("%s()\n", __FUNCTION__));
1007 memset(&threads, 0, sizeof(threads));
1008 InitSemaphore(&thread_sem);
1010 return TRUE;
1013 static void _Exit_Func(void)
1015 #if 0
1016 pthread_t i;
1017 #endif
1019 D(bug("%s()\n", __FUNCTION__));
1021 // wait for the threads?
1022 #if 0
1023 for (i = 0; i < PTHREAD_THREADS_MAX; i++)
1024 pthread_join(i, NULL);
1025 #endif
1028 #ifdef __AROS__
1029 ADD2INIT(_Init_Func, 0);
1030 ADD2EXIT(_Exit_Func, 0);
1031 #else
1032 static CONSTRUCTOR_P(_Init_Func, 100)
1034 return !_Init_Func();
1037 static DESTRUCTOR_P(_Exit_Func, 100)
1039 _Exit_Func();
1041 #endif