Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added ex1/ex1
Binary file not shown.
24 changes: 23 additions & 1 deletion ex1/ex1.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
// 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>

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;
}
Binary file added ex2/ex2
Binary file not shown.
48 changes: 46 additions & 2 deletions ex2/ex2.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,58 @@
// 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>

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;
}
14 changes: 14 additions & 0 deletions ex2/text.txt
Original file line number Diff line number Diff line change
@@ -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
Binary file added ex3/ex3
Binary file not shown.
17 changes: 16 additions & 1 deletion ex3/ex3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Binary file added ex4/ex4
Binary file not shown.
11 changes: 10 additions & 1 deletion ex4/ex4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stdio.h>
#include <unistd.h>
Expand All @@ -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;
}
Binary file added ex5/ex5
Binary file not shown.
29 changes: 28 additions & 1 deletion ex5/ex5.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Binary file added ex6/ex6
Binary file not shown.
15 changes: 13 additions & 2 deletions ex6/ex6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
5 changes: 4 additions & 1 deletion stretch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions stretch/src/balance.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7650
Binary file added stretch/src/bankers
Binary file not shown.
42 changes: 32 additions & 10 deletions stretch/src/bankers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

// ^^^^^^^^^^^^^^^^^^
}
Expand All @@ -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);
}

// ^^^^^^^^^^^^^^^^^^

Expand All @@ -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
Expand Down