Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /** @file parmake.c */
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #include "parser.h"
- #include "queue.h"
- //Struct for holding rules
- typedef struct _rule_t {
- char * target;
- queue_t dependencies;
- queue_t commands;
- int being_run;
- } rule_t;
- typedef struct _thread_arg {
- queue_t * ready_run;
- queue_t * running;
- } thread_arg;
- void callback_target(char * target);
- void callback_dependency(char * target, char * dependency);
- void callback_command(char * target, char * command);
- void thread_make(thread_arg * arg);
- int search(queue_t * q, char * target);
- int search_targets(queue_t * q, char * target);
- void run_rule(rule_t * rule);
- void destroy_queue_rule(queue_t * q);
- void destroy_queue_char(queue_t * q);
- //A queue of rules and a queue of target names
- queue_t rules;
- queue_t target_q;
- //Create a mutex lock for the threads
- static pthread_mutex_t rules_lock = PTHREAD_MUTEX_INITIALIZER;
- static pthread_mutex_t run_lock = PTHREAD_MUTEX_INITIALIZER;
- static pthread_mutex_t running_lock = PTHREAD_MUTEX_INITIALIZER;
- void print_rules()
- {
- int i;
- for(i = 0; i<rules.size; i++) {
- rule_t * rule = (rule_t *)queue_at(&rules, i);
- printf("Target: %s\n", rule->target);
- int j;
- for(j=0; j<rule->dependencies.size; j++) {
- char * dependency = (char *) queue_at(&(rule->dependencies), j);
- printf(" Dependency: %s\n", dependency);
- }
- for(j=0; j<rule->commands.size; j++) {
- char * command = (char *) queue_at(&(rule->commands), j);
- printf(" Command: %s\n", command);
- }
- }
- }
- /**
- * Entry point to parmake.
- */
- int main(int argc, char **argv)
- {
- //Set the default values for the arguments
- char * makefile = malloc(100);
- strcpy(makefile, "makefile");
- int num_threads = 1;
- //Parse the arguments
- int opt;
- while((opt = getopt(argc, argv, "f:j:")) != -1) {
- switch(opt) {
- case 'f':
- strcpy(makefile, optarg);
- //See if the file exists
- if(strcmp(makefile, "") == 0) { //no makefile was specified
- if(access("makefile", F_OK) == 0)
- strcpy(makefile,"makefile");
- else {
- if(access("Makefile", F_OK))
- return -1;
- else
- strcpy(makefile, "Makefile");
- }
- }
- else if(access(makefile, F_OK))
- return -1;
- break;
- case 'j':
- num_threads = atoi(optarg);
- if(num_threads == 0)
- return -1;
- break;
- default: //We get something unexpected
- fprintf(stderr, "Failure parsing arguments");
- return -1;
- }
- }
- //Get an array of the targets
- int size = argc-optind; //Number of targets
- char ** targets = malloc((size+1)*sizeof(char*));
- int i;
- for(i=0;i<size;i++) { //Go through arv and add all targets to this array
- targets[i] = malloc(strlen(argv[optind+i])+1);
- strcpy(targets[i], argv[optind+i]);
- }
- targets[i] = NULL; //Add NULL to the end of the array
- /**
- printf("Makefile is %s\n", makefile);
- printf("Target: %s\n", targets[0]);
- printf("Num_Threads: %d\n", num_threads);
- */
- //Initialize the rules queue and parse the makefile
- queue_init(&rules);
- queue_init(&target_q);
- parser_parse_makefile(makefile, targets, callback_target, callback_dependency, callback_command);
- //Spawn the proper number of threads and have them make
- pthread_t threads[num_threads];
- queue_t ready_run; //Create a queue of rules that can be run
- queue_t running; //Create a queue of rules that are being run
- queue_init(&ready_run);
- queue_init(&running);
- thread_arg arg;
- arg.running = &running;
- arg.ready_run = &ready_run;
- for(i=0; i<num_threads; i++) {
- int error = pthread_create(&threads[i], NULL, thread_make, (void *) &arg);
- if(error)
- fprintf(stderr, "Error creating thread %d\n", i);
- }
- //Move rules to be run to the ready_run queue and have the threads do work on it
- while(queue_size(&rules) != 0) {
- //Start from the back and see if there are any rules that can be run
- pthread_mutex_lock(&rules_lock);
- rule_t * rule = (rule_t *) queue_at(&rules,queue_size(&rules)-1);
- pthread_mutex_unlock(&rules_lock);
- if(queue_size(&(rule->dependencies)) == 0) { //There are no dependencies
- //Lock the rules queue, remove the rule from the queue and put it into the to be run queue
- pthread_mutex_lock(&rules_lock);
- queue_remove_at(&rules, queue_size(&rules)-1);
- pthread_mutex_unlock(&rules_lock);
- pthread_mutex_lock(&run_lock);
- queue_enqueue(&ready_run, (void *) rule);
- pthread_mutex_unlock(&run_lock);
- //printf("added rule: %s\n", rule->target);
- }
- else {
- //Search the rules queue, and the to be run queue to see if the dependency is there for each dependency
- int run = 0;
- int all_files = 1;
- time_t time_last_modified = 0;
- int j;
- for(j=0; j<queue_size(&(rule->dependencies)); j++) {
- //printf("looping 3\n");
- char * dep = queue_at(&(rule->dependencies), j);
- pthread_mutex_lock(&rules_lock);
- int in_rules = search(&rules, dep);
- pthread_mutex_unlock(&rules_lock);
- pthread_mutex_lock(&run_lock);
- int in_run = search(&ready_run, dep);
- pthread_mutex_unlock(&run_lock);
- pthread_mutex_lock(&running_lock);
- int is_running = search(&running, dep);
- pthread_mutex_unlock(&running_lock);
- int is_rule = search_targets(&target_q, dep);
- //printf("%d %d %d %d\n", in_rules, in_run, is_running, is_rule);
- 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
- //printf("dependency not satisfied for: %s because of %s and run:%d\n", rule->target, dep,run);
- all_files = 0;
- break;
- }
- else if(is_rule < 0) { //The dependency is a file on disk
- //Get the modification time of the file and see if it is the newest
- struct stat info;
- stat(dep, &info);
- if(info.st_mtime > time_last_modified)
- time_last_modified = info.st_mtime;
- }
- }
- if(all_files == 1) { //All the dependencies were files
- //See if the rule itself is a file, and if so, get its modification time
- if(access(rule->target, F_OK) == 0) { //The rule is a file
- //Get the modification time of the rule and see if it is older than its dependencies
- struct stat rule_mod_time;
- stat(rule->target, &rule_mod_time);
- if(rule_mod_time.st_mtime > time_last_modified) { //The rule is newer than the dependencies
- //Remove the rule from the rules queue, delete it, and consider it run
- pthread_mutex_lock(&rules_lock);
- queue_remove_at(&rules, search(&rules, rule->target));
- pthread_mutex_unlock(&rules_lock);
- //Free the rule
- destroy_queue_char(&(rule->dependencies));
- destroy_queue_char(&(rule->commands));
- free(rule->target);
- free(rule);
- }
- else
- run = 1;
- }
- else
- run = 1;
- }
- if(run != 0) { //We can run the rule
- pthread_mutex_lock(&rules_lock);
- queue_remove_at(&rules, queue_size(&rules)-1);
- pthread_mutex_unlock(&rules_lock);
- pthread_mutex_lock(&run_lock);
- queue_enqueue(&ready_run, (void *) rule);
- pthread_mutex_unlock(&run_lock);
- //printf("2) added rule: %s\n", rule->target);
- }
- }
- }
- //Join the threads
- //printf("joining threads %d\n", num_threads);
- void * status;
- for(i=0; i<num_threads;i++) {
- int error = pthread_join(threads[i], (void *) &status);
- if(error)
- fprintf(stderr, "Error joining thread %d\n", i);
- //printf("joined thread: %d\n", i);
- }
- //printf("joined threads\n");
- //Free all used memory
- free(makefile);
- int k;
- for(k=0; i<size; k++)
- free(targets[k]);
- free(targets);
- destroy_queue_rule(&rules);
- destroy_queue_rule(&ready_run);
- destroy_queue_rule(&running);
- destroy_queue_char(&target_q);
- return 0;
- }
- //Creates a new rule with the specified target and adds it to the rules queue
- void callback_target(char * target)
- {
- //Create a new rule with the specified target, initialize its queues, and add it to rules
- rule_t * new_rule = malloc(sizeof(rule_t));
- new_rule->target = malloc(strlen(target)+1);
- strcpy(new_rule->target, target);
- new_rule->being_run = 0;
- queue_init(&(new_rule->dependencies));
- queue_init(&(new_rule->commands));
- queue_enqueue(&rules, (void *) new_rule);
- //Add the target to the targets queue
- char * new_target = malloc(strlen(target)+1);
- strcpy(new_target, target);
- queue_enqueue(&target_q, (void *) new_target);
- }
- //Adds to the specified dependency to the target contained in a rule in the rules queue
- void callback_dependency(char * target, char * dependency)
- {
- //Find the last target added and add the dependency to that rule
- rule_t * rule = (rule_t *) queue_at(&rules, queue_size(&rules)-1);
- char * new_dependency = malloc(strlen(dependency)+1);
- strcpy(new_dependency, dependency);
- queue_enqueue(&(rule->dependencies), (void *) new_dependency);
- }
- //Adds the specified command to the target contained in a rule in the rules queue
- void callback_command(char * target, char * command)
- {
- //Find the last target added and add the command to that rule
- rule_t * rule = (rule_t *) queue_at(&rules, queue_size(&rules)-1);
- char * new_command = malloc(strlen(command)+1);
- strcpy(new_command, command);
- queue_enqueue(&(rule->commands), (void *) new_command);
- }
- //Runs all of the commands in the given rule
- void run_rule(rule_t * rule)
- {
- if(rule == NULL)
- return;
- //Loop through all of the commands in the rule and run them
- int size = queue_size((&(rule->commands)));
- while(size > 0) {
- char * com = (char *) queue_dequeue(&(rule->commands));
- int result = system(com);
- if(result != 0)
- exit(1);
- size--;
- free(com);
- }
- //printf("ran rule: %s\n", rule->target);
- }
- //Searches the given queue for the specified target
- int search(queue_t * q, char * target)
- {
- int i;
- for(i=0; i<queue_size(q); i++) {
- rule_t * rule = (rule_t *) queue_at(q,i);
- if(!strcmp(target, rule->target))
- return i;
- }
- return -1;
- }
- int search_targets(queue_t * q, char * target)
- {
- int i;
- for(i=0; i<queue_size(q); i++) {
- char * rule = (char *) queue_at(q,i);
- if(!strcmp(target, rule))
- return i;
- }
- return -1;
- }
- void thread_make(thread_arg * arg)
- {
- queue_t * ready_run = arg->ready_run;
- queue_t * running = arg->running;
- //Loop while the rules queue and the ready_run queue are not empty
- pthread_mutex_lock(&run_lock);
- int ready_size = queue_size(ready_run);
- pthread_mutex_unlock(&run_lock);
- pthread_mutex_lock(&rules_lock);
- int rules_size = queue_size(&rules);
- pthread_mutex_unlock(&rules_lock);
- int counter = 0;
- while(1) {
- //Remove a job to be run from the ready to be run queue and run it
- pthread_mutex_lock(&run_lock);
- rule_t * rule = (rule_t *) queue_dequeue(ready_run);
- pthread_mutex_unlock(&run_lock);
- if(rule == NULL) {//Do nothing
- }
- else {
- pthread_mutex_lock(&running_lock);
- queue_enqueue(running, (void *) rule);
- pthread_mutex_unlock(&running_lock);
- run_rule(rule);
- //Remove the rule from the running queue
- pthread_mutex_lock(&running_lock);
- int result = search(running, rule->target);
- queue_remove_at(running, result);
- pthread_mutex_unlock(&running_lock);
- //Free all memory associated with the rule
- destroy_queue_char(&(rule->dependencies));
- destroy_queue_char(&(rule->commands));
- free(rule->target);
- free(rule);
- }
- pthread_mutex_lock(&run_lock);
- ready_size = queue_size(ready_run);
- pthread_mutex_unlock(&run_lock);
- pthread_mutex_lock(&rules_lock);
- rules_size = queue_size(&rules);
- pthread_mutex_unlock(&rules_lock);
- //printf("%d %d\n", rules_size, ready_size);
- if(ready_size == 0 && rules_size == 0) {
- //printf("finishing thread\n");
- //printf("counter: %d\n");
- counter++;
- if(counter == 10000)
- break;
- }
- }
- }
- //Frees all memory allocated and sent to the queue
- void destroy_queue_char(queue_t * q) {
- /**
- int i;
- for(i=0; i<queue_size(q)+1; i++) {
- char * temp = queue_dequeue(q);
- if(temp != NULL)
- free(temp);
- }
- */
- char * temp = (char *) queue_dequeue(q);
- while(temp != NULL) {
- free(temp);
- temp = queue_dequeue(q);
- }
- if(queue_size(q) > 0)
- printf("failure freeing\n");
- }
- //Frees all memory allocated and sent to the queue
- void destroy_queue_rule(queue_t * q) {
- rule_t * temp = (rule_t *) queue_dequeue(q);
- while(temp != NULL) {
- destroy_queue_char(&(temp->commands));
- destroy_queue_char(&(temp->dependencies));
- free(temp->target);
- free(temp);
- temp = queue_dequeue(q);
- }
- queue_destroy(q);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement