diff --git a/ex1/ex1 b/ex1/ex1 new file mode 100755 index 000000000..d55c5cc51 Binary files /dev/null and b/ex1/ex1 differ diff --git a/ex1/ex1.c b/ex1/ex1.c index c4b111641..fe7998159 100644 --- a/ex1/ex1.c +++ b/ex1/ex1.c @@ -1,6 +1,8 @@ // Write a program that calls `fork()`. Before calling `fork()`, have the main process access a variable // (e.g., x) and set its value to something (e.g., 100). What value is the variable in the child process? + // The value is the same in the child process // What happens to the variable when both the child and parent change the value of x? + // Each retain their own copies and only edit their respective x #include #include @@ -8,7 +10,27 @@ int main(void) { - // Your code here + int x = 100; + + int rc = fork(); + + if (rc < 0) + { + printf("Fork failed\n"); + exit(1); + } + if (rc == 0) + { + printf("x is %d in the child process\n", x); + x = 300; + printf("x was changed to %d in the child process\n", x); + } + if (rc > 0) + { + printf("x is %d in the parent process\n", x); + x = 500; + printf("x was changed to %d in the parent process\n", x); + } return 0; } diff --git a/ex2/ex2 b/ex2/ex2 new file mode 100755 index 000000000..951c97321 Binary files /dev/null and b/ex2/ex2 differ diff --git a/ex2/ex2.c b/ex2/ex2.c index 4245375b9..4795a6d4c 100644 --- a/ex2/ex2.c +++ b/ex2/ex2.c @@ -1,6 +1,10 @@ // Write a program that opens the text.txt file (with the `fopen()` library call) located in this directory // and then calls `fork()` to create a new process. Can both the child and parent access the file descriptor -// returned by `fopen()`? What happens when they are written to the file concurrently? +// returned by `fopen()`? + // Yes they both are able to access the file descriptor because it is simply stored as an integer. + // But only the parent seems to read the file when I execute my program. +// What happens when they are written to the file concurrently? + // They both can write to the file, but mistakes happened when I ran it a few times. #include #include @@ -8,7 +12,47 @@ int main(void) { - // Your code here + FILE *file = fopen("text.txt", "r+"); + fprintf(file, "Hello, world!\n"); + + int rc = fork(); + if (rc < 0) + { + printf("Fork failed"); + exit(1); + } + if (rc == 0) + { + printf("Begin reading file on child process\n"); + while(1) { + int c = fgetc(file); + if( feof(file) ) { + break ; + } + printf("%c", c); + } + + fprintf(file, "Hello from the child process\n"); + + fclose(file); + } + if (rc > 0) + { + printf("Begin reading file on parent process\n"); + + while(1) { + int c = fgetc(file); + if( feof(file) ) { + break ; + } + printf("%c", c); + } + + fprintf(file, "Hello from the parent process\n"); + + fclose(file); + } + return 0; } diff --git a/ex2/text.txt b/ex2/text.txt index e69de29bb..97ca418b7 100644 --- a/ex2/text.txt +++ b/ex2/text.txt @@ -0,0 +1,14 @@ +Hello, world! +ello from the parent process +Hello, world!Hello from the child process +Hello from the parent process +Hello, world!Hello from the child process +Hello from the parent process +Hello, world! +Hello from the child process +Hello from the parent process +Hello, world! +Hello from the child process +Hello from the parent process +Hello, world! +Hello from the child process diff --git a/ex3/ex3 b/ex3/ex3 new file mode 100755 index 000000000..7e2cc5dfe Binary files /dev/null and b/ex3/ex3 differ diff --git a/ex3/ex3.c b/ex3/ex3.c index 3a3698c1f..e8128f557 100644 --- a/ex3/ex3.c +++ b/ex3/ex3.c @@ -9,7 +9,22 @@ int main(void) { - // Your code here + int rc = fork(); + + if (rc < 0) + { + printf("Fork failed"); + exit(1); + } + if (rc == 0) + { + printf("hello\n"); + } + if (rc > 0) + { + waitpid(rc, NULL, 0); + printf("goodbye\n"); + } return 0; } diff --git a/ex4/ex4 b/ex4/ex4 new file mode 100755 index 000000000..df762226e Binary files /dev/null and b/ex4/ex4 differ diff --git a/ex4/ex4.c b/ex4/ex4.c index 0221ca96e..770cd261e 100644 --- a/ex4/ex4.c +++ b/ex4/ex4.c @@ -2,6 +2,7 @@ // to run the program `/bin/ls`. Try a few variants of `exec()`, such as // `execl()`, `execle()`, `execv()`, and others. Why do you think there // are so many variants of the same basic call? + // They give you different options; such as including arguments as a null terminated array or listing them right in the exec function call, and also determining the environment to execute the desired program. #include #include @@ -10,7 +11,15 @@ int main(void) { - // Your code here + /* + char *args[2]; + args[0] = "/bin/ls"; + args[1] = NULL; + + execv( args[0], args ); + */ + + execl("/bin/ls", "ls", NULL); return 0; } diff --git a/ex5/ex5 b/ex5/ex5 new file mode 100755 index 000000000..79ebd5df1 Binary files /dev/null and b/ex5/ex5 differ diff --git a/ex5/ex5.c b/ex5/ex5.c index cbf3b8e61..18bbd5f35 100644 --- a/ex5/ex5.c +++ b/ex5/ex5.c @@ -16,7 +16,34 @@ char* msg3 = "hello world #3"; int main(void) { - // Your code here + char inbuff[MSGSIZE]; + int p[2]; + + if (pipe(p) < 0) { + printf("Pipe failed\n"); + exit(1); + } + + pid_t rc = fork(); + if (rc < 0) + { + printf("Fork failed\n"); + exit(1); + } + // parent + if (rc > 0) + { + for (int i = 0; i < 3; i++) { + read(p[0], inbuff, MSGSIZE); + printf("%s\n", inbuff); + } + } + // child + else { + write(p[1], msg1, MSGSIZE); + write(p[1], msg2, MSGSIZE); + write(p[1], msg3, MSGSIZE); + } return 0; } diff --git a/ex6/ex6 b/ex6/ex6 new file mode 100755 index 000000000..7d370c2da Binary files /dev/null and b/ex6/ex6 differ diff --git a/ex6/ex6.c b/ex6/ex6.c index 17532d65f..bd61ae3f7 100644 --- a/ex6/ex6.c +++ b/ex6/ex6.c @@ -20,7 +20,18 @@ and `clock_gettime()` should work just fine. int main() { - // Your code here - + int nanosecs = 0; + for (int i = 0; i < number_iter; i++) + { + struct timespec start, stop; + + clock_gettime(CLOCK_MONOTONIC, &start); + write(fileno(stdout), NULL, 0); + clock_gettime(CLOCK_MONOTONIC, &stop); + + nanosecs += BILLION * (stop.tv_sec - start.tv_sec) + stop.tv_nsec - start.tv_nsec; + } + nanosecs /= number_iter; + printf("Average time is: %d nanoseconds\n", nanosecs); return 0; } diff --git a/stretch/README.md b/stretch/README.md index 8fe640818..87f15d6ba 100644 --- a/stretch/README.md +++ b/stretch/README.md @@ -66,16 +66,19 @@ simulated bank account, that is. Don't get your hopes up.) 1. **Short answer**: How can things go wrong if two processes attempt the above plan at the same time? Is there more than one way things can go wrong? + - Without locking the file before reading and writing, one process could read the file right when another process deletes everything before rewriting. There could also be two process that read the file before either have the chance to change the balance, resulting in the wrong calculations of the balance being written to the file. 2. Study and understand the skeleton code in the `src/` directory. **Short answer**: what do each of the arguments to `open()` mean? + - The first one is the path to the desired file, the second one is the flags, and the last argument is the mode the file is opened with (read/write capabilites). 3. Take the skeleton code in the `src/` directory and implement the pieces marked. Run it. **Short answer**: What happens? Do things go as planned and look sensible? What do you speculate is happening? + - Without locking the file, sometimes a process will read that the balance is $0 even though it is not. It is probably reading the file in the middle of when another process is rewriting it. 4. Add calls to [`flock()`](https://linux.die.net/man/2/flock) to capture and release an exclusive lock on the file before reading and @@ -86,7 +89,7 @@ simulated bank account, that is. Don't get your hopes up.) 5. **Short answer**: Why is it working? How has adding locks fixed the problems you noted in question 1? How is overall performance of the application affected? - + - By locking the file when reading and writing, only the respective process can edit the file. That way the file can't be overwritten before the first process gets the chance to update it. The performance will slow down since it essentially turns it into a queue but it also reduces the risk of mistakes happening. ## Stretch Goals diff --git a/stretch/src/balance.txt b/stretch/src/balance.txt new file mode 100644 index 000000000..cd93a2fff --- /dev/null +++ b/stretch/src/balance.txt @@ -0,0 +1 @@ +7650 \ No newline at end of file diff --git a/stretch/src/bankers b/stretch/src/bankers new file mode 100755 index 000000000..976da8530 Binary files /dev/null and b/stretch/src/bankers differ diff --git a/stretch/src/bankers.c b/stretch/src/bankers.c index b44aed25c..d4cfb33db 100644 --- a/stretch/src/bankers.c +++ b/stretch/src/bankers.c @@ -90,6 +90,7 @@ int get_random_amount(void) // !!!! IMPLEMENT ME: // Return a random number between 0 and 999 inclusive using rand() + return rand() % 1000; // ^^^^^^^^^^^^^^^^^^ } @@ -114,17 +115,25 @@ int main(int argc, char **argv) // Check to make sure they've added one paramter to the command line // with argc. If they didn't specify anything, print an error // message to stderr, and exit with status 1: - // - // "usage: bankers numprocesses\n" + + if (argc < 2) + { + fprintf(stderr, "usage: bankers numprocesses\n"); + exit(1); + } // Store the number of processes in this variable: // How many processes to fork at once - int num_processes = IMPLEMENT ME + int num_processes = atoi(argv[1]); // Make sure the number of processes the user specified is more than // 0 and print an error to stderr if not, then exit with status 2: - // - // "bankers: num processes must be greater than 0\n" + + if (num_processes < 1) + { + fprintf(stderr, "bankers: num processes must be greater than 0\n"); + exit(2); + } // ^^^^^^^^^^^^^^^^^^ @@ -151,17 +160,30 @@ int main(int argc, char **argv) // Open the balance file (feel free to call the helper // functions, above). + int balance_file = open_balance_file(BALANCE_FILE); + flock(balance_file, LOCK_EX); // Read the current balance + read_balance(balance_file, &balance); // Try to withdraw money - // - // Sample messages to print: - // - // "Withdrew $%d, new balance $%d\n" - // "Only have $%d, can't withdraw $%d\n" + + if (balance >= amount) + { + int new_balance = balance - amount; + write_balance(balance_file, new_balance); + flock(balance_file, LOCK_UN); + printf("Withdrew $%d, new balance $%d (pid: %d)\n", amount, new_balance, (int) getpid()); + } + else + { + flock(balance_file, LOCK_EX); + printf("Only have $%d, can't withdraw $%d (pid: %d)\n", balance, amount, (int) getpid()); + } // Close the balance file + close_balance_file(balance_file); + //^^^^^^^^^^^^^^^^^^^^^^^^^^ // Child process exits