June 1st, 2020 at 1:52 AM
So recently, the lady started her Summer semester and has an Operating Systems class going on now.
The professor said they need to use C for the class. The problem is that the computer science faculty doesn't actually TEACH C until like fourth year right before you get your bachelor's, for some reason. Now the professor said that only the first assignment needs to be done in C and the rest can be done in Java.
How you'd do any low-level work with Java is completely beyond me, you can't even pass by reference in the language, let alone fork a process.
But in any case, she knows that C is my favourite language, and as a result, she came running to me when her code wouldn't compile and she needed help getting started with gcc anyway (For Windows, so naturally it would be too f*** for a complete novice to figure out.)
The Assignment and Setup:
The assignment seems really simple. Only a few lines of code. My solution did it in 75 including some whitespace and extra lines for opening curly braces.
In a (very) watered down summary:
Now I didn't read the whole assignment, so I was missing specifics, but her code was really messy (I don't blame her, this was her first C program) and I decided to do a full rewrite.
The first thing I told her after hearing about the assignment and looking at her code is that it would be impossible to do on Windows, since that's what she was trying to do. The main problem lies in the fact that fork() isn't supported on Windows to create new processes. The other problem is that this was asking to use a variety of Linux syscalls that also aren't implemented quite the same way on Windows.
So instead, I ran her through installing Debian under the Windows Subsystem for Linux (WSL) since she has used Debian in the past and was relatively comfortable with it. Then we installed gcc and made sure it was all working correctly. finally, she got WSL setup to be the main command-line in visual Studio Code (the lightweight FOSS text-editor IDE) so she could do all the development in one place.
More Specifics and How I Cheated:
The only familiarity I have with Linux syscalls is with assembly, and using those calls is very different than using them in C. So as a result, there was a pretty big learning curve for me as well
The professor included a main() that would call the desired function so that wouldn't need to be written. It's a messy snippet, but acceptable enough for the task at hand.
I got hold of that main() and started to get to work.
Here's the rough pseudocode that she had so you can get an idea of functionality:
Extremely simplified. It was more like 100 lines.
But you can see the pattern. It forks, if it's the child process, it'll fork again, and if it's the parent, it'll wait for the child process to finish.
It should iterate over n processes to start, given by the command line argument which I omitted for simplicity.
Output:
Now, this needs to use a Pipe structure, which is basically a queue structure, which is to say that the first thing to go into the pipe is the first thing to come out of the pipe. Think of it as a line-up at your grocery store. Whoever gets there first gets their purchase processed first, and they are the first to leave.
The tricky part is that the pipe is defined as a file descriptor.
On Linux, files can only really be accessed by a single process at the same time for writing. If you don't then you get race conditions. More on this later.
But the point is that because we're forking multiple processes that are all writing to the same pipe (or a virtual file in memory, rather,) then we're going to need to make sure that our processes do not interfere with each other during their respective reading and writing.
So here's how I cheated:
I only allowed the root process (Process 5 in the example above) to read from the pipe.
Then I changed when each process writes to the pipe.
The professor said they need to use C for the class. The problem is that the computer science faculty doesn't actually TEACH C until like fourth year right before you get your bachelor's, for some reason. Now the professor said that only the first assignment needs to be done in C and the rest can be done in Java.
How you'd do any low-level work with Java is completely beyond me, you can't even pass by reference in the language, let alone fork a process.
But in any case, she knows that C is my favourite language, and as a result, she came running to me when her code wouldn't compile and she needed help getting started with gcc anyway (For Windows, so naturally it would be too f*** for a complete novice to figure out.)
The Assignment and Setup:
The assignment seems really simple. Only a few lines of code. My solution did it in 75 including some whitespace and extra lines for opening curly braces.
In a (very) watered down summary:
Quote:Write a C program that uses fork() to create new processes, and make those processes write data to a pipe, and read that data from the pipe.
Now I didn't read the whole assignment, so I was missing specifics, but her code was really messy (I don't blame her, this was her first C program) and I decided to do a full rewrite.
The first thing I told her after hearing about the assignment and looking at her code is that it would be impossible to do on Windows, since that's what she was trying to do. The main problem lies in the fact that fork() isn't supported on Windows to create new processes. The other problem is that this was asking to use a variety of Linux syscalls that also aren't implemented quite the same way on Windows.
So instead, I ran her through installing Debian under the Windows Subsystem for Linux (WSL) since she has used Debian in the past and was relatively comfortable with it. Then we installed gcc and made sure it was all working correctly. finally, she got WSL setup to be the main command-line in visual Studio Code (the lightweight FOSS text-editor IDE) so she could do all the development in one place.
More Specifics and How I Cheated:
The only familiarity I have with Linux syscalls is with assembly, and using those calls is very different than using them in C. So as a result, there was a pretty big learning curve for me as well
The professor included a main() that would call the desired function so that wouldn't need to be written. It's a messy snippet, but acceptable enough for the task at hand.
I got hold of that main() and started to get to work.
Here's the rough pseudocode that she had so you can get an idea of functionality:
Code:
int main() {
functionCallForForking(n);
return 0;
}
void functionCallForForking(int n) {
if(n == 1) {
write(Process 1 Started);
write(Process 1 Ended);
exit();
}
int forks = fork();
if(child) {
write(Process n Started);
functionCallForForking(n-1);
write(Process n Ended);
} else if(parent) {
wait();
exit();
} else {
printf(fork failed);
exit()
}
}
Extremely simplified. It was more like 100 lines.
But you can see the pattern. It forks, if it's the child process, it'll fork again, and if it's the parent, it'll wait for the child process to finish.
It should iterate over n processes to start, given by the command line argument which I omitted for simplicity.
Output:
Code:
$ ./a.out 5
Process 5 Started
Process 4 Started
Process 3 Started
Process 2 Started
Process 1 Started
Process 1 Ended
Process 2 Ended
Process 3 Ended
Process 4 Ended
Process 5 Ended
$ _
Now, this needs to use a Pipe structure, which is basically a queue structure, which is to say that the first thing to go into the pipe is the first thing to come out of the pipe. Think of it as a line-up at your grocery store. Whoever gets there first gets their purchase processed first, and they are the first to leave.
The tricky part is that the pipe is defined as a file descriptor.
On Linux, files can only really be accessed by a single process at the same time for writing. If you don't then you get race conditions. More on this later.
But the point is that because we're forking multiple processes that are all writing to the same pipe (or a virtual file in memory, rather,) then we're going to need to make sure that our processes do not interfere with each other during their respective reading and writing.
So here's how I cheated:
I only allowed the root process (Process 5 in the example above) to read from the pipe.
Then I changed when each process writes to the pipe.