OSSP CVS Repository

ossp - Check-in [414]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 414
Date: 2001-Mar-24 15:27:28 (local)
2001-Mar-24 14:27:28 (UTC)
User:rse
Branch:
Comment: *** empty log message ***
Tickets:
Inspections:
Files:
ossp-pkg/pth/pth_lib.c      added-> 1.45
ossp-pkg/pth/pthread.3      1.97 -> 1.98     2 inserted, 4 deleted
ossp-pkg/pth/pthread.c      added-> 1.52
ossp-pkg/pth/pthread.h.in      1.54 -> 1.55     9 inserted, 1 deleted
ossp-pkg/pth/pthread.pod      1.19 -> 1.20     1 inserted, 3 deleted

ossp-pkg/pth/pth_lib.c -> 1.45

*** /dev/null    Thu May  2 17:15:29 2024
--- -    Thu May  2 17:17:16 2024
***************
*** 0 ****
--- 1,572 ----
+ /*
+ **  GNU Pth - The GNU Portable Threads
+ **  Copyright (c) 1999-2000 Ralf S. Engelschall <rse@engelschall.com>
+ **
+ **  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 <rse@engelschall.com>.
+ **
+ **  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;
+ }
+ 


ossp-pkg/pth/pthread.3 1.97 -> 1.98

--- 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.


ossp-pkg/pth/pthread.c -> 1.52

*** /dev/null    Thu May  2 17:15:29 2024
--- -    Thu May  2 17:17:16 2024
***************
*** 0 ****
--- 1,1115 ----
+ /*
+ **  GNU Pth - The GNU Portable Threads
+ **  Copyright (c) 1999-2000 Ralf S. Engelschall <rse@engelschall.com>
+ **
+ **  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 <rse@engelschall.com>.
+ **
+ **  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);
+ }
+ 


ossp-pkg/pth/pthread.h.in 1.54 -> 1.55

--- 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


ossp-pkg/pth/pthread.pod 1.19 -> 1.20

--- 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<pthread_attr_setinheritsched()>
-function may fail if:
+The I<pthread_attr_setinheritsched()> function may fail if:
 
 =over 4
 

CVSTrac 2.0.1