[RavenclawDev 287] [928] Pythia: 1) Extended Pythia to support remote dynamic configuration.

tk@edam.speech.cs.cmu.edu tk at edam.speech.cs.cmu.edu
Tue Jul 3 23:00:26 EDT 2007


An HTML attachment was scrubbed...
URL: http://mailman.srv.cs.cmu.edu/pipermail/ravenclaw-developers/attachments/20070703/00da9b6e/attachment-0001.html
-------------- next part --------------

Property changes on: Pythia/PythiaDynamicClient
___________________________________________________________________
Name: svn:ignore
   + *.ncb
*.suo
*.user


Added: Pythia/PythiaDynamicClient/Debug/PythiaDynamicClient.lib
===================================================================
(Binary files differ)


Property changes on: Pythia/PythiaDynamicClient/Debug/PythiaDynamicClient.lib
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: Pythia/PythiaDynamicClient/PythiaDynamicClient.cpp
===================================================================
--- Pythia/PythiaDynamicClient/PythiaDynamicClient.cpp	                        (rev 0)
+++ Pythia/PythiaDynamicClient/PythiaDynamicClient.cpp	2007-07-04 03:00:24 UTC (rev 928)
@@ -0,0 +1,70 @@
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#error fixme
+#endif
+
+#include <iostream>
+#include <sstream>
+
+#include "PythiaDynamicClient.h"
+
+using namespace std;
+
+namespace Pythia {
+
+  const short Message::_port = 11044;
+
+  Message::Message(const string& cmd, const string title, const string dir) : _cmd(cmd), _title(title), _dir(dir) {
+#ifdef WIN32
+    WSADATA wsaData;
+    if(WSAStartup(MAKEWORD(2,0),&wsaData)!=0) {
+      cerr << "Socket initialization error" << endl;
+    }
+#endif
+  }
+
+  void Message::send(const string& host) const {
+    SOCKET sockfd;
+    if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+      cerr << "Invalid socket " << GetLastError() << endl;
+      return;
+    }
+
+    SOCKADDR_IN servaddr;
+    {
+      memset(&servaddr, 0, sizeof(servaddr));
+      servaddr.sin_family = AF_INET;
+      servaddr.sin_port = htons(_port);
+      struct hostent* hp;
+      if((hp = gethostbyname(host.c_str())) == NULL) {
+        cerr << "Unable to get hostent for " << host << endl;
+        return;
+      }
+      memcpy(&servaddr.sin_addr, (hp->h_addr_list)[0], sizeof(struct in_addr));
+    }
+
+    int lConnect;
+    if((lConnect = connect(sockfd,(SOCKADDR *)&servaddr,sizeof(SOCKADDR_IN))) != 0) {
+      cerr << "Connect Error" << endl;
+      return;
+    }
+
+    string msg = formMessage();
+    if(::send(sockfd, msg.c_str(), (int)msg.length() ,0) < (int)msg.length()) {
+      cerr << "Send Error" << endl;
+    }
+    
+    closesocket(sockfd);
+  }
+
+  string Message::formMessage() const {
+    ostringstream ret;
+    ret << "PROCESS: " << _cmd << endl;
+    ret << "PROCESS_MONITOR_ARGS: --start" << endl;
+    if(!_dir.empty()) ret << "PROCESS_WORKDIR: " << _dir << endl;
+    if(!_title.empty()) ret << "PROCESS_TITLE: " << _title << endl;
+    return ret.str();
+  }
+
+}
\ No newline at end of file

Added: Pythia/PythiaDynamicClient/PythiaDynamicClient.h
===================================================================
--- Pythia/PythiaDynamicClient/PythiaDynamicClient.h	                        (rev 0)
+++ Pythia/PythiaDynamicClient/PythiaDynamicClient.h	2007-07-04 03:00:24 UTC (rev 928)
@@ -0,0 +1,22 @@
+#ifndef PYTHIA_DYNAMIC_CLIENT_H
+#define PYTHIA_DYNAMIC_CLIENT_H
+
+#include <string>
+using namespace std;
+
+namespace Pythia {
+
+  class Message {
+  private:
+    string _title, _dir, _cmd;
+    static const short _port;
+  public:
+    Message(const string& cmd, const string title=string(), const string dir=string());
+    void send(const string& host) const;
+  protected:
+    string formMessage() const;
+  };
+
+}
+
+#endif
\ No newline at end of file

Added: Pythia/PythiaDynamicClient/PythiaDynamicClient.sln
===================================================================
--- Pythia/PythiaDynamicClient/PythiaDynamicClient.sln	                        (rev 0)
+++ Pythia/PythiaDynamicClient/PythiaDynamicClient.sln	2007-07-04 03:00:24 UTC (rev 928)
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PythiaDynamicClient", "PythiaDynamicClient.vcproj", "{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}.Debug|Win32.Build.0 = Debug|Win32
+		{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}.Release|Win32.ActiveCfg = Release|Win32
+		{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

Added: Pythia/PythiaDynamicClient/PythiaDynamicClient.vcproj
===================================================================
--- Pythia/PythiaDynamicClient/PythiaDynamicClient.vcproj	                        (rev 0)
+++ Pythia/PythiaDynamicClient/PythiaDynamicClient.vcproj	2007-07-04 03:00:24 UTC (rev 928)
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="PythiaDynamicClient"
+	ProjectGUID="{BC3C2AF0-EF36-4587-B384-E154B6EDCC33}"
+	RootNamespace="PythiaDynamicClient"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				WholeProgramOptimization="false"
+				PreprocessorDefinitions="WIN32"
+				RuntimeLibrary="2"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\PythiaDynamicClient.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\PythiaDynamicClient.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: Pythia/PythiaDynamicClient/Release/PythiaDynamicClient.lib
===================================================================
(Binary files differ)


Property changes on: Pythia/PythiaDynamicClient/Release/PythiaDynamicClient.lib
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: Pythia/dist/library.zip
===================================================================
(Binary files differ)

Modified: Pythia/dist/process_monitor.exe
===================================================================
(Binary files differ)

Modified: Pythia/src/basic_process_monitor.py
===================================================================
--- Pythia/src/basic_process_monitor.py	2007-07-02 23:10:19 UTC (rev 927)
+++ Pythia/src/basic_process_monitor.py	2007-07-04 03:00:24 UTC (rev 928)
@@ -680,12 +680,32 @@
 	    return (config_entry[-1] == self.container_set_class) and \
 		   (config_entry[-2] == 1)
 	
+    def DynamicCallback(self, directives):
+	cur_set = self.cur_set
+	cur_container = self.cur_container
+	for key, val in directives:
+	    cur_set, cur_container = self._ConfigureOption(cur_set, cur_container, key, val, 0, self._AssembleConfiguration())
+	cur_container.ConfigDone()        
+	for p in cur_set.processes:
+            if (not (p == None)) and p.title == cur_container.title and p != cur_container:
+                cur_set.processes[-1:] = []
+                cur_container = p
+                break
+        if not cur_set.UnmetRequirements():
+            cur_set.meets_requirements = 1
+        else:
+            cur_set.meets_requirements = 0
+            print "unmet requirements"
+        return cur_container
+
     def _Configure(self, optlist, from_cmdline, config_dict):
 	# So now we work our way through the optlist.
 	cur_set = None
 	cur_container = None
 	for key, val in optlist:
 	    cur_set, cur_container = self._ConfigureOption(cur_set, cur_container, key, val, from_cmdline, config_dict)
+	self.cur_set = cur_set 
+	self.cur_container = cur_container
 
     def _ConfigureOption(self, cur_set, cur_container,
 			 key, val, from_cmdline, config_dict):
@@ -741,7 +761,7 @@
 	    else:
 		kmethod()
 	return cur_set, cur_container
-        
+
     def ChooseConfig(self):
         p_set = None
         if self.num_conforming_process_sets == 0:

Modified: Pythia/src/process_monitor.py
===================================================================
--- Pythia/src/process_monitor.py	2007-07-02 23:10:19 UTC (rev 927)
+++ Pythia/src/process_monitor.py	2007-07-04 03:00:24 UTC (rev 928)
@@ -29,7 +29,7 @@
     -c "bin/hub -pgm_file addmultiply.pgm"
 """
 
-import os, sys, socket, string, signal, select, math, time
+import os, sys, socket, string, signal, select, math, time, Queue
 
 import Tkinter
 from Tkinter import *
@@ -319,7 +319,7 @@
 	Frame.__init__(self, master)
 	self['borderwidth'] = 2
         # Default title.
-        self.master.title("Process monitor")
+        self.master.title("Pythia process monitor")
 	self.pack(fill = 'both', expand = 1)
 	self.top = Frame(self)
 	self.top.pack(side = 'top', fill = 'x', anchor = 'w')
@@ -387,12 +387,26 @@
 	self.process_env = process_env
 	# For temporary files.
 	self.process_env.Initialize()
-	self.master.iconbitmap(default=process_env.icon)
+        try: self.master.iconbitmap(default=process_env.icon)
+        except: pass
         self.process_set = None
         self.UseProcessSet(process_set)
+        self.calls = Queue.Queue(10)
 
+    def QDynamicCallback(self, directives):
+        self.calls.put(directives)
+
+    def handle_calls(self):
+        while not self.calls.empty():
+            directives = self.calls.get()
+            self.DynamicCallback(directives)
+
+    def DynamicCallback(self, directives):
+        proc = self.process_env.DynamicCallback(directives)
+        if not proc == None:
+            self.DynamicProcess(proc)
+
     def UseProcessSet(self, new_set):
-
         # First, shut down and delete all windows, if
         # appropriate.
         if self.process_set:
@@ -454,6 +468,54 @@
             else:
                 self.UseColumnConfig(self.process_env.ncols)
 
+    def DynamicProcess(self, proc):
+	# If this process is already attached then we may just want to start it
+        try:
+	    if not proc.tk == None:
+                if proc.start and proc.Dead():
+                    proc.window_host.Restart()
+                return
+        except:
+            pass
+
+        # Build a frame which has the lower pane as a hidden
+        # component.
+        # Set up the reference line.
+        proc.AddTk(self.tk)
+        self.AttachProcess(proc)
+        if proc.open:
+            proc.reference_entry.Enlarge()
+        if proc.start:
+            proc.window_host.Restart()
+        if proc.keepalive:
+            proc.window_host.KeepAlive()
+        # Now, build the button.
+        b = Button(self.button_row,
+                   text = proc.title,
+                   relief = 'raised',
+                   font = HEADERFONT)
+        proc.compressed_button = b
+        b.configure(command = lambda p = proc, s = self:
+                    s.MakeButtonActive(p))
+
+	# Now, we need to regenerate things.
+	if self.compressed:
+	    # Regenerate the compressed list.
+            self.UnuseCompressedConfig()
+            self.separator_list.append(Frame(self.pane_frame,
+                                             relief = 'sunken',
+                                             height = 2,
+                                             borderwidth = 1))
+            self.UseCompressedConfig(self.numcols, force = 1)
+	else:
+            # Regenerate the uncompressed structure.
+            self.UnuseColumnConfig()
+            self.separator_list.append(Frame(self.pane_frame,
+                                             relief = 'sunken',
+                                             height = 2,
+                                             borderwidth = 1))
+            self.UseColumnConfig(self.numcols, force = 1)
+
     def AttachProcess(self, p):
 	ref = ReferenceEntry(self.pane_frame, self, p)
 	p.SetReferenceEntry(ref)
@@ -677,8 +739,13 @@
 	    p.Poll()
 	self.timer = self.tk.createtimerhandler(500, self.Poll)
 
+    def handle_calls_callback(self):
+        self.handle_calls()
+        self.after(1000, self.handle_calls_callback)
+
     def Run(self):
 	# self.timer = self.tk.createtimerhandler(500, self.Poll)
+        self.handle_calls_callback()
 	self.mainloop()
 
 # We adopt a more complex model, where all the info about
@@ -755,6 +822,8 @@
 from basic_process_monitor import ProcessContainer, \
      ProcessContainerSet, ProcessEnvironment, ConfigurationError
 
+from spawn_listener import SpawnListener
+
 class TkProcessContainer(ProcessContainer):
     config_table = ProcessContainer.config_table + \
 		   [(None, "--input_line", 0, "LineInputMode", 0),
@@ -1178,11 +1247,14 @@
     if hasattr(signal, "SIGQUIT"):
         # Doesn't exist on Windows.
         signal.signal(signal.SIGQUIT, lambda n, stack, s = f: s.force_quit())
+    listener = SpawnListener(f.QDynamicCallback)
     try:
+        listener.start()
 	f.Run()
     except "foo":
 	print "Encountered an unrecoverable error of type %s with argument %s. Exiting." % (`sys.exc_type`, `sys.exc_value`)
 	sys.stdout.flush()
 	f.quit()
+    
 
 main()

Added: Pythia/src/spawn_listener.py
===================================================================
--- Pythia/src/spawn_listener.py	                        (rev 0)
+++ Pythia/src/spawn_listener.py	2007-07-04 03:00:24 UTC (rev 928)
@@ -0,0 +1,43 @@
+# Thomas Harris <tkharris at cs.cmu.edu>
+# December 2006
+# 
+# This process listens for spawn requests on a known tcp port
+
+import socket, threading, string
+
+_port = 11044
+
+class SpawnListener(threading.Thread):
+     def __init__(self, dynamic_callback):
+          threading.Thread.__init__(self)
+          self.setDaemon(1)
+          self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+          self.serversocket.bind(('', _port))
+          self.serversocket.listen(5)
+          self.dynamic_callback = dynamic_callback
+
+     def run(self):
+          while 1:
+               (clientsocket, address) = self.serversocket.accept()
+               msg = ''
+               while 1:
+                    chunk = clientsocket.recv(1024)
+                    if chunk == '':
+                         break
+                    msg = msg + chunk
+               self._processMsg(msg)
+
+     def _processMsg(self, msg):
+          lines = msg.splitlines()
+          directives = []
+          for line in lines:
+               l = string.strip(line)
+               if l and l[0] != '#':
+                    d = string.split(l, None, 1)
+                    if len(d) == 1:
+                         directives.append((d[0], ""))
+                    else:
+                         directives.append((d[0], d[1]))
+          self.dynamic_callback(directives)
+
+


More information about the Ravenclaw-developers mailing list