[Nickle] nickle: Branch 'master' - 4 commits

Keith Packard keithp at keithp.com
Sun Feb 3 20:00:51 PST 2008


 Makefile.am          |    3 
 alarm.c              |    3 
 builtin-namespaces.h |    1 
 builtin-process.c    |  242 +++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin-thread.c     |   18 ++-
 builtin.c            |    1 
 builtin.h            |    6 +
 execute.c            |   15 +--
 main.c               |    2 
 nickle.h             |    8 -
 sched.c              |  202 ++++++++++++++++++++++--------------------
 test/Makefile.am     |    1 
 test/signal.5c       |   20 ++++
 value.h              |    7 -
 14 files changed, 412 insertions(+), 117 deletions(-)

New commits:
commit 116b96de8e915d8fd8c48d6bbc2334e4641c5e7f
Author: Keith Packard <keithp at keithp.com>
Date:   Sun Feb 3 15:31:45 2008 -0800

    Add pid/gid/uid functions in Process namespace

diff --git a/Makefile.am b/Makefile.am
index fd9266c..cded6fa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,7 +49,8 @@ nickle_SOURCES = \
 	builtin-command.c builtin-debug.c builtin-environ.c \
 	builtin-file.c builtin-math.c builtin-namespaces.h \
 	builtin-semaphore.c builtin-sockets.c builtin-string.c \
-	builtin-thread.c builtin-toplevel.c builtin.c builtin.h \
+	builtin-thread.c builtin-toplevel.c builtin-process.c \
+	builtin.c builtin.h \
 	builtin-foreign.c gram.y lex.l
 
 nickle_LDFLAGS=$(NICKLE_LDFLAGS)
diff --git a/builtin-namespaces.h b/builtin-namespaces.h
index 37d13e4..3356343 100644
--- a/builtin-namespaces.h
+++ b/builtin-namespaces.h
@@ -23,3 +23,4 @@ extern void import_Gcd_namespace(void);
 extern void import_Environ_namespace(void);
 extern void import_Socket_namespace(void);
 extern void import_Foreign_namespace(void);
