From 8ffe8c6d64ad4d10fe34415ee77452f23f09722e Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 11:19:05 -0600 Subject: [PATCH 1/8] Initial commit --- README.md | 96 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 4b8dba5fa..937276f97 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,22 @@ Now that we've talked a bit about how processes and system calls work at a high level, it's time to apply these concepts by doing some exercises related to process creation and making system calls. We'll be utilizing the `fork()`, `exec()`, `wait()`, and `pipe()` system calls in order to create processes and even have them pass messages to each other. ## Objective -To introduce and familiarize yourself with some basic system calls pertaining to process + +To introduce and familiarize yourself with some basic system calls pertaining to process creation, to spawn some new processes, and to practice writing more C! ## `fork()` -The `fork()` system call is used by a parent process to create a new child process. Its -actual implementation isn't as intuitive as it could be, though. When a parent process -executes `fork()`, the new child process that is created is an almost exact copy of the -calling process from the operating system's perspective. We say _almost_ an exact copy -to delineate the fact that while the new child process has the same instruction set -(i.e. code) as its parent process, the child process starts executing at the point right -after `fork()` is called in the parent process. + +The `fork()` system call is used by a parent process to create a new child process. Its +actual implementation isn't as intuitive as it could be, though. When a parent process +executes `fork()`, the new child process that is created is an almost exact copy of the +calling process from the operating system's perspective. We say _almost_ an exact copy +to delineate the fact that while the new child process has the same instruction set +(i.e. code) as its parent process, the child process starts executing at the point right +after `fork()` is called in the parent process. Let's look at a program that calls `fork()` to try to give an example of what this means: + ```c // p1.c #include @@ -39,7 +42,9 @@ int main(int argc, char *argv[]) return 0; } ``` + Running this program, one of the possible outputs could be something like this: + ``` prompt> ./p1 hello world (pid: 29146) @@ -48,22 +53,24 @@ hello, child here (pid: 29147) prompt> ``` -So as we can see, the child process doesn't return the exact same output as its parent process, which -is good, because otherwise spawning child processes wouldn't be nearly as useful. Notice that the child -process has its own process identifier (PID); it also has its own address space, program counter, and -execution context that are not the same as its parent's. +So as we can see, the child process doesn't return the exact same output as its parent process, which +is good, because otherwise spawning child processes wouldn't be nearly as useful. Notice that the child +process has its own process identifier (PID); it also has its own address space, program counter, and +execution context that are not the same as its parent's. -More specifically, if we look at the `int rc = fork();` line, which both parent and chlid execute, they -receive different results here. The parent process receives the PID of the child process it just spawned, -while the child process receives 0 if the `fork()` call was successful. +More specifically, if we look at the `int rc = fork();` line, which both parent and chlid execute, they +receive different results here. The parent process receives the PID of the child process it just spawned, +while the child process receives 0 if the `fork()` call was successful. ## `wait()` -So `fork()` allows us to spawn new child processes, but the thing with having multiple processes is that -the order in which they execute is not deterministic, i.e., the parent may execute before the child or -the child may execute before the parent; we can't say for certain. The `wait()` system call (along with -the more complete `waitpid()` system call) allows us to get around this non-determinism if that is something -that needs to be accounted for. Let's add a call to `waitpid()` in our previous example program to ensure that + +So `fork()` allows us to spawn new child processes, but the thing with having multiple processes is that +the order in which they execute is not deterministic, i.e., the parent may execute before the child or +the child may execute before the parent; we can't say for certain. The `wait()` system call (along with +the more complete `waitpid()` system call) allows us to get around this non-determinism if that is something +that needs to be accounted for. Let's add a call to `waitpid()` in our previous example program to ensure that the child always runs before its parent: + ```c // p2.c #include @@ -89,11 +96,14 @@ int main(int argc, char *argv[]) return 0; } ``` -Here, the `waitpid()` function suspends the parent process until the child process pointed at by `rc` terminates. Thus, we ensure that the parent process only runs after the child process has finished its execution. + +Here, the `waitpid()` function suspends the parent process until the child process pointed at by `rc` terminates. Thus, we ensure that the parent process only runs after the child process has finished its execution. ## `exec()` -The `exec()` system call is used in order to run a program that is different from the calling program (since `fork` only executes copies of the program that called it). + +The `exec()` system call is used in order to run a program that is different from the calling program (since `fork` only executes copies of the program that called it). Let's say we wanted to spin up a child process to execute a word count program. Here's how what a program that does that might look like: + ```c // p3.c #include @@ -113,8 +123,8 @@ int main(int argc, char *argv[]) } else if (rc == 0) { // child process satisfies this branch printf("hello, child here (pid: %d) \n", (int) getpid()); char *myargs[3]; // allocate an array of chars to hold 3 bytes - // `strdup` duplicates the given input string - myargs[0] = strdup("wc"); // pass the name of the program we want to run as the first array element + // `strdup` duplicates the given input string + myargs[0] = strdup("wc"); // pass the name of the program we want to run as the first array element myargs[1] = strdup("p3.c"); // argument: the file to count myargs[2] = NULL; // marks the end of the array execvp(myargs[0], myargs); // runs the word count program, passing in the `myargs` array to the word count program as arguments @@ -127,16 +137,19 @@ int main(int argc, char *argv[]) return 0; } ``` -Here, we're doing the same thing as before, forking a new child process from a parent process. Then, inside that -child process, we're calling `execvp()` with the arguments it needs to run the word count program. Note that `exec` -does not spin up _another_ child process from the child process in which we called it. It transforms the process -that called it into the new program that was passed to `exec`, in this case, `wc`, the word count process. That's -why we still had to have the parent process `fork` a new child process. + +Here, we're doing the same thing as before, forking a new child process from a parent process. Then, inside that +child process, we're calling `execvp()` with the arguments it needs to run the word count program. Note that `exec` +does not spin up _another_ child process from the child process in which we called it. It transforms the process +that called it into the new program that was passed to `exec`, in this case, `wc`, the word count process. That's +why we still had to have the parent process `fork` a new child process. ## `pipe()` -Conceptually, a pipe is a uni-directional channel between two processes that would otherwise be isolated from each other. When a pipe is established between two processes, one process has access to the write end of the pipe, while the other has read access to the other end of the pipe. Thus, if you want two-way communication between two processes, two pipes will have to be created between both processes, one in each direction. -Some things to keep in mind when working with pipes is that when a process writes to a pipe, the other process receives the data in FIFO order (which makes sense when you think about the pipe analogy in real life). Additionally, if the process with read access tries to read from the pipe before anything has been written to it, the reading process is suspended until there is some data to read. +Conceptually, a pipe is a uni-directional channel between two processes that would otherwise be isolated from each other. When a pipe is established between two processes, one process has access to the write end of the pipe, while the other has read access to the other end of the pipe. Thus, if you want two-way communication between two processes, two pipes will have to be created between both processes, one in each direction. + +Some things to keep in mind when working with pipes is that when a process writes to a pipe, the other process receives the data in FIFO order (which makes sense when you think about the pipe analogy in real life). Additionally, if the process with read access tries to read from the pipe before anything has been written to it, the reading process is suspended until there is some data to read. + ```c #include #include @@ -151,7 +164,7 @@ char* msg3 = "hello world #3"; int main() { char inbuf[MSGSIZE]; // a buffer that will hold the incoming data that is being written - int p[2]; // a two-element array to hold the read and write file descriptors that are used by the pipe + int p[2]; // a two-element array to hold the read and write file descriptors that are used by the pipe // establish our pipe, passing it the p array so that it gets populated by the read and write file descriptors if (pipe(p) < 0) { @@ -165,7 +178,7 @@ int main() write(p[1], msg3, MSGSIZE); for (int i = 0; i < 3; i++) { - // read 16 bytes of data from the read file descriptor + // read 16 bytes of data from the read file descriptor read(p[0], inbuf, MSGSIZE); printf("% s\n", inbuf); } @@ -173,20 +186,25 @@ int main() return 0; } ``` -This program isn't actually sending data between two different processes. The process that is doing the writing is also doing the reading. This process is essentially just talking to itself. But at least it gives you an idea of how to create pipes and send data between both ends. + +This program isn't actually sending data between two different processes. The process that is doing the writing is also doing the reading. This process is essentially just talking to itself. But at least it gives you an idea of how to create pipes and send data between both ends. ## What You'll be Doing for this Lab + This was your first introduction to making system calls to an operating system kernel. Obviously, there are many more system calls that we'll talk about in a future lesson, but for now we'll just practice with these. Once you've cloned this repo, go into each directory, open up the exercise file, read the prompt, and write some C code! Compile your code with `gcc [NAME OF FILE].c -o [NAME OF EXECUTABLE]`, then run the executable with `./[NAME OF EXECUTABLE]`. ## Further Reading + If you would like to read more on this topic, these chapters from _Operating Systems: Three Easy Pieces_ heavily informed this particular topic and material: [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf](http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-api.pdf) [http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-mechanisms.pdf](http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-mechanisms.pdf) Additionally, it's always a good idea to read the man pages for any system calls you're trying to use: - - The man page for `fork`: [https://linux.die.net/man/2/fork](https://linux.die.net/man/2/fork) - - The man page for `wait` and `waitpid`: [https://linux.die.net/man/3/waitpid](https://linux.die.net/man/3/waitpid) - - The man page for the `exec` family: [https://linux.die.net/man/3/exec](https://linux.die.net/man/3/exec) - - The man page for the `pipe` system call: [https://linux.die.net/man/2/pipe](https://linux.die.net/man/2/pipe) + +- The man page for `fork`: [https://linux.die.net/man/2/fork](https://linux.die.net/man/2/fork) +- The man page for `wait` and `waitpid`: [https://linux.die.net/man/3/waitpid](https://linux.die.net/man/3/waitpid) +- The man page for the `exec` family: [https://linux.die.net/man/3/exec](https://linux.die.net/man/3/exec) +- The man page for the `pipe` system call: [https://linux.die.net/man/2/pipe](https://linux.die.net/man/2/pipe) ## Stretch Goal -Open up the `/stretch` directory. In there, you'll find an involved exercise pertaining to file locking and concurrency. Read the README included in that directory for instructions on what to do. + +Open up the `/stretch` directory. In there, you'll find an involved exercise pertaining to file locking and concurrency. Read the README included in that directory for instructions on what to do. From 6389c9f861fd436e8e0e69ff453063c3c6f44880 Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 13:59:51 -0600 Subject: [PATCH 2/8] Completed ex1 --- ex1/ex1 | Bin 0 -> 8668 bytes ex1/ex1.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100755 ex1/ex1 diff --git a/ex1/ex1 b/ex1/ex1 new file mode 100755 index 0000000000000000000000000000000000000000..effd6cc1cab56330764e010107710ac520caa3fd GIT binary patch literal 8668 zcmeHMU1%It6u#Rw8e?p>FOuTlv=B|DZBlC`_=8Ew;0A-%Ho+f|>uz?E9h~egyR#+% zg-8fw8&?88`67MvL7|Vuhia?Xvee_ujAn{PpkKg-GlaVt$7Zq6?aA6Jk+V@Pyb4O+lqRG4zc6ihc5Vwl+(m z8Qv1H&JPHba?E~dtT{yGC!5=Z#u%HxaFjAaO5d6F=>-z6cjhiU47#rCe&Su)S7w)( zk3uQSekD`hY>L-Ay*sFPzm5oTn9#24-KHCYdNSvDMW=+ec)bsGz2iEbn7nUF%lIbB ze#y;G>412>>$=_r-A^2qrrPL`vXY;1^I7TUCkqNU&&Nl20mvWcoI)J05%dIC&g%dY zq#Pa^8;bN`{#YlR$GGLZ;+<2SZb7q zXg~cF^6`na2wy`B+6nEeluLb{o9WBWd0Ak}Jy4G0rs8J?*Np2e1^8wYxo&RY>fruIW<@Io$15J z4`W%Q+9$OwQ;nVx*p(bp*MDg=8aXcY*4OB9vA6y$y@%+n(mO`)JiJ-!jkH&Btc){R zC^^GnA7zPXjh5^HX zVZbn882JA%uxEewI7hQ*Q1a+H>y%1G@j@xNGRVU^bvQ0FI4{Ow_Iw??C`uA5qSTEH zXV&!vd<#A|Pw4m3FXF`7pCs%DoN|0@oe&KGZT1BuBqYvlcgX1+syP!C-@(~=nz!3G zop$r0hnpKa#TlL#QbLE#U5Vf%5c@&mZiRz=5Mu6+z|vL14WTGL6vIbjn7dZd_~95H zjbZMy;D8a&A_UK(d1l%Ug$xFd(Asa|RJ!%KrF!njYy>n11aDFsk{Z(4GF!OuKbl;M AmH+?% literal 0 HcmV?d00001 diff --git a/ex1/ex1.c b/ex1/ex1.c index c4b111641..f0347043e 100644 --- a/ex1/ex1.c +++ b/ex1/ex1.c @@ -2,6 +2,12 @@ // (e.g., x) and set its value to something (e.g., 100). What value is the variable in the child process? // What happens to the variable when both the child and parent change the value of x? +// 1. What value is the variable in the child process? +// The value is also the same. It looks like the x variable is in a global scope. + +// 2.What happens to the variable when both the child and parent change the value of x? +// The x variable changes due to the scope of being inside the conditional statements. + #include #include #include @@ -9,6 +15,29 @@ int main(void) { // Your code here + int x = 100; + printf("x value before calling fork: %d \n", x); + + int rc = fork(); + + // child process starts execution here + if (rc < 0) + { // fork failed; exit + fprintf(stderr, "fork failed\n"); + exit(1); + } + else if (rc == 0) + { // child process satisfies this branch + x = 200; + printf("hello, child here (pid: %d) \n", (int)getpid()); + printf("x value in child when changed: %d \n", x); + } + else + { + x = 300; + printf("hello, parent here (pid: %d) of child %d \n", (int)getpid(), rc); + printf("x value in parent when changed: %d \n", x); + } return 0; } From d9f24cfdc202bd98543863caff081116590d18cf Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 14:29:54 -0600 Subject: [PATCH 3/8] Completed ex2 --- ex2/ex2 | Bin 0 -> 8708 bytes ex2/ex2.c | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100755 ex2/ex2 diff --git a/ex2/ex2 b/ex2/ex2 new file mode 100755 index 0000000000000000000000000000000000000000..c72bc0046eff2e3b4713d36f58141e7d56e05228 GIT binary patch literal 8708 zcmeHNU1%It6u#Rgn#R~{K_zO%NimuVCXE`1kie$R=*EUNnpmtL*CadJ9lF_FW+$Y1 z2n0eTOAN#Ze*%3F5h*^2?Sr6bMA1~l#^6JcqCP~~K!m<3;`)7eW|G-S?XwT}z?pNt zd(Sy@=eslE?!CG8*B}4fE<|j<5HtIP5RK4ytq^mbv6(v<*@nUaCL~vk5{(|A7g9+!%@lzDP8M=OV5*Ny~Le(7<6^`gCed8f@y2S zOc+X8bSFlOJ5AAg&OxuQ2-fez^S5IcFY{7ES7OnTTUvI#VCnoPZvS)l_ zMc1)&=lpgY?Ja_ zKJ=RGsTW5+$5+Q-2ywJt(8qo$vm>_}Uz1<&7=t0i;d*@D1FFZn?0#1R{ijZvef_~V zVMKTXrquY8z&eUo)hfghe7EYJhW9LWu)!D@(gi#SI}gitmT7{n0N2A_Y!)H|dk2(p zVPPya%tN@J{wv7GE3!xU8XC|BX!}IbY0uiD?Ww733Yc;~l;ikwZh52em+sEX?(+J@ zYp<_Ajy3}tgNlO~A(X!2vSB&)DEv74d}+n=vkt%Wu<*WJQ1E8|NNG5Hepwf5*!F7xSxS=6w!` z{>}0atnsq~+q2W#qH&SSk>o<{87yg%3thNdnyFXkznxzze}X+?M^86eO6GMm%%GuUZfrf~Wi)vieY+WFy^N<+#*fH2r83sGVE7#U z=s+viUA#xh{H}Z#{En+7bG5XZoc${C@|R1MmUj?VX?a&&-&5E3)%B9Pet@eG1B(yX zaC(O-EoWhuxJDIQzgH@i43~CW*Xi9yZ=K#F^j7ITLGLqq$LU>x$6t(XE`Bvmik_aH z(*-Ms-&2O0v5d5xwG2CFOggq}8RPksg@AftI!@j(@_rzLn(IY6@0>T%BLJy-(NZ+( z#aPD1dKMW^+c~?Ku~Mpzs-5>rx1M0gQB|}s;#fKN*5QLH#*0VNiEO?Y9;&M2t&I=k z;V5CtbuQPzPr_39Ta`ke>*ofnf8%O3&DLEe-~Qy=NVGy|Fe&46Y=GoTsJ4E&E6ICP}x42N?lA$fG2vK*%%o^#?$2_Dv| z!*Mx^^I{xk&y=y3q9nE?oF-&g7i?F+H{hqouvuXdwGwgjgy5J0&UyM>^b0u5cGH9j zz#SxF5@-DTEt+5H$!WsGqZ`(XRV&_B)H#hc+6>j-Z0*B3wG4Di>`xW;n?CpaP zbAJSut`cq(g)#TK!niYnyCayJO5ymE5j+&Z+;_pjqx$~^o=@}qmglJlppb<3ST~O` gaO%9552^SF&6YO}!36l!!+`W1x&xy3OezQQFD4GJK>z>% literal 0 HcmV?d00001 diff --git a/ex2/ex2.c b/ex2/ex2.c index 4245375b9..21b34cec0 100644 --- a/ex2/ex2.c +++ b/ex2/ex2.c @@ -1,14 +1,48 @@ -// 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 +// Write a program that opens the text.txt file (with the `fopen()` system 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? +// 1. Can both the child and parent access the file descriptor returned by `fopen()`? +// Yes, both child and parent had access since you can write to fp. + +// 2. What happens when they are written to the file concurrently? +// They both get saved. + #include #include #include int main(void) { - // Your code here - + // Your code here + FILE *fp; + fp = fopen("text.txt", "w"); + printf("===Opening the file in write mode===\n"); + + if (fp == NULL) + { + printf("Error opening file!\n"); + exit(1); + } + + int rc = fork(); + if (rc < 0) + { // fork failed; exit + fprintf(stderr, "fork failed\n"); + exit(1); + } + else if (rc == 0) + { // child process satisfies this branch + fprintf(fp, "%s \n", "child"); + printf("===Finished writing to file (Child)===\n"); + } + else + { + fprintf(fp, "%s \n", "parent"); + printf("===Finished writing to file (Parent)===\n"); + } + + printf("===Closing the file===\n"); + fclose(fp); return 0; } From 7b938f9e672c62468776298d1887d2dd6b5bebae Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 14:30:41 -0600 Subject: [PATCH 4/8] Forgot to add text.txt file to previous commit --- ex2/text.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ex2/text.txt b/ex2/text.txt index e69de29bb..cf90a34a2 100644 --- a/ex2/text.txt +++ b/ex2/text.txt @@ -0,0 +1,2 @@ +parent +child From b8cf1725e23b4404fa930a6d34f5cd57f446218e Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 14:36:11 -0600 Subject: [PATCH 5/8] Completed ex3 --- ex3/ex3 | Bin 0 -> 8668 bytes ex3/ex3.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100755 ex3/ex3 diff --git a/ex3/ex3 b/ex3/ex3 new file mode 100755 index 0000000000000000000000000000000000000000..ac055123b02dc345607c030d6ac3988e81879df1 GIT binary patch literal 8668 zcmeHMU1%It82vU)G{&^qzDPu?)4Wku&52c92vI`Y_C|E>X&$)9anVl`Z2|nBpzWL6% zKi}LrcV@YJ@ArTH_V=SAsVyRn9uXOWr~5?Ci323^B;187bz+*`RfUT0~ir8?F->GBF%u6AVW?TPPKHivdw+$$Xc#;bBnqiK!>=HCTsUX~d~g z^*G)doIgLD-BdiIpoY$PvIQT1CwVKKR4)ZM-G`>>nBR=X(;FQZu#KYtof3 zZN}GcI*=#xag32ERVn=2_=Zis-KGP1JRfsK_hOUH@9Ox`*N){Tk4E2wlh6&Ec3X=n z!aN4*@)3Nu`-z+|e?Ow;EQ4j8@cV5bvYc}{48IQk7~;D-MczSt9DV{GH@2n6b%@s! zyXe0)SqP5Ljzf|`_~=62AFY&&qot)v37qy6oa4BX`J=Rc{&4>CmG|%LdiBFS2T|t0 zQ*hZfpq*H2Irv%XdEhkbj6v@P^YA;58}FNivyRWucWWI#1F6liU_7Um>VY@6@5nxk zt6W4Q*mH2^zvhH`?lGKtS+fdQ1*`&A0jq#jz$#!B`0o`s?XLXlF5h!*=KkW%n&)v@ z$vs$p?|}@ha&hKf>~pa|bT4Mz)v+5WIPmR-?=Jk%oC5rcE60`G{pKr(y34sIfZWxW zzCgGp%}HJVdus>cfv;C?HeU>@Ki1{<&|*ZRW(xr=+~ph2+uyV^cfi`2pY`<@eO=er zySR!RU)^yPVd7Lf^Eu+$EDKwA+wJx&m!+-SL|mA*ek9sObc<+==u4pKnt#TbE|e=? zX+ZE_vQl#fWTsXt6_-397@zEE0$4oufO9Q;2$4Q!{tps!4LyjS>2P%owh2h$Rx6|f3e1*`)9PX)G*44>x6wvQ_w zU6(xHpO=$(mS!|X;AI}_ScYvK>1hqqV`1lR%QmId){;(44{2h*hc zK{r_z>})}IisVQsoZI%OxmjfMrWOJZXXgdpZs%N~T$KzrG`7ek?$FR8z~Z4)coN9H z5bo;?0dVgl+8aS6)W%JgINzJ#FC_Tk1m{jsygzr8;+%Ucy>OmE^DLTYrslkNJbZ-i gdIzV{-OsJ`bH`>QlsOc5L)u8xP|mKo!revw0oVjHi2wiq literal 0 HcmV?d00001 diff --git a/ex3/ex3.c b/ex3/ex3.c index 3a3698c1f..d3726284e 100644 --- a/ex3/ex3.c +++ b/ex3/ex3.c @@ -11,5 +11,24 @@ int main(void) { // Your code here + // starting process + int rc = fork(); + + // child process starts execution here + if (rc < 0) + { // fork failed; exit + fprintf(stderr, "fork failed\n"); + exit(1); + } + else if (rc == 0) + { // child process satisfies this branch + printf("hello \n"); + } + else + { + wait(NULL); + printf("goodbye \n"); + } + return 0; } From b605155ab21a382b49daabd635f323d98dc4ee65 Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 15:35:25 -0600 Subject: [PATCH 6/8] Completed ex4 --- ex4/ex4 | Bin 0 -> 8804 bytes ex4/ex4.c | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100755 ex4/ex4 diff --git a/ex4/ex4 b/ex4/ex4 new file mode 100755 index 0000000000000000000000000000000000000000..6b3fdb9ed05c0bc49a4239ce3d4384cdb837697e GIT binary patch literal 8804 zcmeHNU1(fI6rN2RO=H?@5lf0G-d0v?(fmjQp;$?3Zr#{oQ=34M>U1}IlfAmxUGDDE z)Bf z6l;WcMT~O;j#7@=r$-xI)cAO#O=yg{2~0;ZJ)|r<(`9M_MdK}P$70ZRTlW)h)w&W} z#cUW#St?i3rFBy@-e)_4cs<&qj_U(jbiDhtA&4ilPOj*9utnqfI^J3BPt3fp)28{2 zm&%@-pVSV~cu5qD>veTMahMunqeIF{{+yf7NH;%GP`I%kmvlVVoJ1Ur5%dHt>)NmC zIy5*s80ta&IInsgqmp&SGpCqtQs#5AG&7Yhd~wMaYjKX=j)Y@G@{4vO?;PR*3c z&Q#ZtF3ihK!wK{lnDK8|K|Y_*cp2D`$$-g#$$-g#$$-g#$-w_H17peR?d05Q&-eD< zoSy$PnyS4v_r{uNU*KjYIp5rY4N-EwKe^C%6kDs_s~4_aSn@wd-raLM7EHa@t3Oq3-(L*6A3--_TS`3C3DJACYTtsh z9XM=DM zMlJEGYR{@Rt=f!gCsdnN?Q3X-IKHrFHq(`zH*&f zg4z{o2dRBQ?Fh9?)J{_Sgqoyw5!yt-d)=Byxj84(Dvo-EDQi6I<}y!OBf~?7tOOOU zS*@+2JMHGXb0vYlr@%$8Fy0F%OAjrkJSSgn7&|n~C~yFAL7h}UVTrP;eK4m?=66*R zb?%?rFfy)2)4HK36lvD<_tYl+eXvc-U0PaN9?gJ1viE~H`%3da86P` zM}efO=y9}R+!et*O9}TMis0uW_*evwM(~*kPDe1$ZTS0zW-#x#dH>5h>uq2j2I)KH tfnfRf_O);ezBzwV #include #include @@ -10,7 +13,39 @@ int main(void) { - // Your code here + // Your code here + + // parent asking OS to start new process, 1 process + int rc = fork(); + + // parent and child processes return from fork(), 2 processes + if (rc < 0) + { // fork failed; exit + fprintf(stderr, "fork failed\n"); + exit(1); + } + else if (rc == 0) + { // child + printf("From child, PID: %d, PPID: %d \n\n", getpid(), getppid()); + wait(NULL); // wait for child process to join with the parent + + // execl + int proc1 = execl("/bin/ls", "ls", "-ls", NULL); // returns list direction with long form and file size + printf("proc1 %d \n", proc1); + + // execvp + // char *myargs[4]; + // myargs[0] = "/bin/echo"; // "echo" also works since execv p flag also initiates search + // myargs[1] = "echo"; + // myargs[2] = "web development"; + // myargs[3] = NULL; + // int proc2 = execvp(myargs[0], myargs); // 1st argument always is program to run, echos array arguments + // printf("proc2 %d \n", proc2); + } + else + { // parent + printf("From parent, PID: %d, PPDI: %d \n", getpid(), rc); + } return 0; } From f08a32774b941f66201960c336dd2a909fcf672c Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 15:37:35 -0600 Subject: [PATCH 7/8] Cleaning up ex4 --- ex4/ex4.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ex4/ex4.c b/ex4/ex4.c index 6e2055d46..ff97b7538 100644 --- a/ex4/ex4.c +++ b/ex4/ex4.c @@ -32,15 +32,6 @@ int main(void) // execl int proc1 = execl("/bin/ls", "ls", "-ls", NULL); // returns list direction with long form and file size printf("proc1 %d \n", proc1); - - // execvp - // char *myargs[4]; - // myargs[0] = "/bin/echo"; // "echo" also works since execv p flag also initiates search - // myargs[1] = "echo"; - // myargs[2] = "web development"; - // myargs[3] = NULL; - // int proc2 = execvp(myargs[0], myargs); // 1st argument always is program to run, echos array arguments - // printf("proc2 %d \n", proc2); } else { // parent From 599b81129f276b33456030938e0607d2cb11539f Mon Sep 17 00:00:00 2001 From: Kevin Sooter Date: Wed, 20 Feb 2019 17:18:36 -0600 Subject: [PATCH 8/8] Completed ex5 & ex6 --- ex5/ex5 | Bin 0 -> 9064 bytes ex5/ex5.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------- ex6/ex6 | Bin 0 -> 8596 bytes ex6/ex6.c | 24 +++++++++++++++++++++--- 4 files changed, 66 insertions(+), 10 deletions(-) create mode 100755 ex5/ex5 create mode 100755 ex6/ex6 diff --git a/ex5/ex5 b/ex5/ex5 new file mode 100755 index 0000000000000000000000000000000000000000..bd0b5728f9d800e85ea8068e9208fb886001a72f GIT binary patch literal 9064 zcmeHNZD?Cn7(Qt?-P&r}DMRstyJ}?)w|>k)9hNY6D?JR9>o47O$H;LPj zLa`1OW1$G@1ZCSlks?Kgj8V2S$5ypy5y2_@(I0c9qT(+pL#)qp?z!pB?R0|vyf2*d zzR!6-a?X2BlAH79>zlv)d8ZJeN+AX-gb-o0gG+@tCJabI+>d6WN!ii9J+d$I;`1CW zr%*Y(C1RYbFqCpnq;pTXiSn;49}^m5ZUWO$jTTa7ts_}V4*BCv*I+SFeV`{ryu>vo zUm^y*P|8d;*Oe&^`QxSTcH(W)7A|%jmg#tR=m965j9baHWn;`AZ&b%~mq5(CmuS)a zx-(fjk?Pe3{&)s9j7u$OJ+YU{VnZQiE_FDOipfN(r(fan{TS8pxaTBde+)0&ppN z``sLK*gwBo_;Y@4JYs)59GwzLnT-C^{0tqhLwgW=<8i&%>JmvAi)N!GxM+T99q&GE zLhOyV;OR&U@6(+-o_jX3b%*;NGkp61Op5DZoR``sH7Z0sJ_nj88$v7tTL$i)1whdO zJOVxg-T}_D!8x|B5@H4TSp*mZuSTQZOYZylF7KdE?u5U)X0M95Gtjsvjk%27m`rpv z#*QXqz@!Jz=(nc&-KGO$oBlZW`}fQ5X+OQM1!D$U2u<9L6M{xrEx+cy&>G0K)M;9c z^)n7XH@rmHibfsRymaz9K2|~tbHRLeAI)T~zI9vHVP1(Y7=a!`WBjI7PCg&knE47Q z$Uu;RAOk@Lf(!&1_3CDg@LQZpMc=`r3#Rn!NSJi{FU+=Ekve~D{QN9`GZard4k!6i zd#Cf4VSNfi=NPsyaLp`iNMP>y$cM$ZF>*n@+D%8%$>rrEr;4xoHQOA`iDDEQn2aEg z7da)Qy0B}`d}=a$j8Biv6XwvR^#0F^eB26GkIXlW!fL+ZW7UtT{u9-oQT?Z?Kdbt4 zsvlSVdGtc;9DZmog!bL@4H58>I0t8MV5xCFmd#$H^eCloC^b=^OSZ`Iz#Ct zN*_^TnAua5UZM03rPnCENy$nk`;Ei>b~0u>(k#kgOF3LG(uuTX^h6U$D^?|X`t3s{ zu+8r8GrHr6Wb6r}W5?EwMgs*cRf&d-Q6-d3I%->~?8aLespr-QF)@;tV>8tA>XYDX z{EbSY%*5BgvsQU?bU{$)Hr+U4G5MD@pVs^b&97_ztLAf>SLol7HJY!~-2J`UsPWU9 z-)0(tI>SJ1s`qSaDMobJ>L=GAi7IGq@yC6dGY1+weu=bqFek_G*k< zM-o}eO^|s#Lb;W48Wrwr4`CZ%ua!+FVnn7!8g>Bkj)kgD$|bjhK(-ZCPI1VG?L?Ml zxV(_~??8p@i{sU;?p)SFZ9dAGKintkd2=EvqKTAPo9PuTm0}uo)XHYDxkYSQFSb{T z-wfQK%&{9>MO$S+PS0?Nw`I=#$V!Esdl=rA@O~z|TnM+0Td(mExKNKeqtXv*ybc)S zR4Hmh@5Q@)_<#?y4(hdk*@t=k=+*N|&x>F8;WvEvEgwGN!zX>1wO-x;A_b~0&w4Ox zsI2|sib(y>gxRY@1GTY!&sy}q^)pa0U%aQXk9#TmGQG{JZ&Cev*m};kI+0}~&S_Ue g&Ovuhs&ht5r_()`it|J|XVE={&iT_PZ_)eYFUXZBga7~l literal 0 HcmV?d00001 diff --git a/ex5/ex5.c b/ex5/ex5.c index cbf3b8e61..d05c36471 100644 --- a/ex5/ex5.c +++ b/ex5/ex5.c @@ -1,7 +1,7 @@ // Write a program that forks a child and creates a shared pipe -// between the parent and child processes. Have the child write -// the three messages to the parent and have the parent print out -// the messages. +// between the parent and child processes. Have the child write +// the three messages to the parent and have the parent print out +// the messages. #include #include @@ -10,13 +10,51 @@ #define MSGSIZE 16 -char* msg1 = "hello world #1"; -char* msg2 = "hello world #2"; -char* msg3 = "hello world #3"; +char *msg1 = "hello world #1"; +char *msg2 = "hello world #2"; +char *msg3 = "hello world #3"; int main(void) { // Your code here - + char buffer[MSGSIZE]; // sets up a buffer of 16 bytes + int p[2]; // sets up pipe, returns 2 file descriptors for each end of pipe + + // PIPE FAIL CHECK + if (pipe(p) < 0) + { + fprintf(stderr, "pipe failed\n"); + exit(1); + } + + // FORK + int rc = fork(); + + // FORK FAIL CHECK + if (rc < 0) + { + fprintf(stderr, "fork failed\n"); + exit(1); + } + + // CHILD - reads messages from parent + if (rc == 0) + { + printf("From child, PID: %d, PPID: %d\n", getpid(), getppid()); + for (int i = 0; i < 3; i++) + { + read(p[0], buffer, MSGSIZE); // p[0] is the read end by default + printf("%s \n", buffer); + } + } + // PARENT - write messages for child + else + { + printf("From parent: PID: %d, PPID: %d\n", getpid(), rc); + write(p[1], msg1, MSGSIZE); // p[1] is the write end by default + 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 0000000000000000000000000000000000000000..9653c974c90c2db5e5b10bb3839de8e12576f777 GIT binary patch literal 8596 zcmeHNL1-LR7=GJSjT)M*phUDVZCzUx5>r$H+LAOGozR%HW`!WgYqC2@1}C%2?u<P11s_4{VtB(oFa#fyjc!$1H3 z{qMbh{`bvHc>7*%{_)FS_X&|{6Jl|n5TX;By+?>;VZamOQK$u#^6bDX<{Rc~V~n;+ zrWO7pVxC**C}rN9$hUS0$7fq(LSfVW{Lt(d zi%BSD)eoks+o5#6(;$TT9#TDG91mz$`R-MLD4(3Q-LhRlES)c}@^!2J#N>TjcGXv? z`W45UQ619x-c|W}RXcG~T5_X7%D}tectz=W)1?r%K99>PAD=meIGrPEiLQLEeIQ86 zp@IBBq6N>7yv5HkZTVdB&V|ZuQhKheF3e4pTv_%jd*<7IP2g~REaX3lrJN}xUXxw< zvZ}szm4G-op85FR#UiCU`ET`gseD~(0C6%O=NrEx?6UJ+jSP>TF^7iZZ^B6N22A-d zBvT0HQEnJNg75ZOdWI03OFL|c;ZynyC~O&)aXw4d_!%&By>wWJ3D^grXQ4@9Uuu$v zWIO#XjK4n}1jc8_l0*lzC#Y6>TxY7MxZoCnDUU%}#}nVbw>JOHiH#2~Tv}c_dhy%| z#0+Q#Dh@mlD*celj*l`=!_Tr!$#Kk|dH9_th4<})vMrp$jUVu5AhS~o>KR|C`u1G+ z>2B2JOhu!ggkkvyORICm0r-;ZW@{zbY+RyKe|`cBLaTnNW?pG5C)zh^=H-SLb_q7DXM#=3 z`AvNN@rzbla0Bp`RSWJ~^`HTK7k;B=uGP);rHxF@T)*>vv)Qy(PVy(w72djb)vB9~ z-Yx6*U#*&X8{=-TiN@n-HhXcS&xdLo*3wt!-@LZk%xxmt%x#6&Z*d)2IrIh0z<4wF z3GC`DF5=ElxWnwj^uD8al-?G+!I81SGxF83(Xss4=5Gn-vG}()wykdRN7A5z^U@?dB|`c2{uzS#RSFF?BZGc E4JPeCod5s; literal 0 HcmV?d00001 diff --git a/ex6/ex6.c b/ex6/ex6.c index 17532d65f..06fe33a2d 100644 --- a/ex6/ex6.c +++ b/ex6/ex6.c @@ -13,14 +13,32 @@ and `clock_gettime()` should work just fine. #include #include -#include +#include // for clock_gettime -#define number_iter 1000000 +#define number_iter 1000000 // 1 million iterations #define BILLION 1000000000L +// AVERAGE OF 1 MILLION ITERATIONS - CLOCK_MONOTONIC (~99k-102k nanosecs) int main() { // Your code here - + uint64_t diff; // variable for difference between start and end times + long long unsigned int total_times; // variable for total of 1 million iterations + long long unsigned int average_time; // variable to hold average of 1 million iterations + struct timespec start, end; // declare 2 structs to hold start and end times (includes secs and nanosecs in each struct) + + // CLOCK_MONOTONIC - Unspecified starting point for measuring elapsed time + for (int i = 0; i < number_iter; i++) + { // loops through 1 million times + clock_gettime(CLOCK_MONOTONIC, &start); // start the elapse timer + fileno(stdout); // empty write to stdout + clock_gettime(CLOCK_MONOTONIC, &end); // end the elapse timer + + diff = BILLION * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec; // total up differences of start and end + total_times = total_times + diff; // add the total time to total_times buffer variable + } + + average_time = total_times / number_iter; // calculates average time + printf("CLOCK_MONOTONIC Average Time = %llu nanoseconds\n", average_time); return 0; }