diff --git a/Week 6-workshop/README.md b/Week 6-workshop/README.md new file mode 100644 index 0000000..fc4df61 --- /dev/null +++ b/Week 6-workshop/README.md @@ -0,0 +1,6 @@ +## Workshop 6 content + +Workshop content: https://web.archive.org/web/20210904135855/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/workshop6.php \ +`plotchess.sh`: https://web.archive.org/web/20210904140621/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/plotchess.sh\ +`goodchessmove.c`: https://web.archive.org/web/20210904140051/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/goodchessmove.c \ +`manychessmoves.c` solution: https://web.archive.org/web/20210904140231/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/manychessmoves.c\ \ No newline at end of file diff --git a/Week 6-workshop/goodchessmove.c b/Week 6-workshop/goodchessmove.c new file mode 100644 index 0000000..574d67c --- /dev/null +++ b/Week 6-workshop/goodchessmove.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main(int argc, char const *argv[]) +{ + if (argc != 3) + { + printf("Usage: goodchessmove [GAMESTATE] [OUTPUT]\n"); + exit(EXIT_FAILURE); + } + + // placeholder for a real chess program + printf("Executing chess move. GAMESTATE: %s, OUTPUT: %s\n", + argv[1], argv[2]); + + // do chess + sleep(5); + + fflush(stdout); + printf("Finished executing chess move. Wrote %s\n", argv[2]); + exit(EXIT_SUCCESS); +} diff --git a/Week 6-workshop/manychessmoves.c b/Week 6-workshop/manychessmoves.c new file mode 100644 index 0000000..f59d4a2 --- /dev/null +++ b/Week 6-workshop/manychessmoves.c @@ -0,0 +1,111 @@ + +#include +#include +#include +#include +#include +#include + +struct current_instance { + char *gamestate; + char *output; + int instance_no; +}; + +struct fork_list { + pid_t *fork_list; + int concurrent_forks; +}; + +int execute_chessmove(struct current_instance *instance) +{ + // concatenate original filename and the instance number + int len = snprintf(NULL, 0, "%s-%d ", instance->output, instance->instance_no); + char output_filename[len]; + snprintf(output_filename, len, "%s-%d ", instance->output, instance->instance_no); + char *arguments[] = { + "./goodchessmove", + instance->gamestate, + output_filename, + NULL + }; + return execvp(arguments[0], arguments); +} + +pid_t new_fork(struct current_instance *instance) +{ + pid_t pid; + switch (pid = fork()) + { + case -1: + printf("fork() failed\n"); + exit(EXIT_FAILURE); + case 0: + exit( execute_chessmove(instance) ); + } + return pid; +} + +void populate_forks(int fork_count, struct fork_list *forks, struct current_instance *instance) +{ + if (fork_count > forks->concurrent_forks) { + fork_count = forks->concurrent_forks; + } + + for (size_t i = 0; i < fork_count; i++) { + forks->fork_list[i] = new_fork(instance); + instance->instance_no++; + } +} + +void replace_fork(pid_t old_pid, struct fork_list *forks, struct current_instance *instance) +{ + for (size_t i = 0; i < forks->concurrent_forks; i++) { + if (forks->fork_list[i] == old_pid) { + forks->fork_list[i] = new_fork(instance); + instance->instance_no++; + return; + } + } +} + +int numberOfCores(void) // From worshop spec. +{ + return sysconf(_SC_NPROCESSORS_ONLN); +} + +int main(int argc, char *argv[]) +{ + if (argc != 4) + { + printf("Usage: manychessmoves [N PROCESSES] [GAMESTATE] [OUTPUT]\n"); + exit(EXIT_FAILURE); + } + + int n_forks = atoi(argv[1]); + int concurrent_forks = numberOfCores(); + pid_t fork_pids[concurrent_forks]; + + struct fork_list fork_list = { fork_pids, concurrent_forks }; + struct current_instance instance = { argv[2], argv[3], 0 }; + + populate_forks(n_forks, &fork_list, &instance); + + pid_t child; + int status; + while (concurrent_forks > 0) + { + child = wait( &status ); + if (status != 0) { + printf("chess instance failed.\n"); + exit(EXIT_FAILURE); + } + + if (instance.instance_no < n_forks) { + replace_fork(child, &fork_list, &instance); + } else { + concurrent_forks--; + } + } + exit(EXIT_SUCCESS); +}