-/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- *
- * As a special exception, the Free Software Foundation gives permission
- * for additional uses of the text contained in its release of GUILE.
- *
- * The exception is that, if you link the GUILE library with other files
- * to produce an executable, this does not by itself cause the
- * resulting executable to be covered by the GNU General Public License.
- * Your use of that executable is in no way restricted on account of
- * linking the GUILE library code into it.
- *
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This exception applies only to the code released by the
- * Free Software Foundation under the name GUILE. If you copy
- * code from other Free Software Foundation releases into a copy of
- * GUILE, as the General Public License permits, the exception does
- * not apply to the code that you add in this way. To avoid misleading
- * anyone as to the status of such modified files, you must delete
- * this exception notice from them.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * If you write modifications of your own for GUILE, it is your choice
- * whether to permit this exception to apply to your modifications.
- * If you do not wish that, delete this exception notice. */
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
\f
-/* $Id: coop.c,v 1.31 2002-08-17 20:39:35 ghouston Exp $ */
+/* $Id: coop.c,v 1.39 2006-04-17 00:05:38 kryde Exp $ */
/* Cooperative thread library, based on QuickThreads */
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <stdio.h>
#ifdef HAVE_UNISTD_H
q->t.all_prev = NULL;
q->t.all_next = NULL;
-#ifdef GUILE_ISELECT
q->t.nfds = 0;
q->t.readfds = NULL;
q->t.writefds = NULL;
q->t.exceptfds = NULL;
q->t.timeoutp = 0;
-#endif
}
t->all_next->all_prev = t->all_prev;
}
-#ifdef GUILE_ISELECT
/* Insert thread t into the ordered queue q.
q is ordered after wakeup_time. Threads which aren't sleeping but
waiting for I/O go last into the queue. */
if (t->next == &q->t)
q->tail = t;
}
-#endif
+\f
-\f/* Thread routines. */
+/* Thread routines. */
coop_q_t coop_global_runq; /* A queue of runable threads. */
coop_q_t coop_global_sleepq; /* A queue of sleeping threads. */
#endif
}
-/* Return the next runnable thread. If no threads are currently runnable,
- and there are sleeping threads - wait until one wakes up. Otherwise,
- return NULL. */
-
-#ifndef GUILE_ISELECT
-coop_t *
-coop_next_runnable_thread()
-{
- int sleepers;
- coop_t *t;
- time_t now;
-
- do {
- sleepers = 0;
- now = time(NULL);
-
- /* Check the sleeping queue */
- while ((t = coop_qget(&coop_global_sleepq)) != NULL)
- {
- sleepers++;
- if (t->wakeup_time <= now)
- coop_qput(&coop_global_runq, t);
- else
- coop_qput(&coop_tmp_queue, t);
- }
- while ((t = coop_qget(&coop_tmp_queue)) != NULL)
- coop_qput(&coop_global_sleepq, t);
-
- t = coop_qget (&coop_global_runq);
-
- } while ((t == NULL) && (sleepers > 0));
-
- return t;
-}
-#endif
-
void
coop_start()
{
coop_new_mutex_init (coop_m *m, coop_mattr *attr)
{
m->owner = NULL;
+ m->level = 0;
coop_qinit(&(m->waiting));
return 0;
}
m->owner = coop_global_curr;
return 0;
}
+ else if (m->owner == coop_global_curr)
+ {
+ m->level++;
+ return 0;
+ }
else
return EBUSY;
}
{
m->owner = coop_global_curr;
}
+ else if (m->owner == coop_global_curr)
+ {
+ m->level++;
+ }
else
{
coop_t *old, *newthread;
/* Record the current top-of-stack before going to sleep */
coop_global_curr->top = &old;
-#ifdef GUILE_ISELECT
newthread = coop_wait_for_runnable_thread();
if (newthread == coop_global_curr)
coop_abort ();
-#else
- newthread = coop_next_runnable_thread();
-#endif
old = coop_global_curr;
coop_global_curr = newthread;
QT_BLOCK (coop_yieldhelp, old, &(m->waiting), newthread->sp);
{
coop_t *old, *newthread;
- newthread = coop_qget (&(m->waiting));
- if (newthread != NULL)
+ if (m->level == 0)
{
- /* Record the current top-of-stack before going to sleep */
- coop_global_curr->top = &old;
-
- old = coop_global_curr;
- coop_global_curr = newthread;
- /* The new thread came into m->waiting through a lock operation.
- It now owns this mutex. */
- m->owner = coop_global_curr;
- QT_BLOCK (coop_yieldhelp, old, &coop_global_runq, newthread->sp);
+ newthread = coop_qget (&(m->waiting));
+ if (newthread != NULL)
+ {
+ /* Record the current top-of-stack before going to sleep */
+ coop_global_curr->top = &old;
+
+ old = coop_global_curr;
+ coop_global_curr = newthread;
+ /* The new thread came into m->waiting through a lock operation.
+ It now owns this mutex. */
+ m->owner = coop_global_curr;
+ QT_BLOCK (coop_yieldhelp, old, &coop_global_runq, newthread->sp);
+ }
+ else
+ {
+ m->owner = NULL;
+ }
}
+ else if (m->level > 0)
+ m->level--;
else
- {
- m->owner = NULL;
- }
+ abort (); /* XXX */
+
return 0;
}
{
m->owner = NULL;
/*fixme* Should we really wait here? Isn't it OK just to proceed? */
-#ifdef GUILE_ISELECT
newthread = coop_wait_for_runnable_thread();
if (newthread == coop_global_curr)
coop_abort ();
-#else
- newthread = coop_next_runnable_thread();
-#endif
}
coop_global_curr->top = &old;
old = coop_global_curr;
int
coop_condition_variable_timed_wait_mutex (coop_c *c,
coop_m *m,
- const struct timespec *abstime)
+ const scm_t_timespec *abstime)
{
coop_t *old, *t;
#ifdef ETIMEDOUT
else
{
m->owner = NULL;
-#ifdef GUILE_ISELECT
coop_global_curr->timeoutp = 1;
coop_global_curr->wakeup_time.tv_sec = abstime->tv_sec;
coop_global_curr->wakeup_time.tv_usec = abstime->tv_nsec / 1000;
coop_timeout_qinsert (&coop_global_sleepq, coop_global_curr);
t = coop_wait_for_runnable_thread();
-#else
- /*fixme* Implement!*/
- t = coop_next_runnable_thread();
-#endif
}
if (t != coop_global_curr)
{
}
int
-coop_condition_variable_signal (coop_c *c)
+coop_condition_variable_broadcast (coop_c *c)
{
coop_t *newthread;
return 0;
}
+int
+coop_condition_variable_signal (coop_c *c)
+{
+ return coop_condition_variable_broadcast (c);
+}
+
+
/* {Keys}
*/
#ifdef GUILE_PTHREAD_COMPAT
/* 1K room for the cond wait routine */
-#ifdef SCM_STACK_GROWS_UP
-#define COOP_STACK_ROOM (256)
+#if SCM_STACK_GROWS_UP
+# define COOP_STACK_ROOM (256)
#else
-#define COOP_STACK_ROOM (-256)
+# define COOP_STACK_ROOM (-256)
#endif
static void *
free (coop_global_curr->joining);
}
-#ifdef GUILE_ISELECT
scm_I_am_dead = 1;
do {
newthread = coop_wait_for_runnable_thread();
} while (newthread == coop_global_curr);
scm_I_am_dead = 0;
-#else
- newthread = coop_next_runnable_thread();
-#endif
coop_all_qremove (&coop_global_allq, coop_global_curr);
old = coop_global_curr;
coop_global_curr = newthread;
coop_qinit((coop_q_t *) t->joining);
}
-#ifdef GUILE_ISELECT
newthread = coop_wait_for_runnable_thread();
if (newthread == coop_global_curr)
return;
-#else
- newthread = coop_next_runnable_thread();
-#endif
old = coop_global_curr;
coop_global_curr = newthread;
QT_BLOCK (coop_yieldhelp, old, (coop_q_t *) t->joining, newthread->sp);
/* There may be no other runnable threads. Return if this is the
case. */
-#if GUILE_ISELECT
if (newthread == coop_global_curr)
return;
-#else
- if (newthread == NULL)
- return;
-#endif
old = coop_global_curr;
return NULL;
}
-#ifdef GUILE_ISELECT
-
unsigned long
scm_thread_usleep (unsigned long usec)
{
return slept > sec ? 0 : sec - slept;
}
-#else /* GUILE_ISELECT */
-
-unsigned long
-scm_thread_sleep (unsigned long s)
-{
- coop_t *newthread, *old;
- time_t now = time (NULL);
- coop_global_curr->wakeup_time = now + s;
-
- /* Put the current thread on the sleep queue */
- coop_qput (&coop_global_sleepq, coop_global_curr);
-
- newthread = coop_next_runnable_thread();
-
- /* If newthread is the same as the sleeping thread, do nothing */
- if (newthread == coop_global_curr)
- return s;
-
- old = coop_global_curr;
-
- coop_global_curr = newthread;
- QT_BLOCK (coop_sleephelp, old, NULL, newthread->sp);
-
- return s;
-}
-
-unsigned long
-scm_thread_usleep (unsigned long usec)
-{
- /* We're so cheap. */
- scm_thread_sleep (usec / 1000000);
- return 0; /* Maybe we should calculate actual time slept,
- but this is faster... :) */
-}
-
-#endif /* GUILE_ISELECT */
-
/*
Local Variables:
c-file-style: "gnu"