Index: head/lib/libc_r/uthread/uthread_detach.c =================================================================== --- head/lib/libc_r/uthread/uthread_detach.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_detach.c (revision 55194) @@ -1,83 +1,82 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_detach(pthread_t pthread) { int rval = 0; - int status; pthread_t next_thread; /* Check for invalid calling parameters: */ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) /* Return an invalid argument error: */ rval = EINVAL; /* Check if the thread has not been detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { /* Flag the thread as detached: */ pthread->attr.flags |= PTHREAD_DETACHED; /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Enter a loop to bring all threads off the join queue: */ while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) { /* Remove the thread from the queue: */ TAILQ_REMOVE(&pthread->join_queue, next_thread, qe); /* Make the thread run: */ PTHREAD_NEW_STATE(next_thread,PS_RUNNING); } /* * Undefer and handle pending signals, yielding if a * scheduling signal occurred while in the critical region. */ _thread_kern_sig_undefer(); } else /* Return an error: */ rval = EINVAL; /* Return the completion status: */ return (rval); } #endif Index: head/lib/libc_r/uthread/uthread_fork.c =================================================================== --- head/lib/libc_r/uthread/uthread_fork.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_fork.c (revision 55194) @@ -1,223 +1,223 @@ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include +#include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" pid_t fork(void) { int i, flags; pid_t ret; pthread_t pthread; pthread_t pthread_save; /* * Defer signals to protect the scheduling queues from access * by the signal handler: */ _thread_kern_sig_defer(); /* Fork a new process: */ if ((ret = _thread_sys_fork()) != 0) { /* Parent process or error. Nothing to do here. */ } else { /* Close the pthread kernel pipe: */ _thread_sys_close(_thread_kern_pipe[0]); _thread_sys_close(_thread_kern_pipe[1]); /* Reset signals pending for the running thread: */ sigemptyset(&_thread_run->sigpend); /* * Create a pipe that is written to by the signal handler to * prevent signals being missed in calls to * _thread_sys_select: */ if (_thread_sys_pipe(_thread_kern_pipe) != 0) { /* Cannot create pipe, so abort: */ PANIC("Cannot create pthread kernel pipe for forked process"); } /* Get the flags for the read pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the read pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Get the flags for the write pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the write pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Reinitialize the GC mutex: */ else if (_mutex_reinit(&_gc_mutex) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC mutex for forked process"); } /* Reinitialize the GC condition variable: */ else if (_cond_reinit(&_gc_cond) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC condvar for forked process"); } /* Initialize the ready queue: */ else if (_pq_init(&_readyq) != 0) { /* Abort this application: */ PANIC("Cannot initialize priority ready queue."); } else { /* * Enter a loop to remove all threads other than * the running thread from the thread list: */ pthread = TAILQ_FIRST(&_thread_list); while (pthread != NULL) { /* Save the thread to be freed: */ pthread_save = pthread; /* * Advance to the next thread before * destroying the current thread: */ pthread = TAILQ_NEXT(pthread, dle); /* Make sure this isn't the running thread: */ if (pthread_save != _thread_run) { /* Remove this thread from the list: */ TAILQ_REMOVE(&_thread_list, pthread_save, tle); if (pthread_save->attr.stackaddr_attr == - NULL && pthread_save->stack != NULL) + NULL && pthread_save->stack != NULL) { if (pthread_save->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* - * Default-size stack. Cache - * it: + * Default-size stack. + * Cache it: */ struct stack *spare_stack; spare_stack = (pthread_save->stack - + PTHREAD_STACK_DEFAULT - - sizeof(struct stack)); - SLIST_INSERT_HEAD( - &_stackq, - spare_stack, - qe); + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, qe); } else /* * Free the stack of * the dead thread: */ free(pthread_save->stack); + } if (pthread_save->specific_data != NULL) free(pthread_save->specific_data); if (pthread_save->poll_data.fds != NULL) free(pthread_save->poll_data.fds); free(pthread_save); } } /* Treat the current thread as the initial thread: */ _thread_initial = _thread_run; /* Re-init the dead thread list: */ TAILQ_INIT(&_dead_list); /* Re-init the waiting and work queues. */ TAILQ_INIT(&_waitingq); TAILQ_INIT(&_workq); /* Re-init the threads mutex queue: */ TAILQ_INIT(&_thread_run->mutexq); /* No spinlocks yet: */ _spinblock_count = 0; /* Don't queue signals yet: */ _queue_signals = 0; /* Initialize signal handling: */ _thread_sig_init(); /* Initialize the scheduling switch hook routine: */ _sched_switch_hook = NULL; /* Clear out any locks in the file descriptor table: */ for (i = 0; i < _thread_dtablesize; i++) { if (_thread_fd_table[i] != NULL) { /* Initialise the file locks: */ memset(&_thread_fd_table[i]->lock, 0, sizeof(_thread_fd_table[i]->lock)); _thread_fd_table[i]->r_owner = NULL; _thread_fd_table[i]->w_owner = NULL; _thread_fd_table[i]->r_fname = NULL; _thread_fd_table[i]->w_fname = NULL; _thread_fd_table[i]->r_lineno = 0;; _thread_fd_table[i]->w_lineno = 0;; _thread_fd_table[i]->r_lockcount = 0;; _thread_fd_table[i]->w_lockcount = 0;; /* Initialise the read/write queues: */ TAILQ_INIT(&_thread_fd_table[i]->r_queue); TAILQ_INIT(&_thread_fd_table[i]->w_queue); } } } } /* * Undefer and handle pending signals, yielding if necessary: */ _thread_kern_sig_undefer(); /* Return the process ID: */ return (ret); } #endif Index: head/lib/libc_r/uthread/uthread_gc.c =================================================================== --- head/lib/libc_r/uthread/uthread_gc.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_gc.c (revision 55194) @@ -1,253 +1,252 @@ /* * Copyright (c) 1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * * Garbage collector thread. Frees memory allocated for dead threads. * */ #include #include +#include #include #include #include #include #include #include "pthread_private.h" pthread_addr_t _thread_gc(pthread_addr_t arg) { int f_debug; int f_done = 0; int ret; sigset_t mask; pthread_t pthread; pthread_t pthread_cln; - pthread_t pthread_nxt; - pthread_t pthread_prv; struct timespec abstime; void *p_stack; /* Block all signals */ sigfillset (&mask); sigprocmask (SIG_BLOCK, &mask, NULL); /* Mark this thread as a library thread (not a user thread). */ _thread_run->flags |= PTHREAD_FLAGS_PRIVATE; /* Set a debug flag based on an environment variable. */ f_debug = (getenv("LIBC_R_DEBUG") != NULL); /* Set the name of this thread. */ pthread_set_name_np(_thread_run,"GC"); while (!f_done) { /* Check if debugging this application. */ if (f_debug) /* Dump thread info to file. */ _thread_dump_info(); /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Check if this is the last running thread: */ if (TAILQ_FIRST(&_thread_list) == _thread_run && TAILQ_NEXT(_thread_run, tle) == NULL) /* * This is the last thread, so it can exit * now. */ f_done = 1; /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); /* * Lock the garbage collector mutex which ensures that * this thread sees another thread exit: */ if (pthread_mutex_lock(&_gc_mutex) != 0) PANIC("Cannot lock gc mutex"); /* No stack of thread structure to free yet: */ p_stack = NULL; pthread_cln = NULL; /* * Enter a loop to search for the first dead thread that * has memory to free. */ for (pthread = TAILQ_FIRST(&_dead_list); p_stack == NULL && pthread_cln == NULL && pthread != NULL; pthread = TAILQ_NEXT(pthread, dle)) { /* Check if the initial thread: */ if (pthread == _thread_initial) { /* Don't destroy the initial thread. */ } /* * Check if this thread has detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { /* Remove this thread from the dead list: */ TAILQ_REMOVE(&_dead_list, pthread, dle); /* * Check if the stack was not specified by * the caller to pthread_create and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* * Default-size stack. Cache * it: */ struct stack *spare_stack; spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT - sizeof(struct stack)); SLIST_INSERT_HEAD(&_stackq, spare_stack, qe); } else { /* * Non-standard stack size. * free() it outside the locks. */ p_stack = pthread->stack; } } /* * Point to the thread structure that must * be freed outside the locks: */ pthread_cln = pthread; } else { /* * This thread has not detached, so do * not destroy it. * * Check if the stack was not specified by * the caller to pthread_create and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* * Default-size stack. Cache * it: */ struct stack *spare_stack; spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT - sizeof(struct stack)); SLIST_INSERT_HEAD(&_stackq, spare_stack, qe); } else { /* * Non-standard stack size. * free() it outside the locks: */ p_stack = pthread->stack; } /* * NULL the stack pointer now * that the memory has been freed: */ pthread->stack = NULL; } } } /* * Check if this is not the last thread and there is no * memory to free this time around. */ if (!f_done && p_stack == NULL && pthread_cln == NULL) { /* Get the current time. */ if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) PANIC("gc cannot get time"); /* * Do a backup poll in 10 seconds if no threads * die before then. */ abstime.tv_sec += 10; /* * Wait for a signal from a dying thread or a * timeout (for a backup poll). */ if ((ret = pthread_cond_timedwait(&_gc_cond, &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) PANIC("gc cannot wait for a signal"); } /* Unlock the garbage collector mutex: */ if (pthread_mutex_unlock(&_gc_mutex) != 0) PANIC("Cannot unlock gc mutex"); /* * If there is memory to free, do it now. The call to * free() might block, so this must be done outside the * locks. */ if (p_stack != NULL) free(p_stack); if (pthread_cln != NULL) /* * Free the memory allocated for the thread * structure. */ free(pthread_cln); } return (NULL); } Index: head/lib/libc_r/uthread/uthread_poll.c =================================================================== --- head/lib/libc_r/uthread/uthread_poll.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_poll.c (revision 55194) @@ -1,99 +1,99 @@ /* * Copyright (c) 1999 Daniel Eischen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int poll(struct pollfd *fds, unsigned int nfds, int timeout) { struct timespec ts; int numfds = nfds; - int i, ret = 0, found = 0; + int i, ret = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { numfds = _thread_dtablesize; } /* Check if a timeout was specified: */ if (timeout == INFTIM) { /* Wait for ever: */ _thread_kern_set_timeout(NULL); } else if (timeout > 0) { /* Convert the timeout in msec to a timespec: */ ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000; /* Set the wake up time: */ _thread_kern_set_timeout(&ts); } else if (timeout < 0) { /* a timeout less than zero but not == INFTIM is invalid */ errno = EINVAL; return (-1); } if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) { data.nfds = numfds; data.fds = fds; /* * Clear revents in case of a timeout which leaves fds * unchanged: */ for (i = 0; i < numfds; i++) { fds[i].revents = 0; } _thread_run->data.poll_data = &data; _thread_run->interrupted = 0; _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__); if (_thread_run->interrupted) { errno = EINTR; ret = -1; } else { ret = data.nfds; } } return (ret); } #endif Index: head/lib/libc_r/uthread/uthread_priority_queue.c =================================================================== --- head/lib/libc_r/uthread/uthread_priority_queue.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_priority_queue.c (revision 55194) @@ -1,335 +1,335 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Prototypes: */ static void pq_insert_prio_list(pq_queue_t *pq, int prio); #if defined(_PTHREADS_INVARIANTS) static int _pq_active = 0; #define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) #define _PQ_SET_ACTIVE() _pq_active = 1 #define _PQ_CLEAR_ACTIVE() _pq_active = 0 #define _PQ_ASSERT_ACTIVE(msg) do { \ if (_pq_active == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_INACTIVE(msg) do { \ if (_pq_active != 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ if ((thrd)->flags & _PQ_IN_SCHEDQ) \ PANIC(msg); \ } while (0) #else #define _PQ_SET_ACTIVE() #define _PQ_CLEAR_ACTIVE() #define _PQ_ASSERT_ACTIVE(msg) #define _PQ_ASSERT_INACTIVE(msg) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) #define _PQ_CHECK_PRIO() #endif int _pq_alloc(pq_queue_t *pq, int minprio, int maxprio) { - int i, ret = 0; + int ret = 0; int prioslots = maxprio - minprio + 1; if (pq == NULL) ret = -1; /* Create the priority queue with (maxprio - minprio + 1) slots: */ else if ((pq->pq_lists = (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL) ret = -1; else { /* Remember the queue size: */ pq->pq_size = prioslots; ret = _pq_init(pq); } return (ret); } int _pq_init(pq_queue_t *pq) { int i, ret = 0; if ((pq == NULL) || (pq->pq_lists == NULL)) ret = -1; else { /* Initialize the queue for each priority slot: */ for (i = 0; i < pq->pq_size; i++) { TAILQ_INIT(&pq->pq_lists[i].pl_head); pq->pq_lists[i].pl_prio = i; pq->pq_lists[i].pl_queued = 0; } /* Initialize the priority queue: */ TAILQ_INIT(&pq->pq_queue); _PQ_CLEAR_ACTIVE(); } return (ret); } void _pq_remove(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); /* * Remove this thread from priority list. Note that if * the priority list becomes empty, it is not removed * from the priority queue because another thread may be * added to the priority list (resulting in a needless * removal/insertion). Priority lists are only removed * from the priority queue when _pq_first is called. */ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); /* This thread is now longer in the priority queue. */ pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_head(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_head: Already in priority queue"); TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_tail(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_tail: Already in priority queue"); TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } pthread_t _pq_first(pq_queue_t *pq) { pq_list_t *pql; pthread_t pthread = NULL; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); _PQ_SET_ACTIVE(); while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && (pthread == NULL)) { if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { /* * The priority list is empty; remove the list * from the queue. */ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link); /* Mark the list as not being in the queue: */ pql->pl_queued = 0; } } _PQ_CLEAR_ACTIVE(); return (pthread); } static void pq_insert_prio_list(pq_queue_t *pq, int prio) { pq_list_t *pql; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); /* * The priority queue is in descending priority order. Start at * the beginning of the queue and find the list before which the * new list should be inserted. */ pql = TAILQ_FIRST(&pq->pq_queue); while ((pql != NULL) && (pql->pl_prio > prio)) pql = TAILQ_NEXT(pql, pl_link); /* Insert the list: */ if (pql == NULL) TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link); else TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link); /* Mark this list as being in the queue: */ pq->pq_lists[prio].pl_queued = 1; } #if defined(_PTHREADS_INVARIANTS) void _waitq_insert(pthread_t pthread) { pthread_t tid; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); if (pthread->wakeup_time.tv_sec == -1) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else { tid = TAILQ_FIRST(&_waitingq); while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) tid = TAILQ_NEXT(tid, pqe); if (tid == NULL) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else TAILQ_INSERT_BEFORE(tid, pthread, pqe); } pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_remove(pthread_t pthread) { /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); TAILQ_REMOVE(&_waitingq, pthread, pqe); pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_setactive(void) { _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); _PQ_SET_ACTIVE(); } void _waitq_clearactive(void) { _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); _PQ_CLEAR_ACTIVE(); } #endif #endif Index: head/lib/libc_r/uthread/uthread_setschedparam.c =================================================================== --- head/lib/libc_r/uthread/uthread_setschedparam.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_setschedparam.c (revision 55194) @@ -1,114 +1,114 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { int old_prio, in_readyq = 0, ret = 0; if ((param == NULL) || (param->sched_priority < PTHREAD_MIN_PRIORITY) || (param->sched_priority > PTHREAD_MAX_PRIORITY) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) /* Return an invalid argument error: */ ret = EINVAL; /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); if (param->sched_priority != pthread->base_priority) { /* * Remove the thread from its current priority * queue before any adjustments are made to its * active priority: */ + old_prio = pthread->active_priority; if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { in_readyq = 1; - old_prio = pthread->active_priority; PTHREAD_PRIOQ_REMOVE(pthread); } /* Set the thread base priority: */ pthread->base_priority = param->sched_priority; /* Recalculate the active priority: */ pthread->active_priority = MAX(pthread->base_priority, pthread->inherited_priority); if (in_readyq) { if ((pthread->priority_mutex_count > 0) && (old_prio > pthread->active_priority)) { /* * POSIX states that if the priority is * being lowered, the thread must be * inserted at the head of the queue for * its priority if it owns any priority * protection or inheritence mutexes. */ PTHREAD_PRIOQ_INSERT_HEAD(pthread); } else PTHREAD_PRIOQ_INSERT_TAIL(pthread); } /* * Check for any mutex priority adjustments. This * includes checking for a priority mutex on which * this thread is waiting. */ _mutex_notify_priochange(pthread); } /* Set the scheduling policy: */ pthread->attr.sched_policy = policy; /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); } return(ret); } #endif Index: head/lib/libc_r/uthread/uthread_socketpair.c =================================================================== --- head/lib/libc_r/uthread/uthread_socketpair.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_socketpair.c (revision 55194) @@ -1,55 +1,56 @@ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * */ +#include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int socketpair(int af, int type, int protocol, int pair[2]) { int ret; if (!((ret = _thread_sys_socketpair(af, type, protocol, pair)) < 0)) if (_thread_fd_table_init(pair[0]) != 0 || _thread_fd_table_init(pair[1]) != 0) { _thread_sys_close(pair[0]); _thread_sys_close(pair[1]); ret = -1; } return (ret); } #endif Index: head/lib/libc_r/uthread/uthread_spec.c =================================================================== --- head/lib/libc_r/uthread/uthread_spec.c (revision 55193) +++ head/lib/libc_r/uthread/uthread_spec.c (revision 55194) @@ -1,200 +1,200 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Static variables: */ static struct pthread_key key_table[PTHREAD_KEYS_MAX]; int pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) { for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { /* Lock the key table entry: */ _SPINLOCK(&key_table[*key].lock); if (key_table[(*key)].allocated == 0) { key_table[(*key)].allocated = 1; key_table[(*key)].destructor = destructor; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); return (0); } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); } return (EAGAIN); } int pthread_key_delete(pthread_key_t key) { int ret = 0; if (key < PTHREAD_KEYS_MAX) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); if (key_table[key].allocated) key_table[key].allocated = 0; else ret = EINVAL; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); } else ret = EINVAL; return (ret); } void _thread_cleanupspecific(void) { - void *data; + void *data = NULL; int key; int itr; void (*destructor)( void *); for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { for (key = 0; key < PTHREAD_KEYS_MAX; key++) { if (_thread_run->specific_data_count) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); destructor = NULL; if (key_table[key].allocated) { if (_thread_run->specific_data[key]) { data = (void *) _thread_run->specific_data[key]; _thread_run->specific_data[key] = NULL; _thread_run->specific_data_count--; destructor = key_table[key].destructor; } } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); /* * If there is a destructore, call it * with the key table entry unlocked: */ if (destructor) destructor(data); } else { free(_thread_run->specific_data); _thread_run->specific_data = NULL; return; } } } free(_thread_run->specific_data); _thread_run->specific_data = NULL; } static inline const void ** pthread_key_allocate_data(void) { const void **new_data; if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); } return (new_data); } int pthread_setspecific(pthread_key_t key, const void *value) { pthread_t pthread; int ret = 0; /* Point to the running thread: */ pthread = _thread_run; if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { if (key < PTHREAD_KEYS_MAX) { if (key_table[key].allocated) { if (pthread->specific_data[key] == NULL) { if (value != NULL) pthread->specific_data_count++; } else { if (value == NULL) pthread->specific_data_count--; } pthread->specific_data[key] = value; ret = 0; } else ret = EINVAL; } else ret = EINVAL; } else ret = ENOMEM; return (ret); } void * pthread_getspecific(pthread_key_t key) { pthread_t pthread; void *data; /* Point to the running thread: */ pthread = _thread_run; /* Check if there is specific data: */ if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) { /* Check if this key has been used before: */ if (key_table[key].allocated) { /* Return the value: */ data = (void *) pthread->specific_data[key]; } else { /* * This key has not been used before, so return NULL * instead: */ data = NULL; } } else /* No specific data has been created, so just return NULL: */ data = NULL; return (data); } #endif Index: head/lib/libkse/thread/thr_detach.c =================================================================== --- head/lib/libkse/thread/thr_detach.c (revision 55193) +++ head/lib/libkse/thread/thr_detach.c (revision 55194) @@ -1,83 +1,82 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_detach(pthread_t pthread) { int rval = 0; - int status; pthread_t next_thread; /* Check for invalid calling parameters: */ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) /* Return an invalid argument error: */ rval = EINVAL; /* Check if the thread has not been detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { /* Flag the thread as detached: */ pthread->attr.flags |= PTHREAD_DETACHED; /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Enter a loop to bring all threads off the join queue: */ while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) { /* Remove the thread from the queue: */ TAILQ_REMOVE(&pthread->join_queue, next_thread, qe); /* Make the thread run: */ PTHREAD_NEW_STATE(next_thread,PS_RUNNING); } /* * Undefer and handle pending signals, yielding if a * scheduling signal occurred while in the critical region. */ _thread_kern_sig_undefer(); } else /* Return an error: */ rval = EINVAL; /* Return the completion status: */ return (rval); } #endif Index: head/lib/libkse/thread/thr_fork.c =================================================================== --- head/lib/libkse/thread/thr_fork.c (revision 55193) +++ head/lib/libkse/thread/thr_fork.c (revision 55194) @@ -1,223 +1,223 @@ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include +#include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" pid_t fork(void) { int i, flags; pid_t ret; pthread_t pthread; pthread_t pthread_save; /* * Defer signals to protect the scheduling queues from access * by the signal handler: */ _thread_kern_sig_defer(); /* Fork a new process: */ if ((ret = _thread_sys_fork()) != 0) { /* Parent process or error. Nothing to do here. */ } else { /* Close the pthread kernel pipe: */ _thread_sys_close(_thread_kern_pipe[0]); _thread_sys_close(_thread_kern_pipe[1]); /* Reset signals pending for the running thread: */ sigemptyset(&_thread_run->sigpend); /* * Create a pipe that is written to by the signal handler to * prevent signals being missed in calls to * _thread_sys_select: */ if (_thread_sys_pipe(_thread_kern_pipe) != 0) { /* Cannot create pipe, so abort: */ PANIC("Cannot create pthread kernel pipe for forked process"); } /* Get the flags for the read pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the read pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Get the flags for the write pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the write pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Reinitialize the GC mutex: */ else if (_mutex_reinit(&_gc_mutex) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC mutex for forked process"); } /* Reinitialize the GC condition variable: */ else if (_cond_reinit(&_gc_cond) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC condvar for forked process"); } /* Initialize the ready queue: */ else if (_pq_init(&_readyq) != 0) { /* Abort this application: */ PANIC("Cannot initialize priority ready queue."); } else { /* * Enter a loop to remove all threads other than * the running thread from the thread list: */ pthread = TAILQ_FIRST(&_thread_list); while (pthread != NULL) { /* Save the thread to be freed: */ pthread_save = pthread; /* * Advance to the next thread before * destroying the current thread: */ pthread = TAILQ_NEXT(pthread, dle); /* Make sure this isn't the running thread: */ if (pthread_save != _thread_run) { /* Remove this thread from the list: */ TAILQ_REMOVE(&_thread_list, pthread_save, tle); if (pthread_save->attr.stackaddr_attr == - NULL && pthread_save->stack != NULL) + NULL && pthread_save->stack != NULL) { if (pthread_save->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* - * Default-size stack. Cache - * it: + * Default-size stack. + * Cache it: */ struct stack *spare_stack; spare_stack = (pthread_save->stack - + PTHREAD_STACK_DEFAULT - - sizeof(struct stack)); - SLIST_INSERT_HEAD( - &_stackq, - spare_stack, - qe); + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, qe); } else /* * Free the stack of * the dead thread: */ free(pthread_save->stack); + } if (pthread_save->specific_data != NULL) free(pthread_save->specific_data); if (pthread_save->poll_data.fds != NULL) free(pthread_save->poll_data.fds); free(pthread_save); } } /* Treat the current thread as the initial thread: */ _thread_initial = _thread_run; /* Re-init the dead thread list: */ TAILQ_INIT(&_dead_list); /* Re-init the waiting and work queues. */ TAILQ_INIT(&_waitingq); TAILQ_INIT(&_workq); /* Re-init the threads mutex queue: */ TAILQ_INIT(&_thread_run->mutexq); /* No spinlocks yet: */ _spinblock_count = 0; /* Don't queue signals yet: */ _queue_signals = 0; /* Initialize signal handling: */ _thread_sig_init(); /* Initialize the scheduling switch hook routine: */ _sched_switch_hook = NULL; /* Clear out any locks in the file descriptor table: */ for (i = 0; i < _thread_dtablesize; i++) { if (_thread_fd_table[i] != NULL) { /* Initialise the file locks: */ memset(&_thread_fd_table[i]->lock, 0, sizeof(_thread_fd_table[i]->lock)); _thread_fd_table[i]->r_owner = NULL; _thread_fd_table[i]->w_owner = NULL; _thread_fd_table[i]->r_fname = NULL; _thread_fd_table[i]->w_fname = NULL; _thread_fd_table[i]->r_lineno = 0;; _thread_fd_table[i]->w_lineno = 0;; _thread_fd_table[i]->r_lockcount = 0;; _thread_fd_table[i]->w_lockcount = 0;; /* Initialise the read/write queues: */ TAILQ_INIT(&_thread_fd_table[i]->r_queue); TAILQ_INIT(&_thread_fd_table[i]->w_queue); } } } } /* * Undefer and handle pending signals, yielding if necessary: */ _thread_kern_sig_undefer(); /* Return the process ID: */ return (ret); } #endif Index: head/lib/libkse/thread/thr_poll.c =================================================================== --- head/lib/libkse/thread/thr_poll.c (revision 55193) +++ head/lib/libkse/thread/thr_poll.c (revision 55194) @@ -1,99 +1,99 @@ /* * Copyright (c) 1999 Daniel Eischen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int poll(struct pollfd *fds, unsigned int nfds, int timeout) { struct timespec ts; int numfds = nfds; - int i, ret = 0, found = 0; + int i, ret = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { numfds = _thread_dtablesize; } /* Check if a timeout was specified: */ if (timeout == INFTIM) { /* Wait for ever: */ _thread_kern_set_timeout(NULL); } else if (timeout > 0) { /* Convert the timeout in msec to a timespec: */ ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000; /* Set the wake up time: */ _thread_kern_set_timeout(&ts); } else if (timeout < 0) { /* a timeout less than zero but not == INFTIM is invalid */ errno = EINVAL; return (-1); } if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) { data.nfds = numfds; data.fds = fds; /* * Clear revents in case of a timeout which leaves fds * unchanged: */ for (i = 0; i < numfds; i++) { fds[i].revents = 0; } _thread_run->data.poll_data = &data; _thread_run->interrupted = 0; _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__); if (_thread_run->interrupted) { errno = EINTR; ret = -1; } else { ret = data.nfds; } } return (ret); } #endif Index: head/lib/libkse/thread/thr_priority_queue.c =================================================================== --- head/lib/libkse/thread/thr_priority_queue.c (revision 55193) +++ head/lib/libkse/thread/thr_priority_queue.c (revision 55194) @@ -1,335 +1,335 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Prototypes: */ static void pq_insert_prio_list(pq_queue_t *pq, int prio); #if defined(_PTHREADS_INVARIANTS) static int _pq_active = 0; #define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) #define _PQ_SET_ACTIVE() _pq_active = 1 #define _PQ_CLEAR_ACTIVE() _pq_active = 0 #define _PQ_ASSERT_ACTIVE(msg) do { \ if (_pq_active == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_INACTIVE(msg) do { \ if (_pq_active != 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ if ((thrd)->flags & _PQ_IN_SCHEDQ) \ PANIC(msg); \ } while (0) #else #define _PQ_SET_ACTIVE() #define _PQ_CLEAR_ACTIVE() #define _PQ_ASSERT_ACTIVE(msg) #define _PQ_ASSERT_INACTIVE(msg) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) #define _PQ_CHECK_PRIO() #endif int _pq_alloc(pq_queue_t *pq, int minprio, int maxprio) { - int i, ret = 0; + int ret = 0; int prioslots = maxprio - minprio + 1; if (pq == NULL) ret = -1; /* Create the priority queue with (maxprio - minprio + 1) slots: */ else if ((pq->pq_lists = (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL) ret = -1; else { /* Remember the queue size: */ pq->pq_size = prioslots; ret = _pq_init(pq); } return (ret); } int _pq_init(pq_queue_t *pq) { int i, ret = 0; if ((pq == NULL) || (pq->pq_lists == NULL)) ret = -1; else { /* Initialize the queue for each priority slot: */ for (i = 0; i < pq->pq_size; i++) { TAILQ_INIT(&pq->pq_lists[i].pl_head); pq->pq_lists[i].pl_prio = i; pq->pq_lists[i].pl_queued = 0; } /* Initialize the priority queue: */ TAILQ_INIT(&pq->pq_queue); _PQ_CLEAR_ACTIVE(); } return (ret); } void _pq_remove(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); /* * Remove this thread from priority list. Note that if * the priority list becomes empty, it is not removed * from the priority queue because another thread may be * added to the priority list (resulting in a needless * removal/insertion). Priority lists are only removed * from the priority queue when _pq_first is called. */ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); /* This thread is now longer in the priority queue. */ pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_head(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_head: Already in priority queue"); TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_tail(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_tail: Already in priority queue"); TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } pthread_t _pq_first(pq_queue_t *pq) { pq_list_t *pql; pthread_t pthread = NULL; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); _PQ_SET_ACTIVE(); while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && (pthread == NULL)) { if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { /* * The priority list is empty; remove the list * from the queue. */ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link); /* Mark the list as not being in the queue: */ pql->pl_queued = 0; } } _PQ_CLEAR_ACTIVE(); return (pthread); } static void pq_insert_prio_list(pq_queue_t *pq, int prio) { pq_list_t *pql; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); /* * The priority queue is in descending priority order. Start at * the beginning of the queue and find the list before which the * new list should be inserted. */ pql = TAILQ_FIRST(&pq->pq_queue); while ((pql != NULL) && (pql->pl_prio > prio)) pql = TAILQ_NEXT(pql, pl_link); /* Insert the list: */ if (pql == NULL) TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link); else TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link); /* Mark this list as being in the queue: */ pq->pq_lists[prio].pl_queued = 1; } #if defined(_PTHREADS_INVARIANTS) void _waitq_insert(pthread_t pthread) { pthread_t tid; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); if (pthread->wakeup_time.tv_sec == -1) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else { tid = TAILQ_FIRST(&_waitingq); while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) tid = TAILQ_NEXT(tid, pqe); if (tid == NULL) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else TAILQ_INSERT_BEFORE(tid, pthread, pqe); } pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_remove(pthread_t pthread) { /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); TAILQ_REMOVE(&_waitingq, pthread, pqe); pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_setactive(void) { _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); _PQ_SET_ACTIVE(); } void _waitq_clearactive(void) { _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); _PQ_CLEAR_ACTIVE(); } #endif #endif Index: head/lib/libkse/thread/thr_setschedparam.c =================================================================== --- head/lib/libkse/thread/thr_setschedparam.c (revision 55193) +++ head/lib/libkse/thread/thr_setschedparam.c (revision 55194) @@ -1,114 +1,114 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { int old_prio, in_readyq = 0, ret = 0; if ((param == NULL) || (param->sched_priority < PTHREAD_MIN_PRIORITY) || (param->sched_priority > PTHREAD_MAX_PRIORITY) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) /* Return an invalid argument error: */ ret = EINVAL; /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); if (param->sched_priority != pthread->base_priority) { /* * Remove the thread from its current priority * queue before any adjustments are made to its * active priority: */ + old_prio = pthread->active_priority; if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { in_readyq = 1; - old_prio = pthread->active_priority; PTHREAD_PRIOQ_REMOVE(pthread); } /* Set the thread base priority: */ pthread->base_priority = param->sched_priority; /* Recalculate the active priority: */ pthread->active_priority = MAX(pthread->base_priority, pthread->inherited_priority); if (in_readyq) { if ((pthread->priority_mutex_count > 0) && (old_prio > pthread->active_priority)) { /* * POSIX states that if the priority is * being lowered, the thread must be * inserted at the head of the queue for * its priority if it owns any priority * protection or inheritence mutexes. */ PTHREAD_PRIOQ_INSERT_HEAD(pthread); } else PTHREAD_PRIOQ_INSERT_TAIL(pthread); } /* * Check for any mutex priority adjustments. This * includes checking for a priority mutex on which * this thread is waiting. */ _mutex_notify_priochange(pthread); } /* Set the scheduling policy: */ pthread->attr.sched_policy = policy; /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); } return(ret); } #endif Index: head/lib/libkse/thread/thr_spec.c =================================================================== --- head/lib/libkse/thread/thr_spec.c (revision 55193) +++ head/lib/libkse/thread/thr_spec.c (revision 55194) @@ -1,200 +1,200 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Static variables: */ static struct pthread_key key_table[PTHREAD_KEYS_MAX]; int pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) { for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { /* Lock the key table entry: */ _SPINLOCK(&key_table[*key].lock); if (key_table[(*key)].allocated == 0) { key_table[(*key)].allocated = 1; key_table[(*key)].destructor = destructor; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); return (0); } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); } return (EAGAIN); } int pthread_key_delete(pthread_key_t key) { int ret = 0; if (key < PTHREAD_KEYS_MAX) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); if (key_table[key].allocated) key_table[key].allocated = 0; else ret = EINVAL; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); } else ret = EINVAL; return (ret); } void _thread_cleanupspecific(void) { - void *data; + void *data = NULL; int key; int itr; void (*destructor)( void *); for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { for (key = 0; key < PTHREAD_KEYS_MAX; key++) { if (_thread_run->specific_data_count) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); destructor = NULL; if (key_table[key].allocated) { if (_thread_run->specific_data[key]) { data = (void *) _thread_run->specific_data[key]; _thread_run->specific_data[key] = NULL; _thread_run->specific_data_count--; destructor = key_table[key].destructor; } } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); /* * If there is a destructore, call it * with the key table entry unlocked: */ if (destructor) destructor(data); } else { free(_thread_run->specific_data); _thread_run->specific_data = NULL; return; } } } free(_thread_run->specific_data); _thread_run->specific_data = NULL; } static inline const void ** pthread_key_allocate_data(void) { const void **new_data; if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); } return (new_data); } int pthread_setspecific(pthread_key_t key, const void *value) { pthread_t pthread; int ret = 0; /* Point to the running thread: */ pthread = _thread_run; if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { if (key < PTHREAD_KEYS_MAX) { if (key_table[key].allocated) { if (pthread->specific_data[key] == NULL) { if (value != NULL) pthread->specific_data_count++; } else { if (value == NULL) pthread->specific_data_count--; } pthread->specific_data[key] = value; ret = 0; } else ret = EINVAL; } else ret = EINVAL; } else ret = ENOMEM; return (ret); } void * pthread_getspecific(pthread_key_t key) { pthread_t pthread; void *data; /* Point to the running thread: */ pthread = _thread_run; /* Check if there is specific data: */ if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) { /* Check if this key has been used before: */ if (key_table[key].allocated) { /* Return the value: */ data = (void *) pthread->specific_data[key]; } else { /* * This key has not been used before, so return NULL * instead: */ data = NULL; } } else /* No specific data has been created, so just return NULL: */ data = NULL; return (data); } #endif Index: head/lib/libpthread/thread/thr_detach.c =================================================================== --- head/lib/libpthread/thread/thr_detach.c (revision 55193) +++ head/lib/libpthread/thread/thr_detach.c (revision 55194) @@ -1,83 +1,82 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_detach(pthread_t pthread) { int rval = 0; - int status; pthread_t next_thread; /* Check for invalid calling parameters: */ if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) /* Return an invalid argument error: */ rval = EINVAL; /* Check if the thread has not been detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { /* Flag the thread as detached: */ pthread->attr.flags |= PTHREAD_DETACHED; /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Enter a loop to bring all threads off the join queue: */ while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) { /* Remove the thread from the queue: */ TAILQ_REMOVE(&pthread->join_queue, next_thread, qe); /* Make the thread run: */ PTHREAD_NEW_STATE(next_thread,PS_RUNNING); } /* * Undefer and handle pending signals, yielding if a * scheduling signal occurred while in the critical region. */ _thread_kern_sig_undefer(); } else /* Return an error: */ rval = EINVAL; /* Return the completion status: */ return (rval); } #endif Index: head/lib/libpthread/thread/thr_fork.c =================================================================== --- head/lib/libpthread/thread/thr_fork.c (revision 55193) +++ head/lib/libpthread/thread/thr_fork.c (revision 55194) @@ -1,223 +1,223 @@ /* * Copyright (c) 1995-1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include +#include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" pid_t fork(void) { int i, flags; pid_t ret; pthread_t pthread; pthread_t pthread_save; /* * Defer signals to protect the scheduling queues from access * by the signal handler: */ _thread_kern_sig_defer(); /* Fork a new process: */ if ((ret = _thread_sys_fork()) != 0) { /* Parent process or error. Nothing to do here. */ } else { /* Close the pthread kernel pipe: */ _thread_sys_close(_thread_kern_pipe[0]); _thread_sys_close(_thread_kern_pipe[1]); /* Reset signals pending for the running thread: */ sigemptyset(&_thread_run->sigpend); /* * Create a pipe that is written to by the signal handler to * prevent signals being missed in calls to * _thread_sys_select: */ if (_thread_sys_pipe(_thread_kern_pipe) != 0) { /* Cannot create pipe, so abort: */ PANIC("Cannot create pthread kernel pipe for forked process"); } /* Get the flags for the read pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the read pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Get the flags for the write pipe: */ else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { /* Abort this application: */ abort(); } /* Make the write pipe non-blocking: */ else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { /* Abort this application: */ abort(); } /* Reinitialize the GC mutex: */ else if (_mutex_reinit(&_gc_mutex) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC mutex for forked process"); } /* Reinitialize the GC condition variable: */ else if (_cond_reinit(&_gc_cond) != 0) { /* Abort this application: */ PANIC("Cannot initialize GC condvar for forked process"); } /* Initialize the ready queue: */ else if (_pq_init(&_readyq) != 0) { /* Abort this application: */ PANIC("Cannot initialize priority ready queue."); } else { /* * Enter a loop to remove all threads other than * the running thread from the thread list: */ pthread = TAILQ_FIRST(&_thread_list); while (pthread != NULL) { /* Save the thread to be freed: */ pthread_save = pthread; /* * Advance to the next thread before * destroying the current thread: */ pthread = TAILQ_NEXT(pthread, dle); /* Make sure this isn't the running thread: */ if (pthread_save != _thread_run) { /* Remove this thread from the list: */ TAILQ_REMOVE(&_thread_list, pthread_save, tle); if (pthread_save->attr.stackaddr_attr == - NULL && pthread_save->stack != NULL) + NULL && pthread_save->stack != NULL) { if (pthread_save->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* - * Default-size stack. Cache - * it: + * Default-size stack. + * Cache it: */ struct stack *spare_stack; spare_stack = (pthread_save->stack - + PTHREAD_STACK_DEFAULT - - sizeof(struct stack)); - SLIST_INSERT_HEAD( - &_stackq, - spare_stack, - qe); + + PTHREAD_STACK_DEFAULT + - sizeof(struct stack)); + SLIST_INSERT_HEAD(&_stackq, + spare_stack, qe); } else /* * Free the stack of * the dead thread: */ free(pthread_save->stack); + } if (pthread_save->specific_data != NULL) free(pthread_save->specific_data); if (pthread_save->poll_data.fds != NULL) free(pthread_save->poll_data.fds); free(pthread_save); } } /* Treat the current thread as the initial thread: */ _thread_initial = _thread_run; /* Re-init the dead thread list: */ TAILQ_INIT(&_dead_list); /* Re-init the waiting and work queues. */ TAILQ_INIT(&_waitingq); TAILQ_INIT(&_workq); /* Re-init the threads mutex queue: */ TAILQ_INIT(&_thread_run->mutexq); /* No spinlocks yet: */ _spinblock_count = 0; /* Don't queue signals yet: */ _queue_signals = 0; /* Initialize signal handling: */ _thread_sig_init(); /* Initialize the scheduling switch hook routine: */ _sched_switch_hook = NULL; /* Clear out any locks in the file descriptor table: */ for (i = 0; i < _thread_dtablesize; i++) { if (_thread_fd_table[i] != NULL) { /* Initialise the file locks: */ memset(&_thread_fd_table[i]->lock, 0, sizeof(_thread_fd_table[i]->lock)); _thread_fd_table[i]->r_owner = NULL; _thread_fd_table[i]->w_owner = NULL; _thread_fd_table[i]->r_fname = NULL; _thread_fd_table[i]->w_fname = NULL; _thread_fd_table[i]->r_lineno = 0;; _thread_fd_table[i]->w_lineno = 0;; _thread_fd_table[i]->r_lockcount = 0;; _thread_fd_table[i]->w_lockcount = 0;; /* Initialise the read/write queues: */ TAILQ_INIT(&_thread_fd_table[i]->r_queue); TAILQ_INIT(&_thread_fd_table[i]->w_queue); } } } } /* * Undefer and handle pending signals, yielding if necessary: */ _thread_kern_sig_undefer(); /* Return the process ID: */ return (ret); } #endif Index: head/lib/libpthread/thread/thr_gc.c =================================================================== --- head/lib/libpthread/thread/thr_gc.c (revision 55193) +++ head/lib/libpthread/thread/thr_gc.c (revision 55194) @@ -1,253 +1,252 @@ /* * Copyright (c) 1998 John Birrell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * * Garbage collector thread. Frees memory allocated for dead threads. * */ #include #include +#include #include #include #include #include #include #include "pthread_private.h" pthread_addr_t _thread_gc(pthread_addr_t arg) { int f_debug; int f_done = 0; int ret; sigset_t mask; pthread_t pthread; pthread_t pthread_cln; - pthread_t pthread_nxt; - pthread_t pthread_prv; struct timespec abstime; void *p_stack; /* Block all signals */ sigfillset (&mask); sigprocmask (SIG_BLOCK, &mask, NULL); /* Mark this thread as a library thread (not a user thread). */ _thread_run->flags |= PTHREAD_FLAGS_PRIVATE; /* Set a debug flag based on an environment variable. */ f_debug = (getenv("LIBC_R_DEBUG") != NULL); /* Set the name of this thread. */ pthread_set_name_np(_thread_run,"GC"); while (!f_done) { /* Check if debugging this application. */ if (f_debug) /* Dump thread info to file. */ _thread_dump_info(); /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); /* Check if this is the last running thread: */ if (TAILQ_FIRST(&_thread_list) == _thread_run && TAILQ_NEXT(_thread_run, tle) == NULL) /* * This is the last thread, so it can exit * now. */ f_done = 1; /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); /* * Lock the garbage collector mutex which ensures that * this thread sees another thread exit: */ if (pthread_mutex_lock(&_gc_mutex) != 0) PANIC("Cannot lock gc mutex"); /* No stack of thread structure to free yet: */ p_stack = NULL; pthread_cln = NULL; /* * Enter a loop to search for the first dead thread that * has memory to free. */ for (pthread = TAILQ_FIRST(&_dead_list); p_stack == NULL && pthread_cln == NULL && pthread != NULL; pthread = TAILQ_NEXT(pthread, dle)) { /* Check if the initial thread: */ if (pthread == _thread_initial) { /* Don't destroy the initial thread. */ } /* * Check if this thread has detached: */ else if ((pthread->attr.flags & PTHREAD_DETACHED) != 0) { /* Remove this thread from the dead list: */ TAILQ_REMOVE(&_dead_list, pthread, dle); /* * Check if the stack was not specified by * the caller to pthread_create and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* * Default-size stack. Cache * it: */ struct stack *spare_stack; spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT - sizeof(struct stack)); SLIST_INSERT_HEAD(&_stackq, spare_stack, qe); } else { /* * Non-standard stack size. * free() it outside the locks. */ p_stack = pthread->stack; } } /* * Point to the thread structure that must * be freed outside the locks: */ pthread_cln = pthread; } else { /* * This thread has not detached, so do * not destroy it. * * Check if the stack was not specified by * the caller to pthread_create and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && pthread->stack != NULL) { if (pthread->attr.stacksize_attr == PTHREAD_STACK_DEFAULT) { /* * Default-size stack. Cache * it: */ struct stack *spare_stack; spare_stack = (pthread->stack + PTHREAD_STACK_DEFAULT - sizeof(struct stack)); SLIST_INSERT_HEAD(&_stackq, spare_stack, qe); } else { /* * Non-standard stack size. * free() it outside the locks: */ p_stack = pthread->stack; } /* * NULL the stack pointer now * that the memory has been freed: */ pthread->stack = NULL; } } } /* * Check if this is not the last thread and there is no * memory to free this time around. */ if (!f_done && p_stack == NULL && pthread_cln == NULL) { /* Get the current time. */ if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) PANIC("gc cannot get time"); /* * Do a backup poll in 10 seconds if no threads * die before then. */ abstime.tv_sec += 10; /* * Wait for a signal from a dying thread or a * timeout (for a backup poll). */ if ((ret = pthread_cond_timedwait(&_gc_cond, &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) PANIC("gc cannot wait for a signal"); } /* Unlock the garbage collector mutex: */ if (pthread_mutex_unlock(&_gc_mutex) != 0) PANIC("Cannot unlock gc mutex"); /* * If there is memory to free, do it now. The call to * free() might block, so this must be done outside the * locks. */ if (p_stack != NULL) free(p_stack); if (pthread_cln != NULL) /* * Free the memory allocated for the thread * structure. */ free(pthread_cln); } return (NULL); } Index: head/lib/libpthread/thread/thr_poll.c =================================================================== --- head/lib/libpthread/thread/thr_poll.c (revision 55193) +++ head/lib/libpthread/thread/thr_poll.c (revision 55194) @@ -1,99 +1,99 @@ /* * Copyright (c) 1999 Daniel Eischen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int poll(struct pollfd *fds, unsigned int nfds, int timeout) { struct timespec ts; int numfds = nfds; - int i, ret = 0, found = 0; + int i, ret = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { numfds = _thread_dtablesize; } /* Check if a timeout was specified: */ if (timeout == INFTIM) { /* Wait for ever: */ _thread_kern_set_timeout(NULL); } else if (timeout > 0) { /* Convert the timeout in msec to a timespec: */ ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000; /* Set the wake up time: */ _thread_kern_set_timeout(&ts); } else if (timeout < 0) { /* a timeout less than zero but not == INFTIM is invalid */ errno = EINVAL; return (-1); } if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) { data.nfds = numfds; data.fds = fds; /* * Clear revents in case of a timeout which leaves fds * unchanged: */ for (i = 0; i < numfds; i++) { fds[i].revents = 0; } _thread_run->data.poll_data = &data; _thread_run->interrupted = 0; _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__); if (_thread_run->interrupted) { errno = EINTR; ret = -1; } else { ret = data.nfds; } } return (ret); } #endif Index: head/lib/libpthread/thread/thr_priority_queue.c =================================================================== --- head/lib/libpthread/thread/thr_priority_queue.c (revision 55193) +++ head/lib/libpthread/thread/thr_priority_queue.c (revision 55194) @@ -1,335 +1,335 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Prototypes: */ static void pq_insert_prio_list(pq_queue_t *pq, int prio); #if defined(_PTHREADS_INVARIANTS) static int _pq_active = 0; #define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) #define _PQ_SET_ACTIVE() _pq_active = 1 #define _PQ_CLEAR_ACTIVE() _pq_active = 0 #define _PQ_ASSERT_ACTIVE(msg) do { \ if (_pq_active == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_INACTIVE(msg) do { \ if (_pq_active != 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ PANIC(msg); \ } while (0) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ if ((thrd)->flags & _PQ_IN_SCHEDQ) \ PANIC(msg); \ } while (0) #else #define _PQ_SET_ACTIVE() #define _PQ_CLEAR_ACTIVE() #define _PQ_ASSERT_ACTIVE(msg) #define _PQ_ASSERT_INACTIVE(msg) #define _PQ_ASSERT_IN_WAITQ(thrd, msg) #define _PQ_ASSERT_IN_PRIOQ(thrd, msg) #define _PQ_ASSERT_NOT_QUEUED(thrd, msg) #define _PQ_CHECK_PRIO() #endif int _pq_alloc(pq_queue_t *pq, int minprio, int maxprio) { - int i, ret = 0; + int ret = 0; int prioslots = maxprio - minprio + 1; if (pq == NULL) ret = -1; /* Create the priority queue with (maxprio - minprio + 1) slots: */ else if ((pq->pq_lists = (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL) ret = -1; else { /* Remember the queue size: */ pq->pq_size = prioslots; ret = _pq_init(pq); } return (ret); } int _pq_init(pq_queue_t *pq) { int i, ret = 0; if ((pq == NULL) || (pq->pq_lists == NULL)) ret = -1; else { /* Initialize the queue for each priority slot: */ for (i = 0; i < pq->pq_size; i++) { TAILQ_INIT(&pq->pq_lists[i].pl_head); pq->pq_lists[i].pl_prio = i; pq->pq_lists[i].pl_queued = 0; } /* Initialize the priority queue: */ TAILQ_INIT(&pq->pq_queue); _PQ_CLEAR_ACTIVE(); } return (ret); } void _pq_remove(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); /* * Remove this thread from priority list. Note that if * the priority list becomes empty, it is not removed * from the priority queue because another thread may be * added to the priority list (resulting in a needless * removal/insertion). Priority lists are only removed * from the priority queue when _pq_first is called. */ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); /* This thread is now longer in the priority queue. */ pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_head(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_head: Already in priority queue"); TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } void _pq_insert_tail(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_pq_insert_tail: Already in priority queue"); TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); /* Mark this thread as being in the priority queue. */ pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; _PQ_CLEAR_ACTIVE(); } pthread_t _pq_first(pq_queue_t *pq) { pq_list_t *pql; pthread_t pthread = NULL; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); _PQ_SET_ACTIVE(); while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && (pthread == NULL)) { if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { /* * The priority list is empty; remove the list * from the queue. */ TAILQ_REMOVE(&pq->pq_queue, pql, pl_link); /* Mark the list as not being in the queue: */ pql->pl_queued = 0; } } _PQ_CLEAR_ACTIVE(); return (pthread); } static void pq_insert_prio_list(pq_queue_t *pq, int prio) { pq_list_t *pql; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); /* * The priority queue is in descending priority order. Start at * the beginning of the queue and find the list before which the * new list should be inserted. */ pql = TAILQ_FIRST(&pq->pq_queue); while ((pql != NULL) && (pql->pl_prio > prio)) pql = TAILQ_NEXT(pql, pl_link); /* Insert the list: */ if (pql == NULL) TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link); else TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link); /* Mark this list as being in the queue: */ pq->pq_lists[prio].pl_queued = 1; } #if defined(_PTHREADS_INVARIANTS) void _waitq_insert(pthread_t pthread) { pthread_t tid; /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); if (pthread->wakeup_time.tv_sec == -1) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else { tid = TAILQ_FIRST(&_waitingq); while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) tid = TAILQ_NEXT(tid, pqe); if (tid == NULL) TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); else TAILQ_INSERT_BEFORE(tid, pthread, pqe); } pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_remove(pthread_t pthread) { /* * Make some assertions when debugging is enabled: */ _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); _PQ_SET_ACTIVE(); _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); TAILQ_REMOVE(&_waitingq, pthread, pqe); pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; _PQ_CLEAR_ACTIVE(); } void _waitq_setactive(void) { _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); _PQ_SET_ACTIVE(); } void _waitq_clearactive(void) { _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); _PQ_CLEAR_ACTIVE(); } #endif #endif Index: head/lib/libpthread/thread/thr_setschedparam.c =================================================================== --- head/lib/libpthread/thread/thr_setschedparam.c (revision 55193) +++ head/lib/libpthread/thread/thr_setschedparam.c (revision 55194) @@ -1,114 +1,114 @@ /* * Copyright (c) 1998 Daniel Eischen . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Daniel Eischen. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { int old_prio, in_readyq = 0, ret = 0; if ((param == NULL) || (param->sched_priority < PTHREAD_MIN_PRIORITY) || (param->sched_priority > PTHREAD_MAX_PRIORITY) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) /* Return an invalid argument error: */ ret = EINVAL; /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); if (param->sched_priority != pthread->base_priority) { /* * Remove the thread from its current priority * queue before any adjustments are made to its * active priority: */ + old_prio = pthread->active_priority; if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { in_readyq = 1; - old_prio = pthread->active_priority; PTHREAD_PRIOQ_REMOVE(pthread); } /* Set the thread base priority: */ pthread->base_priority = param->sched_priority; /* Recalculate the active priority: */ pthread->active_priority = MAX(pthread->base_priority, pthread->inherited_priority); if (in_readyq) { if ((pthread->priority_mutex_count > 0) && (old_prio > pthread->active_priority)) { /* * POSIX states that if the priority is * being lowered, the thread must be * inserted at the head of the queue for * its priority if it owns any priority * protection or inheritence mutexes. */ PTHREAD_PRIOQ_INSERT_HEAD(pthread); } else PTHREAD_PRIOQ_INSERT_TAIL(pthread); } /* * Check for any mutex priority adjustments. This * includes checking for a priority mutex on which * this thread is waiting. */ _mutex_notify_priochange(pthread); } /* Set the scheduling policy: */ pthread->attr.sched_policy = policy; /* * Undefer and handle pending signals, yielding if * necessary: */ _thread_kern_sig_undefer(); } return(ret); } #endif Index: head/lib/libpthread/thread/thr_spec.c =================================================================== --- head/lib/libpthread/thread/thr_spec.c (revision 55193) +++ head/lib/libpthread/thread/thr_spec.c (revision 55194) @@ -1,200 +1,200 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by John Birrell. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #ifdef _THREAD_SAFE #include #include "pthread_private.h" /* Static variables: */ static struct pthread_key key_table[PTHREAD_KEYS_MAX]; int pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) { for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { /* Lock the key table entry: */ _SPINLOCK(&key_table[*key].lock); if (key_table[(*key)].allocated == 0) { key_table[(*key)].allocated = 1; key_table[(*key)].destructor = destructor; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); return (0); } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[*key].lock); } return (EAGAIN); } int pthread_key_delete(pthread_key_t key) { int ret = 0; if (key < PTHREAD_KEYS_MAX) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); if (key_table[key].allocated) key_table[key].allocated = 0; else ret = EINVAL; /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); } else ret = EINVAL; return (ret); } void _thread_cleanupspecific(void) { - void *data; + void *data = NULL; int key; int itr; void (*destructor)( void *); for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { for (key = 0; key < PTHREAD_KEYS_MAX; key++) { if (_thread_run->specific_data_count) { /* Lock the key table entry: */ _SPINLOCK(&key_table[key].lock); destructor = NULL; if (key_table[key].allocated) { if (_thread_run->specific_data[key]) { data = (void *) _thread_run->specific_data[key]; _thread_run->specific_data[key] = NULL; _thread_run->specific_data_count--; destructor = key_table[key].destructor; } } /* Unlock the key table entry: */ _SPINUNLOCK(&key_table[key].lock); /* * If there is a destructore, call it * with the key table entry unlocked: */ if (destructor) destructor(data); } else { free(_thread_run->specific_data); _thread_run->specific_data = NULL; return; } } } free(_thread_run->specific_data); _thread_run->specific_data = NULL; } static inline const void ** pthread_key_allocate_data(void) { const void **new_data; if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) { memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX); } return (new_data); } int pthread_setspecific(pthread_key_t key, const void *value) { pthread_t pthread; int ret = 0; /* Point to the running thread: */ pthread = _thread_run; if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) { if (key < PTHREAD_KEYS_MAX) { if (key_table[key].allocated) { if (pthread->specific_data[key] == NULL) { if (value != NULL) pthread->specific_data_count++; } else { if (value == NULL) pthread->specific_data_count--; } pthread->specific_data[key] = value; ret = 0; } else ret = EINVAL; } else ret = EINVAL; } else ret = ENOMEM; return (ret); } void * pthread_getspecific(pthread_key_t key) { pthread_t pthread; void *data; /* Point to the running thread: */ pthread = _thread_run; /* Check if there is specific data: */ if (pthread->specific_data != NULL && key < PTHREAD_KEYS_MAX) { /* Check if this key has been used before: */ if (key_table[key].allocated) { /* Return the value: */ data = (void *) pthread->specific_data[key]; } else { /* * This key has not been used before, so return NULL * instead: */ data = NULL; } } else /* No specific data has been created, so just return NULL: */ data = NULL; return (data); } #endif