+extern void import_Process_namespace(void);
diff --git a/builtin-process.c b/builtin-process.c
new file mode 100644
index 0000000..0a935ab
--- /dev/null
+++ b/builtin-process.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright © 1988-2008 Keith Packard and Bart Massey.
+ * All Rights Reserved.  See the file COPYING in this directory
+ * for licensing information.
+ */
+
+/*
+ * builtin-process.c
+ *
+ * provide builtin functions for the Process namespace
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <grp.h>
+
+#include "builtin.h"
+
+NamespacePtr ProcessNamespace;
+
+static Value
+do_Process_getuid (void)
+{
+    ENTER ();
+    RETURN (NewInt (getuid()));
+}
+
+static Value
+do_Process_geteuid (void)
+{
+    ENTER ();
+    RETURN (NewInt (geteuid()));
+}
+
+static Value
+do_Process_getgid (void)
+{
+    ENTER ();
+    RETURN (NewInt (getgid()));
+}
+
+static Value
+do_Process_getegid (void)
+{
+    ENTER ();
+    RETURN (NewInt (getegid()));
+}
+
+static Value
+do_Process_getgroups (void)
+{
+    ENTER ();
+    int	    n;
+    gid_t   *list;
+    Value   ret;
+    int	    i;
+
+    n = getgroups (0, NULL);
+    list = AllocateTemp (n * sizeof (gid_t));
+    getgroups (n, list);
+    ret = NewArray (False, False, typePrim[rep_integer], 1, &n);
+    for (i = 0; i < n; i++)
+	ArrayValueSet(&ret->array, i, NewInt (list[i]));
+    RETURN (ret);
+}
+
+static Value
+do_Process_getpid (void)
+{
+    ENTER ();
+    RETURN (NewInt (getpid()));
+}
+
+static Value
+error (Value value)
+{
+    int	err = errno;
+
+    RaiseStandardException (exception_system_error,
+			    FileGetErrorMessage (err),
+			    2, NewInt (err), value);
+    return Void;
+}
+
+static Value
+do_Process_setuid (Value uid)
+{
+    ENTER ();
+    int u = IntPart (uid, "Invalid uid");
+    if (aborting)
+	RETURN(Void);
+    
+    if (setuid (u) < 0)
+	RETURN (error (uid));
+	
+    RETURN (Void);
+}
+
+static Value
+do_Process_seteuid (Value euid)
+{
+    ENTER ();
+    int u = IntPart (euid, "Invalid euid");
+    if (aborting)
+	RETURN(Void);
+    
+    if (seteuid (u) < 0)
+	RETURN (error (euid));
+	
+    RETURN (Void);
+}
+
+static Value
+do_Process_setgid (Value gid)
+{
+    ENTER ();
+    int u = IntPart (gid, "Invalid gid");
+    if (aborting)
+	RETURN(Void);
+    
+    if (setgid (u) < 0)
+	RETURN (error (gid));
+	
+    RETURN (Void);
+}
+
+static Value
+do_Process_setegid (Value egid)
+{
+    ENTER ();
+    int u = IntPart (egid, "Invalid egid");
+    if (aborting)
+	RETURN(Void);
+    
+    if (setegid (u) < 0)
+	RETURN (error (egid));
+	
+    RETURN (Void);
+}
+
+static Value
+do_Process_setgroups (Value groups)
+{
+    ENTER ();
+    int	    n;
+    int	    i;
+    gid_t   *g;
+
+    n = ArrayLimits (&groups->array)[0];
+    g = AllocateTemp (n * sizeof (gid_t));
+    for (i = 0; i < n; i++) {
+	g[i] = IntPart (ArrayValueGet (&groups->array, i), "Invalid gid");
+	if (aborting)
+	    RETURN(Void);
+    }
+    
+    if (setgroups (n, g) < 0)
+	RETURN (error (groups));
+	
+    RETURN (Void);
+}
+
+void
+import_Process_namespace (void)
+{
+    ENTER ();
+
+    static const struct fbuiltin_0 funcs_0[] = {
+	{ do_Process_getuid, "getuid", "i", "", "\n"
+	    " int getuid ()\n"
+	    "\n"
+	    " Return the current uid\n" },
+	{ do_Process_geteuid, "geteuid", "i", "", "\n"
+	    " int geteuid ()\n"
+	    "\n"
+	    " Return the current effective uid\n" },
+	{ do_Process_getgid, "getgid", "i", "", "\n"
+	    " int getgid ()\n"
+	    "\n"
+	    " Return the current gid\n" },
+	{ do_Process_getegid, "getegid", "i", "", "\n"
+	    " int getegid ()\n"
+	    "\n"
+	    " Return the current effective gid\n" },
+	{ do_Process_getgroups, "getgroups", "Ai", "", "\n"
+	    " int[*] getgroups ()\n"
+	    "\n"
+	    " Return the list of additional groups\n" },
+	{ do_Process_getpid, "getpid", "i", "", "\n"
+	    " int getpid ()\n"
+	    "\n"
+	    " Return the current process id." },
+	{ 0 }
+    };
+    static const struct fbuiltin_1 funcs_1[] = {
+	{ do_Process_setuid, "setuid", "v", "i", "\n"
+	    " void setuid (int uid)\n"
+	    "\n"
+	    " Set the current uid." },
+	{ do_Process_seteuid, "seteuid", "v", "i", "\n"
+	    " void seteuid (int euid)\n"
+	    "\n"
+	    " Set the current euid." },
+	{ do_Process_setgid, "setgid", "v", "i", "\n"
+	    " void setgid (int gid)\n"
+	    "\n"
+	    " Set the current gid." },
+	{ do_Process_setegid, "setegid", "v", "i", "\n"
+	    " void setegid (int egid)\n"
+	    "\n"
+	    " Set the current egid." },
+	{ do_Process_setgroups, "setgroups", "v", "Ai", "\n"
+	    " void setgroups (int[*] groups)\n"
+	    "\n"
+	    " Set the list of additional groups." },
+	{ 0 }
+    };
+
+    static const struct ebuiltin excepts[] = {
+	{"system_error",    	exception_system_error,		"sEp", "\n"
+	    " system_error (string message, error_type error, poly value)\n"
+	    "\n"
+	    " Raised when a system function fails.\n"
+	    " 'message' is a printable error string.\n"
+	    " 'error' is a symbolic error code.\n"
+	    " 'value' is the value which failed.\n" },
+	{ 0, 0 },
+    };
+    const struct ebuiltin   *e;
+	
+    ProcessNamespace = BuiltinNamespace (/*parent*/ 0, "Process")->namespace.namespace;
+    
+    for (e = excepts; e->name; e++)
+	BuiltinAddException (&ProcessNamespace, e->exception, e->name, e->args, e->doc);
+
+    BuiltinFuncs0 (&ProcessNamespace, funcs_0);
+    BuiltinFuncs1 (&ProcessNamespace, funcs_1);
+    EXIT ();
+}
+
+    
diff --git a/builtin.c b/builtin.c
index 90bf617..40bc238 100644
--- a/builtin.c
+++ b/builtin.c
@@ -329,6 +329,7 @@ BuiltinInit (void)
     import_Environ_namespace();
     import_Socket_namespace();
     import_Foreign_namespace ();
