X-Git-Url: https://git.ucc.asn.au/?p=progcomp2012.git;a=blobdiff_plain;f=home%2Fprogcomp%2Fjudge%2Fmanager%2Fprogram.cpp;fp=home%2Fprogcomp%2Fjudge%2Fmanager%2Fprogram.cpp;h=0000000000000000000000000000000000000000;hp=660362ac06cc7535c1f2814c9e1bd6579b17c0d4;hb=88fc5a96c424e9a451b98f3b680bc1980345320d;hpb=e3b15cd5dea739f7523920d83bda592db95a7b93 diff --git a/home/progcomp/judge/manager/program.cpp b/home/progcomp/judge/manager/program.cpp deleted file mode 100644 index 660362a..0000000 --- a/home/progcomp/judge/manager/program.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include - -#include - -#include - -#include "thread_util.h" -#include "program.h" - - -using namespace std; - - -/** - * Constructor - * @param executablePath - path to the program that will be run - * - * Creates two pipes - one for each direction between the parent process and the AI program - * Forks the process. - * 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) -{ - //See if file exists... - FILE * file = fopen(executablePath, "r"); - if (file != NULL) - { - fclose(file); - } - else - { - pid = -1; - return; - } - - int readPipe[2]; int writePipe[2]; - assert(pipe(readPipe) == 0); - assert(pipe(writePipe) == 0); - - pid = fork(); - if (pid == 0) - { - close(readPipe[0]); //close end that parent reads from - close(writePipe[1]); //close end that parent writes to - - //TODO: Fix possible bug here if the process is already a daemon - assert(writePipe[0] != 0 && readPipe[1] != 1); - dup2(writePipe[0],0); close(writePipe[0]); //pipe end child reads from goes to STDIN - dup2(readPipe[1], 1); close(readPipe[1]); //pipe end child writes to goes to STDOUT - - //TODO: Somehow force the exec'd process to be unbuffered - setbuf(stdin, NULL); //WARNING: These lines don't appear to have any affect - setbuf(stdout, NULL); //You should add them at the start of the wrapped program. - //If your wrapped program is not written in C/C++, you will probably have a problem - - - - execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable - //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 - } - else - { - close(writePipe[0]); //close end that child writes to - close(readPipe[1]); //close end that child reads from - - input = fdopen(readPipe[0],"r"); output = fdopen(writePipe[1],"w"); - setbuf(input, NULL); - setbuf(output, NULL); - } - -} - -/** - * Destructor - * Writes EOF to the wrapped program and then closes all streams - * Kills the wrapped program if it does not exit within 1 second. - */ -Program::~Program() -{ - if (Running()) //Check if the process created is still running... - { - //fputc(EOF, output); //If it was, tell it to stop with EOF - - TimerThread timer(2); //Wait for 2 seconds - timer.Start(); - while (!timer.Finished()) - { - if (!Running()) - { - timer.Stop(); - break; - } - } - timer.Stop(); - kill(pid, SIGKILL); - } - if (pid > 0) - { - fclose(input); - fclose(output); - } - -} - - - - - -/** - * Sends a message to the wrapped AI program - * WARNING: Always prints a new line after the message (so don't include a new line) - * This is because everything is always line buffered. - * @returns true if the message was successfully sent; false if it was not (ie: the process was not running!) - */ -bool Program::SendMessage(const char * print, ...) -{ - if (!Running()) //Is the process running... - return false; - - va_list ap; - va_start(ap, print); - - if (vfprintf(output, print, ap) < 0 || fprintf(output, "\n") < 0) - { - va_end(ap); - return false; - } - va_end(ap); - - - - - return true; -} - - -/** - * Retrieves a message from the wrapped AI program, waiting a maximum amount of time - * @param buffer - C++ string to store the resultant message in - * @param timeout - Maximum amount of time to wait before failure. If timeout <= 0, then GetMessage will wait indefinately. - * @returns true if the response was recieved within the specified time, false if it was not, or an EOF was recieved, or the process was not running. - */ -bool Program::GetMessage(string & buffer, double timeout) -{ - if (!Running()) - return false; - - assert(&buffer != NULL); - GetterThread getterThread(input, buffer); - assert(&(getterThread.buffer) != NULL); - TimerThread timerThread(timeout*1000000); - - getterThread.Start(); - if (timeout > 0) - timerThread.Start(); - - - while (!getterThread.Finished()) - { - if (timeout > 0 && timerThread.Finished()) - { - getterThread.Stop(); - timerThread.Stop(); - return false; - } - } - - getterThread.Stop(); - timerThread.Stop(); - - - - if (buffer.size() == 1 && buffer[0] == EOF) - return false; - return true; - - -} - -/** - * Returns true iff the process is running - * @returns what I just said, fool - */ -bool Program::Running() const -{ - return (pid > 0 && kill(pid,0) == 0); -} - - - -