[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