+    import_Process_namespace ();
 
     /* Import builtin strings with predefined values */
     BuiltinStrings (svars);
diff --git a/nickle.h b/nickle.h
index f2a53cf..294cf46 100644
--- a/nickle.h
+++ b/nickle.h
@@ -761,6 +761,7 @@ typedef enum _standardException {
     exception_io_error,		    /* string integer file */
     exception_name_error,	    /* string integer string */
     exception_signal,		    /* integer */
+    exception_system_error,	    /* string integer poly */
     _num_standard_exceptions
 } StandardException;
 
commit 2ee7d1bc95bb2bbbbc5792ed11618a229133eb22
Author: Keith Packard <keithp at keithp.com>
Date:   Sun Feb 3 14:36:06 2008 -0800

    Signal exception arguments were not getting forwarded.
    
    Exception arguments must land in thread value register so that they can be
    passed to the exception handler (if any). Also, add a test for signaling.

diff --git a/sched.c b/sched.c
index 203a973..458ce80 100644
--- a/sched.c
+++ b/sched.c
@@ -29,6 +29,7 @@ _ThreadInsert (Value thread)
 	prev = &stopped;
 	break;
     case ThreadFinished:
+    default:
 	return;
     }
     for (; (t = *prev); prev = &t->thread.next)
@@ -51,6 +52,7 @@ _ThreadRemove (Value thread)
 	prev = &stopped;
 	break;
     case ThreadFinished:
+    default:
 	return;
     }
     for (; *prev != thread; prev = &(*prev)->thread.next);
@@ -1225,6 +1227,7 @@ SignalThread (Value thread, Value signal, Bool executing)
 	InstPtr	next;
 	
 	RaiseException (thread, except, args, &next);
+	thread->thread.continuation.value = args;
 	thread->thread.continuation.pc = next;
 	if (thread->thread.state == ThreadSuspended) {
 	    thread->thread.sleep = 0;
diff --git a/test/Makefile.am b/test/Makefile.am
index a40c63c..f3d78e4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -6,6 +6,7 @@ check_SCRIPTS=gcdtest.5c \
 	reftest.5c \
 	modtest.5c \
 	hashtest.5c \
+	signal.5c \
 	round.5c
 
 TESTS_ENVIRONMENT=NICKLESTART=$(top_srcdir)/builtin.5c NICKLEPATH=$(top_srcdir) ../nickle
diff --git a/test/signal.5c b/test/signal.5c
new file mode 100644
index 0000000..d23f185
--- /dev/null
+++ b/test/signal.5c
@@ -0,0 +1,20 @@
+int done = 0;
+
+void child () {
+    try {
+	while (true)
+	    sleep (100);
+    } catch Thread::signal (int i) {
+	done = i;
+    }
+}
+
+void check () {
+    thread t = fork child();
+    sleep (100);
+    Thread::send_signal (t, 12);
+    sleep (100);
+    assert (done == 12, "signal not delivered");
+}
+
+check ();
commit 6adae78f5e70be0031718e0e7ebeff81996951e3
Author: Keith Packard <keithp at keithp.com>
Date:   Sun Feb 3 07:22:28 2008 -0800

    Add signal exceptions, treat SIGINT as raise signal(2)
    
    SIGINT used to interrupt the current thread and enter the debugger with the
    thread 'interrupted'; in this state, the thread could be continued. However,
    this means that threads cannot catch SIGINT and cleanup at process exit.
    This commit changes all this around so that SIGINT simply raises a signal
    exception in all threads.
    
    This patch also keeps the interpreter running until all threads have exited.

diff --git a/alarm.c b/alarm.c
index 243be18..dad7f44 100644
--- a/alarm.c
+++ b/alarm.c
@@ -120,7 +120,8 @@ static Bool
 _sleepDone (void *closure)
 {
     Value   thread = closure;
-    ThreadClearState (thread, ThreadSuspended);
+    if (thread->thread.state == ThreadSuspended)
+	ThreadSetState (thread, ThreadRunning);
     return False;
 }
 
diff --git a/builtin-thread.c b/builtin-thread.c
index 5b16b4a..45acc5b 100644
--- a/builtin-thread.c
+++ b/builtin-thread.c
@@ -24,10 +24,6 @@ import_Thread_namespace()
 {
     ENTER ();
     static const struct fbuiltin_0 funcs_0[] = {
-        { do_Thread_cont, "cont", "i", "", "\n"
-	    " int cont ()\n"
-	    "\n"
-	    " Restarts any interrupted threads.\n" },
         { do_Thread_current, "current", "t", "", "\n"
 	    " thread current ()\n"
 	    "\n"
diff --git a/execute.c b/execute.c
index 7724469..fde8ef0 100644
--- a/execute.c
+++ b/execute.c
@@ -963,9 +963,7 @@ ThreadsRun (Value thread, Value lex)
 	    if (signalInterrupt)
 	    {
 		signalInterrupt = False;
-		if (thread)
-		    ThreadSetState (thread, ThreadInterrupted);
-		(void) write (2, "<abort>\n", 8);
+		ThreadsSignal (NewInt (SIGINT));
 	    }
 	    if (signalTimer)
 	    {
@@ -985,10 +983,15 @@ ThreadsRun (Value thread, Value lex)
 	    if (lex && !(lex->file.flags & (FileInputBlocked|FileOutputBlocked)))
 		break;
 	}
-	else if (thread && !Runnable (thread))
+	else if (thread && thread->thread.state == ThreadFinished)
 	    break;
 	else if (!running)
+	{
+	    /* when all threads are done, and all input is read, time to go */
+	    if (!lex && !stopped)
+		break;
 	    ThreadsBlock ();
+	}
 	else 
 	{
 	    ENTER ();
@@ -1442,7 +1445,8 @@ ThreadsRun (Value thread, Value lex)
 		    if (signalSuspend)
 		    {
 			signalSuspend = False;
-			ThreadSetState (thread, ThreadSuspended);
+			if (thread->thread.state == ThreadRunning)
+			    ThreadSetState (thread, ThreadSuspended);
 		    }
 		    if (signalFinished)
 		    {
@@ -1458,7 +1462,6 @@ ThreadsRun (Value thread, Value lex)
 		    if (signalError)
 		    {
 			signalError = False;
-			ThreadFinish (thread, True);
 		    }
 		    if (signalProfile)
 			signalProfile = False;
diff --git a/main.c b/main.c
index 491b390..2456c13 100644
--- a/main.c
+++ b/main.c
@@ -107,6 +107,8 @@ main (int argc, char **argv)
 	exit(1);
     }
     (void) yyparse ();
+    /* Wait for any running threads to execute */
+    ThreadsRun (0, 0);
     IoFini ();
     FileFini ();
     return lastThreadError;
diff --git a/nickle.h b/nickle.h
index 9eaef9c..f2a53cf 100644
--- a/nickle.h
+++ b/nickle.h
@@ -598,10 +598,10 @@ void	    ThreadStepped (Value thread);
 void	    ThreadsWakeup (Value sleep, WakeKind wake);
 void	    ThreadsRun (Value thread, Value lex);
 void	    ThreadsInterrupt (void);
+void	    ThreadsSignal (Value signal);
 void	    ThreadsContinue (void);
 void	    ThreadFinish (Value thread, Bool error);
 void	    ThreadSetState (Value thread, ThreadState state);
-void	    ThreadClearState (Value thread, ThreadState state);
 void	    ThreadInit (void);
 void	    TraceFunction (Value file, FramePtr frame, CodePtr code, ExprPtr name);
 void	    TraceFrame (Value file, FramePtr frame, ObjPtr obj, InstPtr pc, int depth);
@@ -631,12 +631,9 @@ InstPtr	    JumpStart (Value thread, ContinuationPtr continuation, Value ret);
 JumpPtr	    NewJump (TwixtPtr leave, TwixtPtr enter, 
 		     TwixtPtr parent, ContinuationPtr continuation, Value ret);
 
-#define Runnable(t)    (((t)->thread.state & ~(ThreadSuspended)) == 0)
-
 extern Value	running;    /* current thread */
 extern Value	stopped;    /* stopped threads */
 extern Bool	complete;   /* must complete current inst */
-extern int	runnable;   /* number of non-broken threads */
 extern Bool	profiling;  /* profiling is active */
 
 void	    InstDump (InstPtr inst, int indent, int i, int *branch, int maxbranch);
diff --git a/sched.c b/sched.c
index c34bd65..203a973 100644
--- a/sched.c
+++ b/sched.c
@@ -12,7 +12,6 @@
 
 Value   running;
 Value   stopped;
-int	runnable;
 Bool	signalException;
 
 extern void dumpSleep (void), dumpThreads (void);
@@ -22,14 +21,16 @@ _ThreadInsert (Value thread)
 {
     Value	*prev, t;
 
-    if (Runnable (thread))
-	++runnable;
-    if (thread->thread.state == ThreadRunning)
+    switch (thread->thread.state) {
+    case ThreadRunning:
 	prev = &running;
-    else if (thread->thread.state & ThreadFinished)
-	return;
-    else
+	break;
+    case ThreadSuspended:
 	prev = &stopped;
+	break;
+    case ThreadFinished:
+	return;
+    }
     for (; (t = *prev); prev = &t->thread.next)
 	if (t->thread.priority < thread->thread.priority)
 	    break;
@@ -42,14 +43,16 @@ _ThreadRemove (Value thread)
 {
     Value	*prev;
 
-    if (Runnable (thread))
-	--runnable;
-    if (thread->thread.state == ThreadRunning)
+    switch (thread->thread.state) {
+    case ThreadRunning:
 	prev = &running;
-    else if (thread->thread.state & ThreadFinished)
-	return;
-    else
+	break;
+    case ThreadSuspended:
 	prev = &stopped;
+	break;
+    case ThreadFinished:
+	return;
+    }
     for (; *prev != thread; prev = &(*prev)->thread.next);
     *prev = thread->thread.next;
 }
@@ -57,17 +60,12 @@ _ThreadRemove (Value thread)
 void
 ThreadSetState (Value thread, ThreadState state)
 {
-    _ThreadRemove (thread);
-    thread->thread.state |= state;
-    _ThreadInsert (thread);
-}
-
-void
-ThreadClearState (Value thread, ThreadState state)
-{
-    _ThreadRemove (thread);
-    thread->thread.state &= ~state;
-    _ThreadInsert (thread);
+    if (state != thread->thread.state)
+    {
+	_ThreadRemove (thread);
+	thread->thread.state = state;
+	_ThreadInsert (thread);
+    }
 }
 
 void
@@ -99,11 +97,11 @@ ThreadsWakeup (Value sleep, WakeKind kind)
     for (thread = stopped; thread; thread = next)
     {
 	next = thread->thread.next;
-	if ((thread->thread.state & ThreadSuspended) && 
+	if ((thread->thread.state == ThreadSuspended) && 
 	    thread->thread.sleep == sleep)
 	{
 	    thread->thread.sleep = 0;
-	    ThreadClearState (thread, ThreadSuspended);
+	    ThreadSetState (thread, ThreadRunning);
 	    if (kind == WakeOne)
 		break;
 	}
@@ -115,54 +113,13 @@ Bool	lastThreadError;
 void
 ThreadFinish (Value thread, Bool error)
 {
-    ThreadSetState (thread, ThreadFinished);
-    ThreadsWakeup (thread, WakeAll);
-    lastThreadError = error;
-}
-
-void
-ThreadsInterrupt (void)
-{
-    Value   thread, next;
-    Value   t;
-
-    if (running)
-	t = running;
-    else
-	t = stopped;
-    for (thread = stopped; thread; thread = next)
+    if (thread->thread.state != ThreadFinished)
     {
-	next = thread->thread.next;
-	if (Runnable (thread))
-	    --runnable;
-	thread->thread.state |= ThreadInterrupted;
-    }
-    for (thread = running; thread; thread = next)
-    {
-	next = thread->thread.next;
-	ThreadSetState (thread, ThreadInterrupted);
+	ThreadSetState (thread, ThreadFinished);
+	ThreadsWakeup (thread, WakeAll);
+	lastThreadError = error;
     }
 }
-
-static int
-ThreadContinue (void)
-{
-    Value   thread, next;
-    int	    n;
-
-    n = 0;
-    for (thread = stopped; thread; thread = next)
-    {
-	next = thread->thread.next;
-
-	if (thread->thread.state & ThreadInterrupted)
-	{
-	    n++;
-	    ThreadClearState (thread, ThreadInterrupted);
-	}
-    }
-    return n;
-}
 	    
 Value
 do_Thread_join (Value target)
@@ -175,7 +132,7 @@ do_Thread_join (Value target)
 				2, target, Void);
 	RETURN (Void);
     }
-    if ((target->thread.state & ThreadFinished) == 0)
+    if (target->thread.state != ThreadFinished)
     {
 	ThreadSleep (running, target, PrioritySync);
 	RETURN (Void);
@@ -186,18 +143,16 @@ do_Thread_join (Value target)
 static void
 ThreadListState (Value thread)
 {
-    int	state = thread->thread.state;
-    
-    if (state == ThreadRunning)
+    switch (thread->thread.state) {
+    case ThreadRunning:
 	FilePuts (FileStdout, " running");
-    else
-    {
-	if (state & ThreadSuspended)
-	    FilePuts (FileStdout, " suspended");
-	if (state & ThreadInterrupted)
-	    FilePuts (FileStdout, " interrupted");
-	if (state & ThreadFinished)
-	    FilePuts (FileStdout, " finished");
+	break;
+    case ThreadSuspended:
+	FilePuts (FileStdout, " suspended");
+	break;
+    case ThreadFinished:
+        FilePuts (FileStdout, " finished");
+	break;
     }
 }
 
@@ -293,15 +248,6 @@ do_Thread_get_priority (Value thread)
     RETURN (NewInt (thread->thread.priority));
 }
 
-Value
-do_Thread_cont (void)
-{
-    int	    n;
-    
-    n = ThreadContinue ();
-    return NewInt (n);
-}
-
 static int
 KillThread (Value thread)
 {
@@ -314,7 +260,7 @@ KillThread (Value thread)
 				2, thread, Void);
 	return 0;
     }
-    if (thread->thread.state & ThreadFinished)
+    if (thread->thread.state == ThreadFinished)
 	ret = 0;
     else
 	ret = 1;
@@ -894,8 +840,11 @@ JumpUnhandledException (Value thread)
 {
     Value   continuation = STACK_POP (thread->thread.continuation.stack);
     
+    /* make exec loop reschedule */
+    if (thread == running)
+	SetSignalError ();
     DebugStart (continuation);
-    SetSignalError ();
+    ThreadFinish (thread, True);
 }
 
 /*
@@ -1257,7 +1206,7 @@ JumpStandardException (Value thread, InstPtr *next)
 }
 
 static void
-SignalThread (Value thread, Value signal)
+SignalThread (Value thread, Value signal, Bool executing)
 {
     ENTER ();
     int		i = 1;
@@ -1265,7 +1214,7 @@ SignalThread (Value thread, Value signal)
     SymbolPtr	except = standardExceptions[exception_signal];
     
     ArrayValueSet (&args->array, 0, signal);
-    if (thread == running)
+    if (thread == running && executing)
     {
 	standardException = exception_signal;
 	standardExceptionArgs = args;
@@ -1277,18 +1226,38 @@ SignalThread (Value thread, Value signal)
 	
 	RaiseException (thread, except, args, &next);
 	thread->thread.continuation.pc = next;
-	if (thread->thread.state & ThreadSuspended) {
+	if (thread->thread.state == ThreadSuspended) {
 	    thread->thread.sleep = 0;
-	    ThreadClearState (thread, ThreadSuspended);
+	    ThreadSetState (thread, ThreadRunning);
 	}
     }
     EXIT ();
 }
 
+void
+ThreadsSignal (Value signal)
+{
+    ENTER ();
+    Value   thread, next;
+
+    /* do running first -- signalling makes threads run */
+    for (thread = running; thread; thread = next)
+    {
+	next = thread->thread.next;
+	SignalThread (thread, signal, False);
+    }
+    for (thread = stopped; thread; thread = next)
+    {
+	next = thread->thread.next;
+	SignalThread (thread, signal,  False);
+    }
+    EXIT ();
+}
+
 Value
 do_Thread_signal (Value thread, Value signal)
 {
     ENTER ();
-    SignalThread (thread, signal);
+    SignalThread (thread, signal, True);
     RETURN (Void);
 }
diff --git a/value.h b/value.h
index fbebfe8..e31e1ae 100644
--- a/value.h
+++ b/value.h
@@ -743,10 +743,9 @@ typedef struct _continuation {
 } Continuation;
 
 typedef enum _ThreadState {
-    ThreadRunning = 0,
-    ThreadSuspended = 1,
-    ThreadInterrupted = 2,
-    ThreadFinished = 4
+    ThreadRunning,
+    ThreadSuspended,
+    ThreadFinished
 } ThreadState;
 
 typedef struct _thread {
commit 689ea14db8ca29f3338a03e71be5865089972488
Author: Keith Packard <keithp at keithp.com>
Date:   Sat Feb 2 22:07:54 2008 +1100

    Add 'signal' exception and 'send_signal' function.
    
    The 'send_signal' function raises a 'signal' exception in another thread,
    causing it to abort processing immediately.

diff --git a/builtin-thread.c b/builtin-thread.c
index 01d5040..5b16b4a 100644
--- a/builtin-thread.c
+++ b/builtin-thread.c
@@ -61,6 +61,11 @@ import_Thread_namespace()
 	    "\n"
 	    " Set 't's scheduling priority to 'priority'.\n"
 	    " Return 'priority.\n" },
+	{ do_Thread_signal, "send_signal", "v", "ti", "\n"
+	    " void signal (thread t, int signal)\n"
+	    "\n"
+	    " Raise the signal exception in thread 't'\n"
+	    " passing 'signal' as the argument\n" },
         { 0 }
     };
 
@@ -75,11 +80,20 @@ import_Thread_namespace()
         { 0 }
     };
 
+    static const struct ebuiltin excepts[] = {
+	{"signal",	exception_signal,	"i", "\n"
+	    " signal (int signal)\n"
+	    "\n"
+	    " Sent from the Thread::send_signal function.\n" },
+	{ 0 },
+    };
+
     ThreadNamespace = BuiltinNamespace (/*parent*/ 0, "Thread")->namespace.namespace;
 
     BuiltinFuncs0 (&ThreadNamespace, funcs_0);
     BuiltinFuncs1 (&ThreadNamespace, funcs_1);
     BuiltinFuncs2 (&ThreadNamespace, funcs_2);
     BuiltinFuncsV (&ThreadNamespace, funcs_v);
+    BuiltinExceptions (&ThreadNamespace, excepts);
     EXIT ();
 }
diff --git a/builtin.h b/builtin.h
index 09ed4ee..f90a893 100644
--- a/builtin.h
+++ b/builtin.h
@@ -108,6 +108,12 @@ BuiltinAddFunction (NamespacePtr *namespacep, char *name, char *ret_format,
 	char *doc; \
     }
 
+#define BuiltinExceptions(ns, e) do {\
+    const struct ebuiltin   *ei; \
+    for (ei = (e); ei->name; ei++) { \
+	BuiltinAddException ((ns), ei->exception, ei->name, ei->args, ei->doc); \
+    } } while (0)
+    
 #define BuiltinFuncsGeneric(ns, funcs, stype, bitem, jump) do { \
     BuiltinFunc f; const struct stype *fi; \
     for (fi = (funcs); fi->name; fi++) { \
diff --git a/nickle.h b/nickle.h
index c5ad821..9eaef9c 100644
--- a/nickle.h
+++ b/nickle.h
@@ -763,6 +763,7 @@ typedef enum _standardException {
     exception_open_error,	    /* string integer string */
     exception_io_error,		    /* string integer file */
     exception_name_error,	    /* string integer string */
+    exception_signal,		    /* integer */
     _num_standard_exceptions
 } StandardException;
 
@@ -932,6 +933,7 @@ Value	do_profile (Value);
 
 /* two argument builtins */
 Value	do_Thread_set_priority (Value, Value);
+Value	do_Thread_signal (Value, Value);
 Value	do_File_open (Value, Value);
 Value	do_gcd (Value, Value);
 Value	do_xor (Value, Value);
diff --git a/sched.c b/sched.c
index 573dce3..c34bd65 100644
--- a/sched.c
+++ b/sched.c
@@ -1233,9 +1233,8 @@ RaiseStandardException (StandardException   se,
     i = argc + 1;
     args = NewArray (False, False, typePoly, 1, &i);
     ArrayValueSet (&args->array, 0, NewStrString (string));
-    if (argc)
-	for (i = 0; i < argc; i++)
-	    ArrayValueSet (&args->array, i + 1, va_arg (va, Value));
+    for (i = 0; i < argc; i++)
+	ArrayValueSet (&args->array, i + 1, va_arg (va, Value));
     standardException = se;
     standardExceptionArgs = args;
     SetSignalException ();
@@ -1256,3 +1255,40 @@ JumpStandardException (Value thread, InstPtr *next)
     standardExceptionArgs = 0;
     RETURN (args);
 }
+
+static void
+SignalThread (Value thread, Value signal)
+{
+    ENTER ();
+    int		i = 1;
+    Value	args = NewArray (False, False, typePoly, 1, &i);
+    SymbolPtr	except = standardExceptions[exception_signal];
+    
+    ArrayValueSet (&args->array, 0, signal);
+    if (thread == running)
+    {
+	standardException = exception_signal;
+	standardExceptionArgs = args;
+	SetSignalException ();
+    }
+    else if (except)
+    {
+	InstPtr	next;
+	
+	RaiseException (thread, except, args, &next);
+	thread->thread.continuation.pc = next;
+	if (thread->thread.state & ThreadSuspended) {
+	    thread->thread.sleep = 0;
+	    ThreadClearState (thread, ThreadSuspended);
+	}
+    }
+    EXIT ();
+}
+
+Value
+do_Thread_signal (Value thread, Value signal)
+{
+    ENTER ();
+    SignalThread (thread, signal);
+    RETURN (Void);
+}


More information about the Nickle mailing list