// Responsible for tracking and taking care of slaves // // Copyright (C) 2000 Stephen A. Torri // // This program 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 of the License, or // (at your option) any later version. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Questions, comments or improvements should be sent to: // s.torri@lancaster.ac.uk or storri@stratos.net // #include #include #include //-------------------------------- // Job_List_Item class //-------------------------------- //-------------------------------- // pre: Command and directory are known. // post: Job_List_Item created and initialized. // function: Initialize Job_List_Item before adding to list // // cmd - command to be executed when job removed from list // dir - change to this directory before executing job // ------------------------------- Job_List_Item::Job_List_Item(string cmd, string dir) { command = cmd; directory = dir; isComment = false; } //-------------------------------- // pre: Command, directory and isComment are known. // post: Job_List_Item created and initialized. // function: Initialize Job_List_Item before adding to list // // cmd - command to be executed when job removed from list // dir - change to this directory before executing job // com - the cmd is really a comment. It will not be executed only displayed // ------------------------------- Job_List_Item::Job_List_Item(string cmd, string dir, bool com) { command = cmd; directory = dir; isComment = com; } //-------------------------------- // Job_List_Node class //-------------------------------- //-------------------------------- // pre: Job_List_Item is initialized // post: Job_List_Node created and initalized // function: Create Job_List_Node for adding to list // // job - reference to a Job_List_Item //-------------------------------- Job_List_Node::Job_List_Node(Job_List_Item* job) { next = NULL; prev = NULL; job_ptr = job; } //-------------------------------- // Job_List class //-------------------------------- //-------------------------------- // pre: None // post: Job_List is created and initialized // function: Create a Job_List for adding jobs //-------------------------------- Job_List::Job_List(){ head = NULL; end = NULL; list_size = 0; char c = ' '; string command = "|pwd"; basedir = ""; ipfstream* runPipe = new ipfstream (command.c_str(), ios::in, 0644); while( (c = runPipe->get()) != EOF){ basedir += c; } } Job_List::~Job_List(){} //******************************** // Runtime functions //******************************** //---------------------------------------------- // pre: Job queue is initialized // post: String is added to job queue // function: Used by master to add jobs to the front of the job list. // future: - Check string for security (i.e. is the line not // doing something illegal) // - Break string up into directory, target file name, // and command. Enter into new node as part of a linked // list // // checks: // #1 - "make[" - see if command starts with make. // #1a - see if make line states entering/leaving directory. This // is used to change the basedir of the slaves to the present // working directory of make. // // command - Command to be executed //----------------------------------------------- void Job_List::addJob(string command) { dout << "Job_List::addJob - entering addJob" << endl; JTCSynchronized synchronized(*this); bool isComment = false; string directory = basedir; dout << "Job_List::addJob - basedir = " << basedir << endl; if(startsWith(command, "make[")) { dout << "Job_List::addJob - command starts with `make[`" << endl; int enteringFound = command.find("Entering"); if (enteringFound != -1){ dout << "Job_List::addJob - command contains 'Entering'" << endl; } int leavingFound = command.find("Leaving"); #ifdef DEBUG if (leavingFound != -1){ cout << "Job_List::addJob - command contains 'Leaving'" << endl; } #endif if((enteringFound != -1) || (leavingFound != -1)) { dout << "Job_List::addJob - need to get new Directory" << endl; directory = getNewDirectory(command); basedir=directory; } dout << "Job_List::addJob - lines containing 'make[' are comments" << endl; dout << "Job_List::addJob - command = " << command << endl; dout << "Job_List::addJob - directory = " << directory << endl; isComment = true; } else { dout << "Job_List::addJob - command = " << command << endl; dout << "Job_List::addJob - directory = " << directory << endl; isComment = false; } Job_List_Item* temp_job = new Job_List_Item(command, directory, isComment); dout << "Job_List: addJob - adding node to list" << endl; Job_List_Node* temp_node = new Job_List_Node(temp_job); if(temp_node != NULL){ dout << "Job_List::addJob - temp_node is not NULL" << endl; temp_node->prev = NULL; dout << "Job_List::addJob - temp_node->prev = head" << endl; temp_node->next = head; if(head != NULL){ head->prev = temp_node; } if(end == NULL){ end = temp_node; } head = temp_node; list_size++; dout << "Job_List::addJob - list_size++" << endl; } } //---------------------------------------------- // pre: Job queue is initialized // post: Job is added to job queue // function: Used by slave to add jobs to the front of the job // list when the command and the directory is known. // future: - Check string for security (i.e. is the line not // doing something illegal) // - Break string up into directory, target file name, // and command. Enter into new node as part of a linked // list // // command - Command sent by Master to be executed // directory - Directory slave needs to change to before executing command //----------------------------------------------- void Job_List::addJob(string command, string directory) { dout << "Job_List::addJob - entering addJob" << endl; JTCSynchronized synchronized(*this); dout << "Job_List::addJob - command = " << command << endl; dout << "Job_List::addJob - directory = " << directory << endl; Job_List_Item* temp_job = new Job_List_Item(command, directory); dout << "Job_List: addJob - adding node to list" << endl; Job_List_Node* temp_node = new Job_List_Node(temp_job); if(temp_node != NULL){ dout << "Job_List::addJob - temp_node is not NULL" << endl; temp_node->prev = NULL; dout << "Job_List::addJob - temp_node->prev = head" << endl; temp_node->next = head; if(head != NULL){ head->prev = temp_node; } if(end == NULL){ end = temp_node; } head = temp_node; list_size++; dout << "Job_List::addJob - list_size++" << endl; } } //------------------------------------------------ // pre: Job queue should be initialized and contains items // post: Job queue item is returned. // function: Remove last item and return it. //------------------------------------------------ Job_List_Item* Job_List::getJob() { Job_List_Item* job = NULL; if (! empty()) { job = removeJob( list_size - 1 ); #ifdef DEBUG cout << "Job_List::getJob - command = " << job->command << endl; cout << "Job_List::getJob - directory = " << job->directory << endl; cout << "Job_List::getJob - comment = "; if (job->isComment) { cout << "true" << endl; } else { cout << "false" << endl; } #endif } return job; } //----------------------------- // pre: Job_List is initialized and contains jobs // post: Job_List_Item removed from list // function: Remove the node at "position" if position < size // // position = position of Job_List_Item to be removed //----------------------------- Job_List_Item* Job_List::removeJob(int position){ Job_List_Item* job = NULL; if( position < list_size) { // get reference to where head points (1st node which is position 0) Job_List_Node* iterator = head; Job_List_Node* deleteNode = head; if (position == 0) { // beginning of list // get reference of the node we wish to delete //deleteNode = iterator; // move iterator to node after "target" //iterator = deleteNode->next; // change reference of head to the node after "target" or NULL head = deleteNode->next; // if iterator is not NULL then set prev to point to the head if ( head != NULL) { head->prev = NULL; } else { // no items in list // head == NULL // end == NULL end = head; } } else { // else if (position == list_size - 1) { // end of list for (int i = 0; i < position; i++){ iterator = iterator->next; deleteNode = iterator; } // confirm we are at the end if ( iterator->next == NULL) { // move the iterator back one node iterator = deleteNode->prev; // point the iterator node to NULL (end) iterator->next = NULL; // make end point to the new end of list end = iterator; } else { // we are some where after position 0 but before end // move the iterator back one iterator = deleteNode->prev; // iterator->next = deleteNode->next; position after removed iterator->next = deleteNode->next; // move interator passed removed node iterator = deleteNode->next; // iterator->prev = deleteNode->prev; position before removed iterator->prev = deleteNode->prev; } } deleteNode->next = NULL; deleteNode->prev = NULL; job = deleteNode->job_ptr; list_size--; dout << "Job_List::removeJob - list_size--" << endl; } return job; } //----------------------------------- // pre: Job_List is initialized and contains jobs // post: Job_List_Item is removed from list // function: Remove Job_List_Item matching "job" from list // // job - reference to the desired Job_List_Item to be removed //----------------------------------- Job_List_Item* Job_List::removeJob(Job_List_Item* job){ int position = indexOf(job); return removeJob(position); } int Job_List::indexOf (Job_List_Item* job){ Job_List_Node* iterator = head; // start at first node int position = -1; for (int i = 0; i < list_size; i++) { // Make sure commands are equal if ( iterator->job_ptr->command == job->command ) { position = i; break; } iterator = iterator->next; } return position; } //-------------------------------------- // pre: Job_List is created and initialized. // post: Job_List is the same // function: Returned size of job list //-------------------------------------- int Job_List::size() { JTCSynchronized synchronized(*this); return list_size; } //-------------------------------------- // pre: Job_List is created and initialized. // post: Job_List is the same // function: Return a boolean (true/false) if the list is empty //-------------------------------------- bool Job_List::empty() { JTCSynchronized synchronized(*this); return (list_size == 0) ? true : false; } //--------------------------------------- // pre: Target and test both are valid strings // post: Return result // function: Return true if target contains test. Return false if not. // // target = target string used // test = string we are looking for in target //--------------------------------------- bool Job_List::startsWith(string target, string test){ int result = target.find(test); if (result != -1){ return true; } return false; } //----------------------------------------- // pre: Target string contains a valid directory // post: Return result // function: Return new directory to be used // // target = string with valid directory that we need to obtain //----------------------------------------- string Job_List::getNewDirectory(string target){ string temp = ""; int begin = target.find_first_of("`") + 1; temp = target.erase(0,begin); int size = temp.size(); int end = temp.find_first_of("'"); temp = temp.erase( end , size); dout << "Job_List::getNewDirectory - temp = " << temp << endl; // return new string as the new directory return temp; } //------------------------------------ // pre: Job_List is created and may/may not contain jobs // post: Job_List contains work. All blocking threads awakened (via addJob). // function: Waiting conditions for all job_process threads. If there is no // work to be done (job list empty) then wait. If there is work to be done // then do nothing //------------------------------------ void Job_List::waitForJob() { #ifdef DEBUG cout << "Job_List::waitForJob - Entering waitForJob" << endl; if (! empty() ) { cout << "Job_List::waitForJob - Job List has work" << endl; cout << "Job_List::waitForJob - list size is " << list_size << endl; } #endif while( empty() ) { dout << "Job_List::waitForJob - Size of list is 0" << endl; try{ dout << "Job_List::waitForJob - waiting" << endl; wait(); } catch(const JTCInterruptedException ex) { } } }