[PATCH] Handle case where an AI sends an invalid message and then crashes
[progcomp2012.git] / judge / manager / program.cpp
index d5463f4..00a28e9 100644 (file)
@@ -6,6 +6,14 @@
 
 #include "thread_util.h"
 #include "program.h"
+#include <vector>
+#include <string.h>
+#include <stdio.h>
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 
 using namespace std;
@@ -20,8 +28,49 @@ using namespace std;
  *     The child process closes unused sides of the pipe, and then calls exec to replace itself with the AI program
  *     The parent process closes unused sides of the pipe, and sets up member variables - associates streams with the pipe fd's for convenience.
  */
-Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0)
+Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0), paused(false)
 {
+       
+               
+       /*
+       vector<char*> args;
+       if (executablePath[0] != '"')
+               args.push_back((char*)executablePath);
+       else
+               args.push_back((char*)(executablePath)+1);
+       char * token = NULL;
+       do
+       {
+               token = strstr(args[args.size()-1], " ");
+               if (token == NULL)
+                       break;
+
+               *token = '\0';
+               do
+               {
+                       ++token;
+                       if (*token == '"')
+                               *token = '\0';
+               }
+               while (*token != '\0' && iswspace(*token));
+
+               if (*token != '\0' && !iswspace(*token))
+               {
+                       args.push_back(token);
+               }
+               else
+                       break;
+       }
+       while (token != NULL);
+
+       char **  arguments = NULL;
+        if (args.size() > 0)
+       {
+               arguments = new char*[args.size()];
+               for (unsigned int i=0; i < args.size(); ++i)
+                       arguments[i] = args[i];
+       }
+       */
        //See if file exists and is executable...
        if (access(executablePath, X_OK) != 0)
        {
@@ -51,8 +100,11 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
                                
 
                if (access(executablePath, X_OK) == 0) //Check we STILL have permissions to start the file
+               {
                        execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable
-               
+                       //execv(executablePath,arguments); ///Replace process with desired executable
+               }
+               perror("execv error:\n");
                fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
                exit(EXIT_FAILURE); //We will probably have to terminate the whole program if this happens
        }
@@ -100,8 +152,42 @@ Program::~Program()
        
 }
 
+/**
+ * Forces the program to pause by sending SIGSTOP
+ * Program can be resumed by calling Continue() (which sends SIGCONT)
+ * @returns true if the program could be paused, false if it couldn't (probably because it wasn't running)
+ */
+bool Program::Pause()
+{
+       if (pid > 0 && kill(pid,SIGSTOP) == 0)
+       {
+               paused = true;
+               return true;
+       }
+       return false;
+}
 
+/**
+ * Causes a paused program to continue
+ * @returns true if the program could be continued, false if it couldn't (probably because it wasn't running)
+ */
+bool Program::Continue()
+{
+       if (pid > 0 && kill(pid,SIGCONT) == 0)
+       {
+               paused = false;
+               return true;
+       }
+       return false;
+}
 
+/**
+ * @returns true iff the program is paused
+ */
+bool Program::Paused() const
+{
+       return paused;
+}
 
 
 /**
@@ -143,6 +229,32 @@ bool Program::GetMessage(string & buffer, double timeout)
        if (!Running() || timeout == 0)
                return false;
 
+       struct timeval tv;
+       fd_set readfds;
+       
+       tv.tv_sec = (int)(timeout);
+       tv.tv_usec = (timeout - (double)((int)timeout)) * 1000000;
+       
+       int fd = fileno(input);
+
+       FD_ZERO(&readfds);
+       FD_SET(fd, &readfds);
+
+       select(fd+1, &readfds, NULL, NULL, &tv);
+
+       if (!FD_ISSET(fd, &readfds))
+               return false; //Timed out
+       //fprintf(stderr, "Got message!\n");
+       for (char c = fgetc(input); c != '\n' && (int)(c) != EOF; c = fgetc(input))
+       {       
+               //fprintf(stderr, "%c", c);
+               buffer += c;
+       }
+       //fprintf(stderr, "%s\n", buffer.c_str());
+       //fprintf(stderr,"DONE\n");
+       return true;
+
+       /* Old way, using threads, which apparently is terrible
        assert(&buffer != NULL);
        GetterThread getterThread(input, buffer);
        assert(&(getterThread.buffer) != NULL);
@@ -173,7 +285,7 @@ bool Program::GetMessage(string & buffer, double timeout)
        if (buffer.size() == 1 && buffer[0] == EOF)
                return false;
        return true;
-
+       */
 
 }
 

UCC git Repository :: git.ucc.asn.au