Index: ossp-pkg/pth/pth_lib.c RCS File: /v/ossp/cvs/ossp-pkg/pth/pth_lib.c,v co -q -kk -p'1.45' '/v/ossp/cvs/ossp-pkg/pth/pth_lib.c,v' | diff -u /dev/null - -L'ossp-pkg/pth/pth_lib.c' 2>/dev/null --- ossp-pkg/pth/pth_lib.c +++ - 2024-05-17 13:52:51.126997651 +0200 @@ -0,0 +1,572 @@ +/* +** GNU Pth - The GNU Portable Threads +** Copyright (c) 1999-2000 Ralf S. Engelschall +** +** This file is part of GNU Pth, a non-preemptive thread scheduling +** library which can be found at http://www.gnu.org/software/pth/. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this library; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +** USA, or contact Ralf S. Engelschall . +** +** pth_lib.c: Pth main library code +*/ + /* ``It took me fifteen years to discover + I had no talent for programming, but + I couldn't give it up because by that + time I was too famous.'' + -- Unknown */ +#include "pth_p.h" + +/* return the hexadecimal Pth library version number */ +long pth_version(void) +{ + return PTH_VERSION; +} + +/* implicit initialization support */ +intern int pth_initialized = FALSE; +#if cpp +#define pth_implicit_init() \ + if (!pth_initialized) \ + pth_init(); +#endif + +/* initialize the package */ +int pth_init(void) +{ + pth_attr_t t_attr; + + /* support for implicit initialization calls + and to prevent multiple explict initialization, too */ + if (pth_initialized) + return_errno(FALSE, EPERM); + else + pth_initialized = TRUE; + + pth_debug1("pth_init: enter"); + + /* initialize the scheduler */ + pth_scheduler_init(); + + /* spawn the scheduler thread */ + t_attr = pth_attr_new(); + pth_attr_set(t_attr, PTH_ATTR_PRIO, PTH_PRIO_MAX); + pth_attr_set(t_attr, PTH_ATTR_NAME, "**SCHEDULER**"); + pth_attr_set(t_attr, PTH_ATTR_JOINABLE, FALSE); + pth_attr_set(t_attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_DISABLE); + pth_attr_set(t_attr, PTH_ATTR_STACK_SIZE, 64*1024); + pth_attr_set(t_attr, PTH_ATTR_STACK_ADDR, NULL); + pth_sched = pth_spawn(t_attr, pth_scheduler, NULL); + if (pth_sched == NULL) { + errno_shield { + pth_attr_destroy(t_attr); + pth_scheduler_kill(); + } + return FALSE; + } + + /* spawn a thread for the main program */ + pth_attr_set(t_attr, PTH_ATTR_PRIO, PTH_PRIO_STD); + pth_attr_set(t_attr, PTH_ATTR_NAME, "main"); + pth_attr_set(t_attr, PTH_ATTR_JOINABLE, TRUE); + pth_attr_set(t_attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ENABLE|PTH_CANCEL_DEFERRED); + pth_attr_set(t_attr, PTH_ATTR_STACK_SIZE, 0 /* special */); + pth_attr_set(t_attr, PTH_ATTR_STACK_ADDR, NULL); + pth_main = pth_spawn(t_attr, (void *(*)(void *))(-1), NULL); + if (pth_main == NULL) { + errno_shield { + pth_attr_destroy(t_attr); + pth_scheduler_kill(); + } + return FALSE; + } + pth_attr_destroy(t_attr); + + /* + * The first time we've to manually switch into the scheduler to start + * threading. Because at this time the only non-scheduler thread is the + * "main thread" we will come back immediately. We've to also initialize + * the pth_current variable here to allow the pth_spawn_trampoline + * function to find the scheduler. + */ + pth_current = pth_sched; + pth_mctx_switch(&pth_main->mctx, &pth_sched->mctx); + + /* came back, so let's go home... */ + pth_debug1("pth_init: leave"); + return TRUE; +} + +/* kill the package internals */ +int pth_kill(void) +{ + if (pth_current != pth_main) + return_errno(FALSE, EPERM); + pth_debug1("pth_kill: enter"); + pth_thread_cleanup(pth_main); + pth_scheduler_kill(); + pth_initialized = FALSE; + pth_tcb_free(pth_sched); + pth_tcb_free(pth_main); + pth_debug1("pth_kill: leave"); + return TRUE; +} + +/* scheduler control/query */ +long pth_ctrl(unsigned long query, ...) +{ + long rc; + va_list ap; + + rc = 0; + va_start(ap, query); + if (query & PTH_CTRL_GETTHREADS) { + if (query & PTH_CTRL_GETTHREADS_NEW) + rc += pth_pqueue_elements(&pth_NQ); + if (query & PTH_CTRL_GETTHREADS_READY) + rc += pth_pqueue_elements(&pth_RQ); + if (query & PTH_CTRL_GETTHREADS_RUNNING) + rc += 1; /* pth_current only */ + if (query & PTH_CTRL_GETTHREADS_WAITING) + rc += pth_pqueue_elements(&pth_WQ); + if (query & PTH_CTRL_GETTHREADS_SUSPENDED) + rc += pth_pqueue_elements(&pth_SQ); + if (query & PTH_CTRL_GETTHREADS_DEAD) + rc += pth_pqueue_elements(&pth_DQ); + } + else if (query & PTH_CTRL_GETAVLOAD) { + float *pload = va_arg(ap, float *); + *pload = pth_loadval; + } + else if (query & PTH_CTRL_GETPRIO) { + pth_t t = va_arg(ap, pth_t); + rc = t->prio; + } + else if (query & PTH_CTRL_GETNAME) { + pth_t t = va_arg(ap, pth_t); + rc = (long)t->name; + } + else if (query & PTH_CTRL_DUMPSTATE) { + FILE *fp = va_arg(ap, FILE *); + pth_dumpstate(fp); + } + else + rc = -1; + va_end(ap); + if (rc == -1) + return_errno(-1, EINVAL); + return rc; +} + +/* create a new thread of execution by spawning a cooperative thread */ +static void pth_spawn_trampoline(void) +{ + void *data; + + /* just jump into the start routine */ + data = (*pth_current->start_func)(pth_current->start_arg); + /* and do an implicit exit of the tread with the result value */ + pth_exit(data); + /* no return! */ + abort(); +} +pth_t pth_spawn(pth_attr_t attr, void *(*func)(void *), void *arg) +{ + pth_t t; + unsigned int stacksize; + void *stackaddr; + pth_time_t ts; + + pth_debug1("pth_spawn: enter"); + + /* consistency */ + if (func == NULL) + return_errno(NULL, EINVAL); + + /* support the special case of main() */ + if (func == (void *(*)(void *))(-1)) + func = NULL; + + /* allocate a new thread control block */ + stacksize = (attr == PTH_ATTR_DEFAULT ? 64*1024 : attr->a_stacksize); + stackaddr = (attr == PTH_ATTR_DEFAULT ? NULL : attr->a_stackaddr); + if ((t = pth_tcb_alloc(stacksize, stackaddr)) == NULL) + return NULL; /* errno is inherited */ + + /* configure remaining attributes */ + if (attr != PTH_ATTR_DEFAULT) { + /* overtake fields from the attribute structure */ + t->prio = attr->a_prio; + t->joinable = attr->a_joinable; + t->cancelstate = attr->a_cancelstate; + pth_util_cpystrn(t->name, attr->a_name, PTH_TCB_NAMELEN); + } + else if (pth_current != NULL) { + /* overtake some fields from the parent thread */ + t->prio = pth_current->prio; + t->joinable = pth_current->joinable; + t->cancelstate = pth_current->cancelstate; + pth_snprintf(t->name, PTH_TCB_NAMELEN, "%s.child@%d=0x%lx", + pth_current->name, (unsigned int)time(NULL), + (unsigned long)pth_current); + } + else { + /* defaults */ + t->prio = PTH_PRIO_STD; + t->joinable = TRUE; + t->cancelstate = PTH_CANCEL_DEFAULT; + pth_snprintf(t->name, PTH_TCB_NAMELEN, + "user/%x", (unsigned int)time(NULL)); + } + + /* initialize the time points and ranges */ + pth_time_set(&ts, PTH_TIME_NOW); + pth_time_set(&t->spawned, &ts); + pth_time_set(&t->lastran, &ts); + pth_time_set(&t->running, PTH_TIME_ZERO); + + /* initialize events */ + t->events = NULL; + + /* clear raised signals */ + sigemptyset(&t->sigpending); + t->sigpendcnt = 0; + + /* remember the start routine and arguments for our trampoline */ + t->start_func = func; + t->start_arg = arg; + + /* initialize join argument */ + t->join_arg = NULL; + + /* initialize thread specific storage */ + t->data_value = NULL; + t->data_count = 0; + + /* initialize cancellaton stuff */ + t->cancelreq = FALSE; + t->cleanups = NULL; + + /* initialize mutex stuff */ + pth_ring_init(&t->mutexring); + + /* initialize the machine context of this new thread */ + if (t->stacksize > 0) { /* the "main thread" (indicated by == 0) is special! */ + if (!pth_mctx_set(&t->mctx, pth_spawn_trampoline, + t->stack, ((char *)t->stack+t->stacksize))) { + errno_shield { pth_tcb_free(t); } + return NULL; + } + } + + /* finally insert it into the "new queue" where + the scheduler will pick it up for dispatching */ + if (func != pth_scheduler) { + t->state = PTH_STATE_NEW; + pth_pqueue_insert(&pth_NQ, t->prio, t); + } + + pth_debug1("pth_spawn: leave"); + + /* the returned thread id is just the pointer + to the thread control block... */ + return t; +} + +/* returns the current thread */ +pth_t pth_self(void) +{ + return pth_current; +} + +/* raise a signal for a thread */ +int pth_raise(pth_t t, int sig) +{ + struct sigaction sa; + + if (t == NULL || t == pth_current || (sig < 0 || sig > PTH_NSIG)) + return_errno(FALSE, EINVAL); + if (sig == 0) + /* just test whether thread exists */ + return pth_thread_exists(t); + else { + /* raise signal for thread */ + if (sigaction(sig, NULL, &sa) != 0) + return FALSE; + if (sa.sa_handler == SIG_IGN) + return TRUE; /* fine, nothing to do, sig is globally ignored */ + if (!sigismember(&t->sigpending, sig)) { + sigaddset(&t->sigpending, sig); + t->sigpendcnt++; + } + pth_yield(t); + return TRUE; + } +} + +/* check whether a thread exists */ +intern int pth_thread_exists(pth_t t) +{ + if (!pth_pqueue_contains(&pth_NQ, t)) + if (!pth_pqueue_contains(&pth_RQ, t)) + if (!pth_pqueue_contains(&pth_WQ, t)) + if (!pth_pqueue_contains(&pth_SQ, t)) + if (!pth_pqueue_contains(&pth_DQ, t)) + return_errno(FALSE, ESRCH); /* not found */ + return TRUE; +} + +/* cleanup a particular thread */ +intern void pth_thread_cleanup(pth_t thread) +{ + /* run the cleanup handlers */ + if (thread->cleanups != NULL) + pth_cleanup_popall(thread, TRUE); + + /* run the specific data destructors */ + if (thread->data_value != NULL) + pth_key_destroydata(thread); + + /* release still acquired mutex variables */ + pth_mutex_releaseall(thread); + + return; +} + +/* terminates the current thread */ +static int pth_exit_cb(void *arg) +{ + int rc; + + /* NOTICE: THIS FUNCTION EXECUTES + FROM WITHIN THE SCHEDULER THREAD! */ + rc = 0; + rc += pth_pqueue_elements(&pth_NQ); + rc += pth_pqueue_elements(&pth_RQ); + rc += pth_pqueue_elements(&pth_WQ); + rc += pth_pqueue_elements(&pth_SQ); + rc += pth_pqueue_elements(&pth_DQ); + if (rc == 1 /* just our main thread */) + return TRUE; + else + return FALSE; +} +void pth_exit(void *value) +{ + pth_event_t ev; + + pth_debug2("pth_exit: marking thread \"%s\" as dead", pth_current->name); + + /* main thread is special: + wait until it is the last thread */ + if (pth_current == pth_main) { + ev = pth_event(PTH_EVENT_FUNC, pth_exit_cb); + pth_wait(ev); + pth_event_free(ev, PTH_FREE_THIS); + } + + /* execute cleanups */ + pth_thread_cleanup(pth_current); + + /* mark the current thread as dead, so the scheduler removes us */ + pth_current->join_arg = value; + pth_current->state = PTH_STATE_DEAD; + + if (pth_current != pth_main) { + /* + * Now we explicitly switch into the scheduler and let it + * reap the current thread structure; we can't free it here, + * or we'd be running on a stack which malloc() regards as + * free memory, which would be a somewhat perilous situation. + */ + pth_debug2("pth_exit: switching from thread \"%s\" to scheduler", pth_current->name); + pth_mctx_switch(&pth_current->mctx, &pth_sched->mctx); + abort(); /* not reached! */ + } + else { + /* + * main thread is special: exit the _process_ + * [double-cast to avoid warnings because of size] + */ + pth_kill(); + exit((int)((long)value)); + abort(); /* not reached! */ + } +} + +/* waits for the termination of the specified thread */ +int pth_join(pth_t tid, void **value) +{ + pth_event_t ev; + static pth_key_t ev_key = PTH_KEY_INIT; + + pth_debug2("pth_join: joining thread \"%s\"", tid == NULL ? "-ANY-" : tid->name); + if (tid == pth_current) + return_errno(FALSE, EDEADLK); + if (tid != NULL && !tid->joinable) + return_errno(FALSE, EINVAL); + if (pth_ctrl(PTH_CTRL_GETTHREADS) == 1) + return_errno(FALSE, EDEADLK); + if (tid == NULL) + tid = pth_pqueue_head(&pth_DQ); + if (tid == NULL || (tid != NULL && tid->state != PTH_STATE_DEAD)) { + ev = pth_event(PTH_EVENT_TID|PTH_UNTIL_TID_DEAD|PTH_MODE_STATIC, &ev_key, tid); + pth_wait(ev); + } + if (tid == NULL) + tid = pth_pqueue_head(&pth_DQ); + if (tid == NULL || (tid != NULL && tid->state != PTH_STATE_DEAD)) + return_errno(FALSE, EIO); + if (value != NULL) + *value = tid->join_arg; + pth_pqueue_delete(&pth_DQ, tid); + pth_tcb_free(tid); + return TRUE; +} + +/* delegates control back to scheduler for context switches */ +int pth_yield(pth_t to) +{ + pth_pqueue_t *q = NULL; + + pth_debug2("pth_yield: enter from thread \"%s\"", pth_current->name); + + /* a given thread has to be new or ready or we ignore the request */ + if (to != NULL) { + switch (to->state) { + case PTH_STATE_NEW: q = &pth_NQ; break; + case PTH_STATE_READY: q = &pth_RQ; break; + default: q = NULL; + } + if (q == NULL || !pth_pqueue_contains(q, to)) + return_errno(FALSE, EINVAL); + } + + /* give a favored thread maximum priority in his queue */ + if (to != NULL && q != NULL) + pth_pqueue_favorite(q, to); + + /* switch to scheduler */ + if (to != NULL) + pth_debug2("pth_yield: give up control to scheduler " + "in favour of thread \"%s\"", to->name); + else + pth_debug1("pth_yield: give up control to scheduler"); + pth_mctx_switch(&pth_current->mctx, &pth_sched->mctx); + pth_debug1("pth_yield: got back control from scheduler"); + + pth_debug2("pth_yield: leave to thread \"%s\"", pth_current->name); + return TRUE; +} + +/* suspend a thread until its again manually resumed */ +int pth_suspend(pth_t t) +{ + pth_pqueue_t *q; + + if (t == NULL) + return_errno(FALSE, EINVAL); + if (t == pth_sched || t == pth_current) + return_errno(FALSE, EPERM); + switch (t->state) { + case PTH_STATE_NEW: q = &pth_NQ; break; + case PTH_STATE_READY: q = &pth_RQ; break; + case PTH_STATE_WAITING: q = &pth_WQ; break; + default: q = NULL; + } + if (q == NULL) + return_errno(FALSE, EPERM); + if (!pth_pqueue_contains(q, t)) + return_errno(FALSE, ESRCH); + pth_pqueue_delete(q, t); + pth_pqueue_insert(&pth_SQ, PTH_PRIO_STD, t); + pth_debug2("pth_suspend: suspend thread \"%s\"\n", t->name); + return TRUE; +} + +/* resume a previously suspended thread */ +int pth_resume(pth_t t) +{ + pth_pqueue_t *q; + + if (t == NULL) + return_errno(FALSE, EINVAL); + if (t == pth_sched || t == pth_current) + return_errno(FALSE, EPERM); + if (!pth_pqueue_contains(&pth_SQ, t)) + return_errno(FALSE, EPERM); + pth_pqueue_delete(&pth_SQ, t); + switch (t->state) { + case PTH_STATE_NEW: q = &pth_NQ; break; + case PTH_STATE_READY: q = &pth_RQ; break; + case PTH_STATE_WAITING: q = &pth_WQ; break; + default: q = NULL; + } + pth_pqueue_insert(q, PTH_PRIO_STD, t); + pth_debug2("pth_resume: resume thread \"%s\"\n", t->name); + return TRUE; +} + +/* switch a filedescriptor's I/O mode */ +int pth_fdmode(int fd, int newmode) +{ + int fdmode; + int oldmode; + + /* retrieve old mode (usually cheap) */ + if ((fdmode = fcntl(fd, F_GETFL, NULL)) == -1) + oldmode = PTH_FDMODE_ERROR; + else if (fdmode & O_NONBLOCKING) + oldmode = PTH_FDMODE_NONBLOCK; + else + oldmode = PTH_FDMODE_BLOCK; + + /* set new mode (usually expensive) */ + if (oldmode == PTH_FDMODE_BLOCK && newmode == PTH_FDMODE_NONBLOCK) + fcntl(fd, F_SETFL, (fdmode | O_NONBLOCKING)); + if (oldmode == PTH_FDMODE_NONBLOCK && newmode == PTH_FDMODE_BLOCK) + fcntl(fd, F_SETFL, (fdmode & ~(O_NONBLOCKING))); + + /* return old mode */ + return oldmode; +} + +/* wait for specific amount of time */ +int pth_nap(pth_time_t naptime) +{ + pth_time_t until; + pth_event_t ev; + static pth_key_t ev_key = PTH_KEY_INIT; + + if (pth_time_cmp(&naptime, PTH_TIME_ZERO) == 0) + return_errno(FALSE, EINVAL); + pth_time_set(&until, PTH_TIME_NOW); + pth_time_add(&until, &naptime); + ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key, until); + pth_wait(ev); + return TRUE; +} + +/* runs a constructor once */ +int pth_once(pth_once_t *oncectrl, void (*constructor)(void *), void *arg) +{ + if (oncectrl == NULL || constructor == NULL) + return_errno(FALSE, EINVAL); + if (*oncectrl != TRUE) + constructor(arg); + *oncectrl = TRUE; + return TRUE; +} + Index: ossp-pkg/pth/pthread.3 RCS File: /v/ossp/cvs/ossp-pkg/pth/Attic/pthread.3,v rcsdiff -q -kk '-r1.97' '-r1.98' -u '/v/ossp/cvs/ossp-pkg/pth/Attic/pthread.3,v' 2>/dev/null --- pthread.3 2000/10/03 08:00:35 1.97 +++ pthread.3 2001/03/24 14:27:28 1.98 @@ -1,5 +1,5 @@ .\" Automatically generated by Pod::Man version 1.02 -.\" Sun Oct 1 14:44:35 2000 +.\" Sat Mar 24 15:26:49 2001 .\" .\" Standard preamble: .\" ====================================================================== @@ -728,9 +728,7 @@ The option _POSIX_THREAD_PRIORITY_SCHEDULING is not defined and the implementation does not support the function. .PP -The -\&\fI\fIpthread_attr_setinheritsched()\fI\fR -function may fail if: +The \fI\fIpthread_attr_setinheritsched()\fI\fR function may fail if: .Ip "[\s-1EINVAL\s0]" 4 .IX Item "[EINVAL]" The value of the attribute being set is not valid. Index: ossp-pkg/pth/pthread.c RCS File: /v/ossp/cvs/ossp-pkg/pth/pthread.c,v co -q -kk -p'1.52' '/v/ossp/cvs/ossp-pkg/pth/pthread.c,v' | diff -u /dev/null - -L'ossp-pkg/pth/pthread.c' 2>/dev/null --- ossp-pkg/pth/pthread.c +++ - 2024-05-17 13:52:51.145342612 +0200 @@ -0,0 +1,1115 @@ +/* +** GNU Pth - The GNU Portable Threads +** Copyright (c) 1999-2000 Ralf S. Engelschall +** +** This file is part of GNU Pth, a non-preemptive thread scheduling +** library which can be found at http://www.gnu.org/software/pth/. +** +** This library is free software; you can redistribute it and/or +** modify it under the terms of the GNU Lesser General Public +** License as published by the Free Software Foundation; either +** version 2.1 of the License, or (at your option) any later version. +** +** This library is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public +** License along with this library; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +** USA, or contact Ralf S. Engelschall . +** +** pthread.c: POSIX Thread ("Pthread") API for Pth +*/ + /* ``The nice thing about standards is that + there are so many to choose from. And if + you really don't like all the standards you + just have to wait another year until the one + arises you are looking for'' + -- Tannenbaum, 'Introduction + to Computer Networks' */ + +/* +** HEADER STUFF +*/ + +/* + * Include our own Pthread and then the private Pth header. + * The order here is very important to get correct namespace hiding! + */ +#define _PTHREAD_PRIVATE +#include "pthread.h" +#include "pth_p.h" +#undef _PTHREAD_PRIVATE + +/* general success return value */ +#ifdef OK +#undef OK +#endif +#define OK 0 + +/* +** GLOBAL STUFF +*/ + +static void pthread_shutdown(void) +{ + pth_kill(); + return; +} + +static int pthread_initialized = FALSE; + +#define pthread_initialize() \ + do { \ + if (pthread_initialized == FALSE) { \ + pthread_initialized = TRUE; \ + pth_init(); \ + atexit(pthread_shutdown); \ + } \ + } while (0) + +/* +** THREAD ATTRIBUTE ROUTINES +*/ + +int pthread_attr_init(pthread_attr_t *attr) +{ + pth_attr_t na; + + pthread_initialize(); + if (attr == NULL) + return_errno(EINVAL, EINVAL); + if ((na = pth_attr_new()) == NULL) + return errno; + (*attr) = (pthread_attr_t)na; + return OK; +} + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + pth_attr_t na; + + if (attr == NULL || *attr == NULL) + return_errno(EINVAL, EINVAL); + na = (pth_attr_t)(*attr); + pth_attr_destroy(na); + *attr = NULL; + return OK; +} + +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_getinheritsched(pthread_attr_t *attr, int *inheritsched) +{ + if (attr == NULL || inheritsched == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_setschedparam(pthread_attr_t *attr, struct sched_param *schedparam) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *schedparam) +{ + if (attr == NULL || schedparam == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int schedpolicy) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *schedpolicy) +{ + if (attr == NULL || schedpolicy == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_getscope(pthread_attr_t *attr, int *scope) +{ + if (attr == NULL || scope == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_set((pth_attr_t)(*attr), PTH_ATTR_STACK_SIZE, (unsigned int)stacksize)) + return errno; + return OK; +} + +int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize) +{ + if (attr == NULL || stacksize == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_get((pth_attr_t)(*attr), PTH_ATTR_STACK_SIZE, (unsigned int *)stacksize)) + return errno; + return OK; +} + +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_set((pth_attr_t)(*attr), PTH_ATTR_STACK_ADDR, (char *)stackaddr)) + return errno; + return OK; +} + +int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stackaddr) +{ + if (attr == NULL || stackaddr == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_get((pth_attr_t)(*attr), PTH_ATTR_STACK_ADDR, (char **)stackaddr)) + return errno; + return OK; +} + +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + int s; + + if (attr == NULL) + return_errno(EINVAL, EINVAL); + if (detachstate == PTHREAD_CREATE_DETACHED) + s = FALSE; + else if (detachstate == PTHREAD_CREATE_JOINABLE) + s = TRUE; + else + return_errno(EINVAL, EINVAL); + if (!pth_attr_set((pth_attr_t)(*attr), PTH_ATTR_JOINABLE, s)) + return errno; + return OK; +} + +int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate) +{ + int s; + + if (attr == NULL || detachstate == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_get((pth_attr_t)(*attr), PTH_ATTR_JOINABLE, &s)) + return errno; + if (s == TRUE) + *detachstate = PTHREAD_CREATE_JOINABLE; + else + *detachstate = PTHREAD_CREATE_DETACHED; + return OK; +} + +int pthread_attr_setname_np(pthread_attr_t *attr, char *name) +{ + if (attr == NULL || name == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_set((pth_attr_t)(*attr), PTH_ATTR_NAME, name)) + return errno; + return OK; +} + +int pthread_attr_getname_np(pthread_attr_t *attr, char **name) +{ + if (attr == NULL || name == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_get((pth_attr_t)(*attr), PTH_ATTR_NAME, name)) + return errno; + return OK; +} + +int pthread_attr_setprio_np(pthread_attr_t *attr, int prio) +{ + if (attr == NULL || (prio < PTH_PRIO_MIN || prio > PTH_PRIO_MAX)) + return_errno(EINVAL, EINVAL); + if (!pth_attr_set((pth_attr_t)(*attr), PTH_ATTR_PRIO, prio)) + return errno; + return OK; +} + +int pthread_attr_getprio_np(pthread_attr_t *attr, int *prio) +{ + if (attr == NULL || prio == NULL) + return_errno(EINVAL, EINVAL); + if (!pth_attr_get((pth_attr_t)(*attr), PTH_ATTR_PRIO, prio)) + return errno; + return OK; +} + +/* +** THREAD ROUTINES +*/ + +int pthread_create( + pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + pth_attr_t na; + + pthread_initialize(); + if (thread == NULL || start_routine == NULL) + return_errno(EINVAL, EINVAL); + if (pth_ctrl(PTH_CTRL_GETTHREADS) >= PTHREAD_THREADS_MAX) + return_errno(EAGAIN, EAGAIN); + if (attr != NULL) + na = (pth_attr_t)(*attr); + else + na = PTH_ATTR_DEFAULT; + *thread = (pthread_t)pth_spawn(na, start_routine, arg); + if (*thread == NULL) + return_errno(EAGAIN, EAGAIN); + return OK; +} + +int __pthread_detach(pthread_t thread) +{ + pth_attr_t na; + + if (thread == NULL) + return_errno(EINVAL, EINVAL); + if ((na = pth_attr_of((pth_t)thread)) == NULL) + return errno; + if (!pth_attr_set(na, PTH_ATTR_JOINABLE, FALSE)) + return errno; + pth_attr_destroy(na); + return OK; +} + +pthread_t pthread_self(void) +{ + pthread_initialize(); + return (pthread_t)pth_self(); +} + +int pthread_equal(pthread_t t1, pthread_t t2) +{ + return (t1 == t2); +} + +int pthread_yield_np(void) +{ + pthread_initialize(); + pth_yield(NULL); + return OK; +} + +void pthread_exit(void *value_ptr) +{ + pthread_initialize(); + pth_exit(value_ptr); + return; +} + +int pthread_join(pthread_t thread, void **value_ptr) +{ + pthread_initialize(); + if (!pth_join((pth_t)thread, value_ptr)) + return errno; + if (value_ptr != NULL) + if (*value_ptr == PTH_CANCELED) + *value_ptr = PTHREAD_CANCELED; + return OK; +} + +int pthread_once( + pthread_once_t *once_control, void (*init_routine)(void)) +{ + pthread_initialize(); + if (once_control == NULL || init_routine == NULL) + return_errno(EINVAL, EINVAL); + if (*once_control != 1) + init_routine(); + *once_control = 1; + return OK; +} + +int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + pthread_initialize(); + return pth_sigmask(how, set, oset); +} + +int pthread_kill(pthread_t thread, int sig) +{ + if (!pth_raise((pth_t)thread, sig)) + return errno; + return OK; +} + +/* +** CONTEXT ROUTINES +*/ + +int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) +{ + pthread_initialize(); + if (!pth_key_create((pth_key_t *)key, destructor)) + return errno; + return OK; +} + +int pthread_key_delete(pthread_key_t key) +{ + if (!pth_key_delete((pth_key_t)key)) + return errno; + return OK; +} + +int pthread_setspecific(pthread_key_t key, const void *value) +{ + if (!pth_key_setdata((pth_key_t)key, value)) + return errno; + return OK; +} + +void *pthread_getspecific(pthread_key_t key) +{ + return pth_key_getdata((pth_key_t)key); +} + +/* +** CANCEL ROUTINES +*/ + +int pthread_cancel(pthread_t thread) +{ + if (!pth_cancel((pth_t)thread)) + return errno; + return OK; +} + +void pthread_testcancel(void) +{ + pth_cancel_point(); + return; +} + +int pthread_setcancelstate(int state, int *oldstate) +{ + int s, os; + + if (oldstate != NULL) { + pth_cancel_state(0, &os); + if (os & PTH_CANCEL_ENABLE) + *oldstate = PTHREAD_CANCEL_ENABLE; + else + *oldstate = PTHREAD_CANCEL_DISABLE; + } + if (state != 0) { + pth_cancel_state(0, &s); + if (state == PTHREAD_CANCEL_ENABLE) { + s |= PTH_CANCEL_ENABLE; + s &= ~(PTH_CANCEL_DISABLE); + } + else { + s |= PTH_CANCEL_DISABLE; + s &= ~(PTH_CANCEL_ENABLE); + } + pth_cancel_state(s, NULL); + } + return OK; +} + +int pthread_setcanceltype(int type, int *oldtype) +{ + int t, ot; + + if (oldtype != NULL) { + pth_cancel_state(0, &ot); + if (ot & PTH_CANCEL_DEFERRED) + *oldtype = PTHREAD_CANCEL_DEFERRED; + else + *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; + } + if (type != 0) { + pth_cancel_state(0, &t); + if (type == PTHREAD_CANCEL_DEFERRED) { + t |= PTH_CANCEL_DEFERRED; + t &= ~(PTH_CANCEL_ASYNCHRONOUS); + } + else { + t |= PTH_CANCEL_ASYNCHRONOUS; + t &= ~(PTH_CANCEL_DEFERRED); + } + pth_cancel_state(t, NULL); + } + return OK; +} + +/* +** SCHEDULER ROUTINES +*/ + +int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) +{ + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) +{ + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +/* +** CLEANUP ROUTINES +*/ + +void pthread_cleanup_push(void (*routine)(void *), void *arg) +{ + pthread_initialize(); + pth_cleanup_push(routine, arg); + return; +} + +void pthread_cleanup_pop(int execute) +{ + pth_cleanup_pop(execute); + return; +} + +/* +** AT-FORK SUPPORT +*/ + +struct pthread_atfork_st { + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); +}; +static struct pthread_atfork_st pthread_atfork_info[PTH_ATFORK_MAX]; +static int pthread_atfork_idx = 0; + +static void pthread_atfork_cb_prepare(void *_info) +{ + struct pthread_atfork_st *info = (struct pthread_atfork_st *)_info; + info->prepare(); + return; +} +static void pthread_atfork_cb_parent(void *_info) +{ + struct pthread_atfork_st *info = (struct pthread_atfork_st *)_info; + info->parent(); + return; +} +static void pthread_atfork_cb_child(void *_info) +{ + struct pthread_atfork_st *info = (struct pthread_atfork_st *)_info; + info->child(); + return; +} + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + struct pthread_atfork_st *info; + + if (pthread_atfork_idx > PTH_ATFORK_MAX-1) + return_errno(ENOMEM, ENOMEM); + info = &pthread_atfork_info[pthread_atfork_idx++]; + info->prepare = prepare; + info->parent = parent; + info->child = child; + if (!pth_atfork_push(pthread_atfork_cb_prepare, + pthread_atfork_cb_parent, + pthread_atfork_cb_child, info)) + return errno; + return OK; +} + +/* +** MUTEX ATTRIBUTE ROUTINES +*/ + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + pthread_initialize(); + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *attr, int *prioceiling) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_getprotocol(pthread_mutexattr_t *attr, int *protocol) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +/* +** MUTEX ROUTINES +*/ + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + pth_mutex_t *m; + + pthread_initialize(); + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if ((m = (pth_mutex_t *)malloc(sizeof(pth_mutex_t))) == NULL) + return errno; + if (!pth_mutex_init(m)) + return errno; + (*mutex) = (pthread_mutex_t)m; + return OK; +} + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + free(*mutex); + *mutex = NULL; + return OK; +} + +int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutex_getprioceiling(pthread_mutex_t *mutex, int *prioceiling) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + if (!pth_mutex_acquire((pth_mutex_t *)(*mutex), FALSE, NULL)) + return errno; + return OK; +} + +int pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + if (!pth_mutex_acquire((pth_mutex_t *)(*mutex), TRUE, NULL)) + return errno; + return OK; +} + +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + if (mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + if (!pth_mutex_release((pth_mutex_t *)(*mutex))) + return errno; + return OK; +} + +/* +** LOCK ATTRIBUTE ROUTINES +*/ + +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) +{ + pthread_initialize(); + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +/* +** LOCK ROUTINES +*/ + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + pth_rwlock_t *rw; + + pthread_initialize(); + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if ((rw = (pth_rwlock_t *)malloc(sizeof(pth_rwlock_t))) == NULL) + return errno; + if (!pth_rwlock_init(rw)) + return errno; + (*rwlock) = (pthread_rwlock_t)rw; + return OK; +} + +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + free(*rwlock); + *rwlock = NULL; + return OK; +} + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + if (pthread_rwlock_init(rwlock, NULL) != OK) + return errno; + if (!pth_rwlock_acquire((pth_rwlock_t *)(*rwlock), PTH_RWLOCK_RD, FALSE, NULL)) + return errno; + return OK; +} + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + if (pthread_rwlock_init(rwlock, NULL) != OK) + return errno; + if (!pth_rwlock_acquire((pth_rwlock_t *)(*rwlock), PTH_RWLOCK_RD, TRUE, NULL)) + return errno; + return OK; +} + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + if (pthread_rwlock_init(rwlock, NULL) != OK) + return errno; + if (!pth_rwlock_acquire((pth_rwlock_t *)(*rwlock), PTH_RWLOCK_RW, FALSE, NULL)) + return errno; + return OK; +} + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + if (pthread_rwlock_init(rwlock, NULL) != OK) + return errno; + if (!pth_rwlock_acquire((pth_rwlock_t *)(*rwlock), PTH_RWLOCK_RW, TRUE, NULL)) + return errno; + return OK; +} + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + if (rwlock == NULL) + return_errno(EINVAL, EINVAL); + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + if (pthread_rwlock_init(rwlock, NULL) != OK) + return errno; + if (!pth_rwlock_release((pth_rwlock_t *)(*rwlock))) + return errno; + return OK; +} + +/* +** CONDITION ATTRIBUTE ROUTINES +*/ + +int pthread_condattr_init(pthread_condattr_t *attr) +{ + pthread_initialize(); + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* nothing to do for us */ + return OK; +} + +int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared) +{ + if (attr == NULL) + return_errno(EINVAL, EINVAL); + /* not supported */ + return_errno(ENOSYS, ENOSYS); +} + +/* +** CONDITION ROUTINES +*/ + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + pth_cond_t *cn; + + pthread_initialize(); + if (cond == NULL) + return_errno(EINVAL, EINVAL); + if ((cn = (pth_cond_t *)malloc(sizeof(pth_cond_t))) == NULL) + return errno; + if (!pth_cond_init(cn)) + return errno; + (*cond) = (pthread_cond_t)cn; + return OK; +} + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + if (cond == NULL) + return_errno(EINVAL, EINVAL); + free(*cond); + *cond = NULL; + return OK; +} + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + if (cond == NULL) + return_errno(EINVAL, EINVAL); + if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond_init(cond, NULL) != OK) + return errno; + if (!pth_cond_notify((pth_cond_t *)(*cond), TRUE)) + return errno; + return OK; +} + +int pthread_cond_signal(pthread_cond_t *cond) +{ + if (cond == NULL) + return_errno(EINVAL, EINVAL); + if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond_init(cond, NULL) != OK) + return errno; + if (!pth_cond_notify((pth_cond_t *)(*cond), FALSE)) + return errno; + return OK; +} + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + if (cond == NULL || mutex == NULL) + return_errno(EINVAL, EINVAL); + if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond_init(cond, NULL) != OK) + return errno; + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + if (!pth_cond_await((pth_cond_t *)(*cond), (pth_mutex_t *)(*mutex), NULL)) + return errno; + return OK; +} + +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; +#endif + +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + pth_event_t ev; + static pth_key_t ev_key = PTH_KEY_INIT; + + if (cond == NULL || mutex == NULL || abstime == NULL) + return_errno(EINVAL, EINVAL); +#ifdef __amigaos__ + if (abstime->ts_sec < 0 || abstime->ts_nsec < 0 || abstime->ts_nsec >= 1000000000) +#else + if (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +#endif + return_errno(EINVAL, EINVAL); + if (*cond == PTHREAD_COND_INITIALIZER) + if (pthread_cond_init(cond, NULL) != OK) + return errno; + if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex_init(mutex, NULL) != OK) + return errno; + ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key, +#ifdef __amigaos__ + pth_time(abstime->ts_sec, (abstime->ts_nsec)/1000) +#else + pth_time(abstime->tv_sec, (abstime->tv_nsec)/1000) +#endif + ); + if (!pth_cond_await((pth_cond_t *)(*cond), (pth_mutex_t *)(*mutex), ev)) + return errno; + if (pth_event_occurred(ev)) + return ETIMEDOUT; + return OK; +} + +/* +** POSIX 1003.1j +*/ + +int pthread_abort(pthread_t thread) +{ + if (!pth_abort((pth_t)thread)) + return errno; + return OK; +} + +/* +** THREAD-SAFE REPLACEMENT FUNCTIONS +*/ + +pid_t __pthread_fork(void) +{ + pthread_initialize(); + return pth_fork(); +} + +unsigned int __pthread_sleep(unsigned int sec) +{ + pthread_initialize(); + return pth_sleep(sec); +} + +int __pthread_sigwait(const sigset_t *set, int *sig) +{ + pthread_initialize(); + return pth_sigwait(set, sig); +} + +pid_t __pthread_waitpid(pid_t pid, int *status, int options) +{ + pthread_initialize(); + return pth_waitpid(pid, status, options); +} + +int __pthread_connect(int s, struct sockaddr *addr, socklen_t addrlen) +{ + pthread_initialize(); + return pth_connect(s, addr, addrlen); +} + +int __pthread_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + pthread_initialize(); + return pth_accept(s, addr, addrlen); +} + +int __pthread_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) +{ + pthread_initialize(); + return pth_select(nfds, readfds, writefds, exceptfds, timeout); +} + +int __pthread_poll(struct pollfd *pfd, nfds_t nfd, int timeout) +{ + pthread_initialize(); + return pth_poll(pfd, nfd, timeout); +} + +ssize_t __pthread_read(int fd, void *buf, size_t nbytes) +{ + pthread_initialize(); + return pth_read(fd, buf, nbytes); +} + +ssize_t __pthread_write(int fd, const void *buf, size_t nbytes) +{ + pthread_initialize(); + return pth_write(fd, buf, nbytes); +} + +ssize_t __pthread_readv(int fd, const struct iovec *piovec, int iocnt) +{ + pthread_initialize(); + return pth_readv(fd, piovec, iocnt); +} + +ssize_t __pthread_writev(int fd, const struct iovec *piovec, int iocnt) +{ + pthread_initialize(); + return pth_writev(fd, piovec, iocnt); +} + +ssize_t __pthread_recv(int fd, void *buf, size_t nbytes, int flags) +{ + pthread_initialize(); + return pth_recv(fd, buf, nbytes, flags); +} + +ssize_t __pthread_send(int fd, const void *buf, size_t nbytes, int flags) +{ + pthread_initialize(); + return pth_send(fd, buf, nbytes, flags); +} + +ssize_t __pthread_recvfrom(int fd, void *buf, size_t nbytes, int flags, struct sockaddr *from, int *fromlen) +{ + pthread_initialize(); + return pth_recvfrom(fd, buf, nbytes, flags, from, fromlen); +} + +ssize_t __pthread_sendto(int fd, const void *buf, size_t nbytes, int flags, struct sockaddr *to, int tolen) +{ + pthread_initialize(); + return pth_sendto(fd, buf, nbytes, flags, to, tolen); +} + +ssize_t __pthread_pread(int fd, void *buf, size_t nbytes, off_t offset) +{ + pthread_initialize(); + return pth_pread(fd, buf, nbytes, offset); +} + +ssize_t __pthread_pwrite(int fd, const void *buf, size_t nbytes, off_t offset) +{ + pthread_initialize(); + return pth_pwrite(fd, buf, nbytes, offset); +} + Index: ossp-pkg/pth/pthread.h.in RCS File: /v/ossp/cvs/ossp-pkg/pth/pthread.h.in,v rcsdiff -q -kk '-r1.54' '-r1.55' -u '/v/ossp/cvs/ossp-pkg/pth/pthread.h.in,v' 2>/dev/null --- pthread.h.in 2001/01/01 12:51:08 1.54 +++ pthread.h.in 2001/03/24 14:27:29 1.55 @@ -224,7 +224,7 @@ #define PTHREAD_DESTRUCTOR_ITERATIONS 4 #define PTHREAD_KEYS_MAX 256 #define PTHREAD_STACK_MIN 8192 -#define PTHREAD_THREADS_MAX 10000 /* actually now restriction */ +#define PTHREAD_THREADS_MAX 10000 /* actually yet no restriction */ /* * Flags for threads and thread attributes. @@ -480,6 +480,10 @@ extern ssize_t __pthread_write(int, const void *, size_t); extern ssize_t __pthread_readv(int, const struct iovec *, int); extern ssize_t __pthread_writev(int, const struct iovec *, int); +extern ssize_t __pthread_recv(int, void *, size_t, int); +extern ssize_t __pthread_send(int, const void *, size_t, int); +extern ssize_t __pthread_recvfrom(int, void *, size_t, int, struct sockaddr *, int *); +extern ssize_t __pthread_sendto(int, const void *, size_t, int, struct sockaddr *, int); extern ssize_t __pthread_pread(int, void *, size_t, off_t); extern ssize_t __pthread_pwrite(int, const void *, size_t, off_t); @@ -496,6 +500,10 @@ #define write __pthread_write #define readv __pthread_readv #define writev __pthread_writev +#define recv __pthread_recv +#define send __pthread_send +#define recvfrom __pthread_recvfrom +#define sendto __pthread_sendto #define pread __pthread_pread #define pwrite __pthread_pwrite #endif Index: ossp-pkg/pth/pthread.pod RCS File: /v/ossp/cvs/ossp-pkg/pth/pthread.pod,v rcsdiff -q -kk '-r1.19' '-r1.20' -u '/v/ossp/cvs/ossp-pkg/pth/pthread.pod,v' 2>/dev/null --- pthread.pod 2000/08/18 07:39:09 1.19 +++ pthread.pod 2001/03/24 14:27:29 1.20 @@ -719,9 +719,7 @@ =back -The -I -function may fail if: +The I function may fail if: =over 4