summaryrefslogtreecommitdiff
path: root/mit-pthreads/pthreads/pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'mit-pthreads/pthreads/pthread.c')
-rw-r--r--mit-pthreads/pthreads/pthread.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/mit-pthreads/pthreads/pthread.c b/mit-pthreads/pthreads/pthread.c
new file mode 100644
index 00000000000..6f7e2d53980
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread.c
@@ -0,0 +1,293 @@
+/* ==== pthread.c ============================================================
+ * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
+ * 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 Chris Provenzano.
+ * 4. The name of Chris Provenzano may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``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 CHRIS PROVENZANO 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.
+ *
+ * Description : Pthread functions.
+ *
+ * 1.00 93/07/26 proven
+ * -Started coding this file.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id$";
+#endif
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+
+/* ==========================================================================
+ * sched_yield()
+ */
+int sched_yield()
+{
+ sig_handler_fake(SIGVTALRM);
+ return(OK);
+}
+
+/* ==========================================================================
+ * pthread_yield()
+ */
+void pthread_yield()
+{
+ sig_handler_fake(SIGVTALRM);
+}
+
+/* ==========================================================================
+ * pthread_self()
+ */
+pthread_t pthread_self()
+{
+ return(pthread_run);
+}
+
+/* ==========================================================================
+ * pthread_equal()
+ */
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+ return(t1 == t2);
+}
+
+/* ==========================================================================
+ * pthread_exit()
+ */
+extern void pthread_cleanupspecific(void);
+
+void pthread_exit(void *status)
+{
+ pthread_t pthread;
+
+ /* Save return value */
+ pthread_run->ret = status;
+
+ /* First execute all cleanup handlers */
+ while (pthread_run->cleanup) {
+ pthread_cleanup_pop(1);
+ }
+
+ /* Don't forget the cleanup attr */
+ if (pthread_run->attr.cleanup_attr) {
+ pthread_run->attr.cleanup_attr(pthread_run->attr.arg_attr);
+ }
+
+ /* Next run thread-specific data desctructors */
+ if (pthread_run->specific_data) {
+ pthread_cleanupspecific();
+ }
+
+ pthread_sched_prevent();
+
+ if (!(pthread_run->attr.flags & PTHREAD_DETACHED)) {
+ /*
+ * Are there any threads joined to this one,
+ * if so wake them and let them detach this thread.
+ */
+ while (pthread = pthread_queue_deq(&(pthread_run->join_queue))) {
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ pthread->state = PS_RUNNING;
+ }
+ pthread_queue_enq(&pthread_dead_queue, pthread_run);
+ pthread_resched_resume(PS_DEAD);
+ } else {
+ pthread_queue_enq(&pthread_alloc_queue, pthread_run);
+ pthread_resched_resume(PS_UNALLOCED);
+ }
+
+ /* This thread will never run again */
+ PANIC();
+
+}
+
+/*----------------------------------------------------------------------
+ * Function: __pthread_is_valid
+ * Purpose: Scan the list of threads to see if a specified thread exists
+ * Args:
+ * pthread = The thread to scan for
+ * Returns:
+ * int = 1 if found, 0 if not
+ * Notes:
+ * The kernel is assumed to be locked
+ *----------------------------------------------------------------------*/
+int
+__pthread_is_valid( pthread_t pthread )
+{
+ int rtn = 0; /* Assume not found */
+ pthread_t t;
+
+ for( t = pthread_link_list; t; t = t->pll ) {
+ if( t == pthread ) {
+ rtn = 1; /* Found it */
+ break;
+ }
+ }
+
+ return rtn;
+}
+
+/* ==========================================================================
+ * __pthread_free()
+ */
+static inline void __pthread_free(pthread_t new_thread)
+{
+ pthread_sched_prevent();
+ new_thread->state = PS_UNALLOCED;
+ new_thread->attr.stacksize_attr = 0;
+ new_thread->attr.stackaddr_attr = NULL;
+ pthread_queue_enq(&pthread_alloc_queue, new_thread);
+ pthread_sched_resume();
+}
+/* ==========================================================================
+ * __pthread_alloc()
+ */
+/* static inline pthread_t __pthread_alloc(const pthread_attr_t *attr) */
+static pthread_t __pthread_alloc(const pthread_attr_t *attr)
+{
+ pthread_t thread;
+ void * stack;
+ void * old;
+
+ pthread_sched_prevent();
+ thread = pthread_queue_deq(&pthread_alloc_queue);
+ pthread_sched_resume();
+
+ if (thread) {
+ if (stack = attr->stackaddr_attr) {
+ __machdep_stack_repl(&(thread->machdep_data), stack);
+ } else {
+ if ((__machdep_stack_get(&(thread->machdep_data)) == NULL)
+ || (attr->stacksize_attr > thread->attr.stacksize_attr)) {
+ if (stack = __machdep_stack_alloc(attr->stacksize_attr)) {
+ __machdep_stack_repl(&(thread->machdep_data), stack);
+ } else {
+ __pthread_free(thread);
+ thread = NULL;
+ }
+ }
+ }
+ } else {
+ /* We should probable allocate several for efficiency */
+ if (thread = (pthread_t)malloc(sizeof(struct pthread))) {
+ /* Link new thread into list of all threads */
+
+ pthread_sched_prevent();
+ thread->state = PS_UNALLOCED;
+ thread->pll = pthread_link_list;
+ pthread_link_list = thread;
+ pthread_sched_resume();
+
+ if ((stack = attr->stackaddr_attr) ||
+ (stack = __machdep_stack_alloc(attr->stacksize_attr))) {
+ __machdep_stack_set(&(thread->machdep_data), stack);
+ } else {
+ __machdep_stack_set(&(thread->machdep_data), NULL);
+ __pthread_free(thread);
+ thread = NULL;
+ }
+ }
+ }
+ return(thread);
+}
+
+/* ==========================================================================
+ * pthread_create()
+ *
+ * After the new thread structure is allocated and set up, it is added to
+ * pthread_run_next_queue, which requires a sig_prevent(),
+ * sig_check_and_resume()
+ */
+int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+ void * (*start_routine)(void *), void *arg)
+{
+ pthread_t new_thread;
+ int nsec = 100000000;
+ int retval = OK;
+
+ if (! attr)
+ attr = &pthread_attr_default;
+
+ if (new_thread = __pthread_alloc(attr)) {
+
+ __machdep_pthread_create(&(new_thread->machdep_data),
+ start_routine, arg, attr->stacksize_attr, nsec, 0);
+
+ memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t));
+ if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
+ new_thread->pthread_priority = pthread_run->pthread_priority;
+ new_thread->attr.sched_priority = pthread_run->pthread_priority;
+ new_thread->attr.schedparam_policy =
+ pthread_run->attr.schedparam_policy;
+ } else {
+ new_thread->pthread_priority = new_thread->attr.sched_priority;
+ }
+
+ if (!(new_thread->attr.flags & PTHREAD_NOFLOAT)) {
+ machdep_save_float_state(new_thread);
+ }
+
+ /* Initialize signalmask */
+ new_thread->sigmask = pthread_run->sigmask;
+ sigemptyset(&(new_thread->sigpending));
+ new_thread->sigcount = 0;
+
+ pthread_queue_init(&(new_thread->join_queue));
+ new_thread->specific_data = NULL;
+ new_thread->specific_data_count = 0;
+ new_thread->cleanup = NULL;
+ new_thread->queue = NULL;
+ new_thread->next = NULL;
+ new_thread->flags = 0;
+
+ /* PTHREADS spec says we start with cancellability on and deferred */
+ SET_PF_CANCEL_STATE(new_thread, PTHREAD_CANCEL_ENABLE);
+ SET_PF_CANCEL_TYPE(new_thread, PTHREAD_CANCEL_DEFERRED);
+
+ new_thread->error_p = NULL;
+ new_thread->sll = NULL;
+
+ pthread_sched_prevent();
+
+
+ pthread_sched_other_resume(new_thread);
+ /*
+ * Assignment must be outside of the locked pthread kernel incase
+ * thread is a bogus address resulting in a seg-fault. We want the
+ * original thread to be capable of handling the resulting signal.
+ * --proven
+ */
+ (*thread) = new_thread;
+ } else {
+ retval = EAGAIN;
+ }
+ return(retval);
+}