Advertisement
Guest User

Untitled

a guest
Oct 31st, 2014
174
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.82 KB | None | 0 0
  1. /** @file parmake.c */
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <pthread.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <string.h>
  9. #include "parser.h"
  10. #include "queue.h"
  11.  
  12.  
  13. //Struct for holding rules
  14. typedef struct _rule_t {
  15.     char * target;
  16.     queue_t dependencies;
  17.     queue_t commands;
  18.     int being_run;
  19. } rule_t;
  20.  
  21. typedef struct _thread_arg {
  22.     queue_t * ready_run;
  23.     queue_t * running;
  24. } thread_arg;
  25.  
  26. void callback_target(char * target);
  27. void callback_dependency(char * target, char * dependency);
  28. void callback_command(char * target, char * command);
  29. void thread_make(thread_arg * arg);
  30. int search(queue_t * q, char * target);
  31. int search_targets(queue_t * q, char * target);
  32. void run_rule(rule_t * rule);
  33. void destroy_queue_rule(queue_t * q);
  34. void destroy_queue_char(queue_t * q);
  35.  
  36. //A queue of rules and a queue of target names
  37. queue_t rules;
  38. queue_t target_q;
  39.  
  40. //Create a mutex lock for the threads
  41. static pthread_mutex_t rules_lock = PTHREAD_MUTEX_INITIALIZER;
  42. static pthread_mutex_t run_lock = PTHREAD_MUTEX_INITIALIZER;
  43. static pthread_mutex_t running_lock = PTHREAD_MUTEX_INITIALIZER;
  44.  
  45. void print_rules()
  46. {
  47.     int i;
  48.     for(i = 0; i<rules.size; i++) {
  49.         rule_t * rule = (rule_t *)queue_at(&rules, i);
  50.         printf("Target: %s\n", rule->target);
  51.          
  52.         int j;
  53.         for(j=0; j<rule->dependencies.size; j++) {
  54.             char * dependency = (char *) queue_at(&(rule->dependencies), j);
  55.             printf("    Dependency: %s\n", dependency);
  56.         }
  57.  
  58.         for(j=0; j<rule->commands.size; j++) {
  59.             char * command = (char *) queue_at(&(rule->commands), j);
  60.             printf("    Command: %s\n", command);
  61.         }
  62.     }
  63. }
  64. /**
  65.  * Entry point to parmake.
  66.  */
  67. int main(int argc, char **argv)
  68. {
  69.     //Set the default values for the arguments
  70.     char * makefile = malloc(100);
  71.     strcpy(makefile, "makefile");
  72.     int num_threads = 1;
  73.  
  74.     //Parse the arguments
  75.     int opt;
  76.     while((opt = getopt(argc, argv, "f:j:")) != -1) {
  77.         switch(opt) {
  78.         case 'f':
  79.             strcpy(makefile, optarg);
  80.             //See if the file exists
  81.             if(strcmp(makefile, "") == 0) { //no makefile was specified
  82.                 if(access("makefile", F_OK) == 0)
  83.                     strcpy(makefile,"makefile");
  84.                 else {
  85.                     if(access("Makefile", F_OK))
  86.                         return -1;
  87.                     else
  88.                         strcpy(makefile, "Makefile");
  89.                 }
  90.             }
  91.             else if(access(makefile, F_OK))
  92.                 return -1;
  93.             break;
  94.  
  95.         case 'j':
  96.             num_threads = atoi(optarg);
  97.             if(num_threads == 0)
  98.                 return -1;
  99.             break;
  100.  
  101.         default: //We get something unexpected
  102.             fprintf(stderr, "Failure parsing arguments");
  103.             return -1;
  104.         }
  105.     }
  106.  
  107.     //Get an array of the targets
  108.     int size = argc-optind; //Number of targets
  109.     char ** targets = malloc((size+1)*sizeof(char*));
  110.      
  111.     int i;
  112.     for(i=0;i<size;i++) { //Go through arv and add all targets to this array
  113.         targets[i] = malloc(strlen(argv[optind+i])+1);
  114.         strcpy(targets[i], argv[optind+i]);
  115.     }
  116.     targets[i] = NULL; //Add NULL to the end of the array
  117.      
  118.     /**
  119.     printf("Makefile is %s\n", makefile);
  120.     printf("Target: %s\n", targets[0]);
  121.     printf("Num_Threads: %d\n", num_threads);
  122.     */
  123.  
  124.     //Initialize the rules queue and parse the makefile
  125.     queue_init(&rules);
  126.     queue_init(&target_q);
  127.     parser_parse_makefile(makefile, targets, callback_target, callback_dependency, callback_command);
  128.  
  129.     //Spawn the proper number of threads and have them make
  130.     pthread_t threads[num_threads];
  131.     queue_t ready_run; //Create a queue of rules that can be run
  132.     queue_t running; //Create a queue of rules that are being run
  133.     queue_init(&ready_run);
  134.     queue_init(&running);
  135.  
  136.     thread_arg arg;
  137.     arg.running = &running;
  138.     arg.ready_run = &ready_run;
  139.     for(i=0; i<num_threads; i++) {
  140.         int error = pthread_create(&threads[i], NULL, thread_make, (void *) &arg);
  141.         if(error)
  142.             fprintf(stderr, "Error creating thread %d\n", i);
  143.     }
  144.  
  145.     //Move rules to be run to the ready_run queue and have the threads do work on it
  146.     while(queue_size(&rules) != 0) {
  147.         //Start from the back and see if there are any rules that can be run        
  148.         pthread_mutex_lock(&rules_lock);
  149.         rule_t * rule = (rule_t *) queue_at(&rules,queue_size(&rules)-1);
  150.         pthread_mutex_unlock(&rules_lock);
  151.          
  152.         if(queue_size(&(rule->dependencies)) == 0) { //There are no dependencies
  153.             //Lock the rules queue, remove the rule from the queue and put it into the to be run queue
  154.             pthread_mutex_lock(&rules_lock);
  155.             queue_remove_at(&rules, queue_size(&rules)-1);
  156.             pthread_mutex_unlock(&rules_lock);
  157.  
  158.             pthread_mutex_lock(&run_lock);
  159.             queue_enqueue(&ready_run, (void *) rule);
  160.             pthread_mutex_unlock(&run_lock);
  161.             //printf("added rule: %s\n", rule->target);
  162.         }
  163.         else {
  164.             //Search the rules queue, and the to be run queue to see if the dependency is there for each dependency
  165.             int run = 0;
  166.             int all_files = 1;
  167.             time_t time_last_modified = 0;
  168.              
  169.             int j;
  170.             for(j=0; j<queue_size(&(rule->dependencies)); j++) {
  171.                 //printf("looping 3\n");
  172.                 char * dep = queue_at(&(rule->dependencies), j);
  173.                  
  174.                 pthread_mutex_lock(&rules_lock);
  175.                 int in_rules = search(&rules, dep);
  176.                 pthread_mutex_unlock(&rules_lock);
  177.                  
  178.                 pthread_mutex_lock(&run_lock);
  179.                 int in_run = search(&ready_run, dep);
  180.                 pthread_mutex_unlock(&run_lock);
  181.                  
  182.                 pthread_mutex_lock(&running_lock);
  183.                 int is_running = search(&running, dep);
  184.                 pthread_mutex_unlock(&running_lock);
  185.  
  186.                 int is_rule = search_targets(&target_q, dep);
  187.                 //printf("%d     %d      %d      %d\n", in_rules, in_run, is_running, is_rule);
  188.                  
  189.                 if(in_rules >= 0 || in_run >= 0 || is_running >= 0) {//We have found a dependency yet to be satisfied and it is in a queue
  190.                     //printf("dependency not satisfied for: %s because of %s and run:%d\n", rule->target, dep,run);
  191.                     all_files = 0;
  192.                     break;
  193.                 }
  194.                 else if(is_rule < 0) { //The dependency is a file on disk
  195.                     //Get the modification time of the file and see if it is the newest
  196.                     struct stat info;
  197.                     stat(dep, &info);
  198.                     if(info.st_mtime > time_last_modified)
  199.                         time_last_modified = info.st_mtime;
  200.                 }
  201.             }
  202.             if(all_files == 1) { //All the dependencies were files
  203.                 //See if the rule itself is a file, and if so, get its modification time
  204.                 if(access(rule->target, F_OK) == 0) { //The rule is a file
  205.                     //Get the modification time of the rule and see if it is older than its dependencies
  206.                     struct stat rule_mod_time;
  207.                     stat(rule->target, &rule_mod_time);
  208.                     if(rule_mod_time.st_mtime > time_last_modified) { //The rule is newer than the dependencies
  209.                         //Remove the rule from the rules queue, delete it, and consider it run
  210.                         pthread_mutex_lock(&rules_lock);
  211.                         queue_remove_at(&rules, search(&rules, rule->target));
  212.                         pthread_mutex_unlock(&rules_lock);
  213.                          
  214.                         //Free the rule
  215.                         destroy_queue_char(&(rule->dependencies));
  216.                         destroy_queue_char(&(rule->commands));
  217.                         free(rule->target);
  218.                         free(rule);
  219.                     }
  220.                     else
  221.                         run = 1;
  222.                 }
  223.                 else
  224.                     run = 1;
  225.             }
  226.             if(run != 0) { //We can run the rule                    
  227.                 pthread_mutex_lock(&rules_lock);
  228.                 queue_remove_at(&rules, queue_size(&rules)-1);
  229.                 pthread_mutex_unlock(&rules_lock);
  230.  
  231.                 pthread_mutex_lock(&run_lock);
  232.                 queue_enqueue(&ready_run, (void *) rule);
  233.                 pthread_mutex_unlock(&run_lock);
  234.                 //printf("2) added rule: %s\n", rule->target);
  235.             }
  236.         }
  237.     }
  238.  
  239.     //Join the threads
  240.     //printf("joining threads %d\n", num_threads);
  241.     void * status;
  242.     for(i=0; i<num_threads;i++) {
  243.         int error = pthread_join(threads[i], (void *) &status);
  244.         if(error)
  245.             fprintf(stderr, "Error joining thread %d\n", i);
  246.         //printf("joined thread: %d\n", i);
  247.     }
  248.     //printf("joined threads\n");
  249.  
  250.     //Free all used memory
  251.     free(makefile);
  252.     int k;
  253.     for(k=0; i<size; k++)
  254.         free(targets[k]);
  255.     free(targets);
  256.     destroy_queue_rule(&rules);
  257.     destroy_queue_rule(&ready_run);
  258.     destroy_queue_rule(&running);
  259.     destroy_queue_char(&target_q);
  260.     return 0;
  261. }
  262.  
  263. //Creates a new rule with the specified target and adds it to the rules queue
  264. void callback_target(char * target)
  265. {
  266.     //Create a new rule with the specified target, initialize its queues, and add it to rules
  267.     rule_t * new_rule = malloc(sizeof(rule_t));
  268.     new_rule->target = malloc(strlen(target)+1);
  269.     strcpy(new_rule->target, target);
  270.     new_rule->being_run = 0;
  271.  
  272.     queue_init(&(new_rule->dependencies));
  273.     queue_init(&(new_rule->commands));
  274.  
  275.     queue_enqueue(&rules, (void *) new_rule);
  276.  
  277.     //Add the target to the targets queue
  278.     char * new_target = malloc(strlen(target)+1);
  279.     strcpy(new_target, target);
  280.     queue_enqueue(&target_q, (void *) new_target);
  281. }
  282.  
  283. //Adds to the specified dependency to the target contained in a rule in the rules queue
  284. void callback_dependency(char * target, char * dependency)
  285. {
  286.     //Find the last target added and add the dependency to that rule
  287.     rule_t * rule = (rule_t *) queue_at(&rules, queue_size(&rules)-1);
  288.     char * new_dependency = malloc(strlen(dependency)+1);
  289.     strcpy(new_dependency, dependency);
  290.     queue_enqueue(&(rule->dependencies), (void *) new_dependency);
  291. }
  292.  
  293. //Adds the specified command to the target contained in a rule in the rules queue
  294. void callback_command(char * target, char * command)
  295. {
  296.     //Find the last target added and add the command to that rule
  297.     rule_t * rule = (rule_t *) queue_at(&rules, queue_size(&rules)-1);
  298.     char * new_command = malloc(strlen(command)+1);
  299.     strcpy(new_command, command);
  300.     queue_enqueue(&(rule->commands), (void *) new_command);
  301. }
  302.  
  303. //Runs all of the commands in the given rule
  304. void run_rule(rule_t * rule)
  305. {
  306.     if(rule == NULL)
  307.         return;
  308.     //Loop through all of the commands in the rule and run them
  309.     int size = queue_size((&(rule->commands)));
  310.     while(size > 0) {
  311.         char * com = (char *) queue_dequeue(&(rule->commands));
  312.         int result = system(com);
  313.         if(result != 0)
  314.             exit(1);
  315.         size--;
  316.         free(com);
  317.     }
  318.     //printf("ran rule: %s\n", rule->target);
  319. }
  320.  
  321. //Searches the given queue for the specified target
  322. int search(queue_t * q, char * target)
  323. {
  324.     int i;
  325.     for(i=0; i<queue_size(q); i++) {
  326.         rule_t * rule = (rule_t *) queue_at(q,i);
  327.         if(!strcmp(target, rule->target))
  328.             return i;
  329.     }
  330.     return -1;
  331. }
  332.  
  333. int search_targets(queue_t * q, char * target)
  334. {
  335.     int i;
  336.     for(i=0; i<queue_size(q); i++) {
  337.         char * rule = (char *) queue_at(q,i);
  338.         if(!strcmp(target, rule))
  339.             return i;
  340.     }
  341.     return -1;
  342. }
  343.  
  344.  
  345. void thread_make(thread_arg * arg)
  346. {
  347.     queue_t * ready_run = arg->ready_run;
  348.     queue_t * running = arg->running;
  349.  
  350.     //Loop while the rules queue and the ready_run queue are not empty
  351.     pthread_mutex_lock(&run_lock);
  352.     int ready_size = queue_size(ready_run);
  353.     pthread_mutex_unlock(&run_lock);
  354.  
  355.     pthread_mutex_lock(&rules_lock);
  356.     int rules_size = queue_size(&rules);
  357.     pthread_mutex_unlock(&rules_lock);
  358.  
  359.     int counter = 0;
  360.     while(1) {
  361.         //Remove a job to be run from the ready to be run queue and run it
  362.         pthread_mutex_lock(&run_lock);
  363.         rule_t * rule = (rule_t *) queue_dequeue(ready_run);
  364.         pthread_mutex_unlock(&run_lock);
  365.          
  366.         if(rule == NULL) {//Do nothing
  367.         }
  368.         else {
  369.             pthread_mutex_lock(&running_lock);
  370.             queue_enqueue(running, (void *) rule);
  371.             pthread_mutex_unlock(&running_lock);
  372.  
  373.             run_rule(rule);
  374.  
  375.             //Remove the rule from the running queue
  376.             pthread_mutex_lock(&running_lock);
  377.             int result = search(running, rule->target);
  378.             queue_remove_at(running, result);
  379.             pthread_mutex_unlock(&running_lock);
  380.              
  381.             //Free all memory associated with the rule
  382.             destroy_queue_char(&(rule->dependencies));
  383.             destroy_queue_char(&(rule->commands));
  384.             free(rule->target);
  385.             free(rule);
  386.         }
  387.         pthread_mutex_lock(&run_lock);
  388.         ready_size = queue_size(ready_run);
  389.         pthread_mutex_unlock(&run_lock);
  390.  
  391.         pthread_mutex_lock(&rules_lock);
  392.         rules_size = queue_size(&rules);
  393.         pthread_mutex_unlock(&rules_lock);
  394.         //printf("%d     %d\n", rules_size, ready_size);
  395.         if(ready_size == 0 && rules_size == 0) {
  396.             //printf("finishing thread\n");
  397.             //printf("counter: %d\n");
  398.             counter++;
  399.             if(counter == 10000)
  400.                 break;
  401.         }
  402.     }
  403. }
  404.  
  405. //Frees all memory allocated and sent to the queue
  406. void destroy_queue_char(queue_t * q) {
  407.     /**
  408.     int i;
  409.     for(i=0; i<queue_size(q)+1; i++) {
  410.         char * temp = queue_dequeue(q);
  411.         if(temp != NULL)
  412.             free(temp);
  413.     }
  414.     */
  415.     char * temp = (char *) queue_dequeue(q);
  416.     while(temp != NULL) {
  417.         free(temp);
  418.         temp = queue_dequeue(q);
  419.     }
  420.     if(queue_size(q) > 0)
  421.         printf("failure freeing\n");
  422. }
  423.  
  424. //Frees all memory allocated and sent to the queue
  425. void destroy_queue_rule(queue_t * q) {
  426.     rule_t * temp = (rule_t *) queue_dequeue(q);
  427.     while(temp != NULL) {
  428.         destroy_queue_char(&(temp->commands));
  429.         destroy_queue_char(&(temp->dependencies));
  430.         free(temp->target);
  431.         free(temp);
  432.         temp = queue_dequeue(q);
  433.     }
  434.     queue_destroy(q);
  435. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement