[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Help-smalltalk] [PATCH] gst-remote tool
From: |
Paolo Bonzini |
Subject: |
[Help-smalltalk] [PATCH] gst-remote tool |
Date: |
Fri, 08 Feb 2008 10:18:45 +0100 |
User-agent: |
Thunderbird 2.0.0.9 (Macintosh/20071031) |
This patch implements the beginnings of a remote control tool for GNU
Smalltalk. It is based on Mike Anderson's GSTI project from
http://www.mail-archive.com/address@hidden/msg00339.html though
in practice I rewrote all the code. Still, the credit for the
multiplexing transcript idea, and especially for using the Compiler
package to have a working multiplexing transcript in the first place
(!), goes to him.
I like a lot the way options like --snapshot, --pid, --kill are
implemented: instead of having a complicated protocol, I just send
Smalltalk commands like "ObjectMemory quit" or "Smalltalk getpid
printNl". getpid(2) is accessed via DLD.
I found a typo in Compiler; that's been backported to the 3.0 branch.
Startup is slow mostly because the TCP package has to be loaded. You
can improve that with a pre-prepared image that has the TCP package in
it; I'll see if I can do something else.
There is still no interface to Swazoo, but that's a minor improvement
compared to having the tool in the first place.
Paolo
diff --git a/Makefile.am b/Makefile.am
index 013a7fe..0e03028 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -118,7 +118,8 @@ gst_tool_LDADD = libgst/libgst.la lib-src/library.la
gst_tool_DEPENDENCIES = libgst/libgst.la lib-src/library.la
gst_tool_LDFLAGS = -export-dynamic
-GST_EXTRA_TOOLS = gst-reload gst-sunit gst-blox gst-package gst-convert gst-doc
+GST_EXTRA_TOOLS = gst-reload gst-sunit gst-blox gst-package gst-convert \
+ gst-doc gst-remote
uninstall-local::
@for i in gst-load $(GST_EXTRA_TOOLS); do \
diff --git a/NEWS b/NEWS
index 097363e..03b552f 100644
--- a/NEWS
+++ b/NEWS
@@ -8,8 +8,12 @@ o ObjectMemory>>#snapshot and ObjectMemory>>#snapshot:
return false in
snapshot. Note that this does not apply to CallinProcesses, since
those are stopped in saved images (will this be true in 3.1?).
+o New tool gst-remote allows remote control of a GNU Smalltalk VM
+ via a TCP socket.
+
o Unbuffered sockets available from class TCP.StreamSocket.
+
New goodies:
o Swazoo web server
diff --git a/kernel/ExcHandling.st b/kernel/ExcHandling.st
index ae2a9bd..b758de0 100644
--- a/kernel/ExcHandling.st
+++ b/kernel/ExcHandling.st
@@ -751,8 +751,7 @@ Object extend [
<category: 'built ins'>
| debugger debuggerClass context |
- Transcript initialize.
- stdout flush.
+ Transcript flush.
debugger := Processor activeDebugger.
debugger isNil ifFalse: [^debugger stopInferior: message].
debuggerClass := thisContext debuggerClass.
@@ -761,7 +760,7 @@ Object extend [
"Default behavior - print backtrace"
RegressionTesting ifFalse: [self basicPrint].
- stdout
+ Transcript
nextPutAll: ' error: ';
display: message;
nl.
@@ -771,7 +770,6 @@ Object extend [
[context isInternalExceptionHandlingContext]
whileTrue: [context := context parentContext].
context backtraceOn: stdout].
- stdout flush.
ContextPart unwind
]
diff --git a/packages/stinst/compiler/StartCompiler.st
b/packages/stinst/compiler/StartCompiler.st
index 133e109..06367b7 100644
--- a/packages/stinst/compiler/StartCompiler.st
+++ b/packages/stinst/compiler/StartCompiler.st
@@ -318,7 +318,7 @@ Behavior extend [
^STInST.STEvaluationDriver new
parseSmalltalk: aString
with: self evaluatorClass
- errorBlock:
+ onError:
[:l :m |
^aBlock
value: 'a Smalltalk String'
diff --git a/gst-tool.c b/gst-tool.c
index c2bec1f..8b3aeb2 100644
--- a/gst-tool.c
+++ b/gst-tool.c
@@ -63,10 +63,16 @@
#include <stdio.h>
#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
const char *program_name;
const char *kernel_dir;
const char *image_file;
int flags = GST_NO_TTY;
+int run_as_daemon;
+int usage;
struct tool {
const char *name;
@@ -120,6 +126,12 @@ struct tool tools[] = {
-n|--namespace: -o|--output: --kernel-directory:",
NULL
},
+ {
+ "gst-remote", "scripts/Remote.st",
+ "-h|--help --version --daemon --server -p|--port -f|--file: -e|--eval: \
+ --pid --kill --snapshot:: -I|--image-file: --kernel-directory:",
+ NULL
+ },
{ NULL, NULL, NULL, NULL }
};
@@ -243,7 +255,61 @@ parse_option (int short_opt, const char *long_opt, const
char *arg)
option_error ("duplicate --kernel-directory option");
kernel_dir = arg;
}
+
+ if (long_opt && !strcmp (long_opt, "daemon"))
+ {
+#ifdef HAVE_FORK
+ run_as_daemon = 1;
+#else
+ fprintf (stderr, "Daemon operation not supported.");
+ exit (77);
+#endif
+ }
+
+ if (long_opt && !strcmp (long_opt, "version"))
+ usage = 1;
+
+ if (short_opt == 'h'
+ || (long_opt && !strcmp (long_opt, "help")))
+ usage = 1;
+}
+
+#ifdef HAVE_FORK
+static void
+fork_daemon (void)
+{
+ int child_pid;
+
+#ifdef SIGHUP
+ signal (SIGHUP, SIG_IGN);
+#endif
+
+ child_pid = fork();
+ if (child_pid < 0)
+ {
+ perror("Failed to fork daemon");
+ exit(1);
+ }
+
+ /* Stop parent. */
+ if (child_pid != 0)
+ exit (0);
+
+ /* Detach and spawn server.
+ Create a new SID for the child process */
+#ifdef HAVE_SETSID
+ if (setsid() < 0)
+ {
+ perror("setsid failed");
+ exit(1);
+ }
+#endif
+
+#ifdef SIGHUP
+ signal (SIGHUP, SIG_DFL);
+#endif
}
+#endif
int
parse_short_options (const char *name, const char *arg)
@@ -395,6 +461,11 @@ main(int argc, const char **argv)
setup_options (tools[i].options);
parse_options (&argv[1]);
+#ifdef HAVE_FORK
+ if (run_as_daemon && !usage)
+ fork_daemon ();
+#endif
+
if (tools[i].force_opt)
{
smalltalk_argv = alloca (sizeof (const char *) * (argc + 1));
diff --git a/scripts/Remote.st b/scripts/Remote.st
new file mode 100644
index 0000000..d4a29ab
--- /dev/null
+++ b/scripts/Remote.st
@@ -0,0 +1,203 @@
+"======================================================================
+|
+| GNU Smalltalk remote control script
+|
+|
+ ======================================================================"
+
+
+"======================================================================
+|
+| Copyright 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
+| Written by Paolo Bonzini.
+|
+| This file is part of GNU Smalltalk.
+|
+| GNU Smalltalk 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.
+|
+| GNU Smalltalk 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
+| GNU Smalltalk; see the file COPYING. If not, write to the Free Software
+| Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+|
+ ======================================================================"
+
+PackageLoader fileInPackage: 'TCP'.
+DLD addLibrary: 'libc'.
+
+SystemDictionary extend [
+ getpid [
+ <cCall: 'getpid' returning: #int args: #()>
+ ]
+]
+
+TextCollector subclass: MultiplexingTextCollector [
+ | default outputs |
+ initialize [
+ outputs := LookupTable new.
+ super initialize
+ ]
+
+ register: aStream [
+ semaphore critical: [ outputs at: Processor activeProcess put: aStream ]
+ ]
+
+ unregister [
+ semaphore critical: [ outputs removeKey: Processor activeProcess ]
+ ]
+
+ primNextPutAll: aString [
+ | dest |
+ dest := outputs at: Processor activeProcess ifAbsent: [ nil ].
+ dest isNil
+ ifTrue: [ super primNextPutAll: aString ]
+ ifFalse: [ dest nextPutAllFlush: aString ]
+ ]
+]
+
+| helpString commands server port host |
+commands := OrderedCollection new.
+server := false.
+port := 5432.
+host := nil.
+
+helpString :=
+'Usage:
+ gst-load [ flag ... ] package ...
+
+Options:
+ --daemon start background server
+ --server start daemon
+ -p --port=PORT connect/listen on given port (default 5432)
+ -f --file=FILE file in FILE
+ -e --eval=CODE evaluate CODE
+ --kill kill daemon
+ --snapshot[=FILE] save image
+ --pid print daemon pid
+ -h --help show this message
+ --version print version information and exit
+'.
+
+"Parse the command-line arguments."
+Smalltalk
+ arguments: '-h|--help --version --daemon --server -p|--port -f|--file:
+ -e|--eval: --pid --kill --snapshot::
+ -I|--image: --kernel-directory:'
+ do: [ :opt :arg |
+
+ opt = 'help' ifTrue: [
+ helpString displayOn: stdout.
+ ObjectMemory quit: 0 ].
+
+ opt = 'version' ifTrue: [
+ ('gst-remote - %1' % {Smalltalk version}) displayNl.
+ ObjectMemory quit: 0 ].
+
+ opt = 'daemon' ifTrue: [
+ server := true ].
+
+ opt = 'server' ifTrue: [
+ server := true ].
+
+ opt = 'port' ifTrue: [
+ port := arg asInteger ].
+
+ opt = 'file' ifTrue: [
+ commands add: 'FileStream fileIn: ',
+ (Directory append: arg to: Directory working) storeString
].
+
+ opt = 'eval' ifTrue: [
+ commands add: arg ].
+
+ opt = 'pid' ifTrue: [
+ commands add: 'Smalltalk getpid printNl' ].
+
+ opt = 'kill' ifTrue: [
+ commands add: 'ObjectMemory quit: 0' ].
+
+ opt = 'snapshot' ifTrue: [
+ arg isNil
+ ifTrue: [ commands add: 'ObjectMemory snapshot' ]
+ ifFalse: [ commands add: 'ObjectMemory snapshot: ',
+ (Directory append: arg to: Directory
working) storeString ] ].
+
+ opt isNil ifTrue: [
+ host isNil ifFalse: [
+ helpString displayOn: stderr.
+ ObjectMemory quit: 1 ].
+ host := arg ] ]
+
+ ifError: [
+ helpString displayOn: stderr.
+ ObjectMemory quit: 1 ].
+
+server ifTrue: [
+ PackageLoader fileInPackage: 'Compiler'.
+ "PackageLoader fileInPackage: 'Swazoo'."
+ s := TCP.ServerSocket port: port bindTo: host.
+ Transcript := MultiplexingTextCollector message: Transcript message.
+ [
+ [
+ [
+ s waitForConnection.
+ conn := s accept.
+ [
+ [ conn isPeerAlive ] whileTrue: [
+ Transcript register: conn.
+ Behavior
+ evaluate: (conn upTo: $<0>)
+ to: nil
+ ifError: [ :fname :line :msg |
+ conn nextPutAll: ('Error at line %1: %2
+' % { line. msg }) ].
+ conn nextPut: $<0>; flush.
+ Transcript unregister.
+ ].
+ [ conn close ] on: Error do: [ :ex | ex return ]
+ ] fork
+ ] repeat
+ ]
+ on: Error
+ do: [ :ex |
+ ('gst-remote server: ', ex messageText, '
+') displayOn: stderr.
+ ex pass.
+ ObjectMemory quit: 1 ].
+ ] fork.
+ Transcript nextPutAll: 'gst-remote server started.'; nl ].
+
+[
+ commands isEmpty ifFalse: [
+ s := host isNil
+ ifTrue: [ TCP.Socket remote: TCP.IPAddress anyLocalAddress port:
port ]
+ ifFalse: [ TCP.Socket remote: host port: port ].
+ commands do: [ :each |
+ s nextPutAll: each; nextPut: $<0>; flush.
+ [ s peekFor: $<0> ] whileFalse: [
+ stdout nextPut: s next; flush.
+ s available
+ ifFalse: [ stdout flush ].
+ s isPeerAlive
+ ifFalse: [ self nextPutAll: 'gst-remote: server
unavailable' ] ]
+ ].
+ s close ]
+]
+ on: Error
+ do: [ :ex |
+ s isPeerAlive ifFalse: [ s close. ex return ].
+ ('gst-remote: ', ex messageText, '
+') displayOn: stderr.
+ "ex pass."
+ server
+ ifTrue: [ stderr flush ]
+ ifFalse: [ ObjectMemory quit: 1 ] ].
+
+server
+ ifTrue: [ Processor activeProcess suspend ]
+ ifFalse: [ ObjectMemory quit ]
- [Help-smalltalk] [PATCH] gst-remote tool,
Paolo Bonzini <=