commit 041f660ccd9a1c69e232a6d3496613ce231f6f92 Author: Michael Zhang Date: Mon Jan 29 17:28:37 2018 -0600 f diff --git a/CSCI 4061_ Exam 2 Review Problems.html b/CSCI 4061_ Exam 2 Review Problems.html new file mode 100644 index 0000000..9dca02e --- /dev/null +++ b/CSCI 4061_ Exam 2 Review Problems.html @@ -0,0 +1,929 @@ + + + +CSCI 4061: Exam 2 Review Problems + + + + + + + + + + +
+Last Updated: 2017-11-18 Sat 11:21 +
+
+

CSCI 4061: Exam 2 Review Problems

+ + + +
+

1 Concurrent Printer

+
+
+

1.1 Printer Manager Process

+
+

+A printer is a shared resource in that there is usually only one +attached to a computing system that many users/processes can access. +

+ +

+Consider managing the printer using a "daemon" (background +process). Programs that want to print do not so directly but instead +contact the daemon to request data be printed. The printer daemon +must get data from client processes, feed it to the printer, notify +the client process of the completion of the printing, and then +pick up the next request if any. +

+ +

+Describe a simple protocol that could accomplish this by specifying +the following: +

+
    +
  • What mechanism will you use to allow the printer daemon process to +communicate with a client? +
  • +
  • How will client processes communicate data to the daemon? Keep in +mind that print files have a variety of types and sizes +
  • +
  • How will the daemon process notify client processes of the +completion of the print job or errors that occurred? +
  • +
  • Keep in mind that the printer daemon is a system process started +when the computer boots. +
  • +
+
+
+ +
+

1.2 Printer Cooperation

+
+

+As an alternative to the above daemon approach to managing a printer, +consider a protocol that DOES NOT involve a manager. In this setting, +the printer is usable directly by any process. However, processes that +print must obey a protocol you will design to avoid problems. The +printer is associated with a known special file /dev/printer. When +data is written to this file, it is sent directly to the +printer. However, if multiple processes write data simultaneously, the +printing results are likely to become corrupted. +

+ +

+Design a protocol that would allow the shared printer resource to be +managed without a manager process. +

+
    +
  • What mechanism would you use for processes want to print to +coordinate using the /dev/printer file? +
  • +
  • Is it possible in your scheme to guarantee fairness: processes that +are ready to print early actually get to print earlier than later +print attempts? +
  • +
+
+
+
+ + +
+

2 Graceful Shutdown

+
+

+Many system programs run for a long time accumulating data from files +that should be written out before shutting down. Occasionally these +"daemon" processes need to be closed down or restarted but should be +exited "gracefully" as in given an opportunity to write essential data +to files before exiting. +

+ +

+Describe a common mechanism in Unix to notify a program that it should +terminate but give it an opportunity to write essential data prior to +exiting. Describe the specific program control structures in the +program and system calls involved in such a graceful shutdown. +

+
+
+ + +
+

3 Critical Section

+
+

+A database manger process is responsible for occasionally writing +database information in main memory to a file so that it is backed up +in the case of a crash. A system administrator can request an +immediate backup by sending the SIGUSR1 signal to the manager +process. Backup requests are considered fairly low priority and can +be honored later. +

+ +

+The manager process is also responsible for handling certain +operations that are critical to integrity of the database and should +not be interrupted by backup requests. +

+ +

+Describe whether it is possible for the manager process to be written +to fulfill both of these requirements. Mention how it might be done +using Unix programming facilities. +

+
+
+ +
+

4 Concurrency and Signals

+
+

+A simple protocol for communication between Process A and Process B +involves the following steps. +

+ +

+Process A +

+
    +
  • A1: Process A writes its PID to Pipe X +
  • +
  • A2: Process A sleeps waiting for a signal +
  • +
  • A3: Process A wakes up from a signal +
  • +
  • A4: Process A reads an integer from Pipe Y +
  • + +
  • B1: Process B reads a PID from Pipe X +
  • +
  • B2: Process B writes an integer to Pipe Y +
  • +
  • B3: Process B signals Process A to wake up and continue +
  • +
+
+ +
+

4.1 Code Outline

+
+

+Give an outline of C code for Process A and Process B which would +(roughly) implement the above protocol. Below +

+ +
+ +
// PROCESS A
+int pipeX[2];  
+int pipeY[2];
+int receive;  // put data "received" from Process B in this integer
+
+// assume both pipes opened appropriately 
+
+// A1: Process A writes its PID to Pipe X
+
+// A2: Process A sleeps waiting for a signal
+
+// A3: Process A wakes up from a signal 
+
+// A4: Process A reads an integer from Pipe Y
+
+
+ +
+ +
// PROCESS B
+int pipeX[2];  
+int pipeY[2];
+int send = 42;  // integer to "send" to Process A
+
+// assume both pipes opened appropriately 
+
+// B1: Process B reads a PID from Pipe X
+
+// B2: Process B writes an integer to Pipe Y
+
+// B3: Process B signals Process A to wake up and continue
+
+
+
+
+ + +
+

4.2 Implementation Flaws

+
+

+A naive implementation of the basic protocol outlined is likely to +contain flaws. For example, if Process A merely calls +

+
sleep(0);
+
+

+to await a signal, it may result in Process A never waking +up. +

+ +

+Describe a sequence of events using the steps A1, A2,.. B1, B2 that +could give rise to the this situation. Also describe how one might fix +this with a slightly more complex sleeping/waiting behavior and +signals handling. +

+
+
+
+ +
+

5 Read vs Select

+
+

+The code below appeared in a lab in files that compared only reading +from two separate files (pipes in this case) versus using the +select() system call. Describe the difference between these blocks. +

+
    +
  • What pattern of reading do you expect in each? Ex: Do you expect +fixed patterns like ABAB.. or ABBABB... or arbitrary +intermingling like ABBABAABBA...? +
  • +
  • Which approach (read()-only or select()/read()) is appropriate +if input is coming at very different rates in pipeA versus pipeB? +Justify your answer. +
  • +
+ +
+ +
// file read_AB.c
+  while(!signaled){                                                
+    char buf[1024];
+    int n;
+
+    n = read(pipeA[PREAD], buf, 1024);                             
+    buf[n] = '\0';
+    fprintf(stdout,"A had: |%s|\n",buf);
+
+    n = read(pipeB[PREAD], buf, 1024);                             
+    buf[n] = '\0';
+    fprintf(stdout,"B had: |%s|\n",buf);
+  }
+
+
+
+ +
// file select_AB.c
+  while(!signaled){                                                
+    fd_set read_set;                                               
+    FD_ZERO(&read_set);                                            
+    FD_SET(pipeA[PREAD], &read_set);                               
+    FD_SET(pipeB[PREAD], &read_set);
+    int maxfd = pipeA[PREAD];                                      
+    maxfd = (maxfd < pipeB[PREAD]) ? pipeB[PREAD] : maxfd;
+
+    select(maxfd+1, &read_set, NULL, NULL, NULL);                  
+
+    char buf[1024];
+    int n;
+    if(FD_ISSET(pipeA[PREAD], &read_set)){                         
+      n = read(pipeA[PREAD], buf, 1024);                           
+      buf[n] = '\0';
+      fprintf(stdout,"A had: |%s|\n",buf);
+    }
+    if(FD_ISSET(pipeB[PREAD], &read_set)){                         
+      n = read(pipeB[PREAD], buf, 1024);                           
+      buf[n] = '\0';
+      fprintf(stdout,"B had: |%s|\n",buf);                         
+    }
+  }
+
+
+
+
+ + +
+

6 Busy Polling versus Interrupt Driven Mutex

+
+

+Cee Lohacker is working on a drone with a small embedded processor and +Unix which provides POSIX threads and mutexes. Unfortunately, the +drone is manufactured in Easternopia and Cee cannot understand the +Easternopian dialect of the documentation. She needs know whether +mutexes on this system use +

+
    +
  • Busy polling to acquire a lock +
  • +
  • Interrupt driven waiting acquire a lock +
  • +
+ +

+Writes the following short C program to test the mutexes and runs it +with the time command. +

+ +
+ +
 1: > cat mut_test.c
+ 2: #include <pthread.h>
+ 3: #include <stdio.h>
+ 4: #include <unistd.h>
+ 5: 
+ 6: int glob = 1;
+ 7: pthread_mutex_t glob_lock;
+ 8: 
+ 9: void *doit(void *param){
+10:   pthread_mutex_lock(&glob_lock);
+11:   glob = glob*2;
+12:   sleep(2);
+13:   pthread_mutex_unlock(&glob_lock);
+14:   return NULL;
+15: }
+16: 
+17: int main(){
+18:   pthread_mutex_init(&glob_lock, NULL);
+19:   printf("BEFORE glob: %d\n",glob);
+20:   pthread_t threads[3];
+21:   for(int i=0; i<3; i++){
+22:     pthread_create(&threads[i], NULL, doit, NULL);
+23:   }
+24:   for(int i=0; i<3; i++){
+25:     pthread_join(threads[i], (void **) NULL); 
+26:   }
+27:   printf("AFTER glob: %d\n",glob);
+28:   pthread_mutex_destroy(&glob_lock);
+29:   return 0;
+30: }
+31: 
+32: > gcc mut_test.c -lpthread
+33: 
+34: > time a.out
+35: BEFORE glob: 1
+36: AFTER glob: ???   # glob final value
+37: 
+38: real	???       # Wall time
+39: user	???       # User CPU time
+40: sys	???
+
+
+ +

+Answer the following questions +

+
    +
  1. What is the expected value for glob after the code is run (marked +# glob final value)? +
  2. +
  3. Assuming the mutexes use BUSY polling, what times are expected for +
      +
    • Real/Wall time? +
    • +
    • User CPU time? +
    • +
    +

    +Explain your reasoning. +

    +
  4. +
  5. Assuming the mutexes use INTERRUPT-DRIVEN waiting, what times are +expected for +
      +
    • Real/Wall time? +
    • +
    • User CPU time? +
    • +
    +

    +Explain your reasoning. +

    +
  6. +
+
+
+ +
+

7 Processes vs Threads

+
+
+

7.1 Similarities and Differences

+
+

+Outline the similarities and differences between Processes and +Threads. Describe some details of the assumptions that each makes +about what memory is shared versus private. Describe the tradeoffs +associated with using one versus the others on issues such as system +tools, security, and efficiency. +

+
+
+ +
+

7.2 Thread Pitfalls

+
+

+Recall the Pi calculation program discussed in class. One version of +this program spawned multiple threads to run the following worker +function. +

+
+ +
int total_hits = 0;
+int points_per_thread = -1;
+
+void *compute_pi(void *arg){
+  long thread_id = (long) arg;
+  unsigned int rstate = 123456789 * thread_id;
+  for (int i = 0; i < points_per_thread; i++) { 
+    double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX);
+    double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX);
+    if (x*x + y*y <= 1.0){
+      total_hits++;
+    }
+  } 
+  return NULL;
+}
+
+
+
    +
  1. Why was it necessary to use the rand_r() function rather than the +standard rand() function to generate random numbers? +
  2. +
  3. Do all the worker threads generate identical random sequences of +numbers or are they different? Explain your reasoning. +
  4. +
  5. It was determined in discussion that this version always +underestimates the value of Pi. Explain why and how one might fix +this while also maintaining the efficiency of using multiple +threads to get speedup. +
  6. +
+
+
+
+
+
+
Author: Chris Kauffman (kauffman@phaedrus)
Date: 2017-11-18 Sat 11:21
+
+ + +
\ No newline at end of file diff --git a/CSCI 4061_ Exam 2 Review Problems_files/cmdline_frame.html b/CSCI 4061_ Exam 2 Review Problems_files/cmdline_frame.html new file mode 100644 index 0000000..7895e96 --- /dev/null +++ b/CSCI 4061_ Exam 2 Review Problems_files/cmdline_frame.html @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/agreement.txt b/agreement.txt new file mode 100644 index 0000000..ed60f1c --- /dev/null +++ b/agreement.txt @@ -0,0 +1,11 @@ +I have familiarized myself with the contents of the CSCI 4061 syllabus +and agree to abide by the policies contained within it. I will obey +the PRIME DIRECTIVE. I understand that the Kauffman section of 4061 +(001) is not coordinated with the Tripathi section (010) and will not +seek or render unauthorized help from students or staff in that +section. As a University of Minnesota student, I agree to follow the +Student Code of Conduct and will treat my classmates and the course +staff with honest respect. + +Signed, +Michael Zhang diff --git a/atoms b/atoms new file mode 100755 index 0000000..a0ba3f3 Binary files /dev/null and b/atoms differ diff --git a/atoms.c b/atoms.c new file mode 100644 index 0000000..56087c7 --- /dev/null +++ b/atoms.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + char elem[2]; + double x, y, z; + int charge; + double mass; +} atom_t; + +void write_atoms(char *fname, atom_t *atoms, int len) { + int fd = open(fname, O_CREAT | O_WRONLY); + for (int i = 0; i < len; ++i) { + write(fd, &atoms[i], sizeof(atom_t)); + } + close(fd); +} + +double *read_masses(char *fname, int *setlen) { + int fd = open(fname, O_RDONLY); + int size = lseek(fd, 0, SEEK_END); + double *result = (double *)malloc(size); + lseek(fd, 0, SEEK_SET); + int count = 0; + atom_t atom; + while (1) { + int bytes = read(fd, &atom, sizeof(atom_t)); + if (!bytes) break; + result[count++] = atom.mass; + } + close(fd); + *setlen = count; + return result; +} + +int main() { + atom_t atoms[5] = {{"C", 0.0, 1.0, 2.5, 0, 12.011}, + {"O", 1.0, 3.5, 6.0, 0, 15.999}}; + write_atoms("atoms.dat", atoms, 5); + int len = -1; + double *masses = read_masses("atoms.dat", &len); + printf("read %d masses:\n", len); + for (int i = 0; i < len; ++i) { + printf("mass[%d] = %lf\n", i, masses[i]); + } + free(masses); + return 0; +} diff --git a/atoms.dat b/atoms.dat new file mode 100644 index 0000000..0282ef4 Binary files /dev/null and b/atoms.dat differ diff --git a/b b/b new file mode 100644 index 0000000..e69de29 diff --git a/lab01-code/QUESTIONS.txt b/lab01-code/QUESTIONS.txt new file mode 100644 index 0000000..7feceea --- /dev/null +++ b/lab01-code/QUESTIONS.txt @@ -0,0 +1,67 @@ + __________________ + + LAB 01 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 +========= + + Show output of the collatz sequence program starting at 17. + +Enter the starting integer: 17 +The next value in the Collatz sequence is 52 +Show output of steps (0:NO, any other int: yes): 1 +Step 0: 17 +Step 1: 52 +Step 2: 26 +Step 3: 13 +Step 4: 40 +Step 5: 20 +Step 6: 10 +Step 7: 5 +Step 8: 16 +Step 9: 8 +Step 10: 4 +Step 11: 2 +Step 12: 1 +The starting value 17 converged to 1 in 12 steps + +PROBLEM 2 +========= + + Paste the Makefile you created for the lcd-clock project below. + +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +clock_sim: lcd_clock.o lcd_clock_main.o lcd_clock.h lcd_update.o + $(CC) -o clock_sim $^ + @echo "clock_sim ready for duty" + +lcd_clock.o: lcd_clock.c lcd_clock.h + $(CC) -c $< + +lcd_clock_main.o: lcd_clock_main.c lcd_clock.h + $(CC) -c $< + +lcd_update.o: lcd_update.c lcd_clock.h + $(CC) -c $< + +test: clock_tests + @echo "Running clock_tests" + ./clock_tests + @echo "Tests Complete" + +clock_tests: lcd_tests.c lcd_clock.o lcd_update.o lcd_clock.h + $(CC) -o $@ $^ + +clean: + rm -f *.o diff --git a/lab01-code/collatz/Makefile b/lab01-code/collatz/Makefile new file mode 100644 index 0000000..31a6e40 --- /dev/null +++ b/lab01-code/collatz/Makefile @@ -0,0 +1,31 @@ +# See Makefile-commented for explanation +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +collcalc : collatz.o collatz_main.o + $(CC) -o collcalc collatz.o collatz_main.o + @echo collcalc is ready + +collatz_main.o : collatz_main.c collatz.h + $(CC) -c collatz_main.c + +collatz.o : collatz.c collatz.h + $(CC) -c $< + +test : collatz_test + ./collatz_test + +collatz_test : collatz_test.o collatz.o collatz.h + $(CC) -o $@ $^ + +collatz_test.o : collatz_test.c collatz.h + $(CC) -c $< + +clean: + @echo Cleaning up object files + rm -f *.o + +realclean: + @echo Removing objects and programs + rm -f *.o collcalc collatz_test + diff --git a/lab01-code/collatz/Makefile-commented b/lab01-code/collatz/Makefile-commented new file mode 100644 index 0000000..ed89fef --- /dev/null +++ b/lab01-code/collatz/Makefile-commented @@ -0,0 +1,52 @@ +# Makefile to create the collatz programs. To use, type +# > make +# Which will create the collcalc program. Alternatively +# > make collcalc +# will also create the collcalc program. +# +# To create the test program and run it do +# > make test +# +# Makefiles are divided into "rules" comprised of target, +# dependencies, and commands to execute to finish the target. +# +# target : dependency1 dependency2 +# command1 +# command2 +# @command3 which is not printed +# command4 +# +# Some targets are files to create like the "collcalc" program or +# "collatz_main.o" file. Other targets are "virtual" which simply +# specify other targets to do or commands to run. + +CFLAGS = -Wall -g # variable holding options to the c compile +CC = gcc $(CFLAGS) # variable holding the compilation command + +collcalc : collatz.o collatz_main.o collatz.h # collcalc is a program, depends on two files, is default target + $(CC) -o collcalc collatz.o collatz_main.o # when the other files are ready, compile collcalc + @echo collcalc is ready # issue a report that the program is ready + +collatz_main.o : collatz_main.c collatz.h # collatz_main.o depends on two source files + $(CC) -c collatz_main.c # compile only, don't link yet + +collatz.o : collatz.c collatz.h # collatz.o depends on collatz.c and collatz.h + $(CC) -c $< # compile, use shortcut $< which becomes "collatz.c" + +test : collatz_test # test is another target, depends on collatz_test program + ./collatz_test # when collatz_test exists, run it + +collatz_test : collatz_test.o collatz.o collatz.h # program depends on several object files and header + $(CC) -o $@ $^ # compile using shortcuts: $@ becomes collatz_test, $^ is all dependecies + +collatz_test.o : collatz_test.c collatz.h # object file depends on C source and header + $(CC) -c $< # compile to object code using shortcut, $< becomes "collatz_test.c" + +clean: # No dependencies: clean is the de facto cleanup target + @echo Cleaning up object files # Report what's happening + rm -f *.o # Remove all the .o files which are likely no longer needed + +realclean: + @echo Removing objects and programs # "realclean" often used to get rid of everything + rm -f *.o collcalc collatz_test # remove .o and programs that have been built + diff --git a/lab01-code/collatz/collatz.c b/lab01-code/collatz/collatz.c new file mode 100644 index 0000000..9171205 --- /dev/null +++ b/lab01-code/collatz/collatz.c @@ -0,0 +1,34 @@ +#include +#include "collatz.h" + +/* Compute the next step in the collatz sequence */ +int collatz_next(int n){ + if(n < 1){ + return -1; + } + else if(n==1){ + return 1; + } + else if(n % 2 == 0){ + return n / 2; + } + else{ + return n*3 + 1; + } +} + +// Count how many steps are in the collatz sequence +int collatz_steps(int n, int print_output){ + int steps = 0; + if(print_output){ + printf("Step %d: %d\n",steps,n); + } + while(n > 1){ + n = collatz_next(n); + steps++; + if(print_output){ + printf("Step %d: %d\n",steps,n); + } + } + return steps; +} diff --git a/lab01-code/collatz/collatz.h b/lab01-code/collatz/collatz.h new file mode 100644 index 0000000..5477cd6 --- /dev/null +++ b/lab01-code/collatz/collatz.h @@ -0,0 +1,44 @@ +// Header file for collatz problems + +#ifndef COLLATZ_H +#define COLLZTZ_H 1 + +// Returns next number in the collatz sequence. If parameter n is less +// than 1, return -1. If n is equal to 1, return 1 as the sequence has +// converged. If n is bigger than 1, determine if it is even or +// odd. If n is even, return half its value. If n is odd, return three +// times its value plus one. +int collatz_next(int n); + + +// Returns the number of steps to converge to 1 for starting point +// n. Use the function collatz_next() in a loop to determine the next +// value at each step. Return the number of steps to converge, 15 in +// the example below where n=22. If paramter n is less than or equal +// to 1, return 0. +// +// If the argument print_output is zero, this function should not +// print anything. If the argument is non-zero, print each step in +// the sequence starting with the initial value of at Step 0. For +// example, if n=22 and print_output=1, produce output like the +// following: +// +// Step 0: 22 +// Step 1: 11 +// Step 2: 34 +// Step 3: 17 +// Step 4: 52 +// Step 5: 26 +// Step 6: 13 +// Step 7: 40 +// Step 8: 20 +// Step 9: 10 +// Step 10: 5 +// Step 11: 16 +// Step 12: 8 +// Step 13: 4 +// Step 14: 2 +// Step 15: 1 +int collatz_steps(int n, int print_output); + +#endif diff --git a/lab01-code/collatz/collatz.o b/lab01-code/collatz/collatz.o new file mode 100644 index 0000000..5c736e7 Binary files /dev/null and b/lab01-code/collatz/collatz.o differ diff --git a/lab01-code/collatz/collatz_main.c b/lab01-code/collatz/collatz_main.c new file mode 100644 index 0000000..d50d564 --- /dev/null +++ b/lab01-code/collatz/collatz_main.c @@ -0,0 +1,21 @@ +#include +#include "collatz.h" + +int main(int argc, char **argv){ + int nstart; + printf("Enter the starting integer: "); + scanf("%d", &nstart); + + int nnext = collatz_next(nstart); + printf("The next value in the Collatz sequence is %d\n",nnext); + + int verbose; + printf("Show output of steps (0:NO, any other int: yes): "); + scanf("%d", &verbose); + + int steps = collatz_steps(nstart,verbose); + printf("The starting value %d converged to 1 in %d steps\n", + nstart,steps); + return 0; +} + diff --git a/lab01-code/collatz/collatz_main.o b/lab01-code/collatz/collatz_main.o new file mode 100644 index 0000000..5c65fe3 Binary files /dev/null and b/lab01-code/collatz/collatz_main.o differ diff --git a/lab01-code/collatz/collatz_test.c b/lab01-code/collatz/collatz_test.c new file mode 100644 index 0000000..ec264dd --- /dev/null +++ b/lab01-code/collatz/collatz_test.c @@ -0,0 +1,56 @@ +#include +#include "collatz.h" + +#define TESTID "P2" +int failures = 0; + +void test_next(int test, int n, int expected){ + int actual = collatz_next(n); + if(expected != actual){ + printf("Failed %s Test %d\nCall: collatz_next(%d)\nExpect: %d\nActual: %d\n", + TESTID,test, n,expected,actual); + failures++; + } +} + +#define MAX_SIZE 5096 + +void test_steps(int test, int n, int expected){ + int actual = collatz_steps(n,0); + if(expected != actual){ + printf("Failed %s Test %d\nCall: collatz_steps(%d)\nExpect: %d\nActual: %d\n", + TESTID,test, n,expected,actual); + failures++; + return; + } + +} + +int main(int argc, char **argv){ + int test = 1; + test_next(test++, 1 , 1 ); + test_next(test++, 0 , -1 ); + test_next(test++, -5 , -1 ); + test_next(test++, 5 , 16 ); + test_next(test++, 16 , 8 ); + test_next(test++, 20 , 10 ); + test_next(test++, 15 , 46 ); + + test_steps(test++, -7, 0 ); + test_steps(test++, 1, 0 ); + test_steps(test++, 5, 5 ); + test_steps(test++, 14, 17); + test_steps(test++, 30, 18); + test_steps(test++, 22, 15); + test_steps(test++, 6, 8 ); + + if(failures == 0){ + printf("OK\n"); + } + else{ + printf("FAILURES\n"); + } + printf("Passed %d / %d tests\n",test-failures,test); + + return 0; +} diff --git a/lab01-code/collatz/collcalc b/lab01-code/collatz/collcalc new file mode 100755 index 0000000..35b90b7 Binary files /dev/null and b/lab01-code/collatz/collcalc differ diff --git a/lab01-code/lcd-clock/Makefile b/lab01-code/lcd-clock/Makefile new file mode 100644 index 0000000..b8b713e --- /dev/null +++ b/lab01-code/lcd-clock/Makefile @@ -0,0 +1,26 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +clock_sim: lcd_clock.o lcd_clock_main.o lcd_clock.h lcd_update.o + $(CC) -o clock_sim $^ + @echo "clock_sim ready for duty" + +lcd_clock.o: lcd_clock.c lcd_clock.h + $(CC) -c $< + +lcd_clock_main.o: lcd_clock_main.c lcd_clock.h + $(CC) -c $< + +lcd_update.o: lcd_update.c lcd_clock.h + $(CC) -c $< + +test: clock_tests + @echo "Running clock_tests" + ./clock_tests + @echo "Tests Complete" + +clock_tests: lcd_tests.c lcd_clock.o lcd_update.o lcd_clock.h + $(CC) -o $@ $^ + +clean: + rm -f *.o diff --git a/lab01-code/lcd-clock/clock_tests b/lab01-code/lcd-clock/clock_tests new file mode 100755 index 0000000..79b59db Binary files /dev/null and b/lab01-code/lcd-clock/clock_tests differ diff --git a/lab01-code/lcd-clock/lcd_clock.c b/lab01-code/lcd-clock/lcd_clock.c new file mode 100644 index 0000000..1dad48d --- /dev/null +++ b/lab01-code/lcd-clock/lcd_clock.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include "lcd_clock.h" + +#define LCD_MAX_BITS 30 + + +/* Global variable used to control the LCD display. Making changes to + this variable will change the clock time */ +int LCD_DISPLAY_PORT; + +/* Time of day in seconds; set by the hardware, read only */ +int TIME_OF_DAY_SEC; + +/* Reset an lcd_display to be empty */ +void reset_lcd_display(lcd_display *lcd){ + int i,j; + for(i=0; i<5; i++){ + for(j=0; j<32; j++){ + lcd->chars[i][j] = ' '; + } + lcd->chars[i][31] = '\0'; + } + lcd->chars[1][12] = 'o'; + lcd->chars[3][12] = 'o'; +} + +/* Print an lcd_display */ +void print_lcd_display(lcd_display *lcd){ + int i=0; + for(i=0; i<5; i++){ + printf("%s\n",lcd->chars[i]); + } +} + +/* Data and functions to set the state of the lcd clock display */ + +/* Position and char in display */ +typedef struct { + int r,c; char ch; +} charpos; + +/* Collection of characters corresponding to one bit in the state being set */ +typedef struct { + int len; + charpos pos[2]; +} charpos_coll; + +/* Correspondence of bit positions to which characters should be set */ +charpos_coll bits2chars[LCD_MAX_BITS] = { + { .len=2, .pos={{ 0,19,'~'}, { 0,20,'~'},} }, // 0 + { .len=1, .pos={{ 1,21,'|'}, } }, // 1 + { .len=1, .pos={{ 3,21,'|'}, } }, // 2 + { .len=2, .pos={{ 4,19,'~'}, { 4,20,'~'},} }, // 3 + { .len=1, .pos={{ 3,18,'|'}, } }, // 4 + { .len=1, .pos={{ 1,18,'|'}, } }, // 5 + { .len=2, .pos={{ 2,19,'~'}, { 2,20,'~'},} }, // 6 + + { .len=2, .pos={{ 0,14,'~'}, { 0,15,'~'},} }, // 7 + { .len=1, .pos={{ 1,16,'|'}, } }, // 8 + { .len=1, .pos={{ 3,16,'|'}, } }, // 9 + { .len=2, .pos={{ 4,14,'~'}, { 4,15,'~'},} }, // 10 + { .len=1, .pos={{ 3,13,'|'}, } }, // 11 + { .len=1, .pos={{ 1,13,'|'}, } }, // 12 + { .len=2, .pos={{ 2,14,'~'}, { 2,15,'~'},} }, // 13 + + { .len=2, .pos={{ 0, 9,'~'}, { 0,10,'~'},} }, // 14 + { .len=1, .pos={{ 1,11,'|'}, } }, // 15 + { .len=1, .pos={{ 3,11,'|'}, } }, // 16 + { .len=2, .pos={{ 4, 9,'~'}, { 4,10,'~'},} }, // 17 + { .len=1, .pos={{ 3, 8,'|'}, } }, // 18 + { .len=1, .pos={{ 1, 8,'|'}, } }, // 19 + { .len=2, .pos={{ 2, 9,'~'}, { 2,10,'~'},} }, // 20 + + { .len=2, .pos={{ 0, 4,'~'}, { 0, 5,'~'},} }, // 21 + { .len=1, .pos={{ 1, 6,'|'}, } }, // 22 + { .len=1, .pos={{ 3, 6,'|'}, } }, // 23 + { .len=2, .pos={{ 4, 4,'~'}, { 4, 5,'~'},} }, // 24 + { .len=1, .pos={{ 3, 3,'|'}, } }, // 25 + { .len=1, .pos={{ 1, 3,'|'}, } }, // 26 + { .len=2, .pos={{ 2, 4,'~'}, { 2, 5,'~'},} }, // 27 + + { .len=2, .pos={{ 3, 0,'A'}, { 3, 1,'M'},} }, // 28 + { .len=2, .pos={{ 4, 0,'P'}, { 4, 1,'M'},} }, // 29 +}; + +/* Assumes ints are at least 32 bits */ +void set_lcd_display_state(lcd_display *lcd, int state){ + int i,j; + int mask = 0x1; + reset_lcd_display(lcd); + for(i=0; ichars[pos.r][pos.c] = pos.ch; + } + } + } +} + + +/* Use the global LCD_DISPLAY_PORT to print the time */ +void print_lcd_clock(){ + lcd_display lcd; + set_lcd_display_state(&lcd, LCD_DISPLAY_PORT); + print_lcd_display(&lcd); + return; +} + + +/* Print the most signficant (right-most) to least signficant bit in + the integer passed in */ +#define INT_BITS 32 +void showbits(int x){ + int i; + int mask = 0x1; + for(i=INT_BITS-1; i>=0; i--){ + int shifted_mask = mask << i; + if(shifted_mask & x){ + putchar('1'); + } else { + putchar('0'); + } + } + /* Equivalent short version */ + // (x&(1< +#include +#include +#include "lcd_clock.h" + +int main(int argc, char **argv){ + + if(argc < 2){ /* Set TIME_OF_DAY_SEC to the actual time */ + time_t rawtime; /* Get raw time */ + time( &rawtime ); + struct tm *info; /* Store broken down time */ + info = localtime( &rawtime ); /* Get a broken down time */ + + /* Calculate the seconds since the beginning of the day */ + TIME_OF_DAY_SEC = info->tm_sec + 60*info->tm_min + 60*60*info->tm_hour; + } + else{ /* Set time based on argument given */ + TIME_OF_DAY_SEC = atoi(argv[1]); + } + printf("TIME_OF_DAY_SEC set to: %d\n", TIME_OF_DAY_SEC); + + int time_max = 24 * 60 * 60; + if(TIME_OF_DAY_SEC >= time_max){ + printf("Time %d exceeds max %d\n",TIME_OF_DAY_SEC,time_max); + return -1; + } + + tod_t tod = time_breakdown(TIME_OF_DAY_SEC); + + printf("tod = time_breakdown( %5d );\n",TIME_OF_DAY_SEC); + + printf("tod is { \n"); + printf(" .hours = %d\n",tod.hours); + printf(" .minutes = %d\n",tod.minutes); + printf(" .seconds = %d\n",tod.seconds); + printf(" .ispm = %d\n",tod.ispm); + printf("} \n"); + printf("Simulated time is: %02d : %02d : %02d %s\n", + tod.hours,tod.minutes,tod.seconds,(tod.ispm ? "pm" : "am")); + + printf("\nChecking results for display bits\n"); + + int state = display_bits_from_tod(tod); + printf("state = display_bits_from_tod(tod);\n"); + + printf("\nstate is:\n"); + printf(" 3 2 1 0\n"); + printf("index: 10987654321098765432109876543210\n"); + printf("bits: "); showbits(state); printf("\n"); + printf("guide: | | | | |\n"); + + printf("\nRunning lcd_update()\n"); + + lcd_update(); + + printf("\nLCD_DISPLAY_PORT is:\n"); + printf(" 3 2 1 0\n"); + printf("index: 10987654321098765432109876543210\n"); + printf("bits: "); showbits(LCD_DISPLAY_PORT); printf("\n"); + printf("guide: | | | | |\n"); + + + + printf("\nLCD Clock Display:\n"); + print_lcd_clock(); + + return 0; +} diff --git a/lab01-code/lcd-clock/lcd_tests.c b/lab01-code/lcd-clock/lcd_tests.c new file mode 100644 index 0000000..a8eaf3c --- /dev/null +++ b/lab01-code/lcd-clock/lcd_tests.c @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include +#include "lcd_clock.h" + +#define TESTID "lcd_update.c" +int failures = 0; +int testn = 0; + +#define TOLERANCE 1e-4 + +#define GENTEST 0 + +int compare_tod_t(tod_t x, tod_t y){ + return + x.hours == y.hours && + x.minutes == y.minutes && + x.seconds == y.seconds && + x.ispm == y.ispm; +} + +void print_tod_t(tod_t tod){ + printf("{\n"); + printf(" .hours = %d,\n",tod.hours); + printf(" .minutes = %d,\n",tod.minutes); + printf(" .seconds = %d,\n",tod.seconds); + printf(" .ispm = %d,\n",tod.ispm); + printf("}\n"); +} + +void test_time_breakdown(int time_sec, tod_t expect){ + testn++; + printf("Running %s Test %d for time_breakdown()\n", TESTID,testn); + TIME_OF_DAY_SEC = -1; + LCD_DISPLAY_PORT = -1; + + tod_t actual = time_breakdown(time_sec); + + if(TIME_OF_DAY_SEC != -1 || LCD_DISPLAY_PORT != -1){ + printf("\nFailed %s Test %d for time_breakdown()\n", TESTID,testn); + printf("Do not modify TIME_OF_DAY_SEC or LCD_DISPLAY_PORT in this function\n"); + failures++; + } + else if( !compare_tod_t(actual,expect) ){ + printf("\nFailed %s Test %d for time_breakdown()\n", TESTID,testn); + printf("Actual and Expected tod_t differ\n"); + printf("time_sec: %d\n",time_sec); + printf("EXPECT: "); print_tod_t(expect); + printf("ACTUAL: "); print_tod_t(actual); + failures++; + } + return; +} + +void test_display_bits_from_tod(tod_t tod, int expect){ + testn++; + printf("Running %s Test %d for display_bits_from_tod()\n", TESTID,testn); + TIME_OF_DAY_SEC = -1; + LCD_DISPLAY_PORT = -1; + + int actual = display_bits_from_tod(tod); + + if(TIME_OF_DAY_SEC != -1 || LCD_DISPLAY_PORT != -1){ + printf("\nFailed %s Test %d for display_bits_from_tod()\n", TESTID,testn); + printf("Do not modify TIME_OF_DAY_SEC or LCD_DISPLAY_PORT in this function\n"); + failures++; + } + else if(actual != expect){ + printf("\nFailed %s Test %d for display_bits_from_tod()\n", TESTID,testn); + printf("Actual and Expected bits differ\n"); + printf("tod = \n"); print_tod_t(tod); + printf(" 3 2 1 0\n"); + printf("index: 10987654321098765432109876543210\n"); + printf("EXPECT: "); showbits(expect); printf("\n"); + printf("ACTUAL: "); showbits(actual); printf("\n"); + printf("guide: | | | | |\n"); + printf("\n"); + failures++; + } + return; +} + +void test_lcd_update(int time_sec, int expect){ + testn++; + printf("Running %s Test %d for lcd_update()\n", TESTID,testn); + TIME_OF_DAY_SEC = time_sec; + lcd_update(); + if(LCD_DISPLAY_PORT != expect || TIME_OF_DAY_SEC != time_sec){ + printf("\nFailed %s Test %d for lcd_update()\n", TESTID,testn); + printf("Expect TIME_OF_DAY_SEC: %d\n",time_sec); + printf("Actual TIME_OF_DAY_SEC: %d\n",TIME_OF_DAY_SEC); + printf("Bits of LCD_DISPLAY_PORT\n"); + printf("index: 10987654321098765432109876543210\n"); + printf("EXPECT: "); showbits(expect); printf("\n"); + printf("ACTUAL: "); showbits(LCD_DISPLAY_PORT); printf("\n"); + printf("guide: | | | | |\n"); + printf("\n"); + failures++; + } + return; +} + + +typedef struct { + int time_sec; + tod_t tod; + int bits; +} lcd_test_case; + +/* Global array of test data; terminated by a struct with time_sec=-1 */ +lcd_test_case tests[] = { + { .time_sec = 0, + .tod = { + .hours = 12, + .minutes = 0, + .seconds = 0, + .ispm = 0, + }, + .bits=0b00010000110101101101111110111111, + }, + { .time_sec = 101, + .tod = { + .hours = 12, + .minutes = 1, + .seconds = 41, + .ispm = 0, + }, + .bits=0b00010000110101101101111110000110, + }, + { .time_sec = 4170, + .tod = { + .hours = 1, + .minutes = 9, + .seconds = 30, + .ispm = 0, + }, + .bits=0b00010000000000011001111111101111, + }, + { .time_sec = 43199, + .tod = { + .hours = 11, + .minutes = 59, + .seconds = 59, + .ispm = 0, + }, + .bits=0b00010000110000011011011011101111, + }, + { .time_sec = 43200, + .tod = { + .hours = 12, + .minutes = 0, + .seconds = 0, + .ispm = 1, + }, + .bits=0b00100000110101101101111110111111, + }, + { .time_sec = 47089, + .tod = { + .hours = 1, + .minutes = 4, + .seconds = 49, + .ispm = 1, + }, + .bits=0b00100000000000011001111111100110, + }, + { .time_sec = 67089, + .tod = { + .hours = 6, + .minutes = 38, + .seconds = 9, + .ispm = 1, + }, + .bits=0b00100000000111110110011111111111, + }, + { .time_sec = 86399, + .tod = { + .hours = 11, + .minutes = 59, + .seconds = 59, + .ispm = 1, + }, + .bits=0b00100000110000011011011011101111, + }, + { .time_sec = 46348, + .tod = { + .hours = 12, + .minutes = 52, + .seconds = 28, + .ispm = 1, + }, + .bits=0b00100000110101101111011011011011, + }, + + + { .time_sec = -1, }, +}; + +int main(int argc, char **argv){ + int i; + + /* Run time_breakdown() tests */ + for(i=0; tests[i].time_sec != -1; i++){ + test_time_breakdown(tests[i].time_sec,tests[i].tod); + } + + /* Run display_bits_from_tod() tests */ + for(i=0; tests[i].time_sec != -1; i++){ + test_display_bits_from_tod(tests[i].tod,tests[i].bits); + } + + /* Run lcd_update() tests */ + for(i=0; tests[i].time_sec != -1; i++){ + test_lcd_update(tests[i].time_sec,tests[i].bits); + } + + printf("%s Tests Passed/Run: %d / %d\n",TESTID,(testn-failures),testn); + + return failures; +} diff --git a/lab01-code/lcd-clock/lcd_update.c b/lab01-code/lcd-clock/lcd_update.c new file mode 100644 index 0000000..3f8ad52 --- /dev/null +++ b/lab01-code/lcd-clock/lcd_update.c @@ -0,0 +1,60 @@ +#include "lcd_clock.h" + + +// Breaks down the give time of day in seconds into a tod_t struct +tod_t time_breakdown(int time_of_day_sec){ + int tod_hours = time_of_day_sec / 3600; + int ispm = tod_hours >= 12 ? 1 : 0; + tod_hours = tod_hours % 12; + tod_hours = tod_hours == 0 ? 12 : tod_hours; + int tod_minutes = (time_of_day_sec / 60) % 60; + int tod_seconds = time_of_day_sec % 60; + tod_t tod = {.hours = tod_hours, + .minutes = tod_minutes, + .seconds = tod_seconds, + .ispm = ispm}; + return tod; +} + +// Binary masks for each digit for ease of setting +int digit_masks[10] = { + 0b0111111, // zero + 0b0000110, // one + 0b1011011, // two + 0b1001111, // three + 0b1100110, // four + 0b1101101, // five + 0b1111101, // six + 0b0000111, // seven + 0b1111111, // eight + 0b1101111, // nine +}; + +#define BLANK 0b0000000 // blank +#define AM_MASK (0x1 << 28) +#define PM_MASK (0x1 << 29) + +int display_bits_from_tod(tod_t tod){ + int hr_tens = tod.hours >= 10 ? digit_masks[1] : BLANK; + int hr_ones = digit_masks[tod.hours % 10]; + int mn_tens = digit_masks[tod.minutes / 10]; + int mn_ones = digit_masks[tod.minutes % 10]; + int ampm = tod.ispm ? PM_MASK : AM_MASK; + + int state = 0; + state |= (mn_ones << 0); + state |= (mn_tens << 7); + state |= (hr_ones << 14); + state |= (hr_tens << 21); + state |= ampm; + + return state; +} + +/* Examine the TIME_OF_DAY_SEC to determine hour, minute, and am/pm. + Set the LCD_DISPLAY_PORT bits to show the proper time. */ +void lcd_update(){ + tod_t tod = time_breakdown(TIME_OF_DAY_SEC); + int state = display_bits_from_tod(tod); + LCD_DISPLAY_PORT = state; +} diff --git a/lab01-code/lcd-clock/time-examples.sh b/lab01-code/lcd-clock/time-examples.sh new file mode 100755 index 0000000..126e31a --- /dev/null +++ b/lab01-code/lcd-clock/time-examples.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Loop to produce various example times. clock_sim program must be +# built preceding use. + +for t in 999 7777 121212; do + echo '> clock_sim' $t + ./clock_sim $t + echo + echo +done + diff --git a/lab01-code/lcd-clock/time_breakdown_examples.c b/lab01-code/lcd-clock/time_breakdown_examples.c new file mode 100644 index 0000000..4c8e6c4 --- /dev/null +++ b/lab01-code/lcd-clock/time_breakdown_examples.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include "hw6.h" +#include "lcd_clock.h" + +int main(int argc, char **argv){ + + if(argc < 2){ /* Set TIME_OF_DAY_SEC to the actual time */ + time_t rawtime; /* Get raw time */ + time( &rawtime ); + struct tm *info; /* Store broken down time */ + info = localtime( &rawtime ); /* Get a broken down time */ + + /* Calculate the seconds since the beginning of the day */ + TIME_OF_DAY_SEC = info->tm_sec + 60*info->tm_min + 60*60*info->tm_hour; + } + else{ /* Set time based on argument given */ + TIME_OF_DAY_SEC = atoi(argv[1]); + } + + int time_max = 24 * 60 * 60; + if(TIME_OF_DAY_SEC >= time_max){ + printf("Time %d exceeds max %d\n",TIME_OF_DAY_SEC,time_max); + return -1; + } + + tod_t tod = time_breakdown(TIME_OF_DAY_SEC); + + printf("tod = time_breakdown( %5d ); //",TIME_OF_DAY_SEC); + + printf(" %02d : %02d : %02d %s\n", + tod.hours,tod.minutes,tod.seconds,(tod.ispm ? "pm" : "am")); + + printf("tod is { \n"); + printf(" .hours = %d\n",tod.hours); + printf(" .minutes = %d\n",tod.minutes); + printf(" .seconds = %d\n",tod.seconds); + printf(" .ispm = %d\n",tod.ispm); + printf("} \n"); + return 0; +} diff --git a/lab02-code/QUESTIONS.txt b/lab02-code/QUESTIONS.txt new file mode 100644 index 0000000..a13577b --- /dev/null +++ b/lab02-code/QUESTIONS.txt @@ -0,0 +1,182 @@ + __________________ + + LAB 02 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `fork1.c' +=================== + +A +~ + + Compile and run the program in `fork1.c'. Show it's output below. + +I am number 1, my pid is 9162 +I am number 0, my pid is 9161 +I am number 3, my pid is 9164 +I am number 8, my pid is 9160 +I am number 4, my pid is 9165 +I am number 2, my pid is 9163 +I am number 7, my pid is 9168 +I am number 5, my pid is 9166 +I am number 6, my pid is 9167 + +B +~ + + Is the output ordered or disordered with respect to the "I am + number..." statements? Why? + +It's disordered in that the output has been printed to the screen out of order, +because spawning each process and then executing the print statement could take +an indeterminate amount of time for each process, so it ends up out of order. +However, PIDs are in the same order as the child's number, since PIDs are usually +created in an incremental manner so processes created later will have a larger +PID. + +C +~ + + Add calls to the wait() or waitpid() function to ensure that the + output is ordered. + +#include +#include +#include + +int main(void) { + int i; + for (i = 0; i < 8; i++) { + pid_t child = fork(); + if (child == 0) { + break; + } else { // make sure this is only executed on the parent process + waitpid(child, 0, 0); // wait for the child process to exit with status 0 + } + } + printf("I am number %d, my pid is %d\n", i, getpid()); + return 0; +} + + +D +~ + + How many parents and children are there in this program? What is their + arrangement? + +There's 1 parent and 8 children, with the parent process printing "I am +number 8" (since it only prints after it's spawned all the children, leaving +i = 8 when it reaches the printf statement). + + +PROBLEM 2 `fork-exec1.c' +======================== + +A +~ + + Compile and run the program in `fork-exec1.c'. Show it's output below. + +Running command 'ls' +------------------ +total 84K +drwxr-xr-x 2 michael michael 4.0K Sep 18 02:26 . +drwxrwxr-x 4 michael michael 4.0K Sep 18 02:18 .. +-rwxrwxr-x 1 michael michael 8.6K Sep 18 02:24 fork1 +-rw-r--r-- 1 michael michael 408 Sep 18 02:25 fork1.c +-rwxrwxr-x 1 michael michael 8.6K Sep 18 02:26 fork-exec1 +-rw-r--r-- 1 michael michael 360 Sep 13 13:56 fork-exec1.c +-rw-r--r-- 1 michael michael 2.4K Sep 18 02:26 QUESTIONS.txt + + +B +~ + + Adjust the contents of the `child_argv[]' array. Try remove the "-l" + element, try adding on ".." prior to the final NULL, or make other + modifications INCLUDING for the 0th "ls" string. Recompile and + describe whether the output has changed. + +Changed the line to: + char *child_argv[] = {"ls","-lc","-ah","/home",NULL}; + +Ouptut: + +Running command 'ls' +------------------ +total 24K +drwxr-xr-x 4 root root 4.0K Sep 5 10:27 . +drwxr-xr-x 24 root root 4.0K Sep 12 17:24 .. +drwxr-xr-x 3 root root 4.0K Sep 5 10:27 .ecryptfs +drwx------ 44 michael michael 12K Sep 18 02:29 michael + + +C +~ + + Change the child_cmd string from "ls" to be something else like "gcc" + or "cat". Recompile ad explain what happens now. + +Changed the line to: + char *child_argv[] = {"--", "derpalerp",NULL}; + char *child_cmd = "cowsay"; + +Output: + +Running command 'cowsay' +------------------ + ___________ +< derpalerp > + ----------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + + +D +~ + + Currently `fork-exec1.c' does not reach the bottom statements. + ,---- + | printf("------------------\n"); + | printf("Finished\n"); + `---- + Correct this by doing the following: + - Fork a child process + - Have ONLY the child process call execvp() + - Have the parent process wait() for the child + +#include +#include +#include +#include + +int main(void){ + + char *child_argv[] = {"--", "derpalerp",NULL}; + char *child_cmd = "cowsay"; + + printf("Running command '%s'\n",child_cmd); + printf("------------------\n"); + + pid_t child = fork(); + if (child == 0) { // child + execvp(child_cmd,child_argv); + } else { + waitpid(child, 0, 0); + printf("------------------\n"); + printf("Finished\n"); + } + return 0; +} diff --git a/lab02-code/fork-exec1 b/lab02-code/fork-exec1 new file mode 100755 index 0000000..4ae7fd4 Binary files /dev/null and b/lab02-code/fork-exec1 differ diff --git a/lab02-code/fork-exec1.c b/lab02-code/fork-exec1.c new file mode 100644 index 0000000..b1a75f9 --- /dev/null +++ b/lab02-code/fork-exec1.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +int main(void){ + + char *child_argv[] = {"--", "derpalerp",NULL}; + char *child_cmd = "cowsay"; + + printf("Running command '%s'\n",child_cmd); + printf("------------------\n"); + + pid_t child = fork(); + if (child == 0) { // child + execvp(child_cmd,child_argv); + } else { + waitpid(child, 0, 0); + printf("------------------\n"); + printf("Finished\n"); + } + return 0; +} + diff --git a/lab02-code/fork1 b/lab02-code/fork1 new file mode 100755 index 0000000..a724481 Binary files /dev/null and b/lab02-code/fork1 differ diff --git a/lab02-code/fork1.c b/lab02-code/fork1.c new file mode 100644 index 0000000..92d51a8 --- /dev/null +++ b/lab02-code/fork1.c @@ -0,0 +1,17 @@ +#include +#include +#include + +int main(void) { + int i; + for (i = 0; i < 8; i++) { + pid_t child = fork(); + if (child == 0) { + break; + } else { // make sure this is only executed on the parent process + waitpid(child, 0, 0); // wait for the child process to exit with status 0 + } + } + printf("I am number %d, my pid is %d\n", i, getpid()); + return 0; +} diff --git a/lab03-code/QUESTIONS.txt b/lab03-code/QUESTIONS.txt new file mode 100644 index 0000000..858ba39 --- /dev/null +++ b/lab03-code/QUESTIONS.txt @@ -0,0 +1,151 @@ + __________________ + + LAB 03 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `wait-fork.c' +======================= + +A +~ + + Compile and run the program in `wait-loop.c'. Does the loop in the + program ever end? How must one "exit" the program? + +The program doesn't end, since there's a while loop that continuously asks the +user for input, without any option that makes it exit. The only way to "exit" +the program is to terminate it either through sending the signal using ^C, or +else opening another terminal window and killing the process by id. + + +B +~ + + Alter the code so that when the child has completed execution, the + program breaks out of the loop and the program ends normally. Paste in + the code you used for this. + + +#include +#include +#include +#include +#include + +int main(void) { + // Make sure to compile sleep_print first: + // gcc -o sleep_print sleep_print.c + char *child_argv[] = {"./sleep_print", "5", "CHILD: Awake and Done", NULL}; + pid_t child_pid = fork(); + if (child_pid == 0) { + execvp(child_argv[0], child_argv); + perror("errno indicates"); + printf("Couldn't run '%s': is it compiled??\n", child_argv[0]); + exit(1); + } + + while (1) { + printf("Type text then press enter to check on child:\n"); + char buffer[1024]; + char *input = fgets(buffer, 1024, stdin); + input[strlen(input) - 1] = '\0'; // Eliminate newline in buffer + printf("Entered text: '%s'\n", input); + + printf("Waiting\n"); + int status; + pid_t pid = waitpid(child_pid, &status, 0); + if (pid == child_pid) { + printf("CHILD FINISHED: "); + printf("\n"); + break; + } else { + printf("Child not finished: wait returned %d\n", pid); + } + printf("\n"); + } + printf("Exiting wait-loop\n"); + return 0; +} + + +C +~ + + Adjust the code so that the exit status of the child process is + printed when it finishes. Make sure to use the macros + `WIFEXITED(status)' and `WEXITSTATUS(status)' to deal with the + `status' set by `waitpid()'. Paste the code you added for your + answer. + + + if (WIFEXITED(status)) { + printf("CHILD FINISHED: %d", WEXITSTATUS(status)); + printf("\n"); + break; + } + +D +~ + + Make changes so that if the user types in the string `quit', the + program exits immediately without waiting further for the + child. Example: + ,---- + | > a.out + | Type text then press enter to check on child: + | quit + | Entered text: 'quit' + | Quitting + | Exiting wait-loop + | > CHILD: Awake and Done + `---- + Note that the child eventually prints output to the screen which is + fine. + + You will need to check the user input using the `strncmp()' + function. Do some research on this function as it will prove generally + useful. + + Paste the code you used below. + + +E +~ + + The current call to `waitpid()' blocks, pausing execution of the + parent process until the child finishes. Look up the option to pass to + `waitpid()' that will allow it to do a non-blocking wait which returns + immediately if the child is not finished. A sample behavior is below. + ,---- + | > a.out + | Type text then press enter to check on child: + | stuff + | Entered text: 'stuff' + | Waiting + | Child not finished: wait returned 0 + | + | Type text then press enter to check on child: + | more stuff + | Entered text: 'more stuff' + | Waiting + | Child not finished: wait returned 0 + | + | Type text then press enter to check on child: + | CHILD: Awake and Done + | Looks like you're finally up + | Entered text: 'Looks like you're finally up' + | Waiting + | CHILD FINISHED: Exit status 5 + | Exiting wait-loop + | > + `---- + + Paste your entire code for `wait-loop.c' below. diff --git a/lab03-code/sleep_die b/lab03-code/sleep_die new file mode 100755 index 0000000..3696271 Binary files /dev/null and b/lab03-code/sleep_die differ diff --git a/lab03-code/sleep_die.c b/lab03-code/sleep_die.c new file mode 100644 index 0000000..2105326 --- /dev/null +++ b/lab03-code/sleep_die.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +// usage: sleep_die secs +// +// Sleep for given number of seconds then raise SIGINT which will +// cause the program to die. +int main(int argc, char *argv[]){ + + int secs = atoi(argv[1]); + + struct timespec tm = { + .tv_nsec = 0, + .tv_sec = secs, + }; + nanosleep(&tm,NULL); + printf("O happy dagger! This is thy sheath;\n"); + printf("there rust, and let me die.\n"); + raise(SIGINT); + + return secs; +} + diff --git a/lab03-code/sleep_print b/lab03-code/sleep_print new file mode 100755 index 0000000..a64c0a1 Binary files /dev/null and b/lab03-code/sleep_print differ diff --git a/lab03-code/sleep_print.c b/lab03-code/sleep_print.c new file mode 100644 index 0000000..024f2cf --- /dev/null +++ b/lab03-code/sleep_print.c @@ -0,0 +1,24 @@ +#include +#include +#include + +// usage: sleep_print secs message +// +// Sleep for the given number of seconds then print the given message +int main(int argc, char *argv[]){ + + int secs = atoi(argv[1]); + + struct timespec tm = { + .tv_nsec = 0, + .tv_sec = secs, + }; + nanosleep(&tm,NULL); + for(int i=2; i +#include +#include +#include +#include + +int main(void) { + // Make sure to compile sleep_print first: + // gcc -o sleep_print sleep_print.c + char *child_argv[] = {"./sleep_print", "5", "CHILD: Awake and Done", NULL}; + pid_t child_pid = fork(); + if (child_pid == 0) { + execvp(child_argv[0], child_argv); + perror("errno indicates"); + printf("Couldn't run '%s': is it compiled??\n", child_argv[0]); + exit(1); + } + + while (1) { + printf("Type text then press enter to check on child:\n"); + char buffer[1024]; + char *input = fgets(buffer, 1024, stdin); + input[strlen(input) - 1] = '\0'; // Eliminate newline in buffer + printf("Entered text: '%s'\n", input); + + printf("Waiting\n"); + int status; + pid_t pid = waitpid(child_pid, &status, 0); + if (pid == child_pid) { + if (WIFEXITED(status)) { + printf("CHILD FINISHED: %d", WEXITSTATUS(status)); + printf("\n"); + break; + } + } else { + printf("Child not finished: wait returned %d\n", pid); + } + printf("\n"); + } + printf("Exiting wait-loop\n"); + return 0; +} diff --git a/lab04-code/QUESTIONS.txt b/lab04-code/QUESTIONS.txt new file mode 100644 index 0000000..b3f24aa --- /dev/null +++ b/lab04-code/QUESTIONS.txt @@ -0,0 +1,137 @@ + __________________ + + LAB 04 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `parent_listen.c' +=========================== + +A +~ + + Compile and run the program in `parent_listen.c'. Show it's output + below. + +Child wrote 17 bytes +Parent read 17 bytes +Child said: 'Send $$$ please!' + + +B +~ + + Consider the call to pipe(). Do some research to figure out what a + pipe does and explain in a few sentences. + +According to the manpage, a pipe is "a unidirectional data channel that can be +used for interprocess communication." Simply put, it's a way for processes to +communicate with each other through a file-like object, with a read end and a +write end that can be used by separate processes. + + +C +~ + + Observe the calls to read() and write(). Their meaning should be + self-evident (read and write data) but the parameters to these + functions are interesting. Do some reading and explain the 3 + parameters to each of them. Also explain their return value. + +The arguments for read and write are: int fd, void *buf, and size_t count. count +is obvious, and *buf is the buffer that the function is writing to, but the +argument of interest is fd. fd is a numerical file descriptor that can be used +to ask the kernel to make read/write transfers. File descriptors can be linked +to tty IO (stdin, stdout) or files or even sockets or pipes. + +Also, the return value is simply the number of bytes that have been transferred. + + +D +~ + + If you run the program a number of times, you may see output in + different orders: the child may report writing data before the parent + has read it. Adjust the position of the wait() call to guarantee that + the order is always + - Child wrote + - Parent read + - Child said + Paste your code below. + +The wait() call will guarantee that the rest of the code will not run until the +child has terminated, or, more specifically, until after the print statement has +been executed. The code does not need to be changed. + + +PROBLEM 2 `capture_stdout.c' +============================ + +A +~ + + Compile and run the program in `capture_stdout.c'. Show its output. + +Process 28530 Piping +28530 Read from the my_pipe +28530 Read: '28530 In the pipe, five by five' + + +B +~ + + The calls `dup()' and `dup2()' are used in this program to manipulate + file descriptors. Explain the effects of the lines below. + ,---- + | int stdout_bak = dup(STDOUT_FILENO); + | dup2(my_pipe[PWRITE], STDOUT_FILENO); + | ... + | dup2(stdout_bak, STDOUT_FILENO); + `---- + +The first line makes a copy of STDOUT_FILENO and stores it into stdout_bak. The +second line changes my_pipe[PWRITE] to be the fd of STDOUT_FILENO, and finally +the last line changes STDOUT_FILENO back to the stored value that was created in +the first of the three lines. + + +C +~ + + The use of `printf()' normally puts output directly on the + screen. Explain why the statement + ,---- + | printf("%d In the pipe, five by five", + | getpid()); + `---- + does not print to screen as usual. + +This statement does not print because by this time, the output tty STDOUT_FILENO +has had its fd changed such that it will be writing to a pipe rather than the +standard tty output. + + +D +~ + + Modify the code so that the `In the pipe...' expression is printed by + a child process. + - Add a `fork()' AFTER `dup2()' redirects standard output but before + the print + - Add an `if()' to distinguish between parent and child + - The child should print then exit + - The parent should restore stdout then read from the pipe + - Add a `wait()' to guarantee the parent waits for the child to + complete prior to reading from the pipe + Paste your completed code below + + + + diff --git a/lab04-code/capture_stdout b/lab04-code/capture_stdout new file mode 100755 index 0000000..62f9ad0 Binary files /dev/null and b/lab04-code/capture_stdout differ diff --git a/lab04-code/capture_stdout.c b/lab04-code/capture_stdout.c new file mode 100644 index 0000000..e1faf54 --- /dev/null +++ b/lab04-code/capture_stdout.c @@ -0,0 +1,44 @@ +// Redirect standard output temporarily to a pipe, then restore +// standard output and retrieve the captured output +#include +#include +#include +#include + +#define PREAD 0 // index of read end of pipe +#define PWRITE 1 // index of write end of pipe + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); // Turn off I/O buffering + + printf("Process %d Piping\n", getpid()); + int my_pipe[2]; + pipe(my_pipe); + + int stdout_bak = + dup(STDOUT_FILENO); // Duplicate stdout so it can be restored later + dup2(my_pipe[PWRITE], STDOUT_FILENO); // Redirect stdout to pipe + + pid_t pid = fork(); + + if (pid == 0) { + printf( + "%d In the pipe, five by five", // Should not show up on the screen + getpid()); + close(my_pipe[PWRITE]); // Close the write end of the pipe + exit(0); + } + wait(NULL); + dup2(stdout_bak, + STDOUT_FILENO); // Restore stdout: redirect to backed up fd + + printf("%d Read from the my_pipe\n", getpid()); + char buf[2048]; + int bytes_read = read(my_pipe[PREAD], buf, 2048); + + buf[bytes_read] = '\0'; // Not null-terminated by default, append '\0' + close(my_pipe[PREAD]); // Close read end + printf("%d Read: '%s'\n", getpid(), buf); // Show earlier output + + return 0; +} diff --git a/lab04-code/parent_listen b/lab04-code/parent_listen new file mode 100755 index 0000000..8723f1c Binary files /dev/null and b/lab04-code/parent_listen differ diff --git a/lab04-code/parent_listen.c b/lab04-code/parent_listen.c new file mode 100644 index 0000000..8a5dd55 --- /dev/null +++ b/lab04-code/parent_listen.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#define PREAD 0 // index of read end of pipe +#define PWRITE 1 // index of write end of pipe +#define BUFSIZE 1024 + +int main(int argc, char *argv[]) { + + int par_child_pipe[2]; + int pipe_result = pipe(par_child_pipe); + if(pipe_result != 0) { + perror("Failed to create pipe"); + exit(1); + } + + pid_t child_pid = fork(); + if(child_pid <0){ + perror("Failed to fork"); + exit(1); + } + + // CHILD CODE + if(child_pid == 0){ + char *msg = "Send $$$ please!"; + int msg_len = strlen(msg)+1; + int bytes_written = write(par_child_pipe[PWRITE], msg, msg_len); + printf("Child wrote %d bytes\n",bytes_written); + fflush(stdout); + + close(par_child_pipe[PWRITE]); + close(par_child_pipe[PREAD]); + exit(0); + } + + // PARENT CODE + wait(NULL); + + char buffer[BUFSIZE]; + // printf("Child %d started\n",child_pid); + int bytes_read = read(par_child_pipe[PREAD], buffer, BUFSIZE); + close(par_child_pipe[PWRITE]); + close(par_child_pipe[PREAD]); + + printf("Parent read %d bytes\n",bytes_read); + printf("Child said: '%s'\n",buffer); + + // wait(NULL); + + return 0; +} diff --git a/lab05-code/3K.txt b/lab05-code/3K.txt new file mode 100644 index 0000000..a1b28de --- /dev/null +++ b/lab05-code/3K.txt @@ -0,0 +1,139 @@ +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 +70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 +102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 +127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 +152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 +177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 +202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 +227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 +252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 +277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 +302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 +327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 +352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 +377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 +402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 +427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 +452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 +477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 +502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 +527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 +552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 +577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 +602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 +627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 +652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 +677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 +702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 +727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 +752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 +777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 +802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 +827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 +852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 +877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 +902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 +927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 +952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 +977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 +1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 +1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 +1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 +1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 +1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 +1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 +1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 +1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 +1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 +1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 +1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 +1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 +1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 +1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 +1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 +1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 +1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 +1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 +1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 +1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 +1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 +1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 +1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 +1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 +1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 +1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 +1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 +1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 +1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 +1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 +1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 +1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 +1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 +1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 +1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 +1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 +1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 +1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 +1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 +1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 +1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 +1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 +1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 +1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 +1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 +1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 +1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 +1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 +1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 +1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 +2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 +2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 +2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 +2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 +2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 +2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 +2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 +2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 +2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 +2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 +2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 +2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 +2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 +2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 +2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 +2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 +2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 +2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 +2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 +2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 +2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 +2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 +2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 +2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 +2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 +2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 +2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 +2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 +2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 +2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 +2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 +2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 +2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 +2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 +2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 +2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 +2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 +2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 +2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 +2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 +2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 +2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 +2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 +2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 +2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 +2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 +2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 +2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 +2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 +2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 diff --git a/lab05-code/4K.txt b/lab05-code/4K.txt new file mode 100644 index 0000000..d073d0b --- /dev/null +++ b/lab05-code/4K.txt @@ -0,0 +1,237 @@ +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 +56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 +82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 +106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 +126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 +146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 +166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 +186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 +206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 +226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 +246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 +266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 +286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 +306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 +326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 +346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 +366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 +386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 +406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 +426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 +446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 +466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 +486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 +506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 +526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 +546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 +566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 +586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 +606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 +626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 +646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 +666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 +686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 +706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 +726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 +746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 +766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 +786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 +806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 +826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 +846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 +866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 +886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 +906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 +926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 +946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 +966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 +986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 +1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 +1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 +1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 +1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 +1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 +1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 +1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 +1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 +1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 +1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 +1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 +1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 +1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 +1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 +1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 +1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 +1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 +1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 +1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 +1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 +1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 +1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 +1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 +1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 +1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 +1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 +1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 +1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 +1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 +1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 +1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 +1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 +1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 +1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 +1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 +1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 +1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 +1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 +1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 +1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 +1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 +1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 +1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 +1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 +1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 +1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 +1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 +1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 +1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 +1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 +1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 +1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 +1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 +1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 +1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 +1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 +1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 +1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 +1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 +1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 +1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 +1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 +1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 +2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 +2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 +2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 +2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 +2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 +2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 +2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 +2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 +2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 +2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 +2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 +2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 +2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 +2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 +2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 +2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 +2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 +2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 +2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 +2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 +2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 +2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 +2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 +2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 +2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 +2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 +2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 +2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 +2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 +2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 +2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 +2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 +2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 +2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 +2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 +2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 +2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 +2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 +2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 +2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 +2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 +2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 +2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 +2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 +2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 +2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 +2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 +2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 +2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 +2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 +2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 +2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 +2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 +2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 +2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 +2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 +2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 +2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 +2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 +2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 +2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 +2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 +3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 +3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 +3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 +3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 +3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 +3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 +3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 +3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 +3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 +3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 +3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 +3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 +3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 +3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 +3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 +3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 +3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 +3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 +3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 +3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 +3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 +3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 +3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 +3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 +3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 +3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 +3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 +3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 +3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 +3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 +3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 +3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 +3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 +3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 +3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 +3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 +3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 +3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 +3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 +3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 +3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 +3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 +3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 +3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 +3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 +3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 +3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 +3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 +3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 +3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 +3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 +3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 +3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 +3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 +3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 +3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 +3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 +3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 +3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 +3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 +3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 +3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 +3996 3997 3998 3999 4000 \ No newline at end of file diff --git a/lab05-code/8K.txt b/lab05-code/8K.txt new file mode 100644 index 0000000..5cc5287 --- /dev/null +++ b/lab05-code/8K.txt @@ -0,0 +1,487 @@ +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 +30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 +56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 +82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 +106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 +126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 +146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 +166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 +186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 +206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 +226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 +246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 +266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 +286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 +306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 +326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 +346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 +366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 +386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 +406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 +426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 +446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 +466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 +486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 +506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 +526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 +546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 +566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 +586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 +606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 +626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 +646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 +666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 +686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 +706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 +726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 +746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 +766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 +786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 +806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 +826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 +846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 +866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 +886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 +906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 +926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 +946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 +966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 +986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 +1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 +1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 +1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 +1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 +1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 +1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 +1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 +1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 +1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 +1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 +1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 +1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 +1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 +1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 +1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 +1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 +1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 +1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 +1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 +1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 +1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 +1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 +1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 +1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 +1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 +1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 +1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 +1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 +1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 +1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 +1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 +1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 +1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 +1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 +1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 +1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 +1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 +1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 +1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 +1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 +1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 +1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 +1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 +1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 +1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 +1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 +1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 +1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 +1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 +1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 +1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 +1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 +1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 +1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 +1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 +1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 +1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 +1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 +1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 +1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 +1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 +1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 +1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 +2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 +2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 +2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 +2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 +2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 +2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 +2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 +2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 +2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 +2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 +2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 +2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 +2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 +2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 +2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 +2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 +2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 +2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 +2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 +2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 +2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 +2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 +2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 +2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 +2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 +2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 +2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 +2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 +2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 +2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 +2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 +2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 +2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 +2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 +2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 +2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 +2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 +2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 +2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 +2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 +2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 +2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 +2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 +2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 +2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 +2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 +2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 +2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 +2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 +2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 +2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 +2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 +2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 +2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 +2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 +2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 +2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 +2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 +2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 +2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 +2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 +2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 +3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 +3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 +3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 +3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 +3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 +3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 +3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 +3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 +3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 +3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 +3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 +3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 +3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 +3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 +3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 +3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 +3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 +3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 +3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 +3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 +3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 +3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 +3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 +3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 +3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 +3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 +3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 +3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 +3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 +3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 +3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 +3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 +3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 +3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 +3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 +3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 +3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 +3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 +3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 +3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 +3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 +3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 +3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 +3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 +3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 +3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 +3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 +3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 +3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 +3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 +3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 +3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 +3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 +3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 +3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 +3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 +3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 +3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 +3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 +3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 +3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 +3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 +3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 +4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 +4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 +4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 +4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 +4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 +4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 +4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 +4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 +4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 +4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 +4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 +4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 +4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 +4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 +4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 +4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 +4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 +4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 +4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 +4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 +4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 +4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 +4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 +4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 +4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 +4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 +4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 +4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 +4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 +4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 +4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 +4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 +4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 +4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 +4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 +4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 +4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 +4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 +4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 +4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 +4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 +4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 +4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 +4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 +4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 +4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 +4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 +4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 +4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 +4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 +4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 +4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 +4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 +4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 +4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 +4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 +4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 +4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 +4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 +4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 +4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 +4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 +5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 +5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 +5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 +5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 +5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 +5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 +5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 +5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 +5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 +5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 +5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 +5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 +5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 +5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 +5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 +5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 +5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 +5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 +5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 +5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 +5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 +5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 +5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 +5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 +5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 +5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 +5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 +5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 +5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 +5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 +5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 +5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 +5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 +5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 +5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 +5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 +5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 +5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 +5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 +5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 +5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 +5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 +5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 +5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 +5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 +5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 +5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 +5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 +5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 +5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 +5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 +5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 +5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 +5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 +5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 +5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 +5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 +5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 +5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 +5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 +5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 +5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 +5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 +6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 +6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 +6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 +6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 +6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 +6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 +6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 +6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 +6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 +6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 +6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 +6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 +6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 +6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 +6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 +6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 +6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 +6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 +6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 +6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 +6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 +6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 +6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 +6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 +6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 +6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 +6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 +6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 +6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 +6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 +6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 +6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 +6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 +6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 +6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 +6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 +6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 +6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 +6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 +6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 +6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 +6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 +6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 +6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 +6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 +6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 +6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 +6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 +6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 +6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 +6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 +6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 +6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 +6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 +6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 +6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 +6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 +6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 +6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 +6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 +6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 +6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 +7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 +7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 +7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 +7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 +7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 +7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 +7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 +7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 +7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 +7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 +7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 +7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 +7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 +7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 +7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 +7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 +7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 +7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 +7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 +7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 +7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 +7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 +7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 +7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 +7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 +7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 +7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 +7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 +7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 +7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 +7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 +7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 +7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 +7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 +7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 +7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 +7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 +7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 +7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 +7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 +7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 +7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 +7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 +7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 +7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 +7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 +7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 +7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 +7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 +7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 +7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 +7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 +7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 +7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 +7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 +7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 +7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 +7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 +7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 +7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 +7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 +7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 +7996 7997 7998 7999 8000 \ No newline at end of file diff --git a/lab05-code/QUESTIONS.txt b/lab05-code/QUESTIONS.txt new file mode 100644 index 0000000..ae1de48 --- /dev/null +++ b/lab05-code/QUESTIONS.txt @@ -0,0 +1,103 @@ + __________________ + + LAB 05 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `dirops.c' +==================== + +A +~ + + Examine the source code of `dirops.c' closely. It makes use of a + variety of system calls to produce a semi-interesting effect. Compile + and run it several times. Describe the overall intent of the program + based on its output and the code you understand. + +It lists the files in the current directory, their files sizes, determines the +largest file in the directory, and then copies that to a new file +".copy". An observation I made was that the directories . and .. are +fixed at 4096 bytes. + +B ~ + + What set of system calls is used by the program to determine all the + files in the current directory? Describe briefly how these calls work + together. + +readdir returns the next entry in the directory listing. + +C +~ + + Identify the system call that `dirops.c' uses to find the sizes of + files. Describe briefly how this call works. + +This line: stat(file->d_name, &sb); retrieves information from the operating +system about how the file is stored on the disk, including inode numbers, +ownership, file size, and so on. + +D +~ + + The following line sets up the read/write permissions that the copied + file will have. + ,---- + | mode_t perms = S_IRUSR | S_IWUSR; + `---- + Modify this line so that the copied file is readable by the group as + well as the user. + + /Optional challenge:/ Set the permissions to be identical to the + original file. `stat()' is one way to find out the permissions for the + original file. + +I found the list of user permissions in the 'stat' manpage: S_IRGRP. The +modified line looks like: + +mode_t perms = S_IRUSR | S_IWUSR | S_IRGRP; + +In order to find out what the original permissions were, another stat call must +be performed on the file with the largest size. Ideally, this should be done by +file descriptor, but since we are traversing the directory, it's impractical to +keep all the file descriptors open until we identify the largest file. Here's +how I would do it: + +struct stat s; +stat(max_name, &s); +mode_t perms = s.st_mode; + +E +~ + + `dirops.c' contains a subtle bug in the following bit of code towards + the end of the file. + ,---- + | while( (nbytes = read(infd, buf, BUFSIZE)) > 0){ + | write(outfd, buf, BUFSIZE); + | } + `---- + You should observe that every time program is run, it will identify a + copied file as the largest and make another copy due to this bug. It + may help to examine the ends of the copied files with the `tail + file.txt.copy' command which will show the last 10 lines. + + Explain what is wrong with the loop and paste a fixed version below. + +The problem is that the buffer is full before the final loop, which may be less +than BUFSIZE bytes, but the write command is still writing BUFSIZE bytes. Sicne +there's no mechanism to automatically clear out the remaining bytes, they get +written to the file as well. The solution is to only write the number of bytes +that have been read, since it was stored anyways but not used. + + 44 while ((nbytes = read(infd, buf, BUFSIZE)) > 0) { + 45 write(outfd, buf, nbytes); + 46 } diff --git a/lab05-code/dirops b/lab05-code/dirops new file mode 100755 index 0000000..218cecf Binary files /dev/null and b/lab05-code/dirops differ diff --git a/lab05-code/dirops.backup.c b/lab05-code/dirops.backup.c new file mode 100644 index 0000000..ce84df9 --- /dev/null +++ b/lab05-code/dirops.backup.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAMELEN 2048 +#define BUFSIZE 1024 + +int main(int argc, char *argv[]) { + long long max_size = 0; + char max_name[NAMELEN] = {}; + + DIR *dir = opendir("."); + struct dirent *file = NULL; + while( (file = readdir(dir)) != NULL){ + struct stat sb; + stat(file->d_name, &sb); + printf("%-30s : %lld bytes\n", + file->d_name, (long long) sb.st_size); + if(sb.st_size > max_size){ + max_size = sb.st_size; + strncpy(max_name, file->d_name, NAMELEN); + } + } + closedir(dir); + + printf("Largest file: %s with %lld bytes\n", + max_name, max_size); + + char copy_name[NAMELEN]; + snprintf(copy_name, NAMELEN, "%s.copy", max_name); + printf("Copying %s to %s\n",max_name,copy_name); + + char buf[BUFSIZE]; + int infd = open(max_name, O_RDONLY); + int flags = O_WRONLY | O_CREAT | O_TRUNC; + mode_t perms = S_IRUSR | S_IWUSR; + int outfd = open(copy_name, flags, perms); + int nbytes; + while( (nbytes = read(infd, buf, BUFSIZE)) > 0){ + write(outfd, buf, BUFSIZE); + } + printf("Copy complete\n"); + close(infd); + close(outfd); + return 0; +} diff --git a/lab05-code/dirops.c b/lab05-code/dirops.c new file mode 100644 index 0000000..614531b --- /dev/null +++ b/lab05-code/dirops.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAMELEN 2048 +#define BUFSIZE 1024 + +int main(int argc, char *argv[]) { + long long max_size = 0; + char max_name[NAMELEN] = {}; + + DIR *dir = opendir("."); + struct dirent *file = NULL; + while ((file = readdir(dir)) != NULL) { + struct stat sb; + stat(file->d_name, &sb); + printf("%-30s : %lld bytes\n", file->d_name, (long long)sb.st_size); + if (sb.st_size > max_size) { + max_size = sb.st_size; + strncpy(max_name, file->d_name, NAMELEN); + } + } + closedir(dir); + + printf("Largest file: %s with %lld bytes\n", max_name, max_size); + + char copy_name[NAMELEN]; + snprintf(copy_name, NAMELEN, "%s.copy", max_name); + printf("Copying %s to %s\n", max_name, copy_name); + + char buf[BUFSIZE]; + int infd = open(max_name, O_RDONLY); + int flags = O_WRONLY | O_CREAT | O_TRUNC; + mode_t perms = S_IRUSR | S_IWUSR; + int outfd = open(copy_name, flags, perms); + int nbytes; + while ((nbytes = read(infd, buf, BUFSIZE)) > 0) { + write(outfd, buf, nbytes); + } + printf("Copy complete\n"); + close(infd); + close(outfd); + return 0; +} diff --git a/lab06-code/QUESTIONS.txt b/lab06-code/QUESTIONS.txt new file mode 100644 index 0000000..c85406a --- /dev/null +++ b/lab06-code/QUESTIONS.txt @@ -0,0 +1,198 @@ + _________________ + + LAB 06 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `birth_death.c' +========================= + +A +~ + + Compile `circle_of_life.c' to the program `circle_of_life' and run + it. Examine the results and feel free to terminate execution + early. Examine the source code if desired though it is merely a + print/sleep loop. + + Compile `birth_death.c' to the program `birth_death'. This program is + invoked with two arguments, another program name and a "lifetime" + which is an integer number of seconds. Run it like + ,---- + | $> ./birth_death ./circle_of_life 4 + `---- + and show the output below. + +Nants ingonyama bagithi baba +Sithi uhm ingonyama +Nants ingonyama bagithi baba +Sithi uhm ingonyama +kill result: 0 +child process 13697 terminated with signal 2 + + +B +~ + + Examine the source code for `birth_death.c' and determine the system + call the parent program (`birth_death') uses to send signals to the + child program. Paste this line below and explain which signal is being + sent. + +int result = kill(pid,SIGINT) + +This line invokes the kill system call and tells the child to kill itself. + + +C +~ + + `birth_death.c' waits for a child to finish then outputs what signal + caused it to be terminated if that was the cause of death. Paste the + lines of code which determine if a child was terminated due to a + signal below and mention the macros used for this purpose. + + 32 if(WIFSIGNALED(status)){ // check if a signal ended the child + 33 printf("child process %d terminated with signal %d\n", + 34 pid,WTERMSIG(status)); + 35 } + +Macros used were WIFSIGNALED to check if the child was terminated by a signal, +and WTERMSIG which retruns the actual signal. + + +D +~ + + Compile the program `no_interruptions.c' and run it with + `birth_death'. Show your results below. + + Note that you may need to send signals to `no_interruptions' to + forcibly end it. The `pkill' command is useful for this as in + ,---- + | pkill no_inter # send TERM signal to proc name matching "no_inter" + | pkill -KILL no_inter # send KILL signal to proc name matching "no_inter" + `---- + +Ma-na na-na! +Ma-na na-na! +Ma-na na-na! +Ma-na na-na! + +kill result: 0 +No SIGINT-erruptions allowed. +Ma-na na-na! +Ma-na na-na! +Ma-na na-na! +Ma-na na-na! + +Try to SIGTERM me? Piss off! +Ma-na na-na! +Ma-na na-na! +Ma-na na-na! + + +E +~ + + Examine the `no_interruptions.c' code and describe how it is able to + avoid being killed when receiving the interrupt and TERM signals. Show + the lines of code used to accomplish this signal handling. + +It uses signal handlers to catch the signals and handle them by not terminating +itself, contrary to what the signal is telling it to do. The only signal it +can't avoid is SIGKILL (and SIGSTOP but not used here) which forcefully +terminates it. + + 28 // Set handling functions for programs + 29 signal(SIGINT, handle_SIGINT); + 30 signal(SIGTERM, handle_SIGTERM); + + +PROBLEM 2 `start_stop.c' +======================== + +A +~ + + Compile `start_stop.c' to the program `start_stop'. This program is + invoked identically to `birth_death' with two arguments, another + program name and an "interval" which is an integer number of + seconds. Run it like + ,---- + | $> ./start_stop ./circle_of_life 3 + `---- + and show the output below. You may terminate the program early once + you see the pattern. + +Nants ingonyama bagithi baba +Sithi uhm ingonyama +Nants ingonyama bagithi baba +SIGSTOP result: 0 +SIGCONT result: 0 +Sithi uhm ingonyama +Ingonyama +Siyo Nqoba +SIGSTOP result: 0 +SIGCONT result: 0 +Ingonyama Ingonyama nengw' enamabala +From the day we arrive on the planet +And blinking, step into the Sun + + +B +~ + + Describe at a high level the effect that `start_stop' has on a child + process it runs + +start_stop pauses and resumes the execution of the child process periodically +(more precisely, based on the interval passed through the next argument), so in +this case, it would let the child run for 3 seconds, then pause for 3 seconds, +and then resume the loop until the child finished executing. + +C +~ + + Examine the source code of `start_stop.c' and determine the types of + signals it uses to alter behavior of its child process and paste the + corresponding lines of code below. + +It uses the SIGSTOP signall with kill(), which stops the program that's +executing but its behavior is more like pause. It resumes execution with SIGCONT +afterwards. The relevant lines of code are: + + 25 result = kill(pid,SIGSTOP); + 28 result = kill(pid,SIGCONT); + +D +~ + + The program `no_interruptions.c' establishes signal handlers for some + signals allowing it to ignore signals that would normally terminate a + process. Investigate whether it is possible to similarly ignore the + signal used by `start_stop' to pause its child process. Hint: Consider + the provided program `cant_catch_sigstop.c' and run it with + `start_stop'. + +According to the manpage for SIGNAL(2), SIGSTOP cannot be caught by the program: + +The signals SIGKILL and SIGSTOP cannot be caught or ignored. + +As expected, the output of cant_catch_sigstop is: + +I'm awake, I'm awake! +I'm awake, I'm awake! +SIGSTOP result: 0 +SIGCONT result: 0 +I'm awake, I'm awake! +I'm awake, I'm awake! + +and the signal has not been caught. diff --git a/lab06-code/birth_death b/lab06-code/birth_death new file mode 100755 index 0000000..de57646 Binary files /dev/null and b/lab06-code/birth_death differ diff --git a/lab06-code/birth_death.c b/lab06-code/birth_death.c new file mode 100644 index 0000000..72c6f12 --- /dev/null +++ b/lab06-code/birth_death.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + if(argc < 3){ + printf("usage: %s \n",argv[0]); + exit(0); + } + char *child_prog = argv[1]; // program to run as a child + int lifetime = atoi(argv[2]); // time to wait to end child + + int pid = fork(); // fork execution + + if(pid == 0){ // CHILD + execlp(child_prog, child_prog, NULL); // execute specified program + } + + int status, ret; // PARENT + while(1){ // Loop until child done + sleep(lifetime); // sleep for given "lifetime" of child + ret = waitpid(pid, &status, WNOHANG); // check on child + if(ret == pid){ // if child is finished + break; // break from loop + } + int result = kill(pid,SIGINT); // send a interrupt signal to child + printf("kill result: %d\n",result); // check on delivery + } + + if(WIFSIGNALED(status)){ // check if a signal ended the child + printf("child process %d terminated with signal %d\n", + pid,WTERMSIG(status)); + } + + exit(0); +} diff --git a/lab06-code/cant_catch_sigstop b/lab06-code/cant_catch_sigstop new file mode 100755 index 0000000..9fb5923 Binary files /dev/null and b/lab06-code/cant_catch_sigstop differ diff --git a/lab06-code/cant_catch_sigstop.c b/lab06-code/cant_catch_sigstop.c new file mode 100644 index 0000000..0569c4d --- /dev/null +++ b/lab06-code/cant_catch_sigstop.c @@ -0,0 +1,30 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGSTOP(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGSTOP, handle_SIGSTOP); + printf("\nThere's no SIGSTOPping me!\n"); + fflush(stdout); +} + +int main() { + // Set handling functions for programs + signal(SIGSTOP, handle_SIGSTOP); + + /* Infinite loop */ + while (1) { + sleep(1); + printf("I'm awake, I'm awake!\n"); + fflush(stdout); + } + return 0; +} diff --git a/lab06-code/circle_of_life b/lab06-code/circle_of_life new file mode 100755 index 0000000..ecefaa5 Binary files /dev/null and b/lab06-code/circle_of_life differ diff --git a/lab06-code/circle_of_life.c b/lab06-code/circle_of_life.c new file mode 100644 index 0000000..b2f9c25 --- /dev/null +++ b/lab06-code/circle_of_life.c @@ -0,0 +1,50 @@ +#include +#include +#include + +// https://genius.com/Walt-disney-records-circle-of-life-lyrics +char *lyrics[] = { + "Nants ingonyama bagithi baba", + "Sithi uhm ingonyama", + "Nants ingonyama bagithi baba", + "Sithi uhm ingonyama", + "Ingonyama", + "Siyo Nqoba", + "Ingonyama Ingonyama nengw' enamabala ", + "From the day we arrive on the planet", + "And blinking, step into the Sun", + "There's more to be seen than can ever be seen", + "More to do than can ever be done", + "Some say eat or be eaten", + "Some say live and let live", + "But all are agreed as they join the stampede", + "You should never take more than you give", + "In the circle of life", + "It's the wheel of fortune", + "It's the leap of faith", + "It's the band of hope", + "Till we find our place", + "On the path unwinding", + "In the circle, the circle of life", + "Some of us fall by the wayside", + "And some of us soar to the stars", + "And some of us sail through our troubles", + "And some have to live with the scars", + "There's far too much to take in here", + "More to find than can ever be found", + "But the Sun rolling high through the sapphire sky", + "Keeps great and small on the endless round", + NULL +}; + + +int main(){ + int index = 0; + while(lyrics[index] != NULL){ + printf("%s\n",lyrics[index]); + fflush(stdout); + index++; + sleep(1); + } + exit(0); +} diff --git a/lab06-code/no_interruptions b/lab06-code/no_interruptions new file mode 100755 index 0000000..a58ecde Binary files /dev/null and b/lab06-code/no_interruptions differ diff --git a/lab06-code/no_interruptions.c b/lab06-code/no_interruptions.c new file mode 100644 index 0000000..4eb7f5d --- /dev/null +++ b/lab06-code/no_interruptions.c @@ -0,0 +1,39 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGINT(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGINT, handle_SIGINT); + printf("\nNo SIGINT-erruptions allowed.\n"); + fflush(stdout); +} + +// Function run when a SIGTERM is sent to the program +void handle_SIGTERM(int sig_num) { + // Reset handler to catch SIGTERM next time. + signal(SIGTERM, handle_SIGTERM); + printf("\nTry to SIGTERM me? Piss off!\n"); + fflush(stdout); +} + +int main () { + // Set handling functions for programs + signal(SIGINT, handle_SIGINT); + signal(SIGTERM, handle_SIGTERM); + + /* Infinite loop */ + while(1) { + sleep(1); + printf("Ma-na na-na!\n"); + fflush(stdout); + } + return 0; +} diff --git a/lab06-code/start_stop b/lab06-code/start_stop new file mode 100755 index 0000000..9d772b9 Binary files /dev/null and b/lab06-code/start_stop differ diff --git a/lab06-code/start_stop.c b/lab06-code/start_stop.c new file mode 100644 index 0000000..97b609d --- /dev/null +++ b/lab06-code/start_stop.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + if(argc < 3){ + printf("usage: %s \n",argv[0]); + exit(0); + } + char *child_prog = argv[1]; // program to run as a child + int interval = atoi(argv[2]); // time to allow child to run + + int pid = fork(); // fork execution + + if(pid == 0){ // CHILD + execlp(child_prog, child_prog, NULL); // execute specified program + } + + int status, ret; // PARENT + while(1){ // Loop until child done + int result; + sleep(interval); // interval to allow child to run + result = kill(pid,SIGSTOP); // send a stop signal to child + printf("SIGSTOP result: %d\n",result); // check on delivery + sleep(interval); // interval to allow child to run + result = kill(pid,SIGCONT); // send a continue signal to child + printf("SIGCONT result: %d\n",result); // check on delivery + + ret = waitpid(pid, &status, WNOHANG); // check on child + if(ret == pid){ // if child is finished + break; // break from loop + } + } + + if(WIFSIGNALED(status)){ // check if a signal ended the child + printf("child process %d terminated with signal %d\n", + pid,WTERMSIG(status)); + } + + exit(0); +} diff --git a/lab07-code.zip b/lab07-code.zip new file mode 100644 index 0000000..88e3416 Binary files /dev/null and b/lab07-code.zip differ diff --git a/lab07-code/Makefile b/lab07-code/Makefile new file mode 100644 index 0000000..1e32ca5 --- /dev/null +++ b/lab07-code/Makefile @@ -0,0 +1,18 @@ + +all : sleep_print select_AB read_AB + +sleep_print : sleep_print.c + gcc -o $@ $^ + +select_AB : select_AB.c + gcc -o $@ $^ + +read_AB : read_AB.c + gcc -o $@ $^ + +select_AB_children_alive : select_AB_children_alive.c + gcc -o $@ $^ + +clean : + rm -f sleep_print select_AB read_AB + diff --git a/lab07-code/QUESTIONS.txt b/lab07-code/QUESTIONS.txt new file mode 100644 index 0000000..1fb43d0 --- /dev/null +++ b/lab07-code/QUESTIONS.txt @@ -0,0 +1,208 @@ + __________________ + + LAB 07 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `sleep_print.c' +========================= + +A +~ + + Compile `sleep_print.c' using the provided `Makefile' which compiles + it to `sleep_print'. Run the program as + ,---- + | ./sleep_print 1 "hello" + `---- + After a few seconds, press Ctrl-C to send an interrupt signal. Paste + the results of your run below. + + 1 : hello 2 : hello 3 : hello 4 : hello 5 : hello 6 : hello 7 : hello ^Csleep_print: signaled, setting flag + 8 : hello sleep_print: finishing + + +B +~ + + Examine the code for `sleep_print.c' and note the use of the + `sigaction()' function to set up signal handlers. Inspect the signal + handler function and describe how the signal handler causes the + `sleep_print' to shut down in the space below. + + +The signal handler changes a global variable that the while loop is using to +determine whether or not to continue. When the signal handler is called, the +value is changed so the loop stops. + + +PROBLEM 2 `read_AB.c' +===================== + + Note that `read_AB.c' uses the same techniques as `sleep_print.c' to + set up signal handlers and shut down on receiving a signal. + + +A +~ + + Compile `read_AB.c' and run it. Paste the results of running it for a + few seconds below. Use Ctl-C to send an interrupt to end the program. + + +read_AB: listening for children +A had: | 1 : AAAA | +B had: | 1 : BBBB | +A had: | 2 : AAAA | +B had: | 2 : BBBB | +A had: | 3 : AAAA 4 : AAAA 5 : AAAA | +B had: | 3 : BBBB | +A had: | 6 : AAAA 7 : AAAA 8 : AAAA | +^Csleep_print: signaled, setting flag +sleep_print: signaled, setting flag +read_AB: signaled, setting flag +B had: | 4 : BBBB | +read_AB: finishing +sleep_print: signaled, setting flag +sleep_print: signaled, setting flag +sleep_print: finishing +sleep_print: finishing + +B +~ + + Examine the code for `read_AB.c' and note where `pipe(), fork(), + dup2()' are used to set up a communication channel for two children + referred to as A and B. Note that these two children both run + `sleep_print' but A has a 1 second delay while B has a 3 second delay. + Note the main `while()' of `read_AB' which repeatedly reads from the + pipes of its children. + + In the space below explain why the output for the program has the + ordering that it does despite A producing A at a faster rate (every 1 + second) than B (every 3 seconds). + +In the 3 second delay that it took B to print out its second output, A had +already printed out 3 more lines, and they were all loaded up in the pipe ready +to be read. That's why the next line for A had 3 outputs. + +C +~ + + In the output for `read_AB' there should be some lines for Child A + that look like + ,---- + | A had: | 1 : AAAA | + `---- + but also some lines that look like + ,---- + | A had: | 4 : AAAA 5 : AAAA | + `---- + and + ,---- + | A had: |15 : AAAA 16 : AAAA 17 : AAAA | + `---- + while Child B lines always look like + ,---- + | B had: | 4 : BBBB | + `---- + Explain why there is variance in Child A lines while Child B lines + look the same. + +For child A, it really depends on exactly when it started relative to when B +started. For example, + +A: | | | | +B: | | + +may only show 2 counters worth of AAAAs while + +A: | | | | +B: | | + +will show 3counters worth of AAAAs. In the first case, it really just comes down +to the scheduler and the order in which these processes are executed. + +PROBLEM 3 `select_AB.c' +======================= + + Note that `select_AB.c' uses the same techniques as `sleep_print.c' to + set up signal handlers and shut down on receiving a signal. + + +A +~ + + Compile `select_AB.c' and run it. Paste the results of running it for + a few seconds below. Use Ctl-C to send an interrupt to end the + program. + +select_AB: listening for children +A had: | 1 : AAAA | +A had: | 2 : AAAA | +B had: | 1 : BBBB | +A had: | 3 : AAAA | +A had: | 4 : AAAA | +A had: | 5 : AAAA | +B had: | 2 : BBBB | +A had: | 6 : AAAA | +A had: | 7 : AAAA | +A had: | 8 : AAAA | +B had: | 3 : BBBB | +A had: | 9 : AAAA | +A had: |10 : AAAA | +^Csleep_print: signaled, setting flag +sleep_print: signaled, setting flag +select_AB: signaled, setting flag +sleep_print: finishing +sleep_print: finishing +B had: | 4 : BBBB | +select_AB: finishing + + +B +~ + + Examine the code for `select_AB.c'. Like `read_AB', it uses `pipe(), + fork(), dup2()' to set up a communication channel for two children, A + and B, which run `sleep_print' at differing rates. However, the main + `while()' of `select_AB' uses the `select()' system call to sleep + until output is available from a child. + + In the space below explain why the output for the `select_AB' has the + ordering that it does and why it differs from `read_AB'. + +The select() system call "allow a program to monitor multiple file descriptors, +waiting until one or more of the file descriptors become 'ready' for some class +of I/O operation," according to the man page. This means that the parent process +is actually able to monitor both pipes and select whichever one has output +first. Then it prints that directly to the screen. That's why A's output never +get loaded up multiple times in the buffer and B's still prints once every 3 of +A's prints, unlike read_AB, which reads A and B in a fixed order, so if A is +ready to print again before B has even gotten a chance to print, it will just +sit in the queue on top of the previous one. + +C +~ + + The output for `read_AB' contained mixed lengths for child A output as + in + ,---- + | A had: | 1 : AAAA | + | A had: | 4 : AAAA 5 : AAAA | + | A had: |15 : AAAA 16 : AAAA 17 : AAAA | + `---- + + Explain why the output for `select_AB' does not have such differences. + +Since select_AB monitors the pipes, it will print immediately after the pipe +that A used has something to write. If I recall correctly, this is what's used +in many IRC servers to handle inputs coming in from multiple clients. + diff --git a/lab07-code/read_AB b/lab07-code/read_AB new file mode 100755 index 0000000..0bbf947 Binary files /dev/null and b/lab07-code/read_AB differ diff --git a/lab07-code/read_AB.c b/lab07-code/read_AB.c new file mode 100644 index 0000000..bc8fc47 --- /dev/null +++ b/lab07-code/read_AB.c @@ -0,0 +1,78 @@ +// Start two child processes which run sleep_print with differing +// delays and messages. Their output is redirected through pipes +// readable by the parent. The main loop alternates reading from each +// child in turn. Handle interrupt and terminate signals gracefully +// by setting a flag to shut down. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PREAD 0 // read and write ends of pipes +#define PWRITE 1 + +int signaled = 0; // global variable controls exit from main loop + +void handle_signals(int signo){ // handler for some signals + char *msg = "read_AB: signaled, setting flag\n"; // print a message about the signal + write(STDERR_FILENO,msg,strlen(msg)); // avoid fprintf() as it is not reentrant + signaled = 1; // set global variable to indicate signal received + return; +} + +int make_child(int pip[], char *delay, char *msg){ // Create a child which runs sleep_print + pipe(pip); + int pid = fork(); + if(pid != 0){ // PARENT + return pid; // just return child pid + } + dup2(pip[PWRITE], STDOUT_FILENO); // CHILD: redirect standard out to pipe + execlp("./sleep_print","./sleep_print",delay,msg,NULL); // should not return + perror("exec failed"); + exit(1); +} + +int main() { + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigemptyset(&my_sa.sa_mask); // don't block any other signals during handling + my_sa.sa_flags = SA_RESTART; // always restart system calls on signals possible + sigaction(SIGTERM, &my_sa, NULL); // register SIGTERM with given action + sigaction(SIGINT, &my_sa, NULL); // register SIGINT with given action + + int pipeA[2], pipeB[2]; // pipes for children to speak to parent + int pidA = make_child(pipeA, "1", "AAAA"); // create two children with different + int pidB = make_child(pipeB, "3", "BBBB"); // messages and delays between prints + + close(pipeA[PWRITE]); // Parent doesn't use the write ends + close(pipeB[PWRITE]); + + printf("read_AB: listening for children\n"); + + while(!signaled){ // enter a loop to listen until signaled or children die + char buf[1024]; + int n; + + n = read(pipeA[PREAD], buf, 1024); // read from pipeA + buf[n] = '\0'; + fprintf(stdout,"A had: |%s|\n",buf); + + n = read(pipeB[PREAD], buf, 1024); // read from pipeB + buf[n] = '\0'; + fprintf(stdout,"B had: |%s|\n",buf); + } + kill(pidA, SIGTERM); // keyboard interrupt will signal children but a + kill(pidB, SIGTERM); // 'kill read_AB' will not, so always signal them here + + fprintf(stderr,"read_AB: finishing\n"); + exit(0); +} diff --git a/lab07-code/select_AB b/lab07-code/select_AB new file mode 100755 index 0000000..664b174 Binary files /dev/null and b/lab07-code/select_AB differ diff --git a/lab07-code/select_AB.c b/lab07-code/select_AB.c new file mode 100644 index 0000000..27aac91 --- /dev/null +++ b/lab07-code/select_AB.c @@ -0,0 +1,89 @@ +// Start two child processes which run sleep_print with differing +// delays and messages. Their output is redirected through pipes +// readable by the parent. Use select() to grab input from either +// pipe as it becomes available. Handle interrupt and terminate +// signals gracefully by setting a flag to shut down. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PREAD 0 // read and write ends of pipes +#define PWRITE 1 + +int signaled = 0; // global variable controls exit from main loop + +void handle_signals(int signo){ // handler for some signals + char *msg = "select_AB: signaled, setting flag\n"; // print a message about the signal + write(STDERR_FILENO,msg,strlen(msg)); // avoid fprintf() as it is not reentrant + signaled = 1; // set global variable to indicate signal received + return; +} + +int make_child(int pip[], char *delay, char *msg){ // Create a child which runs sleep_print + pipe(pip); + int pid = fork(); + if(pid != 0){ // PARENT + return pid; // just return child pid + } + dup2(pip[PWRITE], STDOUT_FILENO); // CHILD: redirect standard out to pipe + execlp("./sleep_print","./sleep_print",delay,msg,NULL); // should not return + perror("exec failed"); + exit(1); +} + +int main() { + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigemptyset(&my_sa.sa_mask); // don't block any other signals during handling + my_sa.sa_flags = SA_RESTART; // always restart system calls on signals possible + sigaction(SIGTERM, &my_sa, NULL); // register SIGTERM with given action + sigaction(SIGINT, &my_sa, NULL); // register SIGINT with given action + + int pipeA[2], pipeB[2]; // pipes for children to speak to parent + int pidA = make_child(pipeA, "1", "AAAA"); // create two children with different + int pidB = make_child(pipeB, "3", "BBBB"); // messages and delays between prints + + close(pipeA[PWRITE]); // Parent doesn't use the write ends + close(pipeB[PWRITE]); + + printf("select_AB: listening for children\n"); + + while(!signaled){ // enter a loop to listen until signaled or children die + fd_set read_set; // set of file descriptors for select() + FD_ZERO(&read_set); // init the set + FD_SET(pipeA[PREAD], &read_set); // set fds to contain read ends of pipe + FD_SET(pipeB[PREAD], &read_set); + int maxfd = pipeA[PREAD]; // need maximum fd for select() + maxfd = (maxfd < pipeB[PREAD]) ? pipeB[PREAD] : maxfd; + + select(maxfd+1, &read_set, NULL, NULL, NULL); // sleep, wake up if any pipe ready for reading + + char buf[1024]; + int n; + if(FD_ISSET(pipeA[PREAD], &read_set)){ // check if pipeA has anything + n = read(pipeA[PREAD], buf, 1024); // read from pipe + buf[n] = '\0'; + fprintf(stdout,"A had: |%s|\n",buf); + } + if(FD_ISSET(pipeB[PREAD], &read_set)){ // check if pipeB has anything + n = read(pipeB[PREAD], buf, 1024); // read from pipe + buf[n] = '\0'; + fprintf(stdout,"B had: |%s|\n",buf); + } + } + kill(pidA, SIGTERM); // keyboard interrupt will signal children but a + kill(pidB, SIGTERM); // 'kill select_AB' will not, so always signal them here + + fprintf(stderr,"select_AB: finishing\n"); + exit(0); +} diff --git a/lab07-code/sleep_print b/lab07-code/sleep_print new file mode 100755 index 0000000..c1971c7 Binary files /dev/null and b/lab07-code/sleep_print differ diff --git a/lab07-code/sleep_print.c b/lab07-code/sleep_print.c new file mode 100644 index 0000000..5cbdbb1 --- /dev/null +++ b/lab07-code/sleep_print.c @@ -0,0 +1,49 @@ +// In an infinite loop, sleep for an interval and then print a +// message. Catch interrupt and terminate signals and cause the loop +// program to end by adjusting a global flag. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int signaled = 0; // global variable controls exit from main loop +void handle_signals(int signo){ // handler for some signals + char *msg = "sleep_print: signaled, setting flag\n"; // print a message about the signal + write(STDERR_FILENO,msg,strlen(msg)); // avoid fprintf() as it is not reentrant + signaled = 1; // set global variable to indicate signal received + return; +} + +int main(int argc, char *argv[]){ + if(argc < 3){ + printf("usage: %s \n", argv[0]); + exit(1); + } + + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigemptyset(&my_sa.sa_mask); // don't block any other signals during handling + my_sa.sa_flags = SA_RESTART; // always restart system calls on signals possible + sigaction(SIGTERM, &my_sa, NULL); // register SIGTERM with given action + sigaction(SIGINT, &my_sa, NULL); // register SIGINT with given action + + int delay = atoi(argv[1]); // sleep delay + char *message = argv[2]; // message to print + int count=1; + while(!signaled){ + sleep(delay); + printf("%2d : %s ",count,message); + fflush(stdout); + count++; + } + fprintf(stderr,"sleep_print: finishing\n"); // print to stderr in case stdout is going to a pipe + return 0; +} diff --git a/lab08-code.zip b/lab08-code.zip new file mode 100644 index 0000000..2ef4dcb Binary files /dev/null and b/lab08-code.zip differ diff --git a/lab08-code/Makefile b/lab08-code/Makefile new file mode 100644 index 0000000..46f251e --- /dev/null +++ b/lab08-code/Makefile @@ -0,0 +1,15 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +all : em_server em_client + +em_server : em_server.c + $(CC) -o $@ $^ + +em_client : em_client.c + $(CC) -o $@ $^ + +clean : + rm -f em_server em_client *.fifo + + diff --git a/lab08-code/QUESTIONS.txt b/lab08-code/QUESTIONS.txt new file mode 100644 index 0000000..a737f9d --- /dev/null +++ b/lab08-code/QUESTIONS.txt @@ -0,0 +1,102 @@ + __________________ + + LAB 08 QUESTIONS + __________________ + + +- Name: (FILL THIS in) +- NetID: (THE kauf0095 IN kauf0095@umn.edu) + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `server_em.c' +======================= + +A +~ + + Examine the source code for `em_server.c'. Note of the 3 FIFOs that + are used: Requests, Completions, and Data. Describe what appears to + be the purpose of each from the server perspective. + + +B +~ + + What mechanism is used to notify clients that their request has been + filled and that data is ready on the Data FIFO? + + +C +~ + + How many clients have information on each of the FIFOs: + - On the Request FIFO? + - On the Completion FIFO? + - On the Data FIFO? + + +PROBLEM 2 `client_em.c' +======================= + + Note that `read_AB.c' uses the same techniques as `sleep_print.c' to + set up signal handlers and shut down on receiving a signal. + + +A +~ + + Examine the `while()' loop in the client. When waiting for the server + to respond, does the client make use of busy waiting (polling), + interrupt-driven waiting, or something in between? + + +B +~ + + Experiment with changing the while() loop associated with server + responses. Time running 100 transactions using the provided + `run_simulations.sh' script as in + ,---- + | $> time run_simulation.sh 100 > xxx + `---- + Note the timing. You may need to discuss with your TA how to interpret + the results of the shell `time' command which measures CPU utilization + for programs. + + Comment out the `while()' loop associated with waiting and un-comment + the other `while()' loop. Re-run the above script invocation and + report the differences in timing. + + +PROBLEM 3 Protocol +================== + +A +~ + + Describe the overall protocol used by the client and server to + communicate. Use the labels in the messages like `C SERVER' and `B + CLIENT' to help you organize the order what happens when and things + can happen in an unpredictable order. + + +B +~ + + In an initial version of the programs, the client used the following + line to wait for a server response. + ,---- + | raise(SIGSTOP); + `---- + The `raise()' command sends a signal to the running process so that + the effect of this line is to stop the current process until a signal + to continue is received. This approach was found to fail in many + cases causing the entire system to stall. + + Based on your understanding of the protocol above, WHY could simply + stopping the client process result a breakdown? + + You may wish to uncomment and try this version in the code. diff --git a/lab08-code/em_client.c b/lab08-code/em_client.c new file mode 100644 index 0000000..8821d23 --- /dev/null +++ b/lab08-code/em_client.c @@ -0,0 +1,86 @@ +// Client code to look up an email based on name + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// structure to store a lookup_t. client fills in with name, server +// fills in email if found in +typedef struct { + int pid; + char name[256]; + char email[256]; +} lookup_t; + +int signalled = 0; +void handle_signals(int sig_num){ + signalled = 1; +} + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigaction(SIGCONT, &my_sa, NULL); // register SIGCONT with given action + + + if(argc < 2){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + lookup_t request = {}; + request.pid = getpid(); + strcpy(request.name, argv[1]); + + int requests_fd = open("requests.fifo", O_RDWR); // open read/write in case server hasn't started + int completions_fd = open("completions.fifo", O_RDWR); // open read or write only may cause hangs if the + int data_fd = open("data.fifo", O_RDWR); // other end of the pipe has not be openened + + printf("%d A CLIENT: sending request: {pid=%d name=\"%s\" }\n", + request.pid, request.pid, request.name); + write(requests_fd, &request, sizeof(lookup_t)); + printf("%d B CLIENT: pid %d stopping\n",request.pid,request.pid); + + while(!signalled){ + sleep(1); // sleep for 1 second, wake up on on signal + } + + // while(!signalled); // poll for busy waiting + + // raise(SIGSTOP); // buggy waiting + + // if(!signalled){ // also buggy but much harder to hit a stall + // raise(SIGSTOP); // try 'run_simulation.sh 3000' if you have some time + // } + + printf("%d B CLIENT: pid %d signalled to continue\n",request.pid,request.pid); + + lookup_t response; + read(data_fd, &response, sizeof(lookup_t)); + printf("%d C CLIENT: received response: {pid=%d name=\"%s\" email=\"%s\"}\n", + response.pid, response.pid, response.name, response.email); + + + if(request.pid != response.pid){ + printf("CLIENT PROBLEM: PID %d vs %d\n", request.pid, response.pid); + exit(1); + } + + int pid = getpid(); + write(completions_fd, &pid, sizeof(int)); + printf("%d D CLIENT: pid %d indicating completion\n",request.pid,request.pid); + + // printf("CLIENT: result: %s\n",response.email); + + exit(0); +} diff --git a/lab08-code/em_server.c b/lab08-code/em_server.c new file mode 100644 index 0000000..0362586 --- /dev/null +++ b/lab08-code/em_server.c @@ -0,0 +1,101 @@ +// Server code which contains a name/email pairs and will fulfill +// requests from a client through FIFOs. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// data the server has and clients want: pairings of name and email +char *data[][2] = { + {"Chris Kauffman" ,"kauffman@umn.edu"}, + {"Christopher Jonathan" ,"jonat003@umn.edu"}, + {"Amy Larson" ,"larson@cs.umn.edu"}, + {"Chris Dovolis" ,"dovolis@cs.umn.edu"}, + {"Dan Knights" ,"knights@cs.umn.edu"}, + {"George Karypis" ,"karypis@cs.umn.edu"}, + {"Steven Jensen" ,"sjensen@cs.umn.edu"}, + {"Daniel Keefe" ,"dfk@umn.edu"}, + {"Michael W. Whalen" ,"whalen@cs.umn.edu"}, + {"Catherine Qi Zhao" ,"qzhao@umn.edu"}, + {"Dan Challou" ,"challou@cs.umn.edu"}, + {"Steven Wu" ,"zsw@umn.edu"}, + {"Michael Steinbach" ,"steinbac@cs.umn.edu"}, + {"Jon Weissman" ,"jon@cs.umn.edu"}, + {"Victoria Interrante" ,"interran@cs.umn.edu"}, + {"Shana Watters" ,"watt0087@umn.edu"}, + {"James Parker" ,"jparker@cs.umn.edu"}, + {"James Moen" ,"moen0017@cs.umn.edu"}, + {"Daniel Giesel" ,"giese138@umn.edu"}, + {"Jon Read" ,"readx028@umn.edu"}, + {"Sara Stokowski" ,"stoko004@umn.edu"}, + {NULL , NULL}, +}; + +// structure to store a lookup_t. client fills in with name, server +// fills in email if found in +typedef struct { + int pid; + char name[256]; + char email[256]; +} lookup_t; + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + printf("starting server\n"); + + remove("requests.fifo"); + remove("completions.fifo"); + remove("data.fifo"); + printf("SERVER: removed old fifos\n"); + + mkfifo("requests.fifo", S_IRUSR | S_IWUSR); + mkfifo("completions.fifo", S_IRUSR | S_IWUSR); + mkfifo("data.fifo", S_IRUSR | S_IWUSR); + printf("SERVER: created new fifos\n"); + + int requests_fd = open("requests.fifo", O_RDWR); // open read/write in case server hasn't started + int completions_fd = open("completions.fifo", O_RDWR); // open read or write only may cause hangs if the + int data_fd = open("data.fifo", O_RDWR); // other end of the pipe has not be openened + printf("SERVER: opened FIFOs, listening\n"); + + while(1){ + lookup_t request; + read(requests_fd, &request, sizeof(lookup_t)); + printf("%d B SERVER: received request {pid=%d name=\"%s\" }\n", + request.pid, request.pid, request.name); + char *name = request.name; + int found = 0; + for(int i=0; data[i][0] != NULL; i++){ + if(strcmp(name, data[i][0]) == 0){ + strcpy(request.email, data[i][1]); + found = 1; + } + } + if(!found){ + strcpy(request.email, "NOT FOUND"); + } + printf("%d B SERVER: filling request {pid=%d name=\"%s\" email=\"%s\" }\n", + request.pid,request.pid, request.name, request.email); + write(data_fd, &request, sizeof(request)); + printf("%d B SERVER: signaling pid %d\n", + request.pid, request.pid); + kill(request.pid, SIGCONT); + int done_pid = -1; + read(completions_fd, &done_pid, sizeof(int)); + printf("%d E SERVER: %d completion\n",done_pid,done_pid); + if(request.pid != done_pid){ + printf("Server Problems: PID %d vs %d", + request.pid, done_pid); + } + } + + exit(0); +} diff --git a/lab08-code/run_simulation.sh b/lab08-code/run_simulation.sh new file mode 100755 index 0000000..2dbcbf3 --- /dev/null +++ b/lab08-code/run_simulation.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# usage: run_smulations.sh 20 +# +# Start an em_server then run multiple simultaneous em_clients +# connecting to find various emails. Accepts a command line argument +# which is the number of clients to run. + +nclients=10 + +if (( $# >= 1 )); then + nclients=$1 +fi + +names=( + "Chris Kauffman" + "Christopher Jonathan" + "Amy Larson" + "Chris Dovolis" + "Dan Knights" + "George Karypis" + "Steven Jensen" + "Daniel Keefe" + "Michael W. Whalen" + "Catherine Qi Zhao" + "Dan Challou" + "Steven Wu" + "Michael Steinbach" + "Jon Weissman" + "Victoria Interrante" + "Shana Watters" + "James Parker" + "James Moen" + "Daniel Giesel" + "Jon Read" + "Sara Stokowski" +) + +len=${#names[*]} + +# kill em_server +./em_server & +em_server_pid=$! + +# start em_clients +pids=() +for i in `seq 0 $nclients`; do + idx=$((i % len)) + # echo "${names[idx]}" + ./em_client "${names[idx]}" & + pids[i]=$! +done + +# echo "${pids[*]}" + +# wait for jobs to finish +for pid in ${pids[*]}; do + wait $pid +done + +kill $em_server_pid diff --git a/lab09-code.zip b/lab09-code.zip new file mode 100644 index 0000000..415b133 Binary files /dev/null and b/lab09-code.zip differ diff --git a/lab09-code/Makefile b/lab09-code/Makefile new file mode 100644 index 0000000..5622bf4 --- /dev/null +++ b/lab09-code/Makefile @@ -0,0 +1,25 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +all : em_server_mq em_client_mq \ + em_server_fifo em_client_fifo + +em_server_mq : em_server_mq.c + $(CC) -o $@ $^ + +em_client_mq : em_client_mq.c + $(CC) -o $@ $^ + +em_server_fifo : em_server_fifo.c + $(CC) -o $@ $^ + +em_client_fifo : em_client_fifo.c + $(CC) -o $@ $^ + +clean : + rm -f em_server_mq em_client_mq \ + em_server_fifo em_client_fifo \ + *.fifo + + + diff --git a/lab09-code/QUESTIONS.txt b/lab09-code/QUESTIONS.txt new file mode 100644 index 0000000..362b884 --- /dev/null +++ b/lab09-code/QUESTIONS.txt @@ -0,0 +1,101 @@ + __________________ + + LAB 09 QUESTIONS + __________________ + + +- Name: Michael Zhang +- NetID: zhan4854 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1 `em_server_mq.c' and `em_server_mq.c' +=============================================== + +A +~ + + Examine the source code for `em_server_mq.c' and + `em_client_mq.c'. Describe the lines of code which are used to + establish the message queues used for communication. How many message + queues are there? + +There's one message queue for the server, and one for the client. These are +created by msgget(key, 0644 | IPC_CREAT) where key was obtained by ftok using +the identity of the party that called it. + +B +~ + + Describe the sending and receiving functions used in the server to put + messages onto the queue. Focus your attention on the server side + first. Describe each argument of the send/receive functions and its + purpose. You may wish to consult the textbook or manual page for the + functions to get more information. + +To put a message onto the message queue you would use msgsnd, and send the +object containing the request information that you need. + +C +~ + + Describe the protocol that appears to be used for communication. What + steps are taken by a client to make a request for an email address + lookup? How does the server respond? You may find it useful to use the + letters associated with print statements like "A" and "D". Note any + operations that might happen in an arbitrary order. + +The protocol looks like this: + + - The client first sends { name = argv[1], mtype = pid }. + - The server msgrcvs this, reads the name and name and mtype from the request + object and looks up the email associated with the name. + - The server then sends back { name = request.name, mtype = request.mtype, + email = the email that was looked up. } + - The email client makes sure that the pid that the mtype returned is the same + as the pid that it requested with. + +D +~ + + Recall that the previous email lookup server/client that used FIFOs + would answer requests on a Data FIFO. The Server would only allow one + Client to access the Data FIFO at a time. This was to prevent the + client from retrieving data from the queue that was not intended for + them. + + In the Message Queue server/client, potentially many clients are + accessing the To-Client queue simultaneously. Describe why there is + not a problem in this setting. Look carefully at the arguments used in + the `msgrcv()' call in the client. + +This isn't a problem because msgrcv takes in a flag msgtype which in this case +is the pid of the client. This way, msgrcv will only return the messages +intended for the correct client. Of course, this isn't a valid security measure +but it produces the correct result. + +E +~ + + In the FIFO server/client, sleeping and signaling was used to avoid + busily waiting for availability of the data. This complicated the + protocol somewhat in order to get more efficient resource utilization. + + There is NO explicit sleeping in the Message Queue server/client which + might indicate it is less efficient as processes busily wait for + messages. Do some research on `msgsnd() / msgrcv()' calls to determine + if they are busy waiting (polling) or interrupt driven operations. + + Confirm these answers by running `run_simulations_mq.sh' on a large + number of client and timing the results. A sample run might be + ,---- + | > time ./run_simulation_mq.sh 1000 > ~/tmp/xxx + `---- + +According to MSGOP(2), "If insufficient space is available in the queue, then +the default behavior of msgsnd() is to block until space becomes available. If +IPC_NOWAIT is specified in msgflg, then the call instead fails with the error +EAGAIN." This means they will wait for the message queue to become available +(after the other clients have read from it) before it sends. diff --git a/lab09-code/em_client_fifo b/lab09-code/em_client_fifo new file mode 100755 index 0000000..acd6860 Binary files /dev/null and b/lab09-code/em_client_fifo differ diff --git a/lab09-code/em_client_fifo.c b/lab09-code/em_client_fifo.c new file mode 100644 index 0000000..902db6c --- /dev/null +++ b/lab09-code/em_client_fifo.c @@ -0,0 +1,88 @@ +// Client code to look up an email based on name + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// structure to store a lookup_t. client fills in with name, server +// fills in email if found in +typedef struct { + int pid; + char name[256]; + char email[256]; +} lookup_t; + +int signalled = 0; +void handle_signals(int sig_num){ + signalled = 1; +} + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigaction(SIGCONT, &my_sa, NULL); // register SIGCONT with given action + + + if(argc < 2){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + lookup_t request = {}; + request.pid = getpid(); + strcpy(request.name, argv[1]); + + int requests_fd = open("requests.fifo", O_RDWR); // open read/write in case server hasn't started + int completions_fd = open("completions.fifo", O_RDWR); // open read or write only may cause hangs if the + int data_fd = open("data.fifo", O_RDWR); // other end of the pipe has not be openened + + printf("%d A CLIENT: sending request: {pid=%d name=\"%s\" }\n", + request.pid, request.pid, request.name); + write(requests_fd, &request, sizeof(lookup_t)); + printf("%d B CLIENT: pid %d stopping\n",request.pid,request.pid); + + while(!signalled){ + struct timespec tm = {.tv_nsec = 1000}; + nanosleep(&tm,NULL); // sleep a short duration + // sleep(1); // sleep for 1 second, wake up on on signal + } + + // while(!signalled); // poll for busy waiting + + // raise(SIGSTOP); // buggy waiting + + // if(!signalled){ // also buggy but much harder to hit a stall + // raise(SIGSTOP); // try 'run_simulation.sh 3000' if you have some time + // } + + printf("%d B CLIENT: pid %d signalled to continue\n",request.pid,request.pid); + + lookup_t response; + read(data_fd, &response, sizeof(lookup_t)); + printf("%d C CLIENT: received response: {pid=%d name=\"%s\" email=\"%s\"}\n", + response.pid, response.pid, response.name, response.email); + + + if(request.pid != response.pid){ + printf("CLIENT PROBLEM: PID %d vs %d\n", request.pid, response.pid); + exit(1); + } + + int pid = getpid(); + write(completions_fd, &pid, sizeof(int)); + printf("%d D CLIENT: pid %d indicating completion\n",request.pid,request.pid); + + // printf("CLIENT: result: %s\n",response.email); + + exit(0); +} diff --git a/lab09-code/em_client_mq b/lab09-code/em_client_mq new file mode 100755 index 0000000..c77ea16 Binary files /dev/null and b/lab09-code/em_client_mq differ diff --git a/lab09-code/em_client_mq.c b/lab09-code/em_client_mq.c new file mode 100644 index 0000000..024d465 --- /dev/null +++ b/lab09-code/em_client_mq.c @@ -0,0 +1,53 @@ +// Client code to look up an email based on name; contacts servers via +// System V IPC message queues. +#include +#include +#include +#include +#include +#include + +// structure to store a lookup. client fills in with name, server +// fills in email if found in +typedef struct { + long mtype; // contains PID of sending process + char name[256]; // name desired + char email[256]; // email associated with name +} lookup_t; + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); + + if(argc < 2){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + key_t key; + key = ftok("em_server_mq.c", 0); + int to_server_qid = msgget(key, 0644 | IPC_CREAT); + key = ftok("em_client_mq.c", 0); + int to_clients_qid = msgget(key, 0644 | IPC_CREAT); + + int my_pid = getpid(); + lookup_t request = {}; + request.mtype = my_pid; + strcpy(request.name, argv[1]); + + printf("%ld A CLIENT: sending request: {pid=%ld name=\"%s\" }\n", + request.mtype, request.mtype, request.name); + msgsnd(to_server_qid, &request, sizeof(lookup_t), 0); + + lookup_t response = {}; + msgrcv(to_clients_qid, &response, sizeof(lookup_t), my_pid, 0); + + printf("%ld D CLIENT: received response: {pid=%ld name=\"%s\" email=\"%s\"}\n", + response.mtype, response.mtype, response.name, response.email); + + if(my_pid != response.mtype){ + printf("CLIENT PROBLEM: PID %d vs %ld\n", my_pid, response.mtype); + exit(1); + } + + exit(0); +} diff --git a/lab09-code/em_server_fifo b/lab09-code/em_server_fifo new file mode 100755 index 0000000..5180c1b Binary files /dev/null and b/lab09-code/em_server_fifo differ diff --git a/lab09-code/em_server_fifo.c b/lab09-code/em_server_fifo.c new file mode 100644 index 0000000..ff5e1a7 --- /dev/null +++ b/lab09-code/em_server_fifo.c @@ -0,0 +1,104 @@ +// Server code which contains a name/email pairs and will fulfill +// requests from a client through FIFOs. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// data the server has and clients want: pairings of name and email +char *data[][2] = { + {"Chris Kauffman", "kauffman@umn.edu"}, + {"Christopher Jonathan", "jonat003@umn.edu"}, + {"Amy Larson", "larson@cs.umn.edu"}, + {"Chris Dovolis", "dovolis@cs.umn.edu"}, + {"Dan Knights", "knights@cs.umn.edu"}, + {"George Karypis", "karypis@cs.umn.edu"}, + {"Steven Jensen", "sjensen@cs.umn.edu"}, + {"Daniel Keefe", "dfk@umn.edu"}, + {"Michael W. Whalen", "whalen@cs.umn.edu"}, + {"Catherine Qi Zhao", "qzhao@umn.edu"}, + {"Dan Challou", "challou@cs.umn.edu"}, + {"Steven Wu", "zsw@umn.edu"}, + {"Michael Steinbach", "steinbac@cs.umn.edu"}, + {"Jon Weissman", "jon@cs.umn.edu"}, + {"Victoria Interrante", "interran@cs.umn.edu"}, + {"Shana Watters", "watt0087@umn.edu"}, + {"James Parker", "jparker@cs.umn.edu"}, + {"James Moen", "moen0017@cs.umn.edu"}, + {"Daniel Giesel", "giese138@umn.edu"}, + {"Jon Read", "readx028@umn.edu"}, + {"Sara Stokowski", "stoko004@umn.edu"}, + {NULL, NULL}, +}; + +// structure to store a lookup_t. client fills in with name, server +// fills in email if found in +typedef struct { + int pid; + char name[256]; + char email[256]; +} lookup_t; + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + printf("starting server\n"); + + remove("requests.fifo"); + remove("completions.fifo"); + remove("data.fifo"); + printf("SERVER: removed old fifos\n"); + + mkfifo("requests.fifo", S_IRUSR | S_IWUSR); + mkfifo("completions.fifo", S_IRUSR | S_IWUSR); + mkfifo("data.fifo", S_IRUSR | S_IWUSR); + printf("SERVER: created new fifos\n"); + + int requests_fd = open( + "requests.fifo", O_RDWR); // open read/write in case server hasn't started + int completions_fd = + open("completions.fifo", + O_RDWR); // open read or write only may cause hangs if the + int data_fd = + open("data.fifo", O_RDWR); // other end of the pipe has not be openened + printf("SERVER: opened FIFOs, listening\n"); + + while (1) { + lookup_t request; + read(requests_fd, &request, sizeof(lookup_t)); + printf("%d B SERVER: received request {pid=%d name=\"%s\" }\n", + request.pid, request.pid, request.name); + char *name = request.name; + int found = 0; + for (int i = 0; data[i][0] != NULL; i++) { + if (strcmp(name, data[i][0]) == 0) { + strcpy(request.email, data[i][1]); + found = 1; + } + } + if (!found) { + strcpy(request.email, "NOT FOUND"); + } + printf( + "%d B SERVER: filling request {pid=%d name=\"%s\" email=\"%s\" }\n", + request.pid, request.pid, request.name, request.email); + write(data_fd, &request, sizeof(request)); + printf("%d B SERVER: signaling pid %d\n", request.pid, request.pid); + kill(request.pid, SIGCONT); + int done_pid = -1; + read(completions_fd, &done_pid, sizeof(int)); + printf("%d E SERVER: %d completion\n", done_pid, done_pid); + if (request.pid != done_pid) { + printf("Server Problems: PID %d vs %d", request.pid, done_pid); + } + } + + exit(0); +} diff --git a/lab09-code/em_server_mq b/lab09-code/em_server_mq new file mode 100755 index 0000000..f40f11e Binary files /dev/null and b/lab09-code/em_server_mq differ diff --git a/lab09-code/em_server_mq.c b/lab09-code/em_server_mq.c new file mode 100644 index 0000000..c472b4a --- /dev/null +++ b/lab09-code/em_server_mq.c @@ -0,0 +1,93 @@ +// Server code which contains a name/email pairs and will fulfill +// requests from a client through System V IPC message queues. +#include +#include +#include +#include +#include +#include +#include + +// data the server has and clients want: pairings of name and email +char *data[][2] = { + {"Chris Kauffman" ,"kauffman@umn.edu"}, + {"Christopher Jonathan" ,"jonat003@umn.edu"}, + {"Amy Larson" ,"larson@cs.umn.edu"}, + {"Chris Dovolis" ,"dovolis@cs.umn.edu"}, + {"Dan Knights" ,"knights@cs.umn.edu"}, + {"George Karypis" ,"karypis@cs.umn.edu"}, + {"Steven Jensen" ,"sjensen@cs.umn.edu"}, + {"Daniel Keefe" ,"dfk@umn.edu"}, + {"Michael W. Whalen" ,"whalen@cs.umn.edu"}, + {"Catherine Qi Zhao" ,"qzhao@umn.edu"}, + {"Dan Challou" ,"challou@cs.umn.edu"}, + {"Steven Wu" ,"zsw@umn.edu"}, + {"Michael Steinbach" ,"steinbac@cs.umn.edu"}, + {"Jon Weissman" ,"jon@cs.umn.edu"}, + {"Victoria Interrante" ,"interran@cs.umn.edu"}, + {"Shana Watters" ,"watt0087@umn.edu"}, + {"James Parker" ,"jparker@cs.umn.edu"}, + {"James Moen" ,"moen0017@cs.umn.edu"}, + {"Daniel Giesel" ,"giese138@umn.edu"}, + {"Jon Read" ,"readx028@umn.edu"}, + {"Sara Stokowski" ,"stoko004@umn.edu"}, + {NULL , NULL}, +}; + +// structure to store a lookup. client fills in with name, server +// fills in email if found in +typedef struct { + long mtype; // contains PID of sending process + char name[256]; // name desired + char email[256]; // email associated with name +} lookup_t; + +int signalled = 0; +void handle_signals(int sig_num){ + signalled = 1; +} + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + struct sigaction my_sa = {}; // portable signal handling setup with sigaction() + my_sa.sa_handler = handle_signals; // run function handle_signals + sigaction(SIGTERM, &my_sa, NULL); // register SIGCONT with given action + sigaction(SIGINT, &my_sa, NULL); // register SIGCONT with given action + + printf("starting server\n"); + + key_t key; + key = ftok("em_server_mq.c", 0); + int to_server_qid = msgget(key, 0644 | IPC_CREAT); + key = ftok("em_client_mq.c", 0); + int to_clients_qid = msgget(key, 0644 | IPC_CREAT); + + printf("SERVER: created/attached to message queues\n"); + + while(!signalled){ + lookup_t request; + msgrcv(to_server_qid, &request, sizeof(lookup_t), 0, 0); + printf("%ld B SERVER: received request {pid=%ld name=\"%s\" }\n", + request.mtype, request.mtype, request.name); + char *name = request.name; + int found = 0; + for(int i=0; data[i][0] != NULL; i++){ + if(strcmp(name, data[i][0]) == 0){ + strcpy(request.email, data[i][1]); + found = 1; + } + } + if(!found){ + strcpy(request.email, "NOT FOUND"); + } + printf("%ld C SERVER: filling request {pid=%ld name=\"%s\" email=\"%s\" }\n", + request.mtype,request.mtype, request.name, request.email); + + msgsnd(to_clients_qid, &request, sizeof(request), 0); + } + + msgctl(to_server_qid, IPC_RMID, NULL); // clean up the message queues + msgctl(to_clients_qid, IPC_RMID, NULL); + + exit(0); +} diff --git a/lab09-code/run_simulation_fifo.sh b/lab09-code/run_simulation_fifo.sh new file mode 100755 index 0000000..eabcc92 --- /dev/null +++ b/lab09-code/run_simulation_fifo.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# usage: run_smulations.sh 20 +# +# Start an em_server then run multiple simultaneous em_clients +# connecting to find various emails. Accepts a command line argument +# which is the number of clients to run. + +nclients=10 + +if (( $# >= 1 )); then + nclients=$1 +fi + +names=( + "Chris Kauffman" + "Christopher Jonathan" + "Amy Larson" + "Chris Dovolis" + "Dan Knights" + "George Karypis" + "Steven Jensen" + "Daniel Keefe" + "Michael W. Whalen" + "Catherine Qi Zhao" + "Dan Challou" + "Steven Wu" + "Michael Steinbach" + "Jon Weissman" + "Victoria Interrante" + "Shana Watters" + "James Parker" + "James Moen" + "Daniel Giesel" + "Jon Read" + "Sara Stokowski" +) + +len=${#names[*]} # length of the array of names + +./em_server_fifo & # start the server +em_server_pid=$! + +# sleep 0.25 # short pause to ensure server starts up + +nclients=$((nclients-1)) # decrement as we are starting at 0 + +pids=() # track em_clients pids +for i in `seq 0 $nclients`; do + idx=$((i % len)) # index of email addressfish out one emal address + email="${names[idx]}" # fish out an email address + # echo "${names[idx]}" + ./em_client_fifo "$email" & # start client with email address + pids[i]=$! # keep track of pid of last process: client +done + +# echo "${pids[*]}" + +# wait for jobs to finish +for pid in ${pids[*]}; do # wait for all clients to finish + wait $pid +done + +kill $em_server_pid # kill the server diff --git a/lab09-code/run_simulation_mq.sh b/lab09-code/run_simulation_mq.sh new file mode 100755 index 0000000..5ba7fb5 --- /dev/null +++ b/lab09-code/run_simulation_mq.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# usage: run_smulations.sh 20 +# +# Start an em_server then run multiple simultaneous em_clients +# connecting to find various emails. Accepts a command line argument +# which is the number of clients to run. + +nclients=10 + +if (( $# >= 1 )); then + nclients=$1 +fi + +names=( + "Chris Kauffman" + "Christopher Jonathan" + "Amy Larson" + "Chris Dovolis" + "Dan Knights" + "George Karypis" + "Steven Jensen" + "Daniel Keefe" + "Michael W. Whalen" + "Catherine Qi Zhao" + "Dan Challou" + "Steven Wu" + "Michael Steinbach" + "Jon Weissman" + "Victoria Interrante" + "Shana Watters" + "James Parker" + "James Moen" + "Daniel Giesel" + "Jon Read" + "Sara Stokowski" +) + +len=${#names[*]} # length of the array of names + +./em_server_mq & # start the server +em_server_pid=$! + +# sleep 0.25 # short pause to ensure server starts up + +nclients=$((nclients-1)) # decrement as we are starting at 0 + +pids=() # track em_clients pids +for i in `seq 0 $nclients`; do + idx=$((i % len)) # index of email addressfish out one emal address + email="${names[idx]}" # fish out an email address + # echo "${names[idx]}" + ./em_client_mq "$email" & # start client with email address + pids[i]=$! # keep track of pid of last process: client +done + +# echo "${pids[*]}" + +# wait for jobs to finish +for pid in ${pids[*]}; do # wait for all clients to finish + wait $pid +done + +kill $em_server_pid # kill the server diff --git a/lab10-code.zip b/lab10-code.zip new file mode 100644 index 0000000..7df96da Binary files /dev/null and b/lab10-code.zip differ diff --git a/lab10-code/.gdb_history b/lab10-code/.gdb_history new file mode 100644 index 0000000..cdc55ec --- /dev/null +++ b/lab10-code/.gdb_history @@ -0,0 +1,3 @@ +run +bt +q diff --git a/lab10-code/.vscode/settings.json b/lab10-code/.vscode/settings.json new file mode 100644 index 0000000..6933a93 --- /dev/null +++ b/lab10-code/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.pyx": "python", + "string.h": "c" + } +} \ No newline at end of file diff --git a/lab10-code/Makefile b/lab10-code/Makefile new file mode 100644 index 0000000..b1c3945 --- /dev/null +++ b/lab10-code/Makefile @@ -0,0 +1,16 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) + +all : philosophers_ipc philosophers_pthread + +philosophers_ipc : philosophers_ipc.c + $(CC) -o $@ $^ + +philosophers_pthread: philosophers_pthread.c + $(CC) -pthread -o $@ $^ + +clean : + rm -f *.o philosophers_ipc # philosophers_pthread + + + diff --git a/lab10-code/peda-session-philosophers_pthread.txt b/lab10-code/peda-session-philosophers_pthread.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/lab10-code/peda-session-philosophers_pthread.txt @@ -0,0 +1 @@ + diff --git a/lab10-code/philosophers_ipc b/lab10-code/philosophers_ipc new file mode 100755 index 0000000..2009111 Binary files /dev/null and b/lab10-code/philosophers_ipc differ diff --git a/lab10-code/philosophers_ipc.c b/lab10-code/philosophers_ipc.c new file mode 100644 index 0000000..b109c31 --- /dev/null +++ b/lab10-code/philosophers_ipc.c @@ -0,0 +1,130 @@ +// Dining philosophers (swansons) using System V Semaphores +// Original: http://www.lisha.ufsc.br/~guto/teaching/os/exercise/phil.html +// Modified by Chris Kauffman +// +// This version uses a C array of semaphores. Each System V semaphore +// itself can be an array but of the 5 distinct semphores in the C array are +// initialized to contain only a single counter at sem_num=0. +// +// Short random delays are added between each philosophers +// thinking/eating cycle to generate some variance in execution order +// +// To see the multiple processes, run the following commands +// > gcc -o philosophers philosophers.c +// > philosophers > xxx & watch -d -n 0.1 'ps ux | grep philosophers' +// Ctrl-c to stop the "watch" command (may screw up the terminal display) + +#include +#include +#include +#include +#include +#include +#include +#include + +#define N_PHILOSOPHERS 5 // Number of philosophers + +const int MEALS_TO_FINISH = + 10; // Number of iterations before philosophers finish +const int MAX_DELAY = 50000; // Maximum delay in nanos between meal iterations + +// Semaphore ids +int utensils[N_PHILOSOPHERS]; // IDs for arrays of IPC semaphores + +int philosopher(int n); // Defined after main() + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + int i, status; + pid_t phil[N_PHILOSOPHERS]; + printf("The Dining Swansons (Philosophers) Problem\n"); + + // Parent process only: + // + // Allocate utensils: semaphores which are initially set to value + // one. Each semaphore is only a single counter with sem_num=0. + for (i = 0; i < N_PHILOSOPHERS; i++) { + utensils[i] = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); + semctl(utensils[i], 0, SETVAL, 1); + } + + // Parent generates child processes + for (i = 0; i < N_PHILOSOPHERS; i++) { + int pid = fork(); + if (pid == 0) { // child has pid 0 + int ret = philosopher(i); // child acts as philosopher + exit(ret); // then exits + } else { // parent gets pid > 0 + phil[i] = pid; // parent tracks children + } + } + + // Parent waits on all children to finish + for (i = 0; i < N_PHILOSOPHERS; i++) { + waitpid(phil[i], &status, 0); + } + + printf("JJ: All Swansons finished, cleaning up the diner\n"); + + // Eliminate the utensils and table semaphores + for (i = 0; i < N_PHILOSOPHERS; i++) { + semctl(utensils[i], 0, IPC_RMID, 0); + } + + return 0; +} + +// Code for dining philosopher child processes +int philosopher(int n) { + int i, first, second; + struct sembuf op; // Used to perform semaphore operations + op.sem_flg = 0; + op.sem_num = + 0; // C array of semaphores each with 1, op always on the 0th sem + srand(time(NULL)); // Seed random number generator + + // Avoid deadlock via slightly different order of utensil requests + // for last philospher + + // first utensil to get, most go for n first, last philospher goes for 0 + // first + first = (n != N_PHILOSOPHERS - 1) ? n : 0; + // second utensil to get, last philopher goes for n second + second = (n != N_PHILOSOPHERS - 1) ? n + 1 : n; + + printf("Swanson %d wants utensils %d and %d\n", n, first, second); + printf("Swanson %d at the table\n", n); + + // Main loop of thinking/eating cycles + for (i = 0; i < MEALS_TO_FINISH; i++) { + int sleep_time = rand() % MAX_DELAY; + usleep(sleep_time); // sleep for for a short time + + printf("%2d: Swanson %d is contemplating his awesomeness ...\n", i, n); + + // get first utensil + op.sem_op = -1; + semop(utensils[first], &op, 1); + printf("%2d: Swanson %d got utensil %d\n", i, n, first); + + // get second utensil + op.sem_op = -1; + semop(utensils[second], &op, 1); + printf("%2d: Swanson %d got utensil %d\n", i, n, second); + + printf("%2d: Swanson %d is eating an egg ...\n", i, n); + usleep(sleep_time); // sleep for for a short time + + // release first utensil + op.sem_op = +1; + semop(utensils[first], &op, 1); + + // release second utensil + op.sem_op = +1; + semop(utensils[second], &op, 1); + } + + printf("Swanson %d leaving the diner\n", n); + exit(n); +} diff --git a/lab10-code/philosophers_pthread b/lab10-code/philosophers_pthread new file mode 100755 index 0000000..4d03cc2 Binary files /dev/null and b/lab10-code/philosophers_pthread differ diff --git a/lab10-code/philosophers_pthread.c b/lab10-code/philosophers_pthread.c new file mode 100644 index 0000000..8c2fc0b --- /dev/null +++ b/lab10-code/philosophers_pthread.c @@ -0,0 +1,108 @@ +// MODIFY THIS FILE to use pthreads rather than IPC. Lines marked with +// **CHANGE** indicate lines that are higly likely to need alterations. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define N_PHILOSOPHERS 5 // Number of philosophers + +const int MEALS_TO_FINISH = 2; // Number of iterations before finish +const int MAX_DELAY = 50000; // Maximum delay in nanos between meal iterations + +pthread_mutex_t utensils[N_PHILOSOPHERS]; + +void *philosopher(void *n); +// **CHANGE** to have prototype compatible with thread entry points + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + int i, status; + pthread_t phil[N_PHILOSOPHERS]; + printf("The Dining Swansons (Philosophers) Problem\n"); + + // Parent thread only: + // + // Allocate utensils: mutexes + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_mutex_init(&utensils[i], NULL); + } + + // Parent generates child processes + int numbers[N_PHILOSOPHERS]; + for (i = 0; i < N_PHILOSOPHERS; i++) { + numbers[i] = i; // workaround for wrong numbers + status = pthread_create(&phil[i], NULL, &philosopher, &numbers[i]); + if (status) { + fprintf(stderr, "Could not create thread: %s\n", strerror(status)); + exit(1); + } + } + + // Parent waits on all children to finish + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_join(phil[i], NULL); + } + + printf("JJ: All Swansons finished, cleaning up the diner\n"); + + // Eliminate the utensils and table semaphores + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_mutex_destroy(&utensils[i]); + } + + return 0; +} + +// Code for dining philosopher child processes +void *philosopher(void *arg) { + int n = *(int *)arg; + int i, first, second; + srand(time(NULL)); // Seed random number generator + + // Avoid deadlock via slightly different order of utensil requests + // for last philospher + + // first utensil to get, most go for n first, last philospher goes for 0 + // first + first = (n != N_PHILOSOPHERS - 1) ? n : 0; + // second utensil to get, last philopher goes for n second + second = (n != N_PHILOSOPHERS - 1) ? n + 1 : n; + + printf("Swanson %d wants utensils %d and %d\n", n, first, second); + printf("Swanson %d at the table\n", n); + + // Main loop of thinking/eating cycles + for (i = 0; i < MEALS_TO_FINISH; i++) { + int sleep_time = rand() % MAX_DELAY; + usleep(sleep_time); // sleep for for a short time + + printf("%2d: Swanson %d is contemplating his awesomeness ...\n", i, n); + + // get first utensil + pthread_mutex_lock(&utensils[first]); + printf("%2d: Swanson %d got utensil %d\n", i, n, first); + + // get second utensil + pthread_mutex_lock(&utensils[second]); + printf("%2d: Swanson %d got utensil %d\n", i, n, second); + + printf("%2d: Swanson %d is eating an egg ...\n", i, n); + usleep(sleep_time); // sleep for for a short time + + // release first utensil + pthread_mutex_unlock(&utensils[first]); + + // release second utensil + pthread_mutex_unlock(&utensils[second]); + } + + printf("Swanson %d leaving the diner\n", n); + return NULL; +} diff --git a/lab10-code/philosophers_pthread.txt b/lab10-code/philosophers_pthread.txt new file mode 100644 index 0000000..8c2fc0b --- /dev/null +++ b/lab10-code/philosophers_pthread.txt @@ -0,0 +1,108 @@ +// MODIFY THIS FILE to use pthreads rather than IPC. Lines marked with +// **CHANGE** indicate lines that are higly likely to need alterations. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define N_PHILOSOPHERS 5 // Number of philosophers + +const int MEALS_TO_FINISH = 2; // Number of iterations before finish +const int MAX_DELAY = 50000; // Maximum delay in nanos between meal iterations + +pthread_mutex_t utensils[N_PHILOSOPHERS]; + +void *philosopher(void *n); +// **CHANGE** to have prototype compatible with thread entry points + +int main() { + setvbuf(stdout, NULL, _IONBF, 0); + int i, status; + pthread_t phil[N_PHILOSOPHERS]; + printf("The Dining Swansons (Philosophers) Problem\n"); + + // Parent thread only: + // + // Allocate utensils: mutexes + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_mutex_init(&utensils[i], NULL); + } + + // Parent generates child processes + int numbers[N_PHILOSOPHERS]; + for (i = 0; i < N_PHILOSOPHERS; i++) { + numbers[i] = i; // workaround for wrong numbers + status = pthread_create(&phil[i], NULL, &philosopher, &numbers[i]); + if (status) { + fprintf(stderr, "Could not create thread: %s\n", strerror(status)); + exit(1); + } + } + + // Parent waits on all children to finish + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_join(phil[i], NULL); + } + + printf("JJ: All Swansons finished, cleaning up the diner\n"); + + // Eliminate the utensils and table semaphores + for (i = 0; i < N_PHILOSOPHERS; i++) { + pthread_mutex_destroy(&utensils[i]); + } + + return 0; +} + +// Code for dining philosopher child processes +void *philosopher(void *arg) { + int n = *(int *)arg; + int i, first, second; + srand(time(NULL)); // Seed random number generator + + // Avoid deadlock via slightly different order of utensil requests + // for last philospher + + // first utensil to get, most go for n first, last philospher goes for 0 + // first + first = (n != N_PHILOSOPHERS - 1) ? n : 0; + // second utensil to get, last philopher goes for n second + second = (n != N_PHILOSOPHERS - 1) ? n + 1 : n; + + printf("Swanson %d wants utensils %d and %d\n", n, first, second); + printf("Swanson %d at the table\n", n); + + // Main loop of thinking/eating cycles + for (i = 0; i < MEALS_TO_FINISH; i++) { + int sleep_time = rand() % MAX_DELAY; + usleep(sleep_time); // sleep for for a short time + + printf("%2d: Swanson %d is contemplating his awesomeness ...\n", i, n); + + // get first utensil + pthread_mutex_lock(&utensils[first]); + printf("%2d: Swanson %d got utensil %d\n", i, n, first); + + // get second utensil + pthread_mutex_lock(&utensils[second]); + printf("%2d: Swanson %d got utensil %d\n", i, n, second); + + printf("%2d: Swanson %d is eating an egg ...\n", i, n); + usleep(sleep_time); // sleep for for a short time + + // release first utensil + pthread_mutex_unlock(&utensils[first]); + + // release second utensil + pthread_mutex_unlock(&utensils[second]); + } + + printf("Swanson %d leaving the diner\n", n); + return NULL; +} diff --git a/lab10-code/pthreads_picalc_mutex.c b/lab10-code/pthreads_picalc_mutex.c new file mode 100644 index 0000000..21f031a --- /dev/null +++ b/lab10-code/pthreads_picalc_mutex.c @@ -0,0 +1,60 @@ +// Working version of threaded picalc. Uses a mutex to lock the global +// variable total_hits so that one thread accesses it at a time. This +// version is inefficient due to the busy waiting and contention +// associated with mutex locking. + +#include +#include +#include + +// Global variables shared by all threads +int total_hits=0; +int points_per_thread = -1; +pthread_mutex_t lock; + +void *compute_pi(void *arg){ + long thread_id = (long) arg; + unsigned int rstate = 123456789 * thread_id; // give each thread its own starting point + for (int i = 0; i < points_per_thread; i++) { + double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + pthread_mutex_lock(&lock); // lock global variable + total_hits++; // update + pthread_mutex_unlock(&lock); // unlock global variable + } + } + return NULL; +} + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s [num_threads]\n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + printf(" num_threads: int, number of threads to use for the computation, default 4\n"); + return -1; + } + + int npoints = atoi(argv[1]); // number of samples + int num_threads = argc>2 ? atoi(argv[2]) : 4; // number of threads + + points_per_thread = npoints / num_threads; // init global variables + pthread_mutex_init(&lock, NULL); // create a lock + + pthread_t threads[num_threads]; // track each thread + + for(long p=0; p /tmp/$$prog.out; echo "-----"; done + for prog in $(PROGS); do wc -l /tmp/$$prog.out; done + +busy : odds_evens_busy.c odds_evens.h + $(CC) -o $@ $< $(LIBS) + +nested_if : odds_evens_busy_nested_if.c odds_evens.h + $(CC) -o $@ $< $(LIBS) + +condvar : odds_evens_condvar.c odds_evens.h + $(CC) -o $@ $< $(LIBS) + + + +clean : + rm -f $(PROGS) + diff --git a/lab11-code/QUESTIONS-10.txt b/lab11-code/QUESTIONS-10.txt new file mode 100644 index 0000000..3ba2d56 --- /dev/null +++ b/lab11-code/QUESTIONS-10.txt @@ -0,0 +1,131 @@ + __________________ + + LAB 11 QUESTIONS + __________________ + + +- Name: John Eidum +- NetID: eidum003 + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1: Condition Variables +============================== + + Examine the three files + - `odds_evens_busy.c' + - `odds_evens_busy_nested_if.c' + - `odds_evens_condvar.c' + Each of these was discussed in class and in a follow-up Piazza + post. Each implements a slight variation on the odd/even worker + problem discussed in class. + + The provided Makefile allows one to run part of the experiment + discussed on the Piazza post by entering + ,---- + | make experiment + `---- + + Describe the 3 different techniques used by each of these + implementations and the timing differences that you get in the + experiment results. Keep in mind that "work" is simulated by short + sleeps by threads so the real/wall timing has little meaning while the + user/sys times have more meaning. + + +YOUR ANSWERS HERE: + +Busy runs busy waiting which can be seen in its while(1) loop. Nested_if checks to see if count is even, locks the count_mutex, then checks if the count variable is even again. Condvar checks for if the count is even within the while loop statement. + +Busy: +User: 0.356s +Sys: 0.480s + +Nested_if: +User: 0.872s +Sys: 0.316s + +Condvar: +User: 0.092s +Sys: 0.340s + + +PROBLEM 2: Mutex Dangers +======================== + + A multi-threaded program has a number of worker threads which each + need to modify global data structures. They are as follows: + - A workers must modify global data X and Y + - B workers must modify global data Y and Z + + +A +~ + + In one protocol design, there are two mutexes + - M1 is associated with accessing data X and Y + - M2 is associated with accessing data Y and Z + That means that + - A workers would acquire M1 when modifying X and Y and release when + finished + - B workers would acquire M2 when modify Y and Z and release when + finished + + Describe a major flaw in this protocol. + + +YOUR ANSWERS HERE: +------------------ +Values will likely be off due to the mutexes working at the same time. Therefore, M1 and M2 may both be given the value Y at the same time and be told to increment the value. However, when M1 increments the value, M2 will not take this into account and the M1 increment will end up being ignored, causing values to be off. + + +B +~ + + In another protocol design, there are three mutexes + - MX is associated with accessing data X + - MY is associated with accessing data Y + - MZ is associated with accessing data Z + + The workers do the following + - A workers acquire MX then MY then modify global data X and Y then + release both mutexes + - B workers acquire MY then MZ then modify global data Y and Z then + release both mutexes + + Identify any problems you see this protocol such as deadlock or + starvation. Describe a major flaw in this protocol. + + +YOUR ANSWERS HERE: +------------------ +This would make Y lock up when either A or B are being used. This will cause significant delay due to the mutexes having to wait for one another to finish modifying every time. + + +C +~ + + A third protocol focuses on the A workers which modify global data X + and Y. The intended changes for X and Y are independent so a + potentially more efficient protocol is the following. + + "A" workers + 1. Atomically check MX and lock it if possible + - If MX is acquired, modify X + - Acquire MY, modify Y + - Release both MX and MY + 2. If MX is NOT available immediately + - Acquire MY, modify Y + - Acquire MX, modify X + - Release MX and MY + + This protocol has the potential for deadlock. Explain a sequence of + events that would lead to deadlock and suggest a change in the + protocol to fix the problem. + + +YOUR ANSWERS HERE: +------------------ +There could be two A workers, with both MX and MY initially available. They start at the same time, and the first worker sees that MX is available and locks it. The second worker sees that MX is not available, so it acquires MY and locks it. Now the first worker is waiting for MY to be unlocked before it releases MX, and the second worker is waiting for MX before it releases MY, causing a deadlock. You could have a lock hierarchy so that locks are always obtained in the same order, that way deadlocking won't occur. Can just ignore the second change. diff --git a/lab11-code/QUESTIONS.txt b/lab11-code/QUESTIONS.txt new file mode 100644 index 0000000..a853d61 --- /dev/null +++ b/lab11-code/QUESTIONS.txt @@ -0,0 +1,159 @@ + __________________ + + LAB 11 QUESTIONS + __________________ + + +- Name: (FILL THIS in) +- NetID: (THE kauf0095 IN kauf0095@umn.edu) + +Answer the questions below according to the lab specification. Write +your answers directly in this text file and submit it to complete Lab01. + + +PROBLEM 1: Condition Variables +============================== + + Examine the three files + - `odds_evens_busy.c' + - `odds_evens_busy_nested_if.c' + - `odds_evens_condvar.c' + Each of these was discussed in class and in a follow-up Piazza + post. Each implements a slight variation on the odd/even worker + problem discussed in class. + + The provided Makefile allows one to run part of the experiment + discussed on the Piazza post by entering + ,---- + | make experiment + `---- + + Describe the 3 different techniques used by each of these + implementations and the timing differences that you get in the + experiment results. Keep in mind that "work" is simulated by short + sleeps by threads so the real/wall timing has little meaning while the + user/sys times have more meaning. + +Output: + +for prog in busy nested_if condvar ; do echo "time $prog:"; time ./$prog > /tmp/$prog.out; echo "-----"; done +time busy: +1.07user 0.91system 0:03.26elapsed 60%CPU (0avgtext+0avgdata 1584maxresident)k +0inputs+3528outputs (0major+82minor)pagefaults 0swaps +----- +time nested_if: +3.50user 0.27system 0:04.15elapsed 90%CPU (0avgtext+0avgdata 1624maxresident)k +0inputs+3528outputs (0major+83minor)pagefaults 0swaps +----- +time condvar: +0.22user 1.11system 0:02.85elapsed 46%CPU (0avgtext+0avgdata 1588maxresident)k +0inputs+3528outputs (0major+84minor)pagefaults 0swaps +----- +for prog in busy nested_if condvar ; do wc -l /tmp/$prog.out; done +40005 /tmp/busy.out +40005 /tmp/nested_if.out +40005 /tmp/condvar.out + +The "busy" implementation uses a while loop to check for when the mutex is +available. + +The "nested_if" implementation simply waits until it has a chance to get the +mutex, and then checks if it's even. Otherwise, it just releases it without +doing anything. (potentially skipping certain iterations?) + +The "condvar" implementation uses pthread_cond_wait to wait until the count is +even and then performs update. + + +YOUR ANSWERS HERE: +------------------ + + +PROBLEM 2: Mutex Dangers +======================== + + A multi-threaded program has a number of worker threads which each + need to modify global data structures. They are as follows: + - A workers must modify global data X and Y + - B workers must modify global data Y and Z + + +A +~ + + In one protocol design, there are two mutexes + - M1 is associated with accessing data X and Y + - M2 is associated with accessing data Y and Z + That means that + - A workers would acquire M1 when modifying X and Y and release when + finished + - B workers would acquire M2 when modify Y and Z and release when + finished + + Describe a major flaw in this protocol. + + +YOUR ANSWERS HERE: +------------------ + +B workers can't acquire lock M1, so when they're trying to access Y, they simply +have to acquire lock M2. At the same time, A workers might have lock M1, so +there could be a write race ending up with the wrong value. + +B +~ + + In another protocol design, there are three mutexes + - MX is associated with accessing data X + - MY is associated with accessing data Y + - MZ is associated with accessing data Z + + The workers do the following + - A workers acquire MX then MY then modify global data X and Y then + release both mutexes + - B workers acquire MY then MZ then modify global data Y and Z then + release both mutexes + + Identify any problems you see this protocol such as deadlock or + starvation. Describe a major flaw in this protocol. + + +YOUR ANSWERS HERE: +------------------ + +The key is in the fact that the workers have to acquire the locks in some order. +B workers can't acquire the MZ lock until they acquire MY, which might be held +by A workers. Therefore, resource Z is being unnecessarily stalled. + +C +~ + + A third protocol focuses on the A workers which modify global data X + and Y. The intended changes for X and Y are independent so a + potentially more efficient protocol is the following. + + "A" workers + 1. Atomically check MX and lock it if possible + - If MX is acquired, modify X + - Acquire MY, modify Y + - Release both MX and MY + 2. If MX is NOT available immediately + - Acquire MY, modify Y + - Acquire MX, modify X + - Release MX and MY + + This protocol has the potential for deadlock. Explain a sequence of + events that would lead to deadlock and suggest a change in the + protocol to fix the problem. + + +YOUR ANSWERS HERE: +------------------ + +The problem is that a worker must try to acquire both locks at the same time. If +one worker has lock MX and another worker has lock MY, then neither of them +would give up the lock until they have both. Conversely, neither of them would +be able to acquire the other lock since it's already possessed. One way to fix +this problem is to not require them to acquire both locks at the same time, or +to specify that lock MX must be acquired before acquiring lock MY to keep +lockless workers from touching MY. diff --git a/lab11-code/busy b/lab11-code/busy new file mode 100755 index 0000000..4d6304e Binary files /dev/null and b/lab11-code/busy differ diff --git a/lab11-code/condvar b/lab11-code/condvar new file mode 100755 index 0000000..8ab15ff Binary files /dev/null and b/lab11-code/condvar differ diff --git a/lab11-code/nested_if b/lab11-code/nested_if new file mode 100755 index 0000000..6ab768b Binary files /dev/null and b/lab11-code/nested_if differ diff --git a/lab11-code/odds_evens.h b/lab11-code/odds_evens.h new file mode 100644 index 0000000..8151833 --- /dev/null +++ b/lab11-code/odds_evens.h @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +#define NUM_THREADS 2 // number of odd/evens threads +#define TOT_THREADS (2*NUM_THREADS) // total threads + +#ifndef THREAD_ITERS +#define THREAD_ITERS 5 // total iterations each thread will add on +#endif + +#ifndef VPRINTF +#define VPRINTF printf +#endif +void ignore(char *s, int i, int j, int k){} // ignore requests to print + +#ifndef SLEEPFUN +#define SLEEPFUN usleep(1) +#endif + +void update(int *x){ + *x = *x+1; + SLEEPFUN; // simulate some "work" done while locked +} diff --git a/lab11-code/odds_evens_busy.c b/lab11-code/odds_evens_busy.c new file mode 100644 index 0000000..773bf17 --- /dev/null +++ b/lab11-code/odds_evens_busy.c @@ -0,0 +1,72 @@ +// odd/even thread coordination on incrementing an global +// variable. This version involves busy waiting on the odd/even +// condition by locking the single mutex every time, checking, and +// releasing if oddness/evenness is not appropriate. +#include "odds_evens.h" + +int count = 0; // global variable all threads are modifiying +pthread_mutex_t count_mutex; // mutex to check count + +// Run by even child threads, increment count when it is even +void *even_work(void *t) { + int tid = *( (int *) t); + for(int i=0; i ./specific_stock stocks-10.dat 17 + | Off end of file + `---- + + Describe the technique and additional system call that is used to + accomplish this. Mention how the return value of `lseek()' is used. + +It uses fstat, which gets the size of the file, and makes sure that the position +it's planning to jump to (which was obtained from the return value of lseek) is +less than the size of the file. Otherwise, it'll print "Off end of file" and +exit. + +C +~ + + Examine the manual page for `lseek()'. Suggest how one might + accomplish the following tasks. + - Move the position of a file descriptor to the end of a file so that + subsequent writes append to the file + - Immediately read the last stock in a binary stock file + Both of these may be useful in a project. + +(1) You could lseek(fd, 0, SEEK_END), which automatically seeks directly to the +end of the file (+0 bytes, which is the offset) + +(2) ASSUMING the only data in this file is stock data, you could seek to the end +of the file minus the size of the stock struct. This would effectively seek to +the last stock in the file. lseek(fd, -sizeof(stock_t), SEEK_END) diff --git a/lab12-code/bin2text b/lab12-code/bin2text new file mode 100755 index 0000000..43de2ca Binary files /dev/null and b/lab12-code/bin2text differ diff --git a/lab12-code/bin2text.c b/lab12-code/bin2text.c new file mode 100644 index 0000000..8e1211a --- /dev/null +++ b/lab12-code/bin2text.c @@ -0,0 +1,29 @@ +// Read a binary stock file and print its contents as text + +#include "header.h" + +int main(int argc, char *argv[]){ + if(argc < 2){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + int in_fd = open(argv[1], O_RDONLY); + FILE *out_file = stdout; // write to standard output + fprintf(out_file,"%s\n",STOCK_HEADER); // print header as first line + int stock_num = 0; // tracks which stock index + while(1){ + stock_num++; + stock_t stock = {}; + int nbytes = read(in_fd, &stock, sizeof(stock_t)); // read one stock in binary format + if(nbytes == 0){ // check for end of input + break; + } + char line[MAXLINE]; + stock2str(&stock, line, MAXLINE); // format and print text versions of the stock + fprintf(out_file,"%s\n", line); + } + + close(in_fd); + return 0; +} diff --git a/lab12-code/bin2text.o b/lab12-code/bin2text.o new file mode 100644 index 0000000..a264924 Binary files /dev/null and b/lab12-code/bin2text.o differ diff --git a/lab12-code/header.h b/lab12-code/header.h new file mode 100644 index 0000000..9a73d74 --- /dev/null +++ b/lab12-code/header.h @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLINE 4096 // max length of lines + +// stock structure +typedef struct { + char symbol[16]; // ticker symbol like GOOG + double open; // price at market open + double close; // price at market close + long volume; // quantity of shares exchanged during day + char name[128]; // name of company +} stock_t; + +// header for text-based stock files +const char *STOCK_HEADER = "Symbol Open Close Volume Name"; + +#define MAX_FIELDS 16 // maximum number of fields allowed in parse_into_tokens() + +// The following function should really be in their own C file but it +// is sufficient to include them in the header for this small lab example. + +// Parse the contents of input_command so that tokens[i] will point to +// the ith space-separated string in it. Set ntok to the number of +// tokens that are found. +void parse_into_tokens(char input_command[], char *tokens[], int *ntok, char *seps){ + int i = 0; + char *tok = strtok(input_command,seps); + while(tok!=NULL && i=0 && str[idx]==' '){ + str[idx] = '\0'; + idx--; + } + return idx+1; +} + +// The string buf contains a text representation of a stock which +// should be parsed to fill the fields of argument stock with its +// fields. line_num may refer to a line number from a file to help +// diagnose bugs. Assumes that stock fields are separated by TABs in +// the string buf. +void str2stock(char buf[], stock_t *stock, int line_num){ + char *fields[MAX_FIELDS]; + int nfields = -1; + parse_into_tokens(buf, fields, &nfields,"\t\n"); // parse based on tab separator + + strcpy(stock->symbol,fields[0]); // char symbol[16]; // ticker symbol like GOOG + sscanf(fields[1], "%lf", &(stock->open)); // double open; // price at market open + sscanf(fields[2], "%lf", &(stock->close)); // double close; // price at market close + sscanf(fields[3], "%ld", &(stock->volume)); // long volume; // quantity of shares exchanged during day + strcpy(stock->name,fields[4]); // char name[128]; // name of company + + trim(stock->symbol); // get rid of whitespace at the end of + trim(stock->name); // the string fields +} + +// Format the fields of stock to create a string representation of it +// in buf. Separate each field with a TAB character. Respects maximum +// size buf_max and will not overflow it. Returns a pointer to buf so +// it can be used in one-liners like +// +// fprintf(out_file,"%s\n", stock2str(&stock, line, MAX_LINE)) +char *stock2str(stock_t *stock, char buf[], int buf_max){ + int off = 0; + off += snprintf(buf+off, buf_max-off, "%s\t",stock->symbol); // char symbol[16]; // ticker symbol like GOOG + off += snprintf(buf+off, buf_max-off, "%.2f\t",stock->open); // double open; // price at market open + off += snprintf(buf+off, buf_max-off, "%.2f\t",stock->close); // double close; // price at market close + off += snprintf(buf+off, buf_max-off, "%ld\t",stock->volume); // long volume; // quantity of shares exchanged during day + off += snprintf(buf+off, buf_max-off, "%s\t",stock->name); // char name[128]; // name of company + buf[off-1]='\0'; + return buf; +} diff --git a/lab12-code/specific_stock b/lab12-code/specific_stock new file mode 100755 index 0000000..d13bff4 Binary files /dev/null and b/lab12-code/specific_stock differ diff --git a/lab12-code/specific_stock.c b/lab12-code/specific_stock.c new file mode 100644 index 0000000..ec41d6b --- /dev/null +++ b/lab12-code/specific_stock.c @@ -0,0 +1,31 @@ +// Print the symbol of a specific stock that is in a binary file. + +#include "header.h" + +int main(int argc, char *argv[]){ + if(argc < 3){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + int in_fd = open(argv[1], O_RDONLY); + int stock_num = atoi(argv[2]); // index of stock to retrieve + FILE *out_file = stdout; // write to standard output + struct stat stat_buf; + + int offset = stock_num * sizeof(stock_t); // calculate offset into file + off_t pos = lseek(in_fd, offset, SEEK_SET); // jump to that location + fstat(in_fd, &stat_buf); // get stats on the open file such as size + if(pos > stat_buf.st_size){ // check for out of bounds + fprintf(out_file,"Off end of file\n"); + } + else{ + stock_t stock = {}; + read(in_fd, &stock, sizeof(stock_t)); // read one stock in binary format + fprintf(out_file,"Stock %d has symbol %s\n", + stock_num,stock.symbol); + } + + close(in_fd); + return 0; +} diff --git a/lab12-code/specific_stock.o b/lab12-code/specific_stock.o new file mode 100644 index 0000000..5626f26 Binary files /dev/null and b/lab12-code/specific_stock.o differ diff --git a/lab12-code/stocks-10.dat b/lab12-code/stocks-10.dat new file mode 100644 index 0000000..4ab671e Binary files /dev/null and b/lab12-code/stocks-10.dat differ diff --git a/lab12-code/stocks-10.txt b/lab12-code/stocks-10.txt new file mode 100644 index 0000000..10bf54a --- /dev/null +++ b/lab12-code/stocks-10.txt @@ -0,0 +1,11 @@ +Symbol Open Low Volume Name +NEA 13.79 13.77 304100 Nuveen AMT-Free Quality Municipal Income Fund +NEE 151.5 151.03 1291000 NextEra Energy, Inc. +NEM 37.72 37.55 3923700 Newmont Mining Corporation +NEP 43.09 41 553600 NextEra Energy Partners, LP +DNB 120.38 119.54 217100 Dun & Bradstreet Corporation (The) +NEU 429.3 425.86 17000 NewMarket Corporation +NEV 14.71 14.64 41000 Nuveen Enhanced Municipal Value Fund +DWDP 70.8 70.53 5606700 DowDuPont Inc. +DNI 13.1 13.05 13600 Dividend and Income Fund +DNP 11.45 11.39 202000 Duff & Phelps Utilities Income, Inc. diff --git a/lab12-code/stocks-2620.dat b/lab12-code/stocks-2620.dat new file mode 100644 index 0000000..100e0a0 Binary files /dev/null and b/lab12-code/stocks-2620.dat differ diff --git a/lab12-code/stocks-2620.txt b/lab12-code/stocks-2620.txt new file mode 100644 index 0000000..80c7f40 --- /dev/null +++ b/lab12-code/stocks-2620.txt @@ -0,0 +1,2621 @@ +Symbol Open Low Volume Name +NEA 13.79 13.77 304100 Nuveen AMT-Free Quality Municipal Income Fund +NEE 151.5 151.03 1291000 NextEra Energy, Inc. +NEM 37.72 37.55 3923700 Newmont Mining Corporation +NEP 43.09 41 553600 NextEra Energy Partners, LP +DNB 120.38 119.54 217100 Dun & Bradstreet Corporation (The) +NEU 429.3 425.86 17000 NewMarket Corporation +NEV 14.71 14.64 41000 Nuveen Enhanced Municipal Value Fund +DWDP 70.8 70.53 5606700 DowDuPont Inc. +DNI 13.1 13.05 13600 Dividend and Income Fund +DNP 11.45 11.39 202000 Duff & Phelps Utilities Income, Inc. +DNR 1.16 1.09 6693200 Denbury Resources Inc. +CTBB 25.33 25.3 59700 Qwest Corporation +SAH 20.25 20.15 229300 Sonic Automotive, Inc. +SAM 176.15 174.95 381200 Boston Beer Company, Inc. (The) +SAN 6.59 6.55 3392100 Banco Santander, S.A. +SAP 111.12 110.86 328400 SAP SE +SAR 22.33 22.15 24200 Saratoga Investment Corp +A 66.68 65.99 1711800 Agilent Technologies, Inc. +B 72.27 71.69 153400 Barnes Group, Inc. +C 72.24 72 15743700 Citigroup Inc. +D 79.03 78.24 1955400 Dominion Energy, Inc. +E 32.91 32.63 89400 ENI S.p.A. +F 12.13 12.12 55273200 Ford Motor Company +G 29.61 29.5 812600 Genpact Limited +VVC 66.75 66.7 212500 Vectren Corporation +H 61.61 61.16 337000 Hyatt Hotels Corporation +I 6.29 6.15 505400 Intelsat S.A. +K 61.87 61.59 2032200 Kellogg Company +L 49.07 48.515 550000 Loews Corporation +M 19.88 19.68 8497300 Macy's Inc +VVI 61.1 60.45 57500 Viad Corp +NFG 56.44 56.44 391600 National Fuel Gas Company +O 56.81 56.71 1258000 Realty Income Corporation +P 7.9 7.88 3408600 Pandora Media, Inc. +Q 99.26 99.065 1137500 Quintiles IMS Holdings, Inc. +NFJ 13.41 13.36 171700 AllianzGI NFJ Dividend, Interest & Premium Strategy Fund +R 79.45 78.68 806900 Ryder System, Inc. +S 7.14 7.055 10231000 Sprint Corporation +T 36.18 35.99 21663500 AT&T Inc. +V 108.25 107.3 5979400 Visa Inc. +VVR 4.44 4.43 476600 Invesco Senior Income Trust +W 69.55 67.46 1736100 Wayfair Inc. +X 26.68 26.49 7673700 United States Steel Corporation +Y 552.66 551 63600 Alleghany Corporation +DOC 17.97 17.95 636000 Physicians Realty Trust +VVV 24 23.89 402400 Valvoline Inc. +BGIO 10.15 10.11 73900 BlackRock 2022 Global Income Opportunity Trust +NFX 30.11 29.555 2645100 Newfield Exploration Company +SBH 17.67 17.59 1762500 Sally Beauty Holdings, Inc. +DOV 94.62 93.9 791500 Dover Corporation +SBR 40.55 40.32 10900 Sabine Royalty Trust +SBS 10 9.74 2351700 Companhia de saneamento Basico Do Estado De Sao Paulo - Sabesp +GSBD 22.54 22.38 118300 Goldman Sachs BDC, Inc. +GDOT 54.13 53.7 192000 Green Dot Corporation +NGG 62 61.79 518500 National Grid Transco, PLC +NGL 11.75 11.3 508600 NGL ENERGY PARTNERS LP +NGS 28.45 28.1 10100 Natural Gas Services Group, Inc. +DPG 16.15 15.99 142400 Duff & Phelps Global Utility Income Fund Inc. +SCA 25.39 25.38 1800 Stellus Capital Investment Corporation +SCD 14.48 14.46 30200 LMP Capital and Income Fund Inc. +DPS 89.44 88.95 679900 Dr Pepper Snapple Group, Inc +SCG 48.78 48.06 1700700 Scana Corporation +CEQP 24.15 23.75 141900 Crestwood Equity Partners LP +SCI 34.26 34.2 758400 Service Corporation International +CTDD 25.53 25.52 78100 Qwest Corporation +TNET 34.18 33.54 175400 TriNet Group, Inc. +SCL 88.34 87.325 53300 Stepan Company +DPZ 193.5 191.83 1316900 Domino's Pizza Inc +SCM 14.15 14 104400 Stellus Capital Investment Corporation +SCS 15.4 15.1 388300 Steelcase Inc. +SCX 8.8 8.5 7700 L.S. Starrett Company (The) +NHA 10.02 10 3400 Nuveen Municipal 2021 Target Term Fund +NHF 23.54 23.54 101000 NexPoint credit Strategies Fund +NHI 77.43 76.955 117100 National Health Investors, Inc. +MITT 19.5 19.5 95700 AG Mortgage Investment Trust, Inc. +SALT 7.7 7.5 530200 Scorpio Bulkers Inc. +TDOC 32.6 32.6 1027000 Teladoc, Inc. +SDR 1.33 1.33 99800 SandRidge Mississippian Trust II +SDT 1.31 1.31 46400 SandRidge Mississippian Trust I +SSTK 33.89 33.72 172900 Shutterstock, Inc. +NID 13.33 13.29 38000 Nuveen Intermediate Duration Municipal Term Fund +NIE 20.64 20.6 79800 AllianzGI Equity & Convertible Income Fund +GIMO 36 35.35 856800 Gigamon Inc. +NIM 10.3 10.22 21800 Nuveen Select Maturities Municipal Fund +NIQ 13.37 13.33 16900 Nuveenn Intermediate Duration Quality Municipal Term Fund +DRD 3.62 3.48 134300 DRDGOLD Limited +DRE 28.91 28.77 1654500 Duke Realty Corporation +DRH 11 10.94 1350600 Diamondrock Hospitality Company +DRI 79.08 78.865 2245500 Darden Restaurants, Inc. +DRQ 43.05 42.1 425000 Dril-Quip, Inc. +SEE 44.49 44.105 2045400 Sealed Air Corporation +SEM 18.35 18.1 1377800 Select Medical Holdings Corporation +SEP 43.72 43.65 307400 Spectra Energy Partners, LP +INB 9.7 9.65 78300 Cohen & Steers Global Income Builder, Inc. +INF 13.2 13.2 202400 Brookfield Global Listed Infrastructure Income Fund +ING 18.36 18.32 2873300 ING Group, N.V. +INN 16.12 15.905 773900 Summit Hotel Properties, Inc. +INT 35.46 35.03 307700 World Fuel Services Corporation +VZA 26.93 26.93 28700 Verizon Communications Inc. +NJR 42.9 42.9 260400 NewJersey Resources Corporation +DSE 6.31 6.18 151500 Duff & Phelps Select Energy MLP Fund Inc. +NJV 14.9 14.87 2700 Nuveen New Jersey Municipal Value Fund +DSL 21.3 21.22 206200 DoubleLine Income Solutions Fund +DSM 8.53 8.53 85500 Dreyfus Strategic Municipal Bond Fund, Inc. +SFE 14.15 14.05 27300 Safeguard Scientifics, Inc. +DST 55.49 54.44 744300 DST Systems, Inc. +DSU 11.8 11.75 55500 Blackrock Debt Strategies Fund, Inc. +DSW 18.81 18.68 1561400 DSW Inc. +DSX 4.06 3.99 619200 Diana Shipping inc. +SFL 14.95 14.85 852400 Ship Finance International Limited +SFR 36.25 36.23 547900 Starwood Waypoint Homes +SFS 6.7 6.55 303000 Smart +TIME 12.75 12.2 960000 Time Inc. +NKE 51.5 51.38 9492600 Nike, Inc. +NKG 13.2 13.16 3300 Nuveen Georgia Quality Municipal Income Fund +DTE 109.63 109.33 1095900 DTE Energy Company +DTF 14.25 14.25 13400 Duff & Phelps Utilities Tax-Free Income, Inc. +MFCB 9.31 9.3 3800 MFC Bancorp Ltd. +NKX 15.79 15.79 55800 Nuveen California AMT-Free Quality Municipal Income Fund +DTJ 25.6 25.6 16100 DTE Energy Company +DTK 25.95 25.95 140300 Deutsche Bank AG +DTQ 25.11 25.05 9400 DTE Energy Company +SGF 12.35 12.35 8000 Aberdeen Singapore Fund, Inc. +DECK 64.95 64.93 610400 Deckers Outdoor Corporation +DTV 55.09 54.8 58300 DTE Energy Company +DTY 27.11 27.07 9400 DTE Energy Company +SGU 11.08 11.08 26700 Star Gas Partners, L.P. +IPG 21.21 20.99 13540600 Interpublic Group of Companies, Inc. (The) +IPI 4.06 3.825 1098700 Intrepid Potash, Inc +SGY 28.63 27.97 84100 Stone Energy Corporation +KREF 21.47 21.3 13000 KKR Real Estate Finance Trust Inc. +SSWN 25.49 25.31 7500 Seaspan Corporation +XCO 1.21 1.21 175000 EXCO Resources NL +MIXT 10.05 9.81 113200 MiX Telematics Limited +DUC 9.16 9.09 73600 Duff & Phelps Utility & Corporate Bond Trust, Inc. +NLS 16.9 16.75 60400 Nautilus Group, Inc. (The) +NLY 12.3 12.27 7031800 Annaly Capital Management Inc +DUK 86.99 86.78 2355500 Duke Energy Corporation +JELD 35.64 35.27 196500 JELD-WEN Holding, Inc. +NVRO 90.47 89.77 145600 Nevro Corp. +GEF.B 64 62.025 7500 Greif Bros. Corporation +EURN 8.6 8.5 379400 Euronav NV +SHG 43.79 43.54 48700 Shinhan Financial Group Co Ltd +SHI 62.56 61.92 10200 SINOPEC Shangai Petrochemical Company, Ltd. +SHO 16.68 16.61 1717200 Sunstone Hotel Investors, Inc. +AAC 7.97 7.83 105800 AAC Holdings, Inc. +SHW 384.56 381.42 519000 Sherwin-Williams Company (The) +IQI 12.67 12.61 75900 Invesco Quality Municipal Income Trust +RMAX 66.1 65.95 67500 RE/MAX Holdings, Inc. +CRD.A 9.9 9.64 3900 Crawford & Company +CRD.B 12.06 11.795 13700 Crawford & Company +AAN 41.73 41.48 342400 Aaron's, Inc. +AAP 86.38 86.2 2100200 Advance Auto Parts Inc +AAT 40.46 40.36 123900 American Assets Trust, Inc. +AAV 5.45 5.4 51700 Advantage Oil & Gas Ltd +MAIN 40.25 39.93 167900 Main Street Capital Corporation +NMI 11.6 11.59 17100 Nuveen Municipal Income Fund, Inc. +NMM 2.1 2.09 259200 Navios Maritime Partners LP +DVA 56.87 56.445 2239600 DaVita Inc. +NMR 5.85 5.79 112500 Nomura Holdings Inc ADR +NMS 15.47 15.29 12400 Nuveen Minnesota Quality Municipal Income Fund +DVD 2 1.975 16200 Dover Motorsports, Inc. +NMT 14.46 14.46 2500 Nuveen Massachusetts Municipal Income Fund +NMY 12.86 12.84 23100 Nuveen Maryland Quality Municipal Income Fund +NMZ 13.67 13.65 100700 Nuveen Municipal High Income Opportunity Fund +JEMD 10.025 10 13300 Nuveen Emerging Markets Debt 2022 Target Term Fund +DVN 35.86 35.185 3160700 Devon Energy Corporation +SID 3.12 3.04 1915100 National Steel Company +ANDV 104.31 103.97 1013200 Andeavor +SIG 60.75 60.75 1061900 Signet Jewelers Limited +ANDX 47.42 47.18 219900 Andeavor Logistics LP +ABB 24.94 24.9 974700 ABB Ltd +ABC 78.89 78.4 1043900 AmerisourceBergen Corporation (Holding Co) +SIX 61.11 59.61 2217900 Six Flags Entertainment Corporation New +ABG 56.85 56.5 171400 Asbury Automotive Group Inc +IRL 13.81 13.55 15700 New Ireland Fund, Inc. (The) +IRM 39.78 39.6 998600 Iron Mountain Incorporated +XEC 115.94 115.25 608900 Cimarex Energy Co +ABM 42.81 42.36 167100 ABM Industries Incorporated +IRR 6.34 6.3 79300 Voya Natural Resources Equity Income Fund +IRS 25.05 24.93 48700 IRSA Inversiones Y Representaciones S.A. +IRT 10.39 10.315 499400 Independence Realty Trust, Inc. +ABR 8.35 8.35 516300 Arbor Realty Trust +ABT 54.59 54.4 5432900 Abbott Laboratories +XEL 48.58 48.37 2808200 Xcel Energy Inc. +ABX 16.14 16.02 7918900 Barrick Gold Corporation +NNA 1.27 1.23 338800 Navios Maritime Acquisition Corporation +NNC 13.32 13.27 14200 Nuveen North Carolina Quality Municipal Income Fd +NNI 51.5 51.11 41200 Nelnet, Inc. +NNN 42.31 42.3 531100 National Retail Properties +NVTA 9.78 9.78 602600 Invitae Corporation +NNY 10.4 10.34 5100 Nuveen New York Municipal Value Fund, Inc. +ANET 188.86 188.86 355100 Arista Networks, Inc. +SJI 32.29 32.04 1348000 South Jersey Industries, Inc. +SJM 105.51 103.63 1171600 J.M. Smucker Company (The) +LKSD 16.01 16 117100 LSC Communications, Inc. +SJR 22 21.91 443300 Shaw Communications Inc. +ADNT 84.45 84.45 472700 Adient plc +ISD 15.15 15.1 107700 Prudential Short Duration High Yield Fund, Inc. +SJT 8.04 7.93 168100 San Juan Basin Royalty Trust +ACC 44 43.46 1468700 American Campus Communities Inc +ISF 25.57 25.56 40600 ING Group, N.V. +BBVA 8.53 8.475 1340300 Banco Bilbao Viscaya Argentaria S.A. +ISG 25.61 25.61 32500 ING Group, N.V. +SJW 62.72 62.46 70100 SJW Group +ACH 22.37 22.345 84100 Aluminum Corporation of China Limited +ACM 35.75 35.6 370900 AECOM +ACN 138.91 138.28 1446700 Accenture plc +ACP 14.75 14.68 58300 Avenue Income Credit Strategies Fund +ACV 22.14 21.95 29700 AllianzGI Diversified Income & Convertible Fund +EHIC 11.33 10.95 93200 eHi Car Services Limited +NOA 4.17 4.05 41700 North American Energy Partners, Inc. +NOC 295.5 293.74 585000 Northrop Grumman Corporation +NOK 5.85 5.82 6370900 Nokia Corporation +DXB 25.5 25.49 49800 Deutsche Bank AG +DXC 91.39 91.17 2411400 DXC Technology Company +ANFI 5.96 5.93 116200 Amira Nature Foods Ltd +NOV 34.94 34.29 3477800 National Oilwell Varco, Inc. +NOW 121.54 121 1084200 ServiceNow, Inc. +VTRB 25.33 25.32 2400 Ventas Realty, Limited Partnership // Ventas Capital Corporati +MFGP 32.5 32 692700 Micro Focus Intl PLC +SKM 26.4 25.9 770000 SK Telecom Co., Ltd. +EMES 7.42 7.13 258000 Emerge Energy Services LP +SKT 24.85 24.85 652500 Tanger Factory Outlet Centers, Inc. +ADC 49.81 49.22 120600 Agree Realty Corporation +ITG 23.6 23.29 156800 Investment Technology Group, Inc. +SKX 24.28 24.28 2259100 Skechers U.S.A., Inc. +CTLT 41.95 41.49 414400 Catalent, Inc. +ADM 43.62 43.4 1271900 Archer-Daniels-Midland Company +ITT 46.71 46.43 501200 ITT Inc. +ADS 228.75 226.52 411400 Alliance Data Systems Corporation +ITW 153.04 152.65 725900 Illinois Tool Works Inc. +ADX 15.47 15.45 88600 Adams Diversified Equity Fund, Inc. +NPK 110.3 109.15 11800 National Presto Industries, Inc. +SPGI 162.76 161.14 857800 S&P Global Inc. +NPN 15.5 15.5 700 Nuveen Pennsylvania Municipal Value Fund +NPO 80.47 78.9 170800 EnPro Industries +NPV 13.25 13.18 33100 Nuveen Virginia Quality Municipal Income Fund +DYN 9.56 9.29 4690900 Dynegy Inc. +SLB 66.88 66.26 6621400 Schlumberger N.V. +SLD 16 15.75 34300 Sutherland Asset Management Corporation +SLF 39.43 39.23 263600 Sun Life Financial Inc. +ITUB 13.97 13.8 6833800 Itau Unibanco Banco Holding SA +SLG 102.81 101.94 923100 SL Green Realty Corporation +AEB 24.53 24.51 26200 Aegon NV +AED 26.33 26.14 210200 Aegon NV +AEE 60.42 60.42 1130300 Ameren Corporation +AEG 5.77 5.76 2307100 Aegon NV +AEH 25.88 25.83 277100 Aegon NV +AEK 26.37 26.37 20300 Aegon NV +AEL 30.17 29.74 212700 American Equity Investment Life Holding Company +AEM 45.07 44.645 1013500 Agnico Eagle Mines Limited +AEO 12.9 12.69 2755700 American Eagle Outfitters, Inc. +AEP 72.84 72.52 1721900 American Electric Power Company, Inc. +AER 52.59 52.35 691200 Aercap Holdings N.V. +AES 11.24 11.18 3623600 The AES Corporation +AET 150.79 150.79 1922700 Aetna Inc. +TISI 12.25 11.9 378100 Team, Inc. +XHR 22.01 21.65 510800 Xenia Hotels & Resorts, Inc. +FAC 1.05 1.05 100 First Acceptance Corporation +FAF 50.72 49.91 822700 First American Corporation (The) +NQP 13.65 13.63 25000 Nuveen Pennsylvania Quality Municipal Income Fund +FAM 11.73 11.67 50300 First Trust/Aberdeen Global Opportunity Income Fund +CORR 36.44 35.83 64200 CorEnergy Infrastructure Trust, Inc. +SMG 100 98.97 233600 Scotts Miracle-Gro Company (The) +SMI 6.49 6.36 691300 Semiconductor Manufacturing International Corporation +SMM 11.28 11.17 67800 Salient Midstream & MLP Fund +SMP 47.15 46.91 45500 Standard Motor Products, Inc. +IVC 14.5 14.4 354500 Invacare Corporation +AFB 13.85 13.82 48200 Alliance National Municipal Income Fund Inc +AFC 25.74 25.665 15000 Ares Capital Corporation +DRUA 25.66 25.59 45600 Dominion Energy, Inc. +IVH 15.95 15.77 54500 Ivy High Income Opportunities Fund +AFG 104.71 104.02 260000 American Financial Group, Inc. +AFI 15.83 15.57 58100 Armstrong Flooring, Inc. +AFL 84.16 83.45 906800 Aflac Incorporated +IVR 17.67 17.67 346300 INVESCO MORTGAGE CAPITAL INC +AFT 16.81 16.73 46400 Apollo Senior Floating Rate Fund Inc. +IVZ 36.34 36.025 1979400 Invesco Plc +XIN 5.78 5.62 178500 Xinyuan Real Estate Co Ltd +NRE 13.77 13.7 72500 NorthStar Realty Europe Corp. +FBC 35.76 35.47 55300 Flagstar Bancorp, Inc. +VOYA 40 39.36 1750300 Voya Financial, Inc. +NRG 26.55 25.91 6414200 NRG Energy, Inc. +NRK 13.11 13.11 165200 Nuveen New York AMT-Free Quality Municipal +MANU 18.2 18.15 14800 Manchester United Ltd. +FBK 37.95 37.64 34100 FB Financial Corporation +NRP 25.95 25.65 8500 Natural Resource Partners LP +FBM 13.59 13.31 150600 Foundation Building Materials, Inc. +FBP 4.85 4.73 1692800 First BanCorp. +NRT 6.81 6.5 27400 North European Oil Royality Trust +GNRC 50.95 50.1 808000 Generac Holdlings Inc. +FBR 16.75 16.17 1869800 Fibria Celulose S.A. +KMPA 26.94 26.81 10900 Kemper Corporation +NRZ 17.17 17.11 1299700 New Residential Investment Corp. +SNA 151.92 151.46 478700 Snap-On Incorporated +SNE 37.07 36.83 562000 Sony Corp Ord +YUMC 42.5 42.43 1974600 Yum China Holdings, Inc. +YUME 4.41 4.41 92800 YuMe, Inc. +GNRT 4.95 4.89 184500 Gener8 Maritime, Inc. +KMPR 58.85 57.65 109400 Kemper Corporation +SNN 37.55 37.48 1463400 Smith & Nephew SNATS, Inc. +SNP 74.93 74.46 92100 China Petroleum & Chemical Corporation +SNR 8.83 8.81 627100 New Senior Investment Group Inc. +AGC 6.24 6.22 74000 Advent Claymore Convertible Securities and Income Fund II +SNV 45.5 44.98 1385600 Synovus Financial Corp. +AGD 10.87 10.84 43100 Alpine Global Dynamic Dividend Fund +SNX 132.41 130.95 145600 Synnex Corporation +TSLF 17.34 17.28 21000 THL Credit Senior Loan Fund +SNY 49.4 49.21 447200 Sanofi +AGI 6.92 6.89 1569200 Alamos Gold Inc. +AGM 76.4 74.265 38500 Federal Agricultural Mortgage Corporation +AGN 199.01 197.3 5097500 Allergan plc. +AGO 37.32 36.99 884100 Assured Guaranty Ltd. +AGR 47.79 47.63 318700 Avangrid, Inc. +LGF.A 30.49 30.23 323400 Lions Gate Entertainment Corporation +AGU 108.25 106.63 204800 Agrium Inc. +LGF.B 29.66 29.35 314400 Lions Gate Entertainment Corporation +AGX 67.15 65.8 139000 Argan, Inc. +TSLX 20.78 20.62 88800 TPG Specialty Lending, Inc. +NSA 24.82 24.65 196300 National Storage Affiliates Trust +NSC 128.77 128.64 1894300 Norfolk Souther Corporation +FCB 47.1 46.55 333500 FCB Financial Holdings, Inc. +PBFX 20.5 20.3 36700 PBF Logistics LP +NSH 19.3 18.9 189900 Nustar GP Holdings, LLC +FCF 14.23 13.92 388300 First Commonwealth Financial Corporation +NSL 6.77 6.76 24200 Nuveen Senior Income Fund +NSM 19.2 19.11 393900 Nationstar Mortgage Holdings Inc. +NSP 93.1 92.7 110900 Insperity, Inc. +FCN 36.5 36.17 140100 FTI Consulting, Inc. +NSS 25.28 25.18 18500 NuStar Logistics, L.P. +FCT 13.33 13.31 79500 First Trust Senior Floating Rate Income Fund II +FCX 15.02 14.66 22915200 Freeport-McMoran, Inc. +COTV 34.8 34.8 165100 Cotiviti Holdings, Inc. +COTY 16.71 15.99 8238200 Coty Inc. +SOI 16.18 15.73 150300 Solaris Oilfield Infrastructure, Inc. +SOL 2.37 2.33 21300 Renesola Ltd. +SON 51.39 51.24 880300 Sonoco Products Company +SOR 40.81 40.75 12800 Source Capital, Inc. +AHC 4.49 4.45 27000 A.H. Belo Corporation +ADSW 24.58 24.43 194200 Advanced Disposal Services, Inc. +NDRO 4.1 4.05 40200 Enduro Royalty Trust +AHH 14.11 14.11 77400 Armada Hoffler Properties, Inc. +AHL 41.9 40.8 546100 Aspen Insurance Holdings Limited +AHP 10.04 9.97 244300 Ashford Hospitality Prime, Inc. +AHT 7.03 6.94 447800 Ashford Hospitality Trust Inc +NTB 36.22 35.46 162800 Bank of N.T. Butterfield & Son Limited (The) +NTC 12.17 12.17 28400 Nuveen Connecticut Quality Municipal Income Fund +FDC 18.03 17.89 6052100 First Data Corporation +NTG 17.69 17.51 124300 Tortoise MLP Fund, Inc. +HIFR 22.77 22.64 48100 InfraREIT, Inc. +NTL 39.99 39.97 1700 Nortel Inversora SA +NTP 12.5 12.2 69600 Nam Tai Property Inc. +FDP 46.91 46.05 143100 Fresh Del Monte Produce, Inc. +FDS 177.99 177.435 227900 FactSet Research Systems Inc. +NTX 14.68 14.68 6800 Nuveen Texas Quality Municipal Income Fund +NTZ 2 2 11900 Natuzzi, S.p.A. +FDX 221.01 219.81 1034000 FedEx Corporation +POST 86.97 86.1 362200 Post Holdings, Inc. +SPA 23.28 23.26 27100 Sparton Corporation +SPE 15.81 15.81 5500 Special Opportunities Fund Inc. +SPG 165.19 164.82 1366100 Simon Property Group, Inc. +SPH 26.58 26.21 212200 Suburban Propane Partners, L.P. +SPN 9.99 9.65 3099500 Superior Energy Services, Inc. +SPR 79.56 78.85 723600 Spirit Aerosystems Holdings, Inc. +AIC 24.5 24.5 2100 Arlington Asset Investment Corp +LCII 122.2 120.15 103400 LCI Industries +AIF 16.37 16.26 26900 Apollo Tactical Income Fund Inc. +AIG 63.85 63.47 5381700 American International Group, Inc. +ASGN 55.28 54.98 228000 On Assignment, Inc. +AIN 57.9 56.95 63100 Albany International Corporation +FCAU 17.49 17.29 2324300 Fiat Chrysler Automobiles N.V. +AIR 38.27 38.11 73300 AAR Corp. +AIT 64.15 63.7 130700 Applied Industrial Technologies, Inc. +AIV 44.17 44.05 802400 Apartment Investment and Management Company +AIY 25.9 25.83 33400 Apollo Investment Corporation +AIZ 96.32 95.85 506500 Assurant, Inc. +NUE 56.97 56.91 2107600 Nucor Corporation +NUM 13.67 13.66 27800 Nuveen Michigan Quality Municipal Income Fund +NUO 15.07 15.04 18300 Nuveen Ohio Quality Municipal Income Fund +FEO 16.93 16.92 12400 First Trust/Aberdeen Emerging Opportunity Fund +NUS 63.99 63.38 395800 Nu Skin Enterprises, Inc. +SPLP 18.3 18.2 7400 Steel Partners Holdings LP +NUV 10.3 10.27 224000 Nuveen AMT-Free Municipal Value Fund +NUW 17.43 17.32 37500 Nuveen AMT-Free Municipal Value Fund +FET 14 13.8 506300 Forum Energy Technologies, Inc. +SFUN 4.43 4.38 2382100 Fang Holdings Limited +KAI 100.3 98.55 43800 Kadant Inc +SQM 59.32 58.61 1936700 Sociedad Quimica y Minera S.A. +KAP 25.28 25.18 800 KCAP Financial, Inc. +KAR 47.98 47.7 679300 KAR Auction Services, Inc +AJG 62.22 61.71 603800 Arthur J. Gallagher & Co. +AJX 14.53 14.5 19200 Great Ajax Corp. +FFA 15.2 15.17 75400 First Trust +FFC 21.45 21.32 56500 Flaherty & Crumrine Preferred Securities Income Fund Inc +NVG 15.5 15.45 249300 Nuveen AMT-Free Municipal Credit Income Fund +TAHO 5.03 4.97 1425900 Tahoe Resources, Inc. +FFG 78.25 76.25 24500 FBL Financial Group, Inc. +NVO 48.91 48.797 1966500 Novo Nordisk A/S +NVR 2951.6 2898.19 20600 NVR, Inc. +NVS 85.85 85.76 1294500 Novartis AG +PGEM 16.95 16.65 75300 Ply Gem Holdings, Inc. +SRC 8.53 8.485 3981000 Spirit Realty Capital, Inc. +SRE 114.28 113.57 1121400 Sempra Energy +SRF 8.59 8.52 6000 Cushing Energy Income Fund (The) +SRG 44.15 43.24 592200 Seritage Growth Properties +SRI 22.17 22.08 133200 Stoneridge, Inc. +KBH 27.23 27.005 1617900 KB Home +SRT 11.93 11.7 24300 StarTek, Inc. +KBR 18.47 18.15 2262600 KBR, Inc. +SRV 12.02 11.82 22800 The Cushing MLP Total Return Fund +AKP 13.8 13.77 26800 Alliance California Municipal Income Fund Inc +AKR 30.22 30.22 349500 Acadia Realty Trust +ASIX 44.5 43.86 246000 AdvanSix Inc. +AKS 5.67 5.65 12515100 AK Steel Holding Corporation +FGB 7 6.88 62800 First Trust Specialty Finance and Financial Opportunities Fund +NWE 58.55 58.31 159100 NorthWestern Corporation +XNY 1.31 1.28 37400 China Xiniya Fashion Limited +NWL 42.49 41.83 4029700 Newell Brands Inc. +JONE 1.39 1.23 721600 Jones Energy, Inc. +NWN 65.5 65.3 75000 Northwest Natural Gas Company +FGL 31.2 31.1 201400 Fidelity and Guaranty Life +FGP 4.92 4.83 357300 Ferrellgas Partners, L.P. +NWY 2.02 1.99 243600 New York & Company, Inc. +SSD 49.7 49.435 249100 Simpson Manufacturing Company, Inc. +SSI 1.78 1.76 134700 Stage Stores, Inc. +GRP.U 40.64 40.31 3300 Granite Real Estate Inc. +SSL 29.14 28.9 214100 Sasol Ltd. +SSP 18.03 17.89 270600 E.W. Scripps Company (The) +ALB 140.5 138.89 1049200 Albemarle Corporation +ALE 78.16 77.58 167400 Allete, Inc. +SSW 7.32 7.28 1607300 Seaspan Corporation +ALG 109.67 107.52 46500 Alamo Group, Inc. +CLDR 15.3 15.17 1124800 Cloudera, Inc. +ALK 80.75 80.04 1150800 Alaska Air Group, Inc. +CLDT 22.15 22.03 139200 Chatham Lodging Trust (REIT) +ALL 92.46 91.12 3196800 Allstate Corporation (The) +WBAI 11.13 10.97 75200 500.com Limited +SCCO 43.5 42.71 711300 Southern Copper Corporation +ALV 125.42 124.75 410300 Autoliv, Inc. +XOM 82.63 82.54 6444100 Exxon Mobil Corporation +ALX 429.68 429.68 4200 Alexander's, Inc. +XON 17.81 17.77 735200 Intrexon Corporation +NXC 15.72 15.6 5500 Nuveen Insured California Select Tax-Free Income Portfolio +NXJ 13.86 13.82 80000 Nuveen New Jersey Quality Municipal Income Fund +NXN 14.12 14.02 3900 Nuveen Insured New York Select Tax-Free Income Portfolio +MATX 27.25 26.82 111400 Matson, Inc. +NXP 14.99 14.94 30400 Nuveen Select Tax Free Income Portfolio +FHN 19.35 18.9 3613500 First Horizon National Corporation +NXQ 14.21 14.12 13700 Nuveen Select Tax Free Income Portfolio II +NXR 15.12 15.09 14100 Nuveen Select Tax Free Income Portfolio III +BF.A 56.24 56.24 10100 Brown Forman Corporation +BF.B 55.24 55.24 506700 Brown Forman Corporation +FHY 13.54 13.52 36300 First Trust Strategic High Income Fund II +STC 37.8 37.5 44000 Stewart Information Services Corporation +STE 90.35 90.35 233500 STERIS plc +STI 60.01 59.11 2508900 SunTrust Banks, Inc. +STK 22.64 22.59 29300 Columbia Seligman Premium Technology Growth Fund, Inc +STL 24.6 24.1 1436600 Sterling Bancorp +STM 20.18 20.06 2919500 STMicroelectronics N.V. +STN 28.35 28.2 12800 Stantec Inc +STO 20.37 20.324 1837500 Statoil ASA +STT 98.64 97.065 1458000 State Street Corporation +AMC 13.85 13.6 1322700 AMC Entertainment Holdings, Inc. +AME 67.75 67.75 885200 AMTEK, Inc. +HSBC 49.19 48.95 1356900 HSBC Holdings plc +AMG 195.57 193.39 243000 Affiliated Managers Group, Inc. +STZ 210.11 209.87 2758600 Constellation Brands Inc +AMH 21.48 21.47 1495400 American Homes 4 Rent +AMN 42 41.74 258500 AMN Healthcare Services Inc +AMP 153.54 152.17 592800 AMERIPRISE FINANCIAL SERVICES, INC. +AMT 139.65 138.07 1393100 American Tower Corporation (REIT) +AMX 18.04 17.9 5991400 America Movil, S.A.B. de C.V. +XPO 66.67 64.58 1178500 XPO Logistics, Inc. +FIF 18.95 18.66 58700 First Trust Energy Infrastructure Fund +FIG 7.99 7.97 185800 Fortress Investment Group LLC +FII 31.69 30.96 815100 Federated Investors, Inc. +NYT 19.2 18.85 1614600 New York Times Company (The) +NYV 14.79 14.77 800 Nuveen New York Municipal Value Fund 2 +FIS 95.24 94.13 963900 Fidelity National Information Services, Inc. +FIT 6.54 6.35 5191500 Fitbit, Inc. +FIV 9.61 9.57 123000 First Trust Senior Floating Rate 2022 Target Term Fund +FIX 36.85 36.1 134600 Comfort Systems USA, Inc. +KED 17.07 16.7 30100 Kayne Anderson Energy Development Company +SUI 88 87.9 272900 Sun Communities, Inc. +KEG 12.06 11.75 70400 Key Energy Services, Inc. +SUM 31.58 30.99 816000 Summit Materials, Inc. +SUN 31.5 31.05 208400 Sunoco LP +KEM 26.36 26.02 1549100 Kemet Corporation +SUP 16.85 16.8 127300 Superior Industries International, Inc. +KEP 17.47 17.434 406700 Korea Electric Power Corporation +ANF 13.03 12.92 1559800 Abercrombie & Fitch Company +USAC 17.04 16.81 41900 USA Compression Partners, LP +ANH 6.08 6.05 142500 Anworth Mortgage Asset Corporation +KEX 65.25 64.95 340300 Kirby Corporation +KEY 18.46 18.15 8031900 KeyCorp +PAA 20.57 20.55 2368800 Plains All American Pipeline, L.P. +FCFS 60.35 60.15 215600 First Cash, Inc. +PAC 95.92 95.36 87100 Grupo Aeroportuario Del Pacifico, S.A. de C.V. +PAG 45.29 45.18 178300 Penske Automotive Group, Inc. +PAH 11.28 10.83 2704600 Platform Specialty Products Corporation +PAI 16.31 16.24 22200 Pacific American Income Shares, Inc. +ANW 4.55 4.5 463100 Aegean Marine Petroleum Network Inc. +PAM 66.43 64 254700 Pampa Energia S.A. +NZF 15.17 15.15 151700 Nuveen Municipal Credit Income Fund +PAR 10.9 10.56 16300 PAR Technology Corporation +PAY 20.26 20.07 636100 Verifone Systems, Inc. +SHAK 33.55 33.55 340100 Shake Shack, Inc. +SVU 18.8 18.5 1569800 SuperValu Inc. +AOD 9.15 9.12 186400 Alpine Total Dynamic Dividend Fund +KFS 6 5.9 11200 Kingsway Financial Services, Inc. +AOI 11.05 10.9 21900 Alliance One International, Inc. +KFY 40.32 39.82 200800 Korn/Ferry International +AON 150.04 148.5 852000 Aon plc +PBA 34.18 33.49 484400 Pembina Pipeline Corp. +CLGX 48.88 48.74 1266900 CoreLogic, Inc. +PBB 26.07 25.945 3200 Prospect Capital Corporation +XRF 11.08 11.06 1428800 China Rapid Finance Limited +AOS 61.15 60.57 592200 Smith (A.O.) Corporation +PBF 27.48 27.4 2135700 PBF Energy Inc. +PBH 47.64 47.29 274300 Prestige Brand Holdings, Inc. +PBI 13.79 13.47 1925500 Pitney Bowes Inc. +XRM 4.9 4.89 24800 Xerium Technologies, Inc. +CBPX 26.5 26.45 226300 Continental Building Products, Inc. +PBR 10.47 10.35 12146900 Petroleo Brasileiro S.A.- Petrobras +PBT 9.25 9.11 68000 Permian Basin Royalty Trust +XRX 33.02 32.64 1194700 Xerox Corporation +KGC 4.25 4.21 6274300 Kinross Gold Corporation +SWJ 25.325 25.26 16400 Stanley Black & Decker, Inc. +SWK 158.59 156.55 655300 Stanley Black & Decker, Inc. +DESP 32.76 30.06 510600 Despegar.com, Corp. +SWM 42 41.35 91400 Schweitzer-Mauduit International, Inc. +SWN 5.57 5.57 11653100 Southwestern Energy Company +SWP 117.26 117.03 1300 Stanley Black & Decker, Inc. +APA 42.57 42.19 3392700 Apache Corporation +APB 14.39 14.39 1300 Asia Pacific Fund, Inc. (The) +APC 48.34 47.95 4374800 Anadarko Petroleum Corporation +APD 153.68 152.8 585600 Air Products and Chemicals, Inc. +HSEA 27.19 27.19 43000 HSBC Holdings plc +HSEB 26.97 26.95 79600 HSBC Holdings plc +APF 18.02 17.95 10300 Morgan Stanley Asia-Pacific Fund, Inc. +SWX 79.06 78.91 173200 Southwest Gas Holdings, Inc. +APH 86.98 86.47 993800 Amphenol Corporation +SWZ 12.8 12.75 10900 Swiss Helvetia Fund, Inc. (The) +APO 31.46 31.23 1097200 Apollo Global Management, LLC +PCF 9.01 8.98 12300 Putnam High Income Bond Fund +PCG 55.4 54.46 27735300 Pacific Gas & Electric Co. +APU 44.74 44.6 96900 AmeriGas Partners, L.P. +PCI 22.72 22.45 1926400 PIMCO Dynamic Credit and Mortgage Income Fund +PCK 10.11 10.11 29900 Pimco California Municipal Income Fund II +PCM 11.67 11.37 72000 PIMCO Commercial Mortgage Securities Trust, Inc. +JBGS 32.49 32.43 625000 JBG SMITH Properties +PCN 17.17 16.85 180700 Pimco Corporate & Income Stategy Fund +PCQ 17.17 17.17 46900 PIMCO California Municipal Income Fund +FLC 21.5 21.45 22500 Flaherty & Crumrine Total Return Fund Inc +FCE.A 25.21 24.94 1038200 Forest City Realty Trust, Inc. +MAXR 60.88 60.88 409800 Maxar Technologies Ltd. +FLO 18.93 18.74 1568500 Flowers Foods, Inc. +FLR 42.67 42.415 1341600 Fluor Corporation +FLS 44.51 44.37 923700 Flowserve Corporation +FLT 160.72 160.36 503400 FleetCor Technologies, Inc. +LMHA 26.88 26.78 23700 Legg Mason, Inc. +FLY 14.29 14.23 24300 Fly Leasing Limited +LMHB 25.08 25.08 81500 Legg Mason, Inc. +SXC 9.85 9.72 269300 SunCoke Energy, Inc. +SXE 2.17 2.05 75600 Southcross Energy Partners, L.P. +SXI 103.6 102.75 27100 Standex International Corporation +SXT 78.49 77.42 196000 Sensient Technologies Corporation +AQN 10.88 10.88 73200 Algonquin Power & Utilities Corp. +USDP 11.3 11.05 40300 USD Partners LP +PDI 30.68 30.11 561100 PIMCO Dynamic Income Fund +PDM 20.34 20.11 829500 Piedmont Office Realty Trust, Inc. +SCHW 44.78 43.34 7189300 The Charles Schwab Corporation +FMC 94.6 94.08 962400 FMC Corporation +PDS 2.6 2.58 1354000 Precision Drilling Corporation +PDT 16.76 16.7 85300 John Hancock Premium Dividend Fund +FMN 14.65 14.61 4100 Federated Premier Municipal Income Fund +FMO 12.68 12.51 105600 Fiduciary/Claymore MLP Opportunity Fund +FMS 47.55 47.54 132800 Fresenius Medical Care Corporation +ANTM 184.16 183.69 2025700 Anthem, Inc. +FMX 93.12 92.35 896000 Fomento Economico Mexicano S.A.B. de C.V. +FMY 14.28 14.16 3400 First Trust +MPLX 34.51 34.44 583300 MPLX LP +SYF 31.59 30.85 4723500 Synchrony Financial +ANTX 51.23 51 84500 Anthem, Inc. +SYK 147 146.65 1249000 Stryker Corporation +KIM 19.25 19.16 3290800 Kimco Realty Corporation +KIO 18.03 17.75 338000 KKR Income Opportunities Fund +ARA 12.73 12.54 216200 American Renal Associates Holdings, Inc +SYT 92.11 92 8800 Syngenta AG +ARC 4.21 4.1 238000 ARC Document Solutions, Inc. +ARD 21 20.805 109000 Ardagh Group S.A. +ARE 123.12 123.01 666300 Alexandria Real Estate Equities, Inc. +SYX 28.22 27.84 70700 Systemax Inc. +SYY 54.59 54.22 1329600 Sysco Corporation +ASPN 4.29 4.21 21100 Aspen Aerogels, Inc. +SUPV 25.05 24.98 921500 Grupo Supervielle S.A. +ARI 18.42 18.41 618700 Apollo Commercial Real Estate Finance +ARL 8.75 8.75 700 American Realty Investors, Inc. +PEB 37.22 36.9 294100 Pebblebrook Hotel Trust +ARR 27.15 27.04 635600 ARMOUR Residential REIT, Inc. +PEG 48.54 48.205 3620300 Public Service Enterprise Group Incorporated +PEI 10.45 10.42 1319000 Pennsylvania Real Estate Investment Trust +ARW 83.06 82.85 231300 Arrow Electronics, Inc. +EROS 14.5 13.15 531200 Eros International PLC +PEN 92.05 92.05 54400 Penumbra, Inc. +PEO 19.65 19.52 29400 Adams Natural Resources Fund, Inc. +PEP 113.22 111.66 3825100 Pepsico, Inc. +FNB 14.1 13.91 1623700 F.N.B. Corporation +PER 2.8 2.8 46700 SandRidge Permian Trust +PES 2.05 1.95 540000 Pioneer Energy Services Corp. +FND 37.91 37.06 257100 Floor & Decor Holdings, Inc. +FNF 34.4 34.37 1499500 Fidelity National Financial, Inc. +UAA 16.23 16.13 2892600 Under Armour, Inc. +FNV 79.21 79 365100 Franco-Nevada Corporation +UAL 67.08 66.8 4806900 United Continental Holdings, Inc. +UAN 3 2.98 141400 CVR Partners, LP +SZC 19.21 18.75 31000 Cushing Renaissance Fund (The) +ASA 11.89 11.8 66400 ASA Gold and Precious Metals Limited +ASB 24.55 24.05 612100 Associated Banc-Corp +ASC 8.9 8.5 206600 Ardmore Shipping Corporation +ASG 5.45 5.39 87200 Liberty All-Star Growth Fund, Inc. +ASH 66.84 66.56 301600 Ashland Global Holdings Inc. +USFD 27.33 27.13 2364100 US Foods Holding Corp. +PFD 15.23 15.06 18800 Flaherty & Crumrine Preferred Income Fund Incorporated +ASR 179.31 177.37 117400 Grupo Aeroportuario del Sureste, S.A. de C.V. +PFE 35.89 35.75 14019600 Pfizer, Inc. +PFG 67.43 67.08 905700 Principal Financial Group Inc +PFH 14.54 14.29 7300 CABCO Series 2004-101 Trust +ASX 6.32 6.27 680300 Advanced Semiconductor Engineering, Inc. +PFL 12.17 11.88 250000 PIMCO Income Strategy Fund +PFN 10.7 10.54 367100 PIMCO Income Strategy Fund II +PFO 12.17 12.16 29400 Flaherty & Crumrine Preferred Income Opportunity Fund Inc +PFS 27.73 27.26 117300 Provident Financial Services, Inc +ZAYO 34.75 34.59 2352700 Zayo Group Holdings, Inc. +FOE 23.43 23.38 471700 Ferro Corporation +FOF 13.35 13.21 75900 Cohen & Steers Closed-End Opportunity Fund, Inc. +UBA 22.56 22.47 51800 Urstadt Biddle Properties Inc. +FOR 17.55 17.5 337600 Forestar Group Inc +KODK 6.5 6.4 117700 Eastman Kodak Company +BNED 6.18 6.18 225900 Barnes & Noble Education, Inc +UBP 18 18 1400 Urstadt Biddle Properties Inc. +UBS 17.33 17.2 1445100 UBS AG +KKR 20.24 20.05 774400 KKR & Co. L.P. +BSAC 31.54 30.93 357100 Banco Santander Chile +ATH 54.8 54.09 438500 Athene Holding Ltd. +ATI 24.9 24.455 1695000 Allegheny Technologies Incorporated +VLRS 11.01 10.67 385400 Controladora Vuela Compania de Aviacion, S.A.B. de C.V. +ATO 86.19 86.08 317000 Atmos Energy Corporation +ATR 89.3 88.71 175300 AptarGroup, Inc. +ATU 26.25 25.9 420400 Actuant Corporation +PGH 1.02 0.98 791300 Pengrowth Energy Corporation +ATV 14.13 13.865 7900 Acorn International, Inc. +PGP 16.7 16.6 34800 Pimco Global Stocksplus & Income Fund +PGR 49 48.08 5517400 Progressive Corporation (The) +FPF 24.91 24.79 104900 First Trust Intermediate Duration Preferred & Income Fund +TARO 107.62 107 63400 Taro Pharmaceutical Industries Ltd. +FPH 13.38 13.2 40400 Five Point Holdings, LLC +FPI 8.98 8.98 128300 Farmland Partners Inc. +PGZ 18 17.75 33300 Principal Real Estate Income Fund +FPL 12.62 12.41 65700 First Trust New Opportunities MLP & Energy Fund +GATX 64.01 63.53 205400 GATX Corporation +AFGE 26.7 26.62 6200 American Financial Group, Inc. +FPT 13.75 13.71 800 Federated Premier Intermediate Municipal Income Fund +AFGH 26.75 26.75 5100 American Financial Group, Inc. +DOOR 67.55 66.55 150500 Masonite International Corporation +ONDK 5.06 4.97 355700 On Deck Capital, Inc. +AUO 4.09 4.05 822500 AU Optronics Corp +PHD 12.13 12.05 53800 Pioneer Floating Rate Trust +PHG 40.17 40.15 1560700 Koninklijke Philips N.V. +PHH 13.75 13.69 98500 PHH Corp +PHI 32.66 32.42 166500 PLDT Inc. +BSBR 9.73 9.53 1532000 Banco Santander Brasil SA +PHK 8.14 8.06 800300 Pimco High Income Fund +AUY 2.61 2.6 8582800 Yamana Gold Inc. +PHM 27.15 27.01 3758400 PulteGroup, Inc. +SPXC 29.66 29.49 181500 SPX Corporation +PHT 10.07 9.99 83100 Pioneer High Income Trust +PHX 24.65 24 24200 Panhandle Royalty Company +SPXX 16 15.99 44300 Nuveen S&P 500 Dynamic Overwrite Fund +KMB 118.08 116.79 1579500 Kimberly-Clark Corporation +UDR 38.67 38.55 934800 United Dominion Realty Trust, Inc. +KMF 14.26 14 124700 Kayne Anderson Midstream Energy Fund, Inc +CVEO 2.52 2.49 424300 Civeo Corporation +KMG 56.8 56.72 390700 KMG Chemicals, Inc. +MULE 22.42 22.04 851800 MuleSoft, Inc. +KMI 18.64 18.53 13074700 Kinder Morgan, Inc. +KMM 8.92 8.89 16000 Scudder Multi-Market Income Trust +GTN.A 13.23 13.23 100 Gray Television, Inc. +AVA 52 51.94 568200 Avista Corporation +AVB 178.9 178.87 574900 AvalonBay Communities, Inc. +AVD 23.4 22.95 51200 American Vanguard Corporation +KMT 42.79 42.24 526900 Kennametal Inc. +AVH 7.34 7.33 114500 Avianca Holdings S.A. +KMX 75.25 75.19 1191600 CarMax Inc +CLNS 12.54 12.54 1826400 Colony NorthStar, Inc. +AVK 16.34 16.225 45600 Advent Claymore Convertible Securities and Income Fund +FRAC 15.86 15.7 393100 Keane Group, Inc. +AVP 2.4 2.31 2664500 Avon Products, Inc. +AVT 40.62 40.56 854300 Avnet, Inc. +PII 102.71 102.61 454100 Polaris Industries Inc. +XYL 65.43 62.24 3114500 Xylem Inc. +AVX 19.52 19.37 119700 AVX Corporation +AVY 102.44 100.93 551400 Avery Dennison Corporation +PIM 4.8 4.8 72400 Putnam Master Intermediate Income Trust +FRA 14.19 14.17 93300 Blackrock Floating Rate Income Strategies Fund Inc +PIR 4.18 4.12 1599400 Pier 1 Imports, Inc. +FRC 97.1 95.83 1620100 FIRST REPUBLIC BANK +TPGE 9.8 9.8 100000 TPG Pace Energy Holdings Corp. +PIY 25.15 25.055 6400 Merrill Lynch Depositor, Inc. +RDS.A 60.98 60.49 2841600 Royal Dutch Shell PLC +RDS.B 62.61 62.045 874100 Royal Dutch Shell PLC +FRO 6.34 6.23 331500 Frontline Ltd. +FRT 128.61 128.32 319600 Federal Realty Investment Trust +KND 6.15 6.05 1188100 Kindred Healthcare, Inc. +KNL 19.74 19.64 211600 Knoll, Inc. +AWF 13.02 12.92 190600 Alliance World Dollar Government Fund II +AWI 53.4 53 189100 Armstrong World Industries Inc +KNX 38.79 38.19 2117300 Knight Transportation, Inc. +AWK 85.12 85.03 1110700 American Water Works +AWP 6.86 6.81 297000 Alpine Global Premier Properties Fund +PJC 60.8 59.95 71200 Piper Jaffray Companies +AWR 53.64 53.64 126700 American States Water Company +PJH 25.55 25.45 88100 Prudential Financial, Inc. +FSB 34.45 34.3 52500 Franklin Financial Network, Inc. +GPJA 25 24.93 104900 Georgia Power Company +FSD 17.13 17.05 111300 First Trust High Income Long Short Fund +PJT 36.85 36.51 53600 PJT Partners Inc. +APAM 35 34.55 252400 Artisan Partners Asset Management Inc. +PGRE 16.4 16.4 2580700 Paramount Group, Inc. +FSM 4.41 4.395 764800 Fortuna Silver Mines Inc. +FSS 21.6 21.36 127600 Federal Signal Corporation +UFI 36.76 36.01 34600 Unifi, Inc. +UFS 44.04 43.715 938500 Domtar Corporation +KOF 70.92 69.98 171700 Coca Cola Femsa S.A.B. de C.V. +SMFG 7.87 7.8 1562200 Sumitomo Mitsui Financial Group Inc +KOP 48.8 48.05 64200 Koppers Holdings Inc. +KOS 7.55 7.49 1588200 Kosmos Energy Ltd. +AXE 86.05 84.8 112900 Anixter International Inc. +ZBH 119.67 118.8 845500 Zimmer Biomet Holdings, Inc. +ZBK 30.45 29.76 1100 Zions Bancorporation +CLPR 11.58 11.2 61000 Clipper Realty Inc. +WTTR 16.08 15.72 331900 Select Energy Services, Inc. +AXL 17.86 17.82 1221200 American Axle & Manufacturing Holdings, Inc. +PLNT 25.95 25.84 502400 Planet Fitness, Inc. +AXP 91.85 91.58 2939500 American Express Company +FCPT 25.53 25.34 141000 Four Corners Property Trust, Inc. +PKD 1 0.95 1131300 Parker Drilling Company +AXR 6.95 6.79 900 AMREP Corporation +PKE 19.04 18.74 52200 Park Electrochemical Corporation +AXS 57.3 56.73 587000 Axis Capital Holdings Limited +PKG 117.07 116.52 711500 Packaging Corporation of America +GKOS 32.97 32.58 256500 Glaukos Corporation +PKI 71.13 69.74 540400 PerkinElmer, Inc. +HIVE 4.2 3.96 341300 Aerohive Networks, Inc. +PKO 26.4 25.91 128200 Pimco Income Opportunity Fund +RRTS 9.08 8.46 89700 Roadrunner Transportation Systems, Inc +FTI 26.21 25.995 3242900 TechnipFMC plc +PKX 74.02 72.9 182000 POSCO +FTK 4.76 4.66 828500 Flotek Industries, Inc. +FTS 36.88 36.8 173400 Fortis Inc. +FTV 72.08 71.48 1318200 Fortive Corporation +UGI 47.29 47.2 651500 UGI Corporation +UGP 24.64 24.59 402600 Ultrapar Participacoes S.A. +AYI 164.22 162.34 499700 Acuity Brands Inc +PLOW 40.1 39.8 45800 Douglas Dynamics, Inc. +PLD 64.97 63.74 2389300 Prologis, Inc. +AYR 24.02 23.5 400200 Aircastle Limited +BIOA 0.59 0.563 1679800 BioAmber Inc. +AYX 21.29 20.87 132300 Alteryx, Inc. +PLT 44.86 44.54 108000 Plantronics, Inc. +FUL 57.31 56.96 294800 H. B. Fuller Company +FUN 63.26 63.11 97500 Cedar Fair, L.P. +PGTI 14.6 14.375 205900 PGT Innovations, Inc. +NXRT 24.45 24.375 79400 NexPoint Residential Trust, Inc. +SHLX 27.04 26.97 147000 Shell Midstream Partners, L.P. +UHS 106.13 105.51 1400000 Universal Health Services, Inc. +CAA 37.9 37.74 634900 CalAtlantic Group, Inc. +UHT 76.35 76.015 23400 Universal Health Realty Income Trust +CAE 17.54 17.35 252800 CAE Inc +CAF 24.16 23.99 74400 Morgan Stanley China A Share Fund Inc. +CAG 34.35 34.12 3497000 ConAgra Brands, Inc. +CAH 64.49 64.1 2278700 Cardinal Health, Inc. +CAI 30.42 30.21 116800 CAI International, Inc. +SMHI 13.4 13.24 42900 SEACOR Marine Holdings Inc. +CAJ 35.7 35.61 105600 Canon, Inc. +CAL 27.48 27.4 231600 Caleres, Inc. +CAT 131.14 130.32 2380300 Caterpillar, Inc. +AZN 34.58 34.49 6444700 Astrazeneca PLC +AZO 600 598.65 389000 AutoZone, Inc. +PMC 29.2 29.15 290600 Pharmerica Corporation +PMF 13.59 13.55 26500 PIMCO Municipal Income Fund +GCAP 6.32 6.16 74400 GAIN Capital Holdings, Inc. +AXTA 28.38 28.29 2422600 Axalta Coating Systems Ltd. +PML 13.31 13.3 126400 Pimco Municipal Income Fund II +PMM 7.58 7.53 66800 Putnam Managed Municipal Income Trust +AZZ 47.2 47.2 107800 AZZ Inc. +PMO 12.7 12.67 24300 Putnam Municipal Opportunities Trust +PMT 16.91 16.83 365500 PennyMac Mortgage Investment Trust +PMX 11.83 11.83 37300 PIMCO Municipal Income Fund III +EOCC 26.87 26.68 163000 Enel Generacion Chile S.A. +GPMT 18.99 18.91 68300 Granite Point Mortgage Trust Inc. +KRA 41.95 41.31 163800 Kraton Corporation +KRC 72.63 72.53 666000 Kilroy Realty Corporation +UIS 8.75 8.6 294900 Unisys Corporation +CBB 20.15 19.8 223700 Cincinnati Bell Inc +CBD 24.38 23.85 415300 Companhia Brasileira de Distribuicao +KRG 20.2 20.15 718900 Kite Realty Group Trust +CBG 39.53 39.47 1664500 CBRE Group, Inc. +CBH 9.87 9.83 13700 AllianzGI Convertible & Income 2024 Target Term Fund +CBI 16.2 15.83 1597800 Chicago Bridge & Iron Company N.V. +CBK 1.35 1.32 32300 Christopher & Banks Corporation +CBL 8.53 8.47 1693000 CBL & Associates Properties, Inc. +KRO 25.78 25.71 430600 Kronos Worldwide Inc +CBM 53.35 51.375 343200 Cambrex Corporation +KRP 16.61 16.6 20000 Kimbell Royalty Partners +USNA 61.65 60.7 83400 USANA Health Sciences, Inc. +CBS 56.74 56.35 2288500 CBS Corporation +CBT 58.32 58 203500 Cabot Corporation +CBU 55.91 54.61 134600 Community Bank System, Inc. +ZEN 29.8 29.45 485200 Zendesk, Inc. +CBZ 16.95 16.725 124500 CBIZ, Inc. +PNC 135.53 134.18 2055700 PNC Financial Services Group, Inc. (The) +PNF 13.12 13.12 8200 PIMCO New York Municipal Income Fund +PNI 12.34 12.34 11400 Pimco New York Municipal Income Fund II +PNM 40.85 40.85 624600 PNM Resources, Inc. (Holding Co.) +PNR 70.89 70.23 841600 Pentair plc. +PNW 87.02 87.02 649900 Pinnacle West Capital Corporation +CCC 21.45 21.45 1639000 Calgon Carbon Corporation +CCE 41.97 41.73 978600 Coca-Cola European Partners plc +CCI 101.95 100.87 2503300 Crown Castle International Corporation +CCJ 9.11 9.065 1111100 Cameco Corporation +KSM 12.18 12.13 9400 Scudder Strategic Municiple Income Trust +CCK 60.23 59.81 593000 Crown Holdings, Inc. +CCL 67.83 67.82 1877900 Carnival Corporation +CCM 3.55 3.55 27100 Concord Medical Services Holdings Limited +CCO 4.45 4.35 360400 Clear Channel Outdoor Holdings, Inc. +KSS 42.76 42.67 3075700 Kohl's Corporation +KST 12.44 12.44 5000 Scudder Strategic Income Trust +KSU 101.25 99.7 2083500 Kansas City Southern +CCS 25.8 25.5 140500 Century Communities, Inc. +CCU 27.85 27.66 40800 Compania Cervecerias Unidas, S.A. +CCV 25.4 25.25 11500 Comcast Corporation +RELX 22.59 22.55 87200 RELX PLC +CCZ 57.8 57.8 100 Comcast Corporation +DYNC 66.3 65.85 6700 Dynegy Inc. +TCAP 13.32 12.47 1468900 Triangle Capital Corporation +BABA 179.58 175.3 20132200 Alibaba Group Holding Limited +POL 41.58 40.97 323700 PolyOne Corporation +POR 44.85 44.85 1234100 Portland General Electric Company +POT 19.32 19.04 2318900 Potash Corporation of Saskatchewan Inc. +SHOP 97 95.4 2475400 Shopify Inc. +MUSA 73.09 73.09 171200 Murphy USA Inc. +KTF 12.31 12.3 134300 Scudder Municiple Income Trust +KTH 33.54 33.54 600 Lehman ABS Corporation +CDE 8.78 8.53 1996700 Coeur Mining, Inc. +KTN 33.3 33.3 2900 Lehman ABS Corporation +KTP 14.5 14.5 12600 Lehman ABS Corporation +CDR 5.72 5.63 535800 Cedar Realty Trust, Inc. +USPH 63.55 62.95 62400 U.S. Physical Therapy, Inc. +PPG 113.12 112.76 1581500 PPG Industries, Inc. +PPL 37.41 37.26 3152500 PPL Corporation +PPR 5.17 5.16 359000 Voya Prime Rate Trust +PPT 5.32 5.32 492600 Putnam Premier Income Trust +PPX 25.52 25.52 9400 PPL Capital Funding, Inc. +SWCH 19.95 19.51 1065800 Switch, Inc. +VNCE 0.51 0.47 132100 Vince Holding Corp. +CEA 25.04 24.92 12900 China Eastern Airlines Corporation Ltd. +BDXA 55.26 55.25 20800 Becton, Dickinson and Company +CEE 24.99 24.8 11500 The Central and Eastern Europe Fund, Inc. +CEL 9.79 9.76 7700 Cellcom Israel, Ltd. +CEM 14.43 14.19 228600 ClearBridge Energy MLP Fund Inc. +CEN 10.34 10.17 107500 Center Coast MLP & Infrastructure Fund +CEO 130.35 129.565 65200 CNOOC Limited +RENN 9.29 9.17 206200 Renren Inc. +SMLP 21.3 20.85 80000 Summit Midstream Partners, LP +TCCA 25.47 25.4 7400 Triangle Capital Corporation +TCCB 25.55 25.52 1200 Triangle Capital Corporation +RENX 21.7 21.7 44900 RELX N.V. +BITA 53.8 50 1199700 Bitauto Holdings Limited +PQG 17.11 17.08 297500 PQ Group Holdings Inc. +HAE 45.29 44.93 292300 Haemonetics Corporation +HAL 44.6 44.145 7556500 Halliburton Company +UMC 2.65 2.61 844700 United Microelectronics Corporation +CVNA 13.9 13.801 271500 Carvana Co. +UMH 15.78 15.61 86300 UMH Properties, Inc. +UNVR 30.08 29.46 452700 Univar Inc. +CFG 37.24 36.6 3307700 Citizens Financial Group, Inc. +INFY 14.62 14.4 7557000 Infosys Limited +CFR 97.68 95.65 317700 Cullen/Frost Bankers, Inc. +WLKP 22.85 22.65 16400 Westlake Chemical Partners LP +CFX 42.67 42.32 542700 Colfax Corporation +PRA 56.05 55.35 70800 ProAssurance Corporation +HBB 38.96 38.53 32400 Hamilton Beach Brands Holding Company +PRH 25.67 25.65 11600 Prudential Financial, Inc. +PRI 89.35 87.3 274600 Primerica, Inc. +HBI 23.39 23.07 4062100 Hanesbrands Inc. +PRO 25.05 24.81 71900 PROS Holdings, Inc. +HBM 8.3 7.905 1093600 Hudbay Minerals Inc. +PRU 109.7 108.34 1605600 Prudential Financial, Inc. +GPRK 9.28 8.93 45500 Geopark Ltd +UNF 157.3 154.35 62600 Unifirst Corporation +UNH 196.58 196.37 8949700 UnitedHealth Group Incorporated +UNM 52.61 51.88 835600 Unum Group +UNP 109.34 108.71 3975200 Union Pacific Corporation +CGA 1.28 1.27 30200 China Green Agriculture, Inc. +UNT 19.26 18.14 619600 Unit Corporation +BFAM 85.1 84.91 235000 Bright Horizons Family Solutions Inc. +CGG 4.57 4.3 12700 CGG +INGR 124.17 123.08 316600 Ingredion Incorporated +CGI 5.25 5.1 292100 Celadon Group, Inc. +KEYS 42.48 42.28 841700 Keysight Technologies Inc. +KWR 150.74 149.39 48400 Quaker Chemical Corporation +PSA 216.74 214.305 723300 Public Storage +PSB 135.87 134.75 76700 PS Business Parks, Inc. +HCA 75.62 75.3 3771200 HCA Healthcare, Inc. +HCC 23.57 23.57 1279200 Warrior Met Coal, Inc. +PSF 28.49 28.32 17900 Cohen & Steers Select Preferred and Income Fund, Inc. +HCI 38.81 38.25 69800 HCI Group, Inc. +PSO 8.82 8.68 1770000 Pearson, Plc +BSMX 9.28 8.84 2472000 Grupo Financiero Santander Mexico S.A. B. de C.V. +HCN 67.84 67.63 1273400 Welltower Inc. +HCP 26.17 26.11 3285800 HCP, Inc. +PSX 90.69 90.4 2398400 Phillips 66 +AFSD 25.11 25.11 38900 Aflac Incorporated +AFSS 25.75 25.72 2300 AmTrust Financial Services, Inc. +AFST 26.3 26.3 12000 AmTrust Financial Services, Inc. +CHA 52.35 52.3 79300 China Telecom Corp Ltd +CHD 47.66 47.38 1119200 Church & Dwight Company, Inc. +CHE 201.24 201.042 61600 Chemed Corp. +CHH 67.4 66.4 271400 Choice Hotels International, Inc. +CHK 3.86 3.73 19314200 Chesapeake Energy Corporation +CHL 50.86 50.52 1118600 China Mobile (Hong Kong) Ltd. +CHN 21.11 21.09 65500 China Fund, Inc. (The) +CHS 7.12 7.07 1653400 Chico's FAS, Inc. +CHT 34.2 34.13 65000 Chunghwa Telecom Co., Ltd. +CHU 14.5 14.46 116200 China Unicom (Hong Kong) Ltd +HDB 96.26 94.49 896600 HDFC Bank Limited +PTR 65.09 64.37 79800 PetroChina Company Limited +MHLA 25.79 25.73 7400 Maiden Holdings, Ltd. +CIEN 21.32 21.12 4313600 Ciena Corporation +TPRE 16.4 16.25 447600 Third Point Reinsurance Ltd. +PTY 16.82 16.51 493600 Pimco Corporate & Income Opportunity Fund +KORS 48.41 48.15 2171500 Michael Kors Holdings Limited +UPS 117.96 117.4 1484400 United Parcel Service, Inc. +CIA 7.42 7.32 45400 Citizens, Inc. +KYE 10.9 10.7 124200 Kayne Anderson Energy Total Return Fund, Inc. +CIB 43.41 43.41 470000 BanColombia S.A. +CIC 9.78 9.76 5700 Capitol Investment Corp. IV +CIE 1.02 0.97 523500 Cobalt International Energy, Inc. +CIF 2.96 2.91 98200 Colonial Intermediate High Income Fund +CIG 2.52 2.5 6356600 Comp En De Mn Cemig ADS +CII 15.7 15.68 102800 Blackrock Capital and Income Strategies Fund Inc +KYN 17.33 17.05 360500 Kayne Anderson MLP Investment Company +KYO 66.02 65.91 5500 Kyocera Corporation +CIM 19.18 19.13 496400 Chimera Investment Corporation +CIO 13.31 13.22 142100 City Office REIT, Inc. +RTEC 26.75 26.7 212100 Rudolph Technologies, Inc. +CIR 55 54.12 31600 CIRCOR International, Inc. +CIT 49.45 48.98 1500300 CIT Group Inc (DEL) +PUK 48.37 48 101500 Prudential Public Limited Company +HEI 90.05 88.8 331800 Heico Corporation +APLE 19.11 19 747700 Apple Hospitality REIT, Inc. +HEP 33.95 33.66 115900 Holly Energy Partners, L.P. +SRLP 26.04 25.4 7900 Sprague Resources LP +HEQ 17.74 17.6 18700 John Hancock Hedged Equity & Income Fund +HES 46.06 45.49 2882200 Hess Corporation +RYAM 13.89 13.81 355200 Rayonier Advanced Materials Inc. +MAA 107.35 106.9 703200 Mid-America Apartment Communities, Inc. +MAC 57.52 57.38 906700 Macerich Company (The) +MAN 122.82 120.52 412600 ManpowerGroup +MAS 38.95 38.83 1547700 Masco Corporation +CVRR 11.3 11.055 308000 CVR Refining, LP +MAV 11.58 11.56 62800 Pioneer Municipal High Income Advantage Trust +RESI 10.84 10.78 169100 Altisource Residential Corporation +LEJU 1.62 1.57 28000 Leju Holdings Limited +QTWO 42.35 41.65 75100 Q2 Holdings, Inc. +SEAS 12.47 12.26 1357200 SeaWorld Entertainment, Inc. +HFC 36.22 36.06 1551200 HollyFrontier Corporation +MCRN 18.72 18.51 628300 Milacron Holdings Corp. +PVG 11.31 11.18 2188400 Pretium Resources, Inc. +PVH 124.17 123.97 575100 PVH Corp. +MHNC 26.35 26.06 10800 Maiden Holdings, Ltd. +URI 145.43 143.01 1525500 United Rentals, Inc. +MBI 6.84 6.83 5341400 MBIA, Inc. +FMSA 4.18 4.01 2396500 Fairmount Santrol Holdings Inc. +MBT 10.55 10.44 2065100 Mobile TeleSystems OJSC +BRK.A 283000 279900 100 Berkshire Hathaway Inc. +CKH 45.1 44.17 96700 SEACOR Holdings, Inc. +BRK.B 187.96 186.5 2273000 Berkshire Hathaway Inc. +ZNH 35.17 34.82 7600 China Southern Airlines Company Limited +HGH 29.71 29.68 27900 Hartford Financial Services Group, Inc. (The) +PWR 37.82 37.33 795800 Quanta Services, Inc. +HGT 1.75 1.65 146900 Hugoton Royalty Trust +HGV 39.66 39.63 283300 Hilton Grand Vacations Inc. +IIPR 19.07 17.94 83000 Innovative Industrial Properties, Inc. +USA 6.15 6.11 590800 Liberty All-Star Equity Fund +USB 54.35 53.75 5299500 U.S. Bancorp +MCA 15.38 15.33 58800 Blackrock MuniYield California Insured Fund, Inc. +MCC 5.8 5.53 530800 Medley Capital Corporation +MCD 164.92 164.75 2379700 McDonald's Corporation +USG 33.14 33.03 1376700 USG Corporation +BXMT 31.73 31.51 288500 Capital Trust, Inc. +MCI 16 15.86 11100 Barings Corporate Investors +USM 36.51 35.66 36900 United States Cellular Corporation +MCK 146.61 145.615 1614100 McKesson Corporation +BXMX 14.02 13.99 145300 Nuveen S&P 500 Buy-Write Income Fund +MCN 7.82 7.82 35200 Madison Covered Call & Equity Strategy Fund +MCO 144.83 143.35 503200 Moody's Corporation +CLB 94.03 93.75 272900 Core Laboratories N.V. +MCR 8.66 8.64 72800 MFS Charter Income Trust +MCS 27.45 27.2 47600 Marcus Corporation (The) +CLD 3.74 3.74 3565900 Cloud Peak Energy Inc +CLF 7.24 7.13 7054600 Cleveland-Cliffs Inc. +MCV 25.1 25.1 2900 Medley Capital Corporation +CLH 56.37 56.195 104700 Clean Harbors, Inc. +MCX 25.72 25.7 1600 Medley Capital Corporation +CLI 23.39 23.3 378700 Mack-Cali Realty Corporation +MCY 56.48 55.91 106400 Mercury General Corporation +CNDT 15.85 15.72 1645800 Conduent Incorporated +CLR 37.4 36.53 1969300 Continental Resources, Inc. +CLS 12.54 12.3 143800 Celestica, Inc. +CLW 43.85 43.3 50800 Clearwater Paper Corporation +CLX 131.8 130.65 608100 Clorox Company (The) +ACCO 13 12.6 595400 Acco Brands Corporation +PXD 143.7 142.36 1525700 Pioneer Natural Resources Company +HHC 123.6 122.14 127700 Howard Hughes Corporation (The) +HASI 24.5 24.37 164300 Hannon Armstrong Sustainable Infrastructure Capital, Inc. +HHS 1.04 1.03 53600 Harte-Hanks, Inc. +TPVG 13.66 13.63 52300 TriplePoint Venture Growth BDC Corp. +MDC 35.53 35.45 313800 M.D.C. Holdings, Inc. +UTF 23.06 22.95 138000 Cohen & Steers Infrastructure Fund, Inc +UTI 3.45 3.28 9900 Universal Technical Institute Inc +UTL 51.5 51.5 22000 UNITIL Corporation +TPVY 25.2 25.17 11500 TriplePoint Venture Growth BDC Corp. +MDP 54.75 53.6 390700 Meredith Corporation +CMA 76.03 74.66 2615900 Comerica Incorporated +MDR 6.79 6.55 2760800 McDermott International, Inc. +CMC 21.2 20.93 1893300 Commercial Metals Company +CMD 95.64 95.26 124600 Cantel Medical Corp. +MDT 77.76 77.39 3809500 Medtronic plc +HUBB 120.24 118.5 294000 Hubbell Inc +MDU 26.93 26.88 426800 MDU Resources Group, Inc. +UTX 118.63 118.18 2026500 United Technologies Corporation +CMG 320.47 320.47 1055600 Chipotle Mexican Grill, Inc. +REVG 27.15 26.6 1652800 REV Group, Inc. +CMI 174.1 173.89 684000 Cummins Inc. +CMO 9.69 9.66 246000 Capstead Mortgage Corporation +CMP 65.85 65.15 342100 Compass Minerals International, Inc. +YELP 43.36 42.92 648000 Yelp Inc. +CMS 47.27 47.2 1331400 CMS Energy Corporation +CMU 4.79 4.75 55300 Colonial Municipal Income Trust +HUBS 81.75 81.45 208700 HubSpot, Inc. +HIE 13.87 13.75 43200 Miller/Howard High Income Equity Fund +HIG 56.31 55.75 1550300 Hartford Financial Services Group, Inc. (The) +HII 236.07 234.77 195500 Huntington Ingalls Industries, Inc. +PYN 10.08 9.99 12000 PIMCO New York Municipal Income Fund III +HIL 5.1 4.95 109900 Hill International, Inc. +HIO 5.14 5.13 182500 Western Asset High Income Opportunity Fund, Inc. +PYS 21.44 21.21 18900 PPlus Trust +PYT 20.94 20.94 100 PPlus Trust +THGA 25.59 25.51 3500 The Hanover Insurance Group, Inc. +HIW 52.41 52.41 340300 Highwoods Properties, Inc. +HIX 7.25 7.245 196400 Western Asset High Income Fund II Inc. +VIPS 8.42 8.31 8437300 Vipshop Holdings Limited +MED 63.05 62.95 133400 MEDIFAST INC +MEI 45.1 44.75 137800 Methode Electronics, Inc. +MEN 11.93 11.9 37100 Blackrock MuniEnhanced Fund, Inc. +CNA 50.48 49.82 142400 CNA Financial Corporation +CNC 92.02 91.535 3005300 Centene Corporation +MET 53.23 52.2 4853600 MetLife, Inc. +GMED 29.05 29.005 523900 Globus Medical, Inc. +CNI 80.08 79.8 878300 Canadian National Railway Company +CNK 35.81 35.39 820400 Cinemark Holdings Inc +CNO 24.54 24.24 540500 CNO Financial Group, Inc. +CNP 29.43 29.27 2240800 CenterPoint Energy, Inc. +CNQ 33.17 32.87 1397600 Canadian Natural Resources Limited +RAD 1.89 1.81 23981500 Rite Aid Corporation +CNS 42.07 41.34 92400 Cohen & Steers Inc +CNX 15.58 15.51 2384500 CONSOL Energy Inc. +BSTI 11.96 11.7 1656700 BEST Inc. +PZC 10.85 10.85 57000 PIMCO California Municipal Income Fund III +PZE 13.15 12.55 17300 Petrobras Argentina S.A. +RAS 0.56 0.51 1661500 RAIT Financial Trust +PZN 11.87 11.83 181000 Pzena Investment Management Inc +MRIN 14.1 13.9 12900 Marin Software Incorporated +GRAM 4.64 4.59 71800 Grana y Montero S.A.A. +HJV 13.24 12.67 7400 MS Structured Asset Corp Saturns GE Cap Corp Series 2002-14 +OAKS 4.5 4.46 95900 Five Oaks Investment Corp. +MFA 8.74 8.71 846300 MFA Financial, Inc. +UVE 24.6 24.15 208000 UNIVERSAL INSURANCE HOLDINGS INC +MFC 20.81 20.65 1807200 Manulife Financial Corp +MFD 13.56 13.48 14000 Macquarie/First Trust Global +MFG 3.59 3.56 340400 Mizuho Financial Group, Inc. +MFL 15.05 14.99 51700 Blackrock MuniHoldings Investment Quality Fund +MFM 7.11 7.1 30100 MFS Municipal Income Trust +MFO 25.41 25.41 11000 MFA Financial, Inc. +UVV 58.75 58 193500 Universal Corporation +COE 13.83 13.56 8400 China Online Education Group +MFT 14.44 14.4 6800 Blackrock MuniYield Investment QualityFund +COF 86.98 85.91 1450400 Capital One Financial Corporation +COG 25.69 25.58 3990100 Cabot Oil & Gas Corporation +MFV 6.61 6.59 8600 MFS Special Value Trust +COH 39.35 39.07 1857900 Coach, Inc. +COL 134.52 134.32 767400 Rockwell Collins, Inc. +DLNG 13.61 13.29 93300 Dynagas LNG Partners LP +RBA 28.61 28.03 384100 Ritchie Bros. Auctioneers Incorporated +COO 237.8 235.52 551500 Cooper Companies, Inc. (The) +COP 49.7 49.32 3579000 ConocoPhillips +RBC 79.75 78.8 217600 Regal Beloit Corporation +COR 111.75 111.74 332000 CoreSite Realty Corporation +REXR 30.31 30.15 456400 Rexford Industrial Realty, Inc. +COT 15.16 14.93 2389000 Cott Corporation +RBS 7.32 7.27 461600 Royal Bank Scotland plc (The) +BANC 20.55 20.3 279700 Banc of California, Inc. +BIO.B 222.85 222.85 100 Bio-Rad Laboratories, Inc. +APRN 5.27 5.2 2381500 Blue Apron Holdings, Inc. +MGA 53.17 52.94 1113300 Magna International, Inc. +SWNC 12.95 12.8 24300 Southwestern Energy Company +MGF 4.91 4.91 24500 MFS Government Markets Income Trust +MGM 29.69 29.63 8612400 MGM Resorts International +CNHI 11.96 11.87 1631900 CNH Industrial N.V. +XOXO 20.02 19.89 43800 XO Group, Inc. +MGP 29.17 29.07 672800 MGM Growth Properties LLC +CPA 130.08 125.71 193900 Copa Holdings, S.A. +CPB 46.63 45.9 2170400 Campbell Soup Company +CPE 11.11 10.97 1837800 Callon Petroleum Company +MGU 26.1 25.95 25300 Macquarie Global Infrastructure Total Return Fund Inc. +CPF 32.59 32.15 79300 CPB Inc. +CPG 7.6 7.48 1417200 Crescent Point Energy Corporation +CPK 80.4 80.4 27100 Chesapeake Utilities Corporation +CPL 17.15 17.13 98900 CPFL Energia S.A. +CPN 14.8 14.78 12039600 Calpine Corporation +CPS 110.31 109.92 117100 Cooper-Standard Holdings Inc. +CPT 93.58 92.88 430400 Camden Property Trust +RCI 53.63 53.48 347700 Rogers Communication, Inc. +RCL 127.4 127 1013600 Royal Caribbean Cruises Ltd. +RCS 9.45 9.3 330400 PIMCO Strategic Income Fund, Inc. +HLF 78.38 76.81 4044500 Herbalife LTD. +HLI 40.52 40.24 202000 Houlihan Lokey, Inc. +HLS 45.25 44.885 625600 HealthSouth Corporation +HLT 71.04 70.72 1549200 Hilton Worldwide Holdings Inc. +HLX 7.87 7.74 1518700 Helix Energy Solutions Group, Inc. +MHD 17.03 16.92 59600 Blackrock MuniHoldings Fund, Inc. +MHF 7.8 7.79 35900 Western Asset Municipal High Income Fund, Inc. +MHI 12.07 12.02 77100 Pioneer Municipal High Income Trust +MHK 257.3 257.13 321100 Mohawk Industries, Inc. +MHN 14.07 14.06 20500 Blackrock MuniHoldings New York Quality Fund, Inc. +MHO 28.38 28.27 228700 M/I Homes, Inc. +DLPH 98 96.79 1590600 Delphi Automotive plc +RDC 13.89 13.32 3376200 Rowan Companies plc +ZTO 15.32 14.9 2330100 ZTO Express (Cayman) Inc. +RDN 19.74 19.49 2043800 Radian Group Inc. +ZTR 13.24 13.225 82200 Virtus Global Dividend & Income Fund Inc. +ZTS 65.65 65.43 2251500 Zoetis Inc. +HMC 30.39 30.33 429300 Honda Motor Company, Ltd. +RDY 36.35 36.18 143500 Dr. Reddy's Laboratories Ltd +HMN 40.75 40.3 140100 Horace Mann Educators Corporation +CINR 25.25 25 13500 Ciner Resources LP +HMY 1.8 1.76 2990700 Harmony Gold Mining Company Limited +APTS 20.16 20.07 409700 Preferred Apartment Communities, Inc. +MIC 72.59 72.25 547100 Macquarie Infrastructure Company +MIE 10.36 10.15 108700 Cohen & Steers MLP Income and Energy Opportunity Fund, Inc. +MIN 4.24 4.22 530200 MFS Intermediate Income Trust +CRC 10.53 10.33 786800 California Resources Corporation +CRH 35.88 35.83 268900 CRH PLC +CRI 92.09 91.57 475500 Carter's, Inc. +MIY 13.99 13.99 25600 Blackrock MuniYield Michigan Quality Fund, Inc. +CRK 4.73 4.47 210600 Comstock Resources, Inc. +CRL 114.02 113.81 171800 Charles River Laboratories International, Inc. +CRM 96.96 95.93 2528300 Salesforce.com Inc +CRR 6.8 6.49 695700 Carbo Ceramics, Inc. +CRS 50.2 49.88 529400 Carpenter Technology Corporation +CRT 14.56 14.5 11800 Cross Timbers Royalty Trust +REG 64.14 64.03 718100 Regency Centers Corporation +CRY 20.3 20.25 105300 CryoLife, Inc. +RES 22.86 22.72 1330200 RPC, Inc. +REV 22.9 22.4 140000 Revlon, Inc. +HNI 42.4 41.98 136000 HNI Corporation +VSLR 3.7 3.65 193500 Vivint Solar, Inc. +REX 90.55 89.94 20100 REX American Resources Corporation +WAB 75 74.32 531700 Westinghouse Air Brake Technologies Corporation +WAC 0.46 0.46 299400 Walter Investment Management Corp. +HNP 25.66 25.3 89300 Huaneng Power International, Inc. +TRCO 40.75 40.56 520600 Tribune Media Company +WAL 53.41 51.87 575900 Western Alliance Bancorporation +UZA 25.65 25.55 9100 United States Cellular Corporation +UZB 26.5 26.4 18900 United States Cellular Corporation +UZC 27.02 26.89 13100 United States Cellular Corporation +NPTN 4.75 4.74 809500 NeoPhotonics Corporation +WAT 183.94 180.44 712300 Waters Corporation +PBR.A 10.18 10.085 6773400 Petroleo Brasileiro S.A.- Petrobras +INSI 19.74 19.7 14900 Insight Select Income Fund +TMHC 22.69 22.45 717200 Taylor Morrison Home Corporation +INST 33.95 33.95 115300 Instructure, Inc. +CSL 99.31 99.31 224800 Carlisle Companies Incorporated +INSW 20.53 20.4 118900 International Seaways, Inc. +CSS 29.73 29.62 30800 CSS Industries, Inc. +CSU 12.22 12.22 121300 Capital Senior Living Corporation +CSV 25.48 24.99 98000 Carriage Services, Inc. +RFI 12.72 12.655 41300 Cohen & Steers Total Return Realty Fund, Inc. +RFP 6.35 6.1 172000 Resolute Forest Products Inc. +RFT 17.25 16.61 47800 RAIT Financial Trust +HOG 45.75 45.25 13981300 Harley-Davidson, Inc. +HON 143.5 142.51 2435600 Honeywell International Inc. +WBC 149.45 147.72 317800 Wabco Holdings Inc. +HOS 3.92 3.83 207300 Hornbeck Offshore Services +HOV 2.29 2.205 1163600 Hovnanian Enterprises Inc +WBK 26.13 26.03 106300 Westpac Banking Corporation +MKC 99.04 98.36 669400 McCormick & Company, Incorporated +WBS 53.29 52.27 401200 Webster Financial Corporation +WBT 21.92 21.92 711200 Welbilt, Inc. +MKL 1073.42 1064.41 15000 Markel Corporation +CTB 36.7 36.5 302600 Cooper Tire & Rubber Company +FELP 4.115 4.115 26000 Foresight Energy LP +CTL 19.72 18.93 18804100 CenturyLink, Inc. +RGA 143.62 142.74 269200 Reinsurance Group of America, Incorporated +AMBR 8.48 8.27 17300 Amber Road, Inc. +RGC 16.06 15.79 2617200 Regal Entertainment Group +CTR 12.12 12.06 120500 ClearBridge Energy MLP Total Return Fund Inc. +CTS 25.7 25.4 41700 CTS Corporation +CTU 25.31 25.31 27600 Qwest Corporation +CTV 26.05 26.01 30700 Qwest Corporation +CTW 25.52 25.5 11000 Qwest Corporation +CTX 25.46 25.4 24300 Qwest Corporation +CTY 25.27 25.26 27900 Qwest Corporation +CTZ 25.42 25.37 17500 Qwest Corporation +RGR 50.45 49.95 129700 Sturm, Ruger & Company, Inc. +RGS 14.95 14.95 202900 Regis Corporation +HPE 14.84 14.545 12841000 Hewlett Packard Enterprise Company +RGT 10.61 10.6 32500 Royce Global Value Trust, Inc. +HPF 21.76 21.72 26700 John Hancock Pfd Income Fund II +TREC 12.55 12.15 31900 Trecora Resources +HPI 21.77 21.77 59900 John Hancock Preferred Income Fund +TCRX 25.23 25.22 1700 THL Credit, Inc. +HPP 33.98 33.86 1142100 Hudson Pacific Properties, Inc. +WCC 59.65 59.5 606600 WESCO International, Inc. +HPQ 21.77 21.46 7137000 HP Inc. +TCRZ 25.835 25.8 2800 THL Credit, Inc. +HPS 18.75 18.69 29200 John Hancock Preferred Income Fund III +WCG 169.47 167.52 482300 WellCare Health Plans, Inc. +WCN 69.53 69.46 563400 Waste Connections, Inc. +TREX 87 86.64 179000 Trex Company, Inc. +MLI 34.75 34.26 99900 Mueller Industries, Inc. +MLM 204.51 203.18 452400 Martin Marietta Materials, Inc. +MLP 16.55 15.55 59700 Maui Land & Pineapple Company, Inc. +CUB 52.15 51.35 119900 Cubic Corporation +MLR 28.25 28.25 18600 Miller Industries, Inc. +CUK 67.41 67.41 332800 Carnival Corporation +RHI 49.09 48.73 363500 Robert Half International Inc. +CUZ 9.47 9.37 5095000 Cousins Properties Incorporated +RHP 64.66 64.23 136900 Ryman Hospitality Properties, Inc. +RHT 120.36 120.08 1198200 Red Hat, Inc. +HQH 25.35 25.3 79100 Tekla Healthcare Investors +HQL 21.84 21.84 52600 Tekla Life Sciences Investors +CABO 756.97 734.15 34000 Cable One, Inc. +WDR 20.43 19.92 525700 Waddell & Reed Financial, Inc. +MMC 84.1 83.29 1437700 Marsh & McLennan Companies, Inc. +MMD 19.93 19.9 49200 MainStay DefinedTerm Municipal Opportunities Fund +MMI 27.4 27.2 73700 Marcus & Millichap, Inc. +INVH 22.56 22.5 1606900 Invitation Homes Inc. +MMM 218.19 216.47 2150800 3M Company +CVA 15.25 15.15 1125500 Covanta Holding Corporation +MMP 69.16 68.55 618200 Magellan Midstream Partners L.P. +FENG 6.19 5.94 775600 Phoenix New Media Limited +MMS 65.1 64.68 151400 Maximus, Inc. +CVE 9.72 9.65 2420200 Cenovus Energy Inc +MMT 6.22 6.2 120700 MFS Multimarket Income Trust +MMU 14.16 14.09 47600 Western Asset Managed Municipals Fund, Inc. +CVG 25.79 25.44 292500 Convergys Corporation +CVI 27.85 27.3 359300 CVR Energy Inc. +VNTR 24.61 24.51 637500 Venator Materials PLC +SEMG 27.7 26.8 781900 Semgroup Corporation +VNTV 69.5 68.75 4185700 Vantiv, Inc. +CNNX 16.4 16.02 240400 Cone Midstream Partners LP +RIC 9.55 9.4 167100 Richmont Mines, Inc. +FTAI 18.5 18.2 299800 Fortress Transportation and Infrastructure Investors LLC +CVS 72.41 72.12 6068700 CVS Health Corporation +RIG 11.03 10.71 13703700 Transocean Ltd. +CVX 120.23 119.83 4844200 Chevron Corporation +RIO 49.9 49.554 1937100 Rio Tinto Plc +HRB 25.39 24.755 2603900 H&R Block, Inc. +HRC 78.11 77.68 456800 Hill-Rom Holdings Inc +HRG 16.19 16.17 1529700 HRG Group, Inc. +RIV 20.05 19.7 70600 RiverNorth Opportunities Fund, Inc. +HRI 49.17 48.8 170100 Herc Holdings Inc. +HRL 31.38 31.36 1731800 Hormel Foods Corporation +WEA 13.84 13.84 45200 Western Asset Bond Fund +WEC 64.96 64.8 1290100 WEC Energy Group, Inc. +CACI 142.5 140.3 72400 CACI International, Inc. +HRS 135.95 135.95 468400 Harris Corporation +CISN 13.2 13.07 64900 Cision Ltd. +TRGP 44.98 44.5 2131000 Targa Resources, Inc. +WES 51.07 50.45 611600 Western Gas Partners, LP +MNE 14.13 14.08 6500 Blackrock Muni New York Intermediate Duration Fund Inc +DIAX 17.15 17.15 109700 Nuveen Dow 30SM Dynamic Overwrite Fund +WEX 122 120.615 629000 WEX Inc. +MNK 32.13 31.51 1966900 Mallinckrodt plc +MNP 15.45 15.44 14800 Western Asset Municipal Partners Fund, Inc. +MNR 16.73 16.66 335200 Monmouth Real Estate Investment Corporation +CWH 42.41 42.36 489900 Camping World Holdings, Inc. +DVMT 81.15 80.81 924900 Dell Technologies Inc. +RJF 85.82 84.05 548900 Raymond James Financial, Inc. +CWT 41.75 41.75 71900 California Water Service Group Holding +STAG 28.02 27.88 249100 Stag Industrial, Inc. +HSC 21.75 21.1 349400 Harsco Corporation +STAY 20.85 20.63 1350200 Extended Stay America, Inc. +CADE 22.73 22.44 56200 Cadence Bancorporation +WFC 54 53.12 18614700 Wells Fargo & Company +HST 19.39 19.26 3869000 Host Hotels & Resorts, Inc. +HSY 110.77 110 559400 Hershey Company (The) +EGIF 16.91 16.85 12500 Eagle Growth and Income Opportunities Fund +MOD 20.6 20.05 301800 Modine Manufacturing Company +WFT 3.9 3.82 15373900 Weatherford International plc +MOH 60.49 60.3 1583200 Molina Healthcare Inc +MON 122.25 121.995 2635600 Monsanto Company +INXN 51.96 51.35 255600 InterXion Holding N.V. +MOS 21.77 20.89 4800000 Mosaic Company (The) +CXE 5.21 5.19 103200 Colonial High Income Municipal Trust +MOV 27.7 27.55 135800 Movado Group Inc. +CXH 9.96 9.925 6900 Colonial Investment Grade Municipal Trust +CXO 133.29 131.84 854400 Concho Resources Inc. +CXP 21.71 21.69 297500 Columbia Property Trust, Inc. +CXW 25.7 25.55 1878700 CoreCivic, Inc. +AZRE 14.69 14.69 7300 Azure Power Global Limited +HTA 29.62 29.62 875700 Healthcare Trust of America, Inc. +HTD 25.8 25.76 110000 John Hancock Tax Advantaged Dividend Income Fund +HTH 26.4 25.53 230200 Hilltop Holdings Inc. +CSLT 4.25 4.2 205800 Castlight Health, inc. +HTY 9.23 9.1 65500 John Hancock Tax-Advantaged Global Shareholder Yield Fund +WGL 85.46 85.45 146900 WGL Holdings Inc +HTZ 25.55 25.33 2158900 Hertz Global Holdings, Inc +WGO 44.1 43.275 497000 Winnebago Industries, Inc. +MPA 14.33 14.33 25900 Blackrock MuniYield Pennsylvania Quality Fund +WGP 39.46 39.13 219000 Western Gas Equity Partners, LP +MPC 55.74 55.73 3017900 Marathon Petroleum Corporation +MPO 14.55 14.55 76400 MIDSTATES PETROLEUM COMPANY, INC. +CYD 23.8 23.27 47000 China Yuchai International Limited +ROYT 1.54 1.48 95300 Pacific Coast Oil Trust +MPV 15.05 14.7 24200 Barings Participation Investors +NMFC 14.4 14.15 265900 New Mountain Finance Corporation +MPW 13.1 13.08 1961900 Medical Properties Trust, Inc. +CYH 5.94 5.81 6782800 Community Health Systems, Inc. +MPX 14.75 14.75 41700 Marine Products Corporation +CIG.C 2.46 2.46 100 Comp En De Mn Cemig ADS +AMGP 19.69 19.6 163300 Antero Midstream GP LP +CYS 8.72 8.68 480300 CYS Investments, Inc. +RLH 8.75 8.525 53900 Red Lion Hotels Corporation +RLI 57.94 57.305 173000 RLI Corp. +YEXT 12.38 12.05 259200 Yext, Inc. +RLJ 22.31 22.12 868200 RLJ Lodging Trust +ARCH 71.12 71.12 408000 Arch Coal, Inc. +ARCO 10 9.85 237700 Arcos Dorados Holdings Inc. +HUM 239.4 237.67 1691900 Humana Inc. +VALE 10.41 10.22 24116400 VALE S.A. +HUN 28.96 28.875 3767200 Huntsman Corporation +CIVI 18.35 18.1 42800 Civitas Solutions, Inc. +WHG 67.5 67.5 20100 Westwood Holdings Group Inc +JILL 4.9 4.79 779100 J. Jill, Inc. +ARCX 16.65 16.64 38400 Arc Logistic Partners LP +WHR 176.67 174.73 798900 Whirlpool Corporation +EAB 24.96 24.96 1200 Entergy Arkansas, Inc. +EAE 24.95 24.95 400 Entergy Arkansas, Inc. +EAI 24.79 24.75 65800 Entergy Arkansas, Inc. +MQT 13.23 13.21 20600 Blackrock MuniYield Quality Fund II, Inc. +EAT 31 30.85 2894700 Brinker International, Inc. +MQY 15.59 15.55 28400 Blackrock MuniYield Quality Fund, Inc. +RMD 77.75 77.51 280700 ResMed Inc. +HCHC 5.3 5.17 148300 HC2 Holdings, Inc. +CZZ 9.11 9.015 893800 Cosan Limited +ARDC 16.47 16.3 91900 Ares Dynamic Credit Allocation Fund, Inc. +RMP 21.4 21.19 125000 Rice Midstream Partners LP +RMT 9.42 9.36 104700 Royce Micro-Cap Trust, Inc. +VSTO 20.77 20.63 425600 Vista Outdoor Inc. +WIA 11.53 11.51 46000 Western Asset/Claymore U.S. Treasury Inflation Prot Secs Fd +HVT 23.6 23.6 66200 Haverty Furniture Companies, Inc. +EQCO 25.02 25.01 16300 Equity Commonwealth +MRC 18.29 18 364900 MRC Global Inc. +WIT 5.5 5.28 3162000 Wipro Limited +WIW 11.24 11.22 59500 Western Asset/Claymore U.S Treasury Inflation Prot Secs Fd 2 +EBF 19.85 19.575 74100 Ennis, Inc. +MRK 63.21 62.88 7028400 Merck & Company, Inc. +MRO 13.85 13.65 9219100 Marathon Oil Corporation +AMID 13.8 13.3 162400 American Midstream Partners, LP +MRT 11.67 11.49 203600 MedEquities Realty Trust, Inc. +EBR 6.49 6.31 198600 Centrais Electricas Brasileiras S.A.- Eletrobras +EBS 40.5 39.99 171500 Emergent Biosolutions, Inc. +GMRE 9.13 9.03 62500 Global Medical REIT Inc. +ACRE 13.59 13.42 109500 Ares Commercial Real Estate Corporation +RNG 42.75 42.4 324500 Ringcentral, Inc. +SERV 46.55 46.23 628000 ServiceMaster Global Holdings, Inc. +RNP 21.87 21.62 79500 Cohen & Steers Reit and Preferred Income Fund Inc +RNR 138.01 137.6 332400 RenaissanceRe Holdings Ltd. +AZUL 26.85 26.47 135300 Azul S.A. +RLGY 32 31.98 1341600 Realogy Holdings Corp. +ARES 18.65 18.25 69600 Ares Management L.P. +MSA 78.89 78.89 150900 MSA Safety Incorporporated +MSB 22.9 22.32 96800 Mesabi Trust +ECA 11.3 11.25 10510800 Encana Corporation +MSD 10.14 10.12 16400 Morgan Stanley Emerging Markets Debt Fund, Inc. +SOJA 27.3 26.87 126200 Southern Company (The) +MSF 17.87 17.81 5900 Morgan Stanley Emerging Markets Fund, Inc. +SOJB 25.39 25.39 78100 Southern Company (The) +MSG 217.88 213.77 141400 MSG Networks Inc. +MSI 89.09 88.53 589000 Motorola Solutions, Inc. +MSL 12.6 12.6 74400 MidSouth Bancorp +MSM 76.1 75.96 1289300 MSC Industrial Direct Company, Inc. +ECL 134.14 132.34 1266600 Ecolab Inc. +MSP 11.89 11.89 8600 Madison Strategic Sector Premium Fund +ECR 2.35 2.28 566900 Eclipse Resources Corporation +ECT 2.45 2.41 47000 ECA Marcellus Trust I +ROG 139 137.62 129700 Rogers Corporation +ROK 186.4 185.97 432400 Rockwell Automation, Inc. +ROL 47.7 47.61 518500 Rollins, Inc. +ROP 251.4 250.37 511900 Roper Technologies, Inc. +HXL 59.35 58.43 570200 Hexcel Corporation +PAGP 21.14 21.11 1780500 Plains Group Holdings, L.P. +MTB 164.53 163.21 573800 M&T Bank Corporation +MTD 668.55 659.83 97400 Mettler-Toledo International, Inc. +MTG 13.11 12.99 4175200 MGIC Investment Corporation +EDD 8.07 8.07 134500 Morgan Stanley Emerging Markets Domestic Debt Fund, Inc. +MTH 47.75 47.4 162000 Meritage Corporation +EDF 16.77 16.77 60200 Stone Harbor Emerging Markets Income Fund +MTL 5.01 4.94 1972800 Mechel PAO +EDI 16.15 16.1 56300 Stone Harbor Emerging Markets Total Income Fund +MTN 216.59 216.21 272600 Vail Resorts, Inc. +EDN 42.98 41.91 127100 Empresa Distribuidora Y Comercializadora Norte S.A. (Edenor) +MTR 15.65 15.33 3900 Mesa Royalty Trust +GMTA 26.44 26.35 6900 GATX Corporation +MTT 22.82 22.77 17000 Western Asset Municipal Defined Opportunity Trust Inc +MTU 6.5 6.47 1871000 Mitsubishi UFJ Financial Group Inc +EDR 36.99 36.51 603300 Education Realty Trust Inc. +MTW 9.26 8.98 882100 Manitowoc Company, Inc. (The) +MTX 72.55 72.1 138000 Minerals Technologies Inc. +EDU 93.55 90.79 1263100 New Oriental Education & Technology Group, Inc. +MTZ 43.65 42.9 872700 MasTec, Inc. +RPM 51.7 51.585 455700 RPM International Inc. +HYB 9.89 9.84 34700 New America High Income Fund, Inc. (The) +RPT 13.34 13.34 235900 Ramco-Gershenson Properties Trust +HYH 43.47 43.24 229400 Halyard Health, Inc. +HYI 15.72 15.59 43300 Western Asset High Yield Defined Opportunity Fund Inc. +TRNO 36.84 36.61 181200 Terreno Realty Corporation +HYT 11.39 11.33 235600 Blackrock Corporate High Yield Fund, Inc. +WLH 23.37 23.11 201900 Lyon William Homes +WLK 84.42 83.62 471700 Westlake Chemical Corporation +WLL 5.26 5.03 20185200 Whiting Petroleum Corporation +MUA 15.7 15.53 52700 Blackrock MuniAssets Fund, Inc. +MUC 14.79 14.79 30900 Blackrock MuniHoldings California Quality Fund, Inc. +EEA 9.7 9.7 7000 European Equity Fund, Inc. (The) +MUE 14 14 53500 Blackrock MuniHoldings Quality Fund II, Inc. +MUH 15.41 15.33 8500 Blackrock MuniHoldings Fund II, Inc. +MUI 14.19 14.17 60500 Blackrock Muni Intermediate Duration Fund Inc +MUJ 14.62 14.58 24800 Blackrock MuniHoldings New Jersey Insured Fund, Inc. +MUR 25.99 25.51 1592100 Murphy Oil Corporation +MODN 14.45 14.1 39700 Model N, Inc. +EEP 15.37 15.24 598700 Enbridge Energy, L.P. +MUS 13.69 13.61 15000 Blackrock MuniHoldings Quality Fund, Inc. +EEQ 15.02 14.83 203300 Enbridge Energy Management LLC +MUX 2.03 2 1637200 McEwen Mining Inc. +EEX 22.74 22.25 62500 Emerald Expositions Events, Inc. +TECK 22.84 22.38 3626400 Teck Resources Ltd +CSRA 31.17 31.04 648200 CSRA Inc. +RQI 12.8 12.73 119900 Cohen & Steers Quality Income Realty Fund Inc +JAG 14 13.71 538300 Jagged Peak Energy Inc. +TMST 17.47 17.095 490800 Timken Steel Corporation +HCLP 8.8 8.6 1288800 Hi-Crush Partners LP +JAX 10.5 10.5 36000 J. Alexander's Holdings, Inc. +HZN 17.2 16.81 142600 Horizon Global Corporation +WMB 29.85 29.755 2661000 Williams Companies, Inc. (The) +HZO 16.3 16.25 163900 MarineMax, Inc. +WMC 10.63 10.58 149500 Western Asset Mortgage Capital Corporation +WMK 41.99 41.81 97100 Weis Markets, Inc. +EQGP 29.7 28.56 110300 EQT GP Holdings, LP +TROX 26.76 26.67 804500 Tronox Limited +MVC 10.25 10.17 49300 MVC Capital, Inc. +WMS 19.75 18.65 403500 Advanced Drainage Systems, Inc. +WMT 85.46 85.321 5851500 Wal-Mart Stores, Inc. +EFC 15.65 15.56 54900 Ellington Financial LLC +EFF 16.68 16.6 24200 Eaton vance Floating-Rate Income Plus Fund +EFL 9.91 9.9 32600 Eaton Vance Floating-Rate 2022 Target Term Trust +MVO 5.49 5.315 32800 MV Oil Trust +MVT 15.52 15.48 13800 Blackrock MuniVest Fund II, Inc. +EFR 14.8 14.76 57100 Eaton Vance Senior Floating-Rate Fund +EFT 14.67 14.61 43400 Eaton Vance Floating Rate Income Trust +EFX 109 108.48 1532000 Equifax, Inc. +RRC 19.51 19.4 4404500 Range Resources Corporation +RRD 9.72 9.64 912400 R.R. Donnelley & Sons Company +ELLI 86.65 86.325 432100 Ellie Mae, Inc. +JBL 28.47 28.47 2455400 Jabil Inc. +JBN 13.45 13.33 3000 Select Asset Inc. +BCEI 34.13 33.6 78500 Bonanza Creek Energy, Inc. +JBR 13.31 12.91 5000 Select Asset Inc. +JBT 103.65 102.905 120000 John Bean Technologies Corporation +SBBC 25.5 25.5 5900 Scorpio Tankers Inc. +WNC 22.49 21.98 462000 Wabash National Corporation +MWA 12.51 12.13 1114900 MUELLER WATER PRODUCTS +WNS 37.4 37.21 179400 WNS (Holdings) Limited +CALX 5.65 5.6 176600 Calix, Inc +EGF 13.6 13.53 2500 Blackrock Enhanced Government Fund, Inc +CNXC 14.9 14.9 17100 CNX Coal Resources LP +EGL 34.17 33.55 147200 Engility Holdings, Inc. +EGN 52.95 52.615 829900 Energen Corporation +EGO 2.15 2.14 2858800 Eldorado Gold Corporation +EGP 91.54 90.67 112500 EastGroup Properties, Inc. +TWLO 31.87 31.63 620800 Twilio Inc. +EGY 0.78 0.74 88800 Vaalco Energy Inc +RSG 62.75 62.675 1250400 Republic Services, Inc. +JCE 15.74 15.67 23600 Nuveen Core Equity Alpha Fund +JCI 41.62 41.095 3429200 Johnson Controls International plc +RSO 10.49 10.43 65300 Resource Capital Corp. +JCO 10.01 10 58400 Nuveen Credit Opportunities 2022 Target Term Fund +JCP 3.35 3.35 11073300 J.C. Penney Company, Inc. Holding Company +CSTM 11.05 10.975 545900 Constellium N.V. +RST 9.93 9.71 18800 Rosetta Stone +IPHI 35.75 35.58 931400 Inphi Corporation +WAAS 13.29 12.74 87900 AquaVenture Holdings Limited +WOR 44.31 44.06 369200 Worthington Industries, Inc. +MXE 10.85 10.71 15800 Mexico Equity and Income Fund, Inc. (The) +MXF 16.19 16.09 72100 Mexico Fund, Inc. (The) +WOW 14.18 14 354100 WideOpenWest, Inc. +MXL 23.14 23 574600 MaxLinear, Inc +EHI 10.37 10.33 51900 Western Asset Global High Income Fund Inc +PFGC 28.3 28.075 558600 Performance Food Group Company +EHT 10.15 10.11 28800 Eaton Vance High Income 2021 Target Term Trust +ZOES 11.87 11.87 363000 Zoe's Kitchen, Inc. +AMOV 17.78 17.62 8500 America Movil, S.A.B. de C.V. +JDD 12.87 12.83 25500 Nuveen Diversified Dividend and Income Fund +RTN 188.36 188.23 810300 Raytheon Company +WPC 69.6 69.05 185900 W.P. Carey Inc. +WPG 8.6 8.53 1520400 Washington Prime Group Inc. +CPAC 12.99 12.92 5600 Cementos Pacasmayo S.A.A. +WPM 19.88 19.75 1413000 Wheaton Precious Metals Corp. +MYC 15.53 15.45 13400 Blackrock MuniYield California Fund, Inc. +MYD 14.82 14.8 43300 Blackrock MuniYield Fund, Inc. +MYE 22.15 22.05 58900 Myers Industries, Inc. +MYF 15.52 15.51 25800 Blackrock MuniYield Investment Fund +WPX 10.97 10.78 4565800 WPX Energy, Inc. +MYI 14.36 14.35 75300 Blackrock MuniYield Quality Fund III, Inc. +EIG 47.2 46.15 56700 Employers Holdings Inc +MYJ 16.27 16.2 12600 Blackrock MuniYield New Jersey Fund, Inc. +WPZ 39.33 39.23 630800 Williams Partners LP +MYN 13.15 13.06 68600 Blackrock MuniYield New York Quality Fund, Inc. +JNPR 26 25.93 4045600 Juniper Networks, Inc. +EIX 77.58 76.93 3760700 Edison International +JEC 58.91 58.08 588900 Jacobs Engineering Group Inc. +TEGP 27.85 27.44 118600 Tallgrass Energy GP, LP +PSTG 16.18 16.16 939200 Pure Storage, Inc. +AA 48.65 47.42 3960600 Alcoa Corporation +AB 25 24.8 150700 AllianceBernstein Holding L.P. +AC 37.4 37.4 10000 Associated Capital Group, Inc. +GRUB 51.21 50.95 499400 GrubHub Inc. +JEQ 9.05 9.01 7000 Aberdeen Japan Equity Fund, Inc. +MTDR 26.68 26.34 1072300 Matador Resources Company +AG 7.02 6.935 2128700 First Majestic Silver Corp. +AI 12.71 12.66 294600 Arlington Asset Investment Corp +AL 44.53 43.66 1004200 Air Lease Corporation +AM 30.41 29.83 543300 Antero Midstream Partners LP +AN 44.01 43.88 765800 AutoNation, Inc. +AP 17.4 17.05 20400 Ampco-Pittsburgh Corporation +AR 19.62 19.55 2057900 Antero Resources Corporation +AT 2.5 2.5 126700 Atlantic Power Corporation +AU 9.36 9.22 2750100 AngloGold Ashanti Limited +OAK 47 46.725 81400 Oaktree Capital Group, LLC +MZF 13.67 13.67 8900 Managed Duration Investment Grade Municipal Fund +OAS 8.63 8.54 7421500 Oasis Petroleum Inc. +BA 256.49 256.26 2515800 Boeing Company (The) +BB 11.37 11.14 5184900 BlackBerry Limited +BC 57.63 57.03 590700 Brunswick Corporation +RVT 15.9 15.87 215900 Royce Value Trust, Inc. +JFR 11.68 11.63 137400 Nuveen Floating Rate Income Fund +ARMK 42.58 42.535 1525400 Aramark +BG 70.78 70.49 802100 Bunge Limited +BH 340.6 338.1 2600 Biglari Holdings Inc. +BK 54.76 53.76 3584400 Bank Of New York Mellon Corporation (The) +WRB 68.28 67.85 379700 W.R. Berkley Corporation +BP 39.02 38.64 5393300 BP p.l.c. +WRD 12.72 12.56 200500 WildHorse Resource Development Corporation +TRTN 37.37 36.69 317900 Triton International Limited +WRE 33.67 33.32 169000 Washington Real Estate Investment Trust +BR 83.1 82.53 256500 Broadridge Financial Solutions, Inc. +BT 18.1 18.05 615400 BT Group plc +OBE 1.04 1.01 1517200 Obsidian Energy Ltd. +CAPL 26 26 46400 CrossAmerica Partners LP +WRI 32.18 32.08 555800 Weingarten Realty Investors +BW 4.28 4.15 1388600 Babcock +WRK 59.08 59.01 1562700 Westrock Company +BX 33.25 33.08 1914500 The Blackstone Group L.P. +BY 20.57 20.35 201300 Byline Bancorp, Inc. +TRTX 19.89 19.68 59500 TPG RE Finance Trust, Inc. +PANW 148.99 148.18 1069000 Palo Alto Networks, Inc. +GWRE 77.92 77.08 418500 Guidewire Software, Inc. +EVHC 41.76 40.95 1719300 Envision Healthcare Corporation +AMRC 7.75 7.65 46300 Ameresco, Inc. +NWHM 11.32 11.12 58200 New Home Company Inc. (The) +JGH 17.31 17.31 61100 Nuveen Global High Income Fund +STNG 3.65 3.64 3230200 Scorpio Tankers Inc. +ARNC 27 26.77 2191400 Arconic Inc. +CB 150.06 149.06 1250600 D/B/A Chubb Limited New +CC 57.05 56.8 1568600 Chemours Company (The) +RWT 16.66 16.54 233200 Redwood Trust, Inc. +CE 107.1 101.88 1749900 Celanese Corporation +CF 36.9 36.47 4643500 CF Industries Holdings, Inc. +CI 185.39 185.28 2278900 Cigna Corporation +CJ 28.91 28.26 573300 C +CL 75.5 74.62 3217600 Colgate-Palmolive Company +CM 89.67 89.17 578000 Canadian Imperial Bank of Commerce +CO 10.77 10.76 200600 China Cord Blood Corporation +CP 167.83 166.92 805900 Canadian Pacific Railway Limited +FBHS 66.32 65.92 662800 Fortune Brands Home & Security, Inc. +CR 82.25 81.85 333600 Crane Company +SBGL 4.75 4.725 2164100 Sibanye Gold Limited +CS 15.97 15.91 4602700 Credit Suisse Group +CW 113.29 112.71 388000 Curtiss-Wright Corporation +CX 7.85 7.85 33973500 Cemex S.A.B. de C.V. +WSM 50.15 50.07 1500800 Williams-Sonoma, Inc. +WSO 159.5 159.19 193000 Watsco, Inc. +OCN 3.64 3.64 1562700 Ocwen Financial Corporation +WSR 13.65 13.44 711500 Whitestone REIT +WST 92.51 89.77 2153900 West Pharmaceutical Services, Inc. +ELC 24.73 24.73 19000 Entergy Louisiana, Inc. +ELF 21.22 21.02 350800 e.l.f. Beauty, Inc. +ELJ 25.24 25.07 2300 Entergy Louisiana, Inc. +ELP 8.81 8.505 594200 Companhia Paranaense de Energia (COPEL) +ELS 87 86.58 410300 Equity Lifestyle Properties, Inc. +ELU 24.87 24.83 1500 Entergy Louisiana, Inc. +ELY 14.02 14 497100 Callaway Golf Company +BURL 88.45 87.6 673500 Burlington Stores, Inc. +JHA 9.97 9.96 80300 Nuveen High Income 2020 Target Term Fund +JHB 10.11 10.07 58400 Nuveen High Income November 2021 Target Term Fund +JHD 10.05 10.04 60700 Nuveen High Income December 2019 Target Term Fund +JHG 35 34.8 448900 Janus Henderson Group plc +JHI 18.15 18.1 3500 John Hancock Investors Trust +RXN 25.79 25.59 3015400 Rexnord Corporation +AROC 12.5 12 302900 Archrock, Inc. +STON 5.95 5.93 329200 StoneMor Partners L.P. +DB 16.72 16.69 3342900 Deutsche Bank AG +DE 127.78 127.78 1777100 Deere & Company +STOR 25.72 25.64 1626200 STORE Capital Corporation +JHS 14.76 14.76 15200 John Hancock Income Securities Trust +DF 10.56 10.43 664700 Dean Foods Company +DG 82.15 81.74 1367000 Dollar General Corporation +OCIP 7.1 7 1500 OCI Partners LP +JHX 14.17 14.17 16700 James Hardie Industries plc. +DK 26.55 26.06 756000 Delek US Holdings, Inc. +JHY 10.03 10.03 32200 Nuveen High Income 2020 Target Term Fund +DL 8 7.53 160000 China Distance Education Holdings Limited +DM 32.6 32.05 86400 Dominion Energy Midstream Partners, LP +DO 15.51 15.07 2419300 Diamond Offshore Drilling, Inc. +DQ 31.45 30.21 236400 DAQO New Energy Corp. +ODC 42.27 41.805 16400 Oil-Dri Corporation Of America +DS 3.69 3.685 176900 Drive Shack Inc. +WTI 3.09 2.99 1743800 W&T Offshore, Inc. +DX 7.34 7.31 214500 Dynex Capital, Inc. +WTM 866.78 866.51 25900 White Mountains Insurance Group, Ltd. +DY 82.52 82.52 228900 Dycom Industries, Inc. +BHGE 33.64 33.3 4636800 Baker Hughes, a GE company +CARS 26.84 26.11 1155400 Cars.com Inc. +WTR 34.85 34.85 264200 Aqua America, Inc. +WTS 67.65 66.85 107900 Watts Water Technologies, Inc. +EMD 15.68 15.65 108800 Western Asset Emerging Markets Debt Fund Inc +WTW 46.6 45.8 837700 Weight Watchers International Inc +EME 70.31 68.83 196300 EMCOR Group, Inc. +EMF 17.2 17.11 34900 Templeton Emerging Markets Fund +EMN 87.6 86.58 2031000 Eastman Chemical Company +EMO 11.78 11.66 81900 ClearBridge Energy MLP Opportunity Fund Inc. +EMP 24.76 24.71 25700 Entergy Mississippi, Inc. +WNRL 24.7 24.65 120800 Western Refining Logistics, LP +EMR 65.57 65.3 3794400 Emerson Electric Company +OMAA 24.73 24.68 10000 OM Asset Management plc +RYB 30.7 28.56 443100 RYB Education, Inc. +OMAM 15.32 15.07 164700 OM Asset Management plc +RYI 9.85 9.05 286800 Ryerson Holding Corporation +RYN 29.8 29.68 341300 Rayonier Inc. +EC 9.85 9.76 1484600 Ecopetrol S.A. +ED 83.02 82.66 1144400 Consolidated Edison Inc +EE 56.85 56.65 363900 El Paso Electric Company +PSXP 52.69 51 174500 Phillips 66 Partners LP +EL 111.01 110.04 1238900 Estee Lauder Companies, Inc. (The) +WAGE 63.95 63.75 238000 WageWorks, Inc. +OEC 23.75 23.025 323800 Orion Engineered Carbons S.A +ES 61.25 61.1 1393800 Eversource Energy +EV 51.5 50.76 501500 Eaton Vance Corporation +EW 108.41 108.225 951400 Edwards Lifesciences Corporation +ENB 41.48 41.03 1568800 Enbridge Inc +ENJ 24.98 24.91 2500 Entergy New Orleans, Inc. +ENO 25.78 25.78 19000 Entergy New Orleans, Inc. +TAC 5.85 5.85 15900 TransAlta Corporation +ENR 47.79 46.06 1163000 Energizer Holdings, Inc. +ENS 68 67.46 399800 Enersys +ENV 53.8 53 236400 Envestnet, Inc +CUBE 26.12 26.04 756100 CubeSmart +TAL 35.97 34.81 3231300 TAL Education Group +ENZ 10.3 9.91 355700 Enzo Biochem, Inc. +RZA 28.13 28.13 34700 Reinsurance Group of America, Incorporated +RZB 28.71 28.22 34000 Reinsurance Group of America, Incorporated +CUBI 33.1 32.42 174500 Customers Bancorp, Inc +TAP 82.67 82.24 1354200 Molson Coors Brewing Company +HMLP 19.35 19.175 93600 Hoegh LNG Partners LP +CUBS 26.1 25.99 1300 Customers Bancorp, Inc +FC 19.65 19.45 12100 Franklin Covey Company +FE 32.16 31.98 3881200 FirstEnergy Corporation +FF 15.45 15.22 43100 FutureFuel Corp. +FI 7.23 7.12 668600 Frank's International N.V. +FL 30.97 30.58 2922400 Foot Locker, Inc. +FN 36.83 36.45 246600 Fabrinet +FR 30.93 30.82 546400 First Industrial Realty Trust, Inc. +OFC 33.08 32.535 771600 Corporate Office Properties Trust +FT 7.28 7.26 37400 Franklin Universal Trust +IPOA 10.2 10.13 26800 Social Capital Hedosophia Holdings Corp. +OFG 8.4 8.2 143300 OFG Bancorp +CATO 13.23 13.08 169900 Cato Corporation (The) +EOD 6.29 6.2 516800 Wells Fargo Global Dividend Opportunity Fund +EOG 97.25 96.56 1695300 EOG Resources, Inc. +EOI 14.31 14.3 73200 Eaton Vance Enhance Equity Income Fund +EOS 15.26 15.23 63700 Eaton Vance Enhanced Equity Income Fund II +TWTR 18.31 18.11 8935400 Twitter, Inc. +EOT 23.43 23.22 40500 Eaton Vance Municipal Income Trust +TBI 23.4 23.15 132000 TrueBlue, Inc. +KDMN 3.35 3.31 215900 Kadmon Holdings, Inc. +GD 212.75 210.95 769900 General Dynamics Corporation +GE 23.22 23 58639000 General Electric Company +JKS 23.41 23.04 357900 JinkoSolar Holding Company Limited +GF 18.69 18.62 14500 New Germany Fund, Inc. (The) +GG 12.99 12.92 5405700 Goldcorp Inc. +GM 45.8 44.955 14700400 General Motors Company +WWE 22.6 22.48 326200 World Wrestling Entertainment, Inc. +GS 244.44 235.19 7088400 Goldman Sachs Group, Inc. (The) +OGE 36.71 36.62 585500 OGE Energy Corporation +WAIR 9.45 9.4 280700 Wesco Aircraft Holdings, Inc. +EPC 71.33 70.7 393800 Energizer Holdings, Inc. +OGS 74.42 73.95 145200 ONE Gas, Inc. +EPD 26.39 25.98 5188900 Enterprise Products Partners L.P. +WWW 27.91 27.79 487000 Wolverine World Wide, Inc. +EPE 2.87 2.76 398400 EP Energy Corporation +EPR 70.8 70.71 323600 EPR Properties +TCF 17.13 16.96 1777600 TCF Financial Corporation +CUDA 22.6 22.43 868500 Barracuda Networks, Inc. +TCI 27.85 27.85 900 Transcontinental Realty Investors, Inc. +TCO 50.16 50.16 315700 Taubman Centers, Inc. +DNOW 13.09 13.02 1091400 NOW Inc. +TCP 53.33 52.22 95300 TC PipeLines, LP +TCS 4.07 4.03 196200 Container Store (The) +SLCA 27.86 27.72 1982500 U.S. Silica Holdings, Inc. +JLL 131.32 130.13 300900 Jones Lang LaSalle Incorporated +ELVT 7.19 7.12 106600 Elevate Credit, Inc. +HD 164.22 161.51 4189100 Home Depot, Inc. (The) +HE 34.71 34.61 340100 Hawaiian Electric Industries, Inc. +JLS 25.85 25.7 62900 Nuveen Mortgage Opportunity Term Fund +HF 43 42.85 237400 HFF, Inc. +HI 39.2 38.675 413200 Hillenbrand Inc +HK 6.14 6.01 5754300 Halcon Resources Corporation +HL 5.18 5.04 3281400 Hecla Mining Company +HP 52.47 52.03 1187700 Helmerich & Payne, Inc. +HR 32.27 32.17 713600 Healthcare Realty Trust Incorporated +HT 19.13 18.87 458700 Hersha Hospitality Trust +OHI 31.68 31.51 1494400 Omega Healthcare Investors, Inc. +HY 77.89 77.57 78300 Hyster-Yale Materials Handling, Inc. +EQC 30.2 30.03 524300 Equity Commonwealth +EQM 74.72 73.51 171300 EQT Midstream Partners, LP +TDA 24.92 24.82 7600 Telephone and Data Systems, Inc. +TDC 32.93 32.035 1170000 Teradata Corporation +TDE 25.54 25.54 5900 Telephone and Data Systems, Inc. +EQR 67.06 66.51 1293500 Equity Residential +TDF 21.73 21.66 37100 Templeton Dragon Fund, Inc. +EQS 2.33 2.29 4100 Equus Total Return, Inc. +TDG 263.42 262.165 428700 Transdigm Group Incorporated +EQT 62.52 62.4 2440800 EQT Corporation +TDI 25.93 25.92 2600 Telephone and Data Systems, Inc. +TDJ 25.54 25.52 13700 Telephone and Data Systems, Inc. +TDS 28.61 28.37 289600 Telephone and Data Systems, Inc. +SLDA 25.9 25.9 500 Sutherland Asset Management Corporation +JMF 11.54 11.46 209400 Nuveen Energy MLP Total Return Fund +TDW 26.81 26.51 22300 Tidewater Inc. +TDY 162 161.11 81300 Teledyne Technologies Incorporated +JMM 7.55 7.55 5100 Nuveen Multi-Market Income Fund +JMP 5.55 5.43 21600 JMP Group LLC +JMT 24.6 24.46 20700 Nuven Mortgage Opportunity Term Fund 2 +IO 8.85 8.55 69900 Ion Geophysical Corporation +IP 57.7 57.7 1374300 International Paper Company +OIA 7.92 7.92 44100 Invesco Municipal Income Opportunities Trust +IR 90.63 90.21 1704900 Ingersoll-Rand plc (Ireland) +IT 123.74 122.05 681400 Gartner, Inc. +ORAN 16.29 16.245 242400 Orange +BHLB 39.15 38.7 111900 Berkshire Hills Bancorp, Inc. +IX 86.06 85.85 21600 Orix Corp Ads +OII 25.42 24.96 1208900 Oceaneering International, Inc. +WYN 109.96 109.39 653700 Wyndham Worldwide Corp +ERA 10.36 9.98 26300 Era Group, Inc. +OIS 24.85 23.95 501500 Oil States International, Inc. +ERF 8.87 8.72 1135100 Enerplus Corporation +ERJ 20.43 19.87 6343400 Embraer-Empresa Brasileira de Aeronautica +TEF 10.57 10.5 1131100 Telefonica SA +TEI 11.62 11.6 56100 Templeton Emerging Markets Income Fund, Inc. +TEL 88.05 87.38 883400 TE Connectivity Ltd. +TEN 62.58 61.55 419700 Tenneco Inc. +TEO 31.22 31.05 171100 Telecom Argentina Stet - France Telecom S.A. +TEP 48.09 47.15 137000 Tallgrass Energy Partners, LP +TER 38.7 38.47 1711600 Teradyne, Inc. +TEX 46.41 45.95 586100 Terex Corporation +JNJ 137.67 137.06 11717300 Johnson & Johnson +JE 5.85 5.73 130200 Just Energy Group, Inc. +SBNA 24.68 24.6 4500 Scorpio Tankers Inc. +WALA 25.91 25.77 31000 Western Alliance Bancorporation +JP 24.68 22.07 1324200 Jupai Holdings Limited +RICE 27.37 27.3 3280800 Rice Energy Inc. +ESE 60.75 59.95 62100 ESCO Technologies Inc. +ESL 93.1 92.65 72100 Esterline Technologies Corporation +ESS 260.49 260.07 158300 Essex Property Trust, Inc. +ESV 5.71 5.55 10280800 ENSCO plc +JOE 18.95 18.5 445900 St. Joe Company (The) +JOF 12.64 12.63 33800 Japan Smaller Capitalization Fund Inc +TFX 239.42 238.75 171100 Teleflex Incorporated +BCRH 15.95 15.3 83900 Blue Capital Reinsurance Holdings Ltd. +KB 50.36 50.1 71300 KB Financial Group Inc +KF 42.54 42.49 5500 Korea Fund, Inc. (The) +KL 12.95 12.95 509100 Kirkland Lake Gold Ltd. +KN 15.41 15.32 726600 Knowles Corporation +KO 46.53 46.31 7699300 Coca-Cola Company (The) +KR 20.41 20.25 16759000 Kroger Company (The) +KS 22.77 22.74 913700 KapStone Paper and Packaging Corporation +ORCL 48.82 48.71 14191300 Oracle Corporation +KT 14.77 14.43 1536800 KT Corporation +OKE 56.25 56.08 1400500 ONEOK, Inc. +KW 19.65 19.425 1037800 Kennedy-Wilson Holdings Inc. +SBOW 22.69 22.655 58300 SilverBow Resorces, Inc. +ETB 16.85 16.74 82900 Eaton Vance Tax-Managed Buy-Write Income Fund +ETE 17.91 17.68 3276500 Energy Transfer Equity, L.P. +ETG 17.4 17.32 84300 Eaton Vance Tax-Advantaged Global Dividend Income Fund +ETH 29.8 29.75 205800 Ethan Allen Interiors Inc. +ETJ 9.37 9.335 363900 Eaton Vance Risk-Managed Diversified Equity Income Fund +NOAH 40.05 38.96 401000 Noah Holdings Ltd. +ETM 11.6 11.4 387400 Entercom Communications Corporation +ETN 77.85 76.6 3535600 Eaton Corporation, PLC +ETO 25.07 24.98 29300 Eaton Vance Tax-Advantage Global Dividend Opp +ETP 18.13 18.05 4775100 Energy Transfer Partners, L.P. +PFSI 18.2 18.15 90500 PennyMac Financial Services, Inc. +ETR 83.45 83.39 1559800 Entergy Corporation +TGH 17.9 17.85 131500 Textainer Group Holdings Limited +TGI 31.35 31 498400 Triumph Group, Inc. +ETV 15.3 15.28 170000 Eaton Vance Corporation +ETW 11.85 11.81 283200 Eaton Vance Corporation +ETY 11.83 11.79 234600 Eaton Vance Tax-Managed Diversified Equity Income Fund +TGP 18.4 17.8 150000 Teekay LNG Partners L.P. +JPC 10.53 10.52 165000 Nuveen Preferred & Income Opportunities Fund +TGS 21.69 21.01 348700 Transportadora De Gas Sa Ord B +TGT 60.15 59.86 3285800 Target Corporation +STWD 21.66 21.64 1462900 STARWOOD PROPERTY TRUST, INC. +JPI 25.43 25.4 27200 Nuveen Preferred and Income Term Fund +JPM 98.04 97.32 10335600 J P Morgan Chase & Co +LB 41.2 40.93 2519100 L Brands, Inc. +LC 6.34 6.23 7183000 LendingClub Corporation +JPS 10.37 10.36 245700 Nuveen Preferred & Income Securities Fund +MTOR 26.29 25.82 1051000 Meritor, Inc. +JPT 25.26 25.26 21100 Nuveen Preferred and Income 2022 Term Fund +LH 149.46 148.6 527700 Laboratory Corporation of America Holdings +LL 34.51 34.26 888200 Lumber Liquidators Holdings, Inc +LM 37.98 37.46 1274400 Legg Mason, Inc. +LN 36.83 36.41 136200 LINE Corporation +LQ 18.17 18.11 920000 La Quinta Holdings Inc. +LW 50.55 49.91 1048700 Lamb Weston Holdings, Inc. +BRFS 14.06 13.82 1176500 BRF S.A. +OLN 35.39 34.76 1947800 Olin Corporation +OLP 25.05 25.05 18700 One Liberty Properties, Inc. +GOLF 17.76 17.67 136000 Acushnet Holdings Corp. +EVRI 7.98 7.88 611400 Everi Holdings Inc. +THC 12.96 12.77 6386800 Tenet Healthcare Corporation +THG 97.34 96.85 162400 The Hanover Insurance Group, Inc. +ENBL 15.65 15.54 53400 Enable Midstream Partners, LP +THO 130.48 129.34 737000 Thor Industries, Inc. +THQ 18.41 18.41 99100 Tekla Healthcare Opportunies Fund +THR 21.01 20.67 173100 Thermon Group Holdings, Inc. +JQC 8.46 8.43 188100 Nuveen Credit Strategies Income Fund +THS 68.6 67.85 417300 Treehouse Foods, Inc. +BAC 26.37 26.11 48644400 Bank of America Corporation +THW 14.42 14.41 103000 Tekla World Healthcare Fund +BAF 15.58 15.37 14300 BlackRock Income Investment Quality Trust +BAH 38.07 37.45 691200 Booz Allen Hamilton Holding Corporation +BAK 29.67 29.08 787000 Braskem S.A. +MA 146.33 145.53 3002400 Mastercard Incorporated +BAM 42.6 42.58 438600 Brookfield Asset Management Inc +MC 42.25 42.1 324000 Moelis & Company +IMAX 20.95 20.4 1212800 Imax Corporation +MD 42.37 41.6 1046600 Mednax, Inc +BAP 208.4 205.05 294500 Credicorp Ltd. +MG 20.715 20.335 29100 Mistras Group Inc +BAS 18.94 18.72 361900 Basic Energy Services, Inc. +GBAB 22.68 22.61 27000 Guggenheim Taxable Municipal Managed Duration Trst +PAYC 78.98 78.65 238200 Paycom Software, Inc. +LEN.B 47.2 47.03 8700 Lennar Corporation +BAX 63.59 63.33 2484300 Baxter International Inc. +MN 3.9 3.6 194100 Manning & Napier, Inc. +MO 65.1 64.81 7507900 Altria Group +OMC 76.41 74.96 5737400 Omnicom Group Inc. +MS 49.69 48.97 15535000 Morgan Stanley +MT 28.86 28.55 3789400 ArcelorMittal +OME 22.1 22.05 320800 Omega Protein Corporation +OMF 30.68 30.27 265000 OneMain Holdings, Inc. +MX 10.8 10.6 203200 MagnaChip Semiconductor Corporation +OMI 27.89 27.89 762800 Owens & Minor, Inc. +OMN 11.05 11 134400 OMNOVA Solutions Inc. +EVA 30.45 30.3 20200 Enviva Partners, LP +OMP 17.71 17.18 79100 Oasis Midstream Partners LP +EVC 5.35 5.25 217500 Entravision Communications Corporation +EVF 6.57 6.57 80300 Eaton Vance Senior Income Trust +EVG 14.23 14.23 28500 Eaton Vance Short Diversified Income Fund +EVH 16.1 15.75 1425700 Evolent Health, Inc +EVN 12.86 12.82 54300 Eaton Vance Municipal Income Trust +EVR 76.5 75.75 664400 Evercore Inc. +TIF 94.71 94.175 1664100 Tiffany & Co. +EVT 22.42 22.405 98700 Eaton Vance Tax Advantaged Dividend Income Fund +BBD 11.49 11.32 5473100 Banco Bradesco Sa +BBF 14.82 14.72 42400 BlackRock Municipal Income Investment Trust +JRI 17.91 17.85 93200 Nuveen Real Asset Income and Growth Fund +BBG 4.21 4.15 1679200 Bill Barrett Corporation +BBK 15.47 15.44 20500 Blackrock Municipal Bond Trust +BBL 37.82 37.33 1108300 BHP Billiton plc +JRO 11.77 11.75 72900 Nuveen Floating Rate Income Opportuntiy Fund +NC 37.2 34.96 27600 NACCO Industries, Inc. +BBN 23.53 23.43 68300 BalckRock Taxable Municipal Bond Trust +NE 4.05 4.03 5846100 Noble Corporation +JRS 11.22 11.2 64200 Nuveen Real Estate Fund +NI 26.33 26.225 1720400 NiSource, Inc +BBT 47.19 46.49 3007800 BB&T Corporation +BBU 29.23 29.16 35000 Brookfield Business Partners L.P. +NL 11.05 10.9 131800 NL Industries, Inc. +BBW 8.6 8.2 154000 Build-A-Bear Workshop, Inc. +NM 1.87 1.78 673400 Navios Maritime Holdings Inc. +BBX 7.36 7.28 68400 BBX Capital Corporation +BBY 54.72 54.17 3662300 Best Buy Co., Inc. +NP 87.1 86 39400 Neenah Paper, Inc. +NQ 3.5 3.42 198100 NQ Mobile Inc. +NR 9.75 9.55 229900 Newpark Resources, Inc. +NS 37.19 35.46 872200 Nustar Energy L.P. +NX 22.6 22.3 120000 Quanex Building Products Corporation +EVTC 15.1 14.9 460200 Evertec, Inc. +JSD 17.38 17.35 13700 Nuveen Short Duration Credit Opportunities Fund +BCC 34.9 34.65 254200 Boise Cascade, L.L.C. +BCE 47.1 46.95 714100 BCE, Inc. +TJX 71.12 71.06 2605000 TJX Companies, Inc. (The) +BCH 93.81 92.65 24300 Banco De Chile +OA 133.25 132.89 493100 Orbital ATK, Inc. +MTRN 43 42.35 40500 Materion Corporation +OC 79.73 79.1 744100 Owens Corning Inc +BCO 84.75 84.45 359300 Brink's Company (The) +BCR 323.1 322.73 280400 C.R. Bard, Inc. +OI 25.66 25.34 647400 Owens-Illinois, Inc. +BCS 10.11 10.07 1825000 Barclays PLC +BCX 8.93 8.9 214600 BlackRock Resources +OR 12.96 12.61 512500 Osisko Gold Royalties Ltd +EXC 39.56 39.22 4238700 Exelon Corporation +EXD 11.79 11.69 34700 Eaton Vance Tax-Advantaged Bond +EXG 9.5 9.47 619800 Eaton Vance Tax-Managed Global Diversified Equity Income Fund +EXK 2.39 2.32 1577900 Endeavour Silver Corporation +TKC 9.54 9.465 574200 Turkcell Iletisim Hizmetleri AS +EXP 108.75 108.67 439300 Eagle Materials Inc +EXR 81.73 81.4 854400 Extra Space Storage Inc +TKF 9.51 9.46 14100 Turkish Investment Fund, Inc. (The) +TEVA 14.75 14.58 14505600 Teva Pharmaceutical Industries Limited +GOOS 20.7 20.37 436900 Canada Goose Holdings Inc. +JTA 13.68 13.6 44500 Nuveen Tax-Advantaged Total Return Strategy Fund +TKR 49.85 49.4 431300 Timken Company (The) +JTD 16.95 16.871 45200 Nuveen Tax-Advantaged Dividend Growth Fund +BDC 84.81 84.3 106900 Belden Inc +CULP 31.65 31 16700 Culp, Inc. +BDJ 9.05 9.01 477000 Blackrock Enhanced Equity Dividend Trust +PB 64.42 63.27 538700 Prosperity Bancshares, Inc. +BDN 17.99 17.9 1056700 Brandywine Realty Trust +YGE 2.33 2.31 19800 Yingli Green Energy Holding Company Limited +PE 26.75 26.47 3613900 Parsley Energy, Inc. +PF 57.22 56.73 527000 Pinnacle Foods, Inc. +PG 93.04 92.4 5316000 Procter & Gamble Company (The) +PH 180.9 180.66 606800 Parker-Hannifin Corporation +PK 28.71 28.47 1054900 Park Hotels & Resorts Inc. +PM 113.12 112.43 3997600 Philip Morris International Inc +BDX 200.85 200.08 956400 Becton, Dickinson and Company +PN 1.5 1.34 500500 Patriot National, Inc. +CBS.A 58.01 57.06 23500 CBS Corporation +PQ 1.94 1.78 106500 Petroquest Energy Inc +ZYME 8.78 8.78 1900 Zymeworks Inc. +PX 141.58 140.72 632900 Praxair, Inc. +OPP 19.39 19.15 56600 RiverNorth/DoubleLine Strategic Opportunity Fund, Inc. +MYOV 14.325 13.53 31900 Myovant Sciences Ltd. +OPY 18.05 17.7 12000 Oppenheimer Holdings, Inc. +IHIT 10.06 10.04 38800 Invesco High Income 2023 Target Term Fund +TLI 10.9 10.84 26800 Western Asset Corporate Loan Fund Inc +TLK 32.06 32.01 451300 PT Telekomunikasi Indonesia, Tbk +LVLT 54.56 53.39 7042400 Level 3 Communications, Inc. +TLP 43.14 42.75 27300 TransMontaigne Partners L.P. +BEL 13.8 13.7 281200 Belmond Ltd. +BEN 44.76 44.29 1424900 Franklin Resources, Inc. +BEP 34.8 34.8 98600 Brookfield Renewable Partners L.P. +GAB 6.53 6.53 195200 Gabelli Equity Trust, Inc. (The) +GAM 36.18 36.18 31200 General American Investors, Inc. +EZT 25.95 25.95 4200 Entergy Texas Inc +WUBA 68.66 67.53 672100 58.com Inc. +DFIN 21.53 21.42 118600 Donnelley Financial Solutions, Inc. +KNOP 23.75 23.55 17800 KNOT Offshore Partners LP +TMK 82.1 81.59 433700 Torchmark Corporation +TMO 190.51 186.64 1893900 Thermo Fisher Scientific Inc +BFK 14.16 14.16 36700 BlackRock Municipal Income Trust +RA 24.17 24.01 178200 Brookfield Real Assets Income Fund Inc. +BFO 15.05 15.01 3600 Blackrock Florida Municipal 2020 Term Trust +RE 239.19 235.16 439700 Everest Re Group, Ltd. +RF 14.96 14.75 8543500 Regions Financial Corporation +BFR 21.81 21.6 266700 BBVA Banco Frances S.A. +RH 79.42 78.5 671900 RH +BFS 64.73 63.82 27600 Saul Centers, Inc. +RL 85.88 85.81 887100 Ralph Lauren Corporation +HRTG 15.48 15.41 361500 Heritage Insurance Holdings, Inc. +RM 24.29 23.83 39500 Regional Management Corp. +BFZ 14.52 14.47 71100 BlackRock California Municipal Income Trust +ORA 63.19 63.09 126400 Ormat Technologies, Inc. +ORC 10.46 10.38 640600 Orchid Island Capital, Inc. +RS 74.87 74.79 329000 Reliance Steel & Aluminum Co. +RT 2.36 2.36 4656400 Ruby Tuesday, Inc. +ORI 19.81 19.515 1459300 Old Republic International Corporation +RY 79.32 79.29 941300 Royal Bank Of Canada +ORN 7.24 7.05 125900 Orion Group Holdings, Inc. +GBL 29.49 29.42 14700 Gamco Investors, Inc. +GBX 50.9 49.9 312600 Greenbrier Companies, Inc. (The) +CHCT 27.39 27.37 115500 Community Healthcare Trust Incorporated +TNC 69.6 68.65 44000 Tennant Company +TNH 80.4 79.4 16600 Terra Nitrogen Company, L.P. +TNK 1.68 1.64 776000 Teekay Tankers Ltd. +TNP 4.66 4.65 517700 Tsakos Energy Navigation Ltd +BGB 16.12 16.02 113000 Blackstone / GSO Strategic Credit Fund +BGC 21.9 21.6 2652300 General Cable Corporation +RNGR 14.48 13.75 39700 Ranger Energy Services, Inc. +PUMP 14.53 14.385 930900 ProPetro Holding Corp. +BGG 22.85 21.85 680400 Briggs & Stratton Corporation +ATEN 7.63 7.56 306300 A10 Networks, Inc. +BGH 20.72 20.67 43000 Babson Global Short Duration High Yield Fund +JWN 40.34 40.1 3992900 Nordstrom, Inc. +SA 12.6 12.505 474800 Seabridge Gold, Inc. +SB 3.31 3.1 439700 Safe Bulkers, Inc +SC 15.45 15.24 1012100 Santander Consumer USA Holdings Inc. +SD 19.27 18.87 97000 SandRidge Energy, Inc. +SF 52.6 51.1 569500 Stifel Financial Corporation +FLOW 42.26 41.54 100600 SPX FLOW, Inc. +BGR 13.6 13.43 166000 BlackRock Energy and Resources Trust +BGS 32.4 32.1 568300 B&G Foods, Inc. +BGT 14.06 13.97 43300 Blackrock Global +SM 19.26 18.53 4221700 SM Energy Company +SN 4.35 4.28 1539500 Sanchez Energy Corporation +BGX 16.42 16.35 30700 Blackstone GSO Long Short Credit Income Fund +SO 51.07 50.73 3691300 Southern Company (The) +BGY 6.64 6.595 272100 BLACKROCK INTERNATIONAL, LTD. +SQ 33.25 32.13 10864400 Square, Inc. +OSB 38.5 38.23 68700 Norbord Inc. +SR 75.85 75.8 96800 Spire Inc. +ST 49.27 48.97 472600 Sensata Technologies Holding N.V. +SU 33.63 33.5 4324700 Suncor Energy Inc. +OSG 2.56 2.51 544000 Overseas Shipholding Group, Inc. +OSK 87.55 86.755 488400 Oshkosh Corporation +GCH 12.26 12.21 10300 Aberdeen Greater China Fund, Inc. +GCI 9.53 9.37 440300 TEGNA Inc. +GCO 23.05 22.55 292900 Genesco Inc. +GCP 29.85 29.15 502100 GCP Applied Technologies Inc. +BHVN 31.77 31.42 120600 Biohaven Pharmaceutical Holding Company Ltd. +ENIA 10.87 10.79 682400 Enel Americas S.A. +GCV 5.75 5.6 25100 Gabelli Convertible and Income Securities Fund, Inc. (The) +ENIC 6.13 5.99 147900 Enel Chile S.A. +TOL 42.79 42.62 1002800 Toll Brothers Inc. +TOO 2.72 2.615 362200 Teekay Offshore Partners L.P. +TOT 54.32 53.96 681100 Total S.A. +BHE 35.55 35.15 246000 Benchmark Electronics, Inc. +BHK 14.07 14.05 134900 Blackrock Core Bond Trust +TD 56.76 56.68 1990100 Toronto Dominion Bank (The) +BHP 42.61 42.23 2326400 BHP Billiton Limited +TG 19.15 18.9 48700 Tredegar Corporation +TI 9.05 8.96 23500 Telecom Italia S.P.A. +TK 8.89 8.87 351700 Teekay Corporation +TM 123.32 123.18 107300 Toyota Motor Corp Ltd Ord +TR 37.2 36.75 74700 Tootsie Roll Industries, Inc. +TS 27.13 26.94 1436400 Tenaris S.A. +TU 35.93 35.86 297600 TELUS Corporation +TV 23.25 23.1 1201800 Grupo Televisa S.A. +TX 31.7 30.66 382300 Ternium S.A. +TY 26 25.9 36800 Tri Continental Corporation +GDI 26.9 26.78 545300 Gardner Denver Holdings, Inc. +GDL 10.29 10.23 15800 The GDL Fund +GDO 18.5 18.39 37500 Western Asset Global Corporate Defined Opportunity Fund Inc. +JW.A 53.15 52.55 252500 John Wiley & Sons, Inc. +GDV 22.67 22.61 134300 Gabelli Dividend +JW.B 52.74 52.74 100 John Wiley & Sons, Inc. +TPB 18.72 18.56 14400 Turning Point Brands, Inc. +TPC 27.95 27.45 214200 Tutor Perini Corporation +TPH 14.72 14.65 1204200 TRI Pointe Group, Inc. +TPL 425 411.27 13100 Texas Pacific Land Trust +ATGE 35.95 35.4 513300 Adtalem Global Education Inc. +BID 50.49 49.77 322300 Sotheby's +TPX 65.57 64.73 685400 Tempur Sealy International, Inc. +BIF 10.55 10.5 228200 USLIFE Income Fund, Inc. +BIG 51.47 51.27 431700 Big Lots, Inc. +TPZ 21.49 21.01 17800 Tortoise Power and Energy Infrastructure Fund, Inc +UA 14.97 14.85 2169100 Under Armour, Inc. +BIO 221.79 216.31 308900 Bio-Rad Laboratories, Inc. +UE 25.08 24.98 407800 Urban Edge Properties +BIP 43.68 43.5 287100 Brookfield Infrastructure Partners LP +DSXN 25.4 25.33 1500 Diana Shipping inc. +BIT 18.61 18.45 216300 BlackRock Multi-Sector Income Trust +UL 59.53 59.23 961300 Unilever PLC +UN 60.94 60.71 1813600 Unilever NV +GEB 25.07 25.05 66900 General Electric Company +GEF 56.88 56.11 198900 Greif Bros. Corporation +GEH 25.45 25.42 20000 General Electric Capital Corporation +IRET 6.28 6.26 377200 Investors Real Estate Trust +GEK 25.45 25.42 35800 General Electric Capital Corporation +GEL 24.05 24.01 645600 Genesis Energy, L.P. +GEO 25.89 25.67 1857200 Geo Group Inc (The) +OUT 24.52 24.165 507600 OUTFRONT Media Inc. +GER 6.73 6.53 417600 Goldman Sachs MLP Energy Renaissance Fund +GES 15.96 15.905 836200 Guess?, Inc. +AEUA 38.3 37.43 6400 Anadarko Petroleum Corporation +LAD 114.65 114.17 185300 Lithia Motors, Inc. +ATHM 60.36 57.91 897200 Autohome Inc. +NETS 11.97 11.13 168000 Netshoes (Cayman) Limited +LAZ 45.97 45.53 341400 Lazard Ltd. +BEDU 28.05 26 635000 Bright Scholar Education Holdings Limited +VC 124.74 123.19 184000 Visteon Corporation +VG 8.25 8.06 930600 Vonage Holdings Corp. +JCAP 21.31 21.06 84600 Jernigan Capital, Inc. +BJZ 15.02 15.02 2500 Blackrock California Municipal 2018 Term Trust +VR 51.39 50.77 1235800 Validus Holdings, Ltd. +GFA 9.05 8.91 121800 Gafisa SA +NYCB 12.82 12.68 2835200 New York Community Bancorp, Inc. +GFF 22.25 21.9 48300 Griffon Corporation +VZ 48.09 47.87 14842800 Verizon Communications Inc. +GFI 4.09 4.075 5707500 Gold Fields Limited +CHGG 16.05 15.55 949200 Chegg, Inc. +ENLC 16.75 16.55 407100 EnLink Midstream, LLC +GFY 17.21 17.17 6600 Western Asset Variable Rate Strategic Fund Inc. +TRC 19.48 18.95 150000 Tejon Ranch Co +ENLK 16.28 16 335000 EnLink Midstream Partners, LP +TRI 47.65 47.65 1605300 Thomson Reuters Corp +TRK 22.85 22.67 46700 Speedway Motorsports, Inc. +TRN 34.03 33.72 766000 Trinity Industries, Inc. +TRP 50.04 49.86 903100 TransCanada Corporation +TRQ 3.35 3.3 1784700 Turquoise Hill Resources Ltd. +SLRA 25.6 25.58 7000 Solar Capital Ltd. +AKO.A 26 26 4600 Embotelladora Andina S.A. +TRU 49.3 48.99 1256900 TransUnion +AKO.B 29.44 29.25 21000 Embotelladora Andina S.A. +TRV 128.44 127.5 1808200 The Travelers Companies, Inc. +BKD 10.15 10.11 2033600 Brookdale Senior Living Inc. +CMCM 8.49 8.28 562400 Cheetah Mobile Inc. +BKE 15.4 15.35 246000 Buckle, Inc. (The) +VCRA 29.4 29.01 98900 Vocera Communications, Inc. +BKH 67.59 67.34 171800 Black Hills Corporation +BKI 46.9 45.75 883900 Black Knight, Inc. +BKK 15.52 15.46 47900 Blackrock Municipal 2020 Term Trust +AJRD 33.18 32.72 1341500 Aerojet Rocketdyne Holdings, Inc. +WD 55.1 54.59 102700 Walker & Dunlop, Inc. +BKN 15.04 14.99 45100 BlackRock Investment Quality Municipal Trust Inc. (The) +WF 46.44 45.32 19000 Woori Bank +WG 3.27 3.15 124700 Willbros Group, Inc. +BKS 7.35 7.2 973100 Barnes & Noble, Inc. +BKT 6.23 6.23 113600 BlackRock Income Trust Inc. (The) +WK 22.35 22.1 93400 Workiva Inc. +BKU 34.4 34.01 870000 BankUnited, Inc. +WM 76.6 76.545 1793500 Waste Management, Inc. +WR 52.07 52.01 996300 Westar Energy, Inc. +GGB 3.56 3.52 4809500 Gerdau S.A. +WU 19.77 19.68 3401400 Western Union Company (The) +ABBV 91.09 90.95 5280400 AbbVie Inc. +WY 34.95 34.82 1649500 Weyerhaeuser Company +GGG 127.25 125.04 295500 Graco Inc. +GGM 23.25 22.94 35900 Guggenheim Credit Allocation Fund +GGP 21.37 21.36 2514300 GGP Inc. +SQNS 1.9 1.82 492100 Sequans Communications S.A. +GGT 9.52 9.43 35700 Gabelli Multi-Media Trust Inc. (The) +NOMD 14.9 14.78 378800 Nomad Foods Limited +GGZ 13.4 13.34 127400 Gabelli Global Small and Mid Cap Value Trust (The) +TSE 71.1 70.55 500400 Trinseo S.A. +TSI 5.75 5.69 40300 TCW Strategic Income Fund, Inc. +LCI 23.45 23.05 1408000 Lannett Co Inc +TSM 40.83 40.54 7582700 Taiwan Semiconductor Manufacturing Company Ltd. +TSN 70.32 70.3 1655100 Tyson Foods, Inc. +LCM 8.72 8.68 23500 Advent/Claymore Enhanced Growth & Income Fund +TSQ 10.39 10.12 43600 Townsquare Media, Inc. +TSS 67.65 67.05 598500 Total System Services, Inc. +TSU 19.04 18.83 697300 TIM Participacoes S.A. +BLD 62.92 62.92 272700 TopBuild Corp. +BLH 14.95 14.95 4000 Blackrock New York Municipal 2018 Term Trust +BLK 477.22 472.795 431700 BlackRock, Inc. +BLL 42.12 41.81 1384400 Ball Corporation +DATA 78.41 78.36 371100 Tableau Software, Inc. +XL 41.77 41.315 4586900 XL Group Ltd. +BLW 16.2 16.15 99000 Citigroup Inc. +BLX 29.35 28.9 81200 Banco Latinoamericano de Comercio Exterior, S.A. +GHC 553.65 547 12200 Graham Holdings Company +OXM 63.21 63.21 71700 Oxford Industries, Inc. +GHL 17.1 17 1028100 Greenhill & Co., Inc. +GHM 22 21.37 19200 Graham Corporation +OXY 64.83 64.23 3092500 Occidental Petroleum Corporation +GHY 14.91 14.795 269400 Prudential Global Short Duration High Yield Fund, Inc. +TTC 62.24 61.93 593000 Toro Company (The) +TTF 10.96 10.85 13800 Thai Fund, Inc. (The) +MVCB 25.3 25.3 100 MVC Capital, Inc. +TTI 2.64 2.62 435000 Tetra Technologies, Inc. +LDF 12.19 12.19 3000 Latin American Discovery Fund, Inc. (The) +TTM 32.96 32.45 1252900 Tata Motors Ltd +QUAD 22.81 22.12 190100 Quad Graphics, Inc +LDL 58.45 57.35 55700 Lydall, Inc. +TTP 18.99 18.73 31900 Tortoise Pipeline & Energy Fund, Inc. +BMA 127.13 125.04 237500 Macro Bank Inc. +LDP 26.83 26.72 63100 Cohen & Steers Limited Duration Preferred and Income Fund, Inc +NEWM 15.52 15.4 359800 New Media Investment Group Inc. +SLTB 25.14 25 1400 Scorpio Bulkers Inc. +LDR 67.3 67.2 375600 Landauer, Inc. +BME 36.67 36.56 26300 Blackrock Health Sciences Trust +NEWR 49.96 49.72 200600 New Relic, Inc. +BMI 42.05 42 932700 Badger Meter, Inc. +ATKR 19.38 19.14 147400 Atkore International Group Inc. +BMO 77.91 77.71 844400 Bank Of Montreal +YPF 22.86 22.56 416500 YPF Sociedad Anonima +FDEU 19.4 19.26 166900 First Trust Dynamic Europe Equity Income Fund +BMS 46.1 46.01 435400 Bemis Company, Inc. +BMY 63.63 63.41 5030700 Bristol-Myers Squibb Company +GIB 52.65 52.65 149700 CGI Group, Inc. +BRSS 34.45 34 53100 Global Brass and Copper Holdings, Inc. +TI.A 7.25 7.16 5400 Telecom Italia S.P.A. +GIL 30.98 30.93 282300 Gildan Activewear, Inc. +GIM 6.67 6.63 269000 Templeton Global Income Fund, Inc. +GIS 51.81 51.31 3049500 General Mills, Inc. +LEA 174.42 172.43 420400 Lear Corporation +LEE 2.4 2.3 63500 Lee Enterprises, Incorporated +TOWR 27.9 27.25 103300 Tower International, Inc. +LEG 47.76 47.61 565300 Leggett & Platt, Incorporated +TUP 61.35 60.61 452400 Tupperware Brands Corporation +LEN 55.86 55.73 2213800 Lennar Corporation +LEO 8.84 8.84 62500 Dreyfus Strategic Municipals, Inc. +BNJ 15.59 15.58 5300 BlackRock New Jersey Municipal Income Trust +ZF 12.71 12.68 70100 Virtus Total Return Fund Inc. +BNS 64.41 64.21 461100 Bank of Nova Scotia (The) +BNY 15.06 15.05 9900 BlackRock New York Investment Quality Municipal Trust Inc. (Th +ZX 1.28 1.26 64000 China Zenix Auto International Limited +ABEV 6.82 6.76 10489500 Ambev S.A. +RACE 115.95 115.35 444200 Ferrari N.V. +OZM 3.32 3.21 147600 Och-Ziff Capital Management Group LLC +SGZA 25.31 25.3 5600 Selective Insurance Group, Inc. +GJR 21.24 21.24 200 Synthetic Fixed-Income Securities, Inc. +GJS 19.41 19.41 100 STRATS Trust +GJV 26.14 26.14 600 Synthetic Fixed-Income Securities, Inc. +CHKR 2.15 2.1 82400 Chesapeake Granite Wash Trust +TVC 25.47 25.37 4900 Tennessee Valley Authority +TVE 25.15 25.12 14100 Tennessee Valley Authority +LFC 15.5 15.42 277100 China Life Insurance Company Limited +BOE 13.73 13.65 145600 Blackrock Global +BOH 83.75 82.76 111300 Bank of Hawaii Corporation +YRD 51.35 50.6 678000 Yirendai Ltd. +LDOS 62 61.73 463800 Leidos Holdings, Inc. +BOX 20.08 20.02 2277600 Box, Inc. +CRCM 16.2 15.78 125900 Care.com, Inc. +KAMN 55.39 55.19 77300 Kaman Corporation +FICO 147.57 146.32 107400 Fair Isaac Corporation +TWI 9.67 9.5 92700 Titan International, Inc. +LGI 17.18 17.08 19900 Lazard Global Total Return and Income Fund +TWN 21.47 21.35 15500 Taiwan Fund, Inc. (The) +TWO 10.15 10.11 1848400 Two Harbors Investments Corp +TWX 101.2 101.05 3855300 Time Warner Inc. +BPI 9.6 9.41 161400 Bridgepoint Education, Inc. +BPK 14.99 14.99 20800 Blackrock Municipal 2018 Term Trust +BPL 54.9 53.04 1018500 Buckeye Partners L.P. +BPT 21 19.8 304300 BP Prudhoe Bay Royalty Trust +BPY 24.26 24.17 115700 Brookfield Property Partners L.P. +QCP 15.7 15.7 431500 Quality Care Properties, Inc. +CHMI 18.65 18.52 110000 Cherry Hill Mortgage Investment Corporation +GLP 18.4 18.05 50700 Global Partners LP +GLT 19.27 18.98 69300 Glatfelter +GLW 29.78 29.65 3728900 Corning Incorporated +AGCO 71.75 71.28 887800 AGCO Corporation +LHO 30.21 30.01 998300 LaSalle Hotel Properties +TXT 53.19 52.81 1520200 Textron Inc. +HESM 21.38 20.55 120200 Hess Midstream Partners LP +HTFA 25.49 25.47 19500 Horizon Technology Finance Corporation +BQH 15.28 15.15 2600 Blackrock New York Municipal Bond Trust +AJXA 25.75 25.74 1100 Great Ajax Corp. +ESNT 42.64 42.19 1061600 Essent Group Ltd. +GME 19.46 19.35 1251000 Gamestop Corporation +GMS 35.04 34.8 295500 GMS Inc. +DPLO 20.05 19.885 457800 Diplomat Pharmacy, Inc. +GMZ 9.22 9.11 84900 Goldman Sachs MLP Income Opportunities Fund +TYG 28.15 27.92 171700 Tortoise Energy Infrastructure Corporation +LII 181.2 179.18 360200 Lennox International, Inc. +TYL 171.5 169.5 187600 Tyler Technologies, Inc. +BRC 38.4 38.05 111600 Brady Corporation +HTGC 12.75 12.61 332500 Hercules Capital, Inc. +BRO 49.39 48.68 945600 Brown & Brown, Inc. +BRS 9.59 9.16 487800 Bristow Group Inc +BRT 10.27 10.08 7200 BRT Apartments Corp. +YUM 76.11 76.035 1410700 Yum! Brands, Inc. +NBHC 36.02 35.36 49300 National Bank Holdings Corporation +BRX 18.95 18.88 1820500 Brixmor Property Group Inc. +HTGX 25.46 25.37 3700 Hercules Capital, Inc. +QEP 8.81 8.505 4918900 QEP Resources, Inc. +GNC 7.8 7.735 1602200 GNC Holdings, Inc. +GNE 6.3 6.26 18600 Genie Energy Ltd. +GNK 12.5 12.2 39400 Genco Shipping & Trading Limited Warrants Expiring 12/31/2021 +GNL 22.22 22.06 187900 Global Net Lease, Inc. +VAC 124.55 124.13 121000 Marriot Vacations Worldwide Corporation +GNT 7.05 6.98 60600 GAMCO Natural Resources, Gold & Income Tust +GNW 3.88 3.81 2022600 Genworth Financial Inc +VAR 102.77 102.35 461400 Varian Medical Systems, Inc. +BSD 14.21 14.13 28400 BlackRock Strategic Municipal Trust Inc. (The) +SNAP 16.29 16.05 15090900 Snap Inc. +BSE 13.44 13.44 4600 Blackrock New York Municipal Income Quality Trust +BSL 17.55 17.49 32800 Blackstone GSO Senior Floating Rate Term Fund +BSM 17.23 17.11 51000 Black Stone Minerals, L.P. +BST 25.67 25.48 79700 BlackRock Science and Technology Trust +BSX 29.13 29.08 4725900 Boston Scientific Corporation +NYLD 18.9 18.7 405100 NRG Yield, Inc. +GOF 21.13 21.11 146400 Guggenheim Strategic Opportunities Fund +GOL 22.68 22.2 135400 Gol Linhas Aereas Inteligentes S.A. +VBF 19.65 19.51 28000 Invesco Bond Fund +HOME 21.84 21.62 136500 At Home Group Inc. +BTA 12.31 12.3 20300 BlackRock Long-Term Municipal Advantage Trust +BTE 2.71 2.65 1013400 Baytex Energy Corp +HEI.A 75.25 74.4 56300 Heico Corporation +XFLT 11 10.95 28200 XAI Octagon Floating Rate & Alternative Income Term Trust +BTI 64.28 63.9 1856000 British American Tobacco p.l.c. +BTO 37.58 37.47 62700 John Hancock Financial Opportunities Fund +BTT 22.64 22.63 73000 BlackRock Municipal Target Term Trust Inc. (The) +BTU 28.86 28.855 639000 Peabody Energy Corporation +BTZ 13.47 13.47 116900 BlackRock Credit Allocation Income Trust +RSPP 34 33.74 1820600 RSP Permian, Inc. +GPC 96.26 96.15 611900 Genuine Parts Company +GPI 69.31 68.98 146800 Group 1 Automotive, Inc. +GPK 14.21 14.14 1316800 Graphic Packaging Holding Company +GPM 8.71 8.71 278000 Guggenheim Enhanced Equity Income Fund +GPN 99.3 97.52 901900 Global Payments Inc. +GPS 27.2 26.25 7262500 Gap, Inc. (The) +TGNA 12.64 12.53 1638900 TEGNA Inc. +GPT 30.8 30.51 1003700 Gramercy Property Trust +ENVA 14.35 14.25 352500 Enova International, Inc. +GPX 30.4 30.15 26100 GP Strategies Corporation +VCO 36.56 36.31 4800 Vina Concha Y Toro +VCV 13.04 13.04 36400 Invesco California Value Municipal Income Trust +LLL 185.91 185.26 297700 L3 Technologies, Inc. +DUKH 25.25 25.22 17100 Duke Energy Corporation +BUD 125.19 125.075 864900 Anheuser-Busch Inbev SA +BUI 21.08 21.05 24400 BlackRock Utility and Infrastructure Trust +LLY 85.9 85.42 3643700 Eli Lilly and Company +QHC 4.75 4.63 113800 Quorum Health Corporation +SDLP 3.81 3.65 134900 Seadrill Partners LLC +ESRT 20.92 20.89 1910500 Empire State Realty Trust, Inc. +PRGO 87 86.055 1126400 Perrigo Company +LMT 318.86 317.02 741600 Lockheed Martin Corporation +VEDL 20.46 20.32 411000 Vedanta Limited +SNDR 24.09 23.84 1063300 Schneider National, Inc. +ATTO 11.6 11.6 26300 Atento S.A. +BVN 14.62 14.53 1707700 Buenaventura Mining Company Inc. +ALDW 11.54 11.42 73000 Alon USA Partners, LP +GRA 72.15 71.28 665400 W.R. Grace & Co. +GRC 32.65 32 27100 Gorman-Rupp Company (The) +VEC 32.98 32.295 69300 Vectrus, Inc. +NBLX 51.16 49.6 82600 Noble Midstream Partners LP +GRR 12.7 12.7 100 Asia Tigers Fund, Inc. (The) +CHSP 28.53 28.37 494200 Chesapeake Lodging Trust +GRX 10.2 10.13 97200 The Gabelli Healthcare & Wellness Trust +LNC 75.62 74.565 878100 Lincoln National Corporation +VER 8.26 8.16 14557500 VEREIT Inc. +LND 4.22 4.22 100 Brasilagro Cia Brasileira De Propriedades Agricolas +VET 34.54 34.42 133900 Vermilion Energy Inc. +BWXT 59.53 59.295 340000 BWX Technologies, Inc. +LNN 89.61 89.475 143000 Lindsay Corporation +BWA 52.11 51.86 1067000 BorgWarner Inc. +JMEI 2.83 2.82 2041300 Jumei International Holding Limited +FNFV 18.3 17.75 208300 Fidelity National Financial, Inc. +LNT 43.05 42.98 985000 Alliant Energy Corporation +BWG 13.22 13.15 86500 Legg Mason BW Global Income Opportunities Fund Inc. +ESTE 10.36 10.35 245500 Earthstone Energy, Inc. +ATUS 24.47 24.33 603800 Altice USA, Inc. +BWP 14.83 14.61 960900 Boardwalk Pipeline Partners L.P. +VEEV 58.8 58.8 1054500 Veeva Systems Inc. +ALEX 45.47 45.34 143900 Alexander & Baldwin Holdings, Inc. +GSH 29.3 29.18 500 Guangshen Railway Company Limited +GSK 40.77 40.59 4775200 GlaxoSmithKline PLC +GSL 1.4 1.4 176100 Global Ship Lease, Inc. +VFC 64.19 64.04 1707000 V.F. Corporation +MKC.V 98.75 98.75 100 McCormick & Company, Incorporated +WPXP 50.1 50.1 29600 WPX Energy, Inc. +EXPR 5.97 5.95 1520500 Express, Inc. +LXFR 12.5 12.41 193200 Luxfer Holdings PLC +LXFT 48.45 48.1 125100 Luxoft Holding, Inc. +BXC 9.3 8.145 395500 BlueLinx Holdings Inc. +LOR 11.49 11.42 21300 Lazard World Dividend & Income Fund, Inc. +GLOB 41.29 41.29 88300 Globant S.A. +BXE 2.48 2.42 33100 Bellatrix Exploration Ltd +LOW 81.26 80.23 5517600 Lowe's Companies, Inc. +GLOG 17.85 17.7 314400 GasLog LP. +FSCE 25.07 25.04 1100 Fifth Street Finance Corp. +BXP 128.16 127.93 506800 Boston Properties, Inc. +BERY 59.04 58.79 691600 Berry Global Group, Inc. +GLOP 23.9 23.55 97400 GasLog Partners LP +BXS 32.25 31.55 607000 BancorpSouth, Inc. +LITB 2.37 2.25 44600 LightInTheBox Holding Co., Ltd. +GTN 15.4 15 400500 Gray Television, Inc. +LADR 13.85 13.74 555300 Ladder Capital Corp +GTS 23.55 23.42 141300 Triple-S Management Corporation +GTT 32.6 32.25 301700 GTT Communications, Inc. +VGI 18.69 18.41 76000 Virtus Global Multi-Sector Income Fund +EPAM 91.1 90.65 172800 EPAM Systems, Inc. +GTY 29.53 29.18 106500 Getty Realty Corporation +VGM 13.43 13.41 48200 Invesco Trust for Investment Grade Municipals +VGR 20.7 20.59 411200 Vector Group Ltd. +LPG 7.9 7.7 90000 Dorian LPG Ltd. +LPI 12.54 12.04 3597900 Laredo Petroleum, Inc. +LPL 12.86 12.71 328900 LG Display Co., Ltd. +BYD 27.84 27.8 977100 Boyd Gaming Corporation +LPT 41.72 41.37 970700 Liberty Property Trust +LPX 28.25 28.224 1098900 Louisiana-Pacific Corporation +BYM 14.85 14.82 29400 Blackrock Municipal Income Quality Trust +GUT 7.1 7.07 63600 Gabelli Utility Trust (The) +NYRT 7.74 7.69 811800 New York REIT, Inc. +VHI 3.13 3.06 513800 Valhi, Inc. +RPAI 13.24 13.19 2127400 Retail Properties of America, Inc. +DAC 1.5 1.45 82100 Danaos Corporation +CMRE 6.15 6.15 766100 Costamare Inc. +DAL 53.48 52.66 6547500 Delta Air Lines, Inc. +DAN 29.03 28.84 1080900 Dana Incorporated +DAR 16.66 16.6 699200 Darling Ingredients Inc. +BZH 19.49 19.29 474200 Beazer Homes USA, Inc. +BETR 7.42 7.3 205000 Amplify Snack Brands, inc. +PRLB 80.65 80.175 81700 Proto Labs, Inc. +GVA 58.83 58.09 213700 Granite Construction Incorporated +VRTV 32.3 32.05 40200 Veritiv Corporation +VIV 16.02 15.94 802100 Telefonica Brasil S.A. +DBD 22.4 22.175 614100 Diebold Nixdorf Incorporated +LRN 17.4 17.33 125600 K12 Inc +DBL 23.76 23.33 74400 DoubleLine Opportunistic Credit Fund +QUOT 16.95 16.7 434000 Quotient Technology Inc. +SDRL 0.29 0.28 3437900 Seadrill Limited +ABRN 25.64 25.64 3700 Arbor Realty Trust +GWB 41.02 40.27 181900 Great Western Bancorp, Inc. +VJET 4.95 4.86 74000 voxeljet AG +GWR 71.15 70.87 245500 Genesee & Wyoming, Inc. +EXTN 31.91 31.44 148400 Exterran Corporation +GWW 188.475 186.43 6078200 W.W. Grainger, Inc. +AVAL 8.94 8.9 233900 Grupo Aval Acciones y Valores S.A. +LSI 81.04 80.96 413400 Life Storage, Inc. +DCI 46.84 46.69 307100 Donaldson Company, Inc. +DCM 23.43 23.41 124600 NTT DOCOMO, Inc +DCO 33.01 32.65 126700 Ducommun Incorporated +DCP 34.88 34.3 286800 DCP Midstream LP +DCT 59.37 58.57 504800 DCT Industrial Trust Inc +EARN 14.35 14.35 44100 Ellington Residential Mortgage REIT +GXP 31.86 31.755 869800 Great Plains Energy Inc +VKQ 12.61 12.58 86900 Invesco Municipal Trust +LTC 47.08 47 75200 LTC Properties, Inc. +DDC 14.17 14.16 561700 Dominion Diamond Corporation +DDD 11.62 11.45 2905100 3D Systems Corporation +DDE 1.01 0.99 19700 Dover Downs Gaming & Entertainment Inc +DDF 10.72 10.7 4900 Delaware Investments Dividend & Income Fund, Inc. +LTM 13.82 13.52 455600 LATAM Airlines Group S.A. +TLRA 4.77 4.73 301200 Telaria, Inc. +DDR 8.65 8.65 5360300 DDR Corp. +DDS 51.12 50.81 308400 Dillard's, Inc. +DDT 25.52 25.48 8900 Dillard's, Inc. +TLRD 13.32 13.26 722500 Tailored Brands, Inc. +MDLQ 25.35 25.28 3900 Medley LLC +MDLX 24.77 24.77 5800 Medley LLC +GYB 22.9 22.9 2500 CABCO Series 2004-101 Trust +MDLY 6 5.95 6400 Medley Management Inc. +GYC 23.55 23.55 700 Corporate Asset Backed Corp CABCO +GDDY 43.89 43.4 660100 GoDaddy Inc. +OOMA 10.2 10.2 25800 Ooma, Inc. +MOG.A 88.23 86.82 77600 Moog Inc. +VLO 77.59 77.27 2358400 Valero Energy Corporation +MOG.B 87.65 87.65 200 Moog Inc. +VLP 42.57 42.04 65700 Valero Energy Partners LP +LUB 2.47 2.43 37300 Luby's, Inc. +DEA 20.74 20.66 120000 Easterly Government Properties, Inc. +SXCP 17.7 17.7 93600 SunCoke Energy Partners, L.P. +VLT 14.99 14.97 12500 Invesco High Income Trust II +VLY 11.97 11.75 1461200 Valley National Bancorp +LUK 25.75 25.53 1725200 Leucadia National Corporation +BOOT 7.75 7.66 198200 Boot Barn Holdings, Inc. +DEI 40.83 40.815 505600 Douglas Emmett, Inc. +DEL 89.22 88.07 25500 Deltic Timber Corporation +ALLE 88.11 86.82 768100 Allegion plc +DEO 135 134.34 301600 Diageo plc +LUV 59 58.64 3673700 Southwest Airlines Company +JMLP 8.81 8.67 24500 Nuveen All Cap Energy MLP Opportunities Fund +DEX 11.79 11.74 21200 Delaware Enhanced Global Dividend +FSIC 8.4 8.25 677400 FS Investment Corporation +IAE 11.03 10.91 36200 Voya Asia Pacific High Dividend Equity Income Fund +ALLY 24.65 24.37 2397300 Ally Financial Inc. +AGM.A 76.34 76.34 100 Federal Agricultural Mortgage Corporation +IAG 5.91 5.52 16326600 Iamgold Corporation +BBDO 11.61 10.76 300 Banco Bradesco Sa +VMC 116.89 116.63 613300 Vulcan Materials Company +GZT 9.77 9.73 1400 Gazit-Globe Ltd. +VMI 159.4 158.3 81800 Valmont Industries, Inc. +VMO 12.9 12.88 115400 Invesco Municipal Opportunity Trust +VMW 115.12 115 1844100 Vmware, Inc. +LVS 62.6 62.065 1901400 Las Vegas Sands Corp. +DFP 26.71 26.67 42000 Flaherty & Crumrine Dynamic Preferred and Income Fund Inc. +DFS 65.41 64.56 1680900 Discover Financial Services +RUBI 3.59 3.46 255500 The Rubicon Project, Inc. +IBA 60.1 59.21 11900 Industrias Bachoco, S.A. de C.V. +IBM 146.63 146.18 6372300 International Business Machines Corporation +IBN 8.41 8.31 6540700 ICICI Bank Limited +IBP 66.15 65.45 149900 Installed Building Products, Inc. +RATE 13.95 13.9 109400 Bankrate, Inc. +AGRO 10.63 10.35 391100 Adecoagro S.A. +VNO 78.64 78.18 704400 Vornado Realty Trust +LFGR 7.45 7.15 16900 Leaf Group Ltd. +ITCB 14.2 14.06 9100 Ita? CorpBanca +WMLP 3.2 3.1 3800 Westmoreland Resource Partners, LP +DGX 91.5 90.79 1393000 Quest Diagnostics Incorporated +ICB 18.18 18.18 6300 MS Income Securities, Inc. +ICD 3.64 3.52 61000 Independence Contract Drilling, Inc. +ICE 68.6 67.98 4417700 Intercontinental Exchange Inc. +ICL 4.43 4.32 163300 Israel Chemicals Shs +QSR 66.77 66.77 1407300 Restaurant Brands International Inc. +VOC 3.65 3.64 19300 VOC Energy Trust +BORN 1.38 1.365 64000 China New Borun Corporation +DHF 3.5 3.49 81400 Dreyfus High Yield Strategies Fund +DHG 15.05 15.05 7800 DWS High Income Opportunities Fund, Inc. +DHI 41.38 40.99 2979900 D.R. Horton, Inc. +LXP 10.51 10.47 501900 Lexington Realty Trust +DHR 85.45 83.81 4838000 Danaher Corporation +LXU 7.55 7.54 235800 Lsb Industries Inc. +DHT 4.06 4.01 427400 DHT Holdings, Inc. +DHX 2.35 2.3 92400 DHI Group, Inc. +IDA 89.84 89.84 207600 IDACORP, Inc. +MSCA 25.88 25.67 2500 Main Street Capital Corporation +IDE 16.23 16.13 60100 Voya Infrastructure, Industrials and Materials Fund +QTM 5.83 5.82 104500 Quantum Corporation +MSCI 123.35 122.06 242400 MSCI Inc +QTS 53.3 53.22 308000 QTS Realty Trust, Inc. +IDT 13.59 13.3 163100 IDT Corporation +SITE 62.6 61.56 381000 SiteOne Landscape Supply, Inc. +VPG 24.5 23.75 22900 Vishay Precision Group, Inc. +BGCA 26 25.91 18800 BGC Partners, Inc. +LYB 97.89 97.45 1527100 LyondellBasell Industries NV +LYG 3.58 3.56 2542900 Lloyds Banking Group Plc +VPV 12.26 12.25 43900 Invesco Pennsylvania Value Municipal Income Trust +JMPB 25.51 25.51 2700 JMP Group LLC +JMPC 25.49 25.49 100 JMP Group LLC +DIN 43.64 43.27 267600 DineEquity, Inc +DIS 98.4 97.86 5942500 Walt Disney Company (The) +LYV 41.9 41.29 1606100 Live Nation Entertainment, Inc. +IEX 121.91 120.925 584800 IDEX Corporation +PRTY 11.95 11.8 864600 Party City Holdco Inc. +NAC 14.83 14.83 156800 Nuveen California Quality Municipal Income Fund +NAD 14.12 14.1 184800 Nuveen Quality Municipal Income Fund +LZB 27.3 27.1 403500 La-Z-Boy Incorporated +NAN 14.05 14.01 45700 Nuveen New York Quality Municipal Income Fund +NAO 1.42 1.36 294500 Nordic American Offshore Ltd +NAP 9 8.92 237800 Navios Maritime Midstream Partners LP +NAT 5.44 5.43 556500 Nordic American Tankers Limited +NAV 42.58 41.69 768100 Navistar International Corporation +NAZ 14.51 14.51 3400 Nuveen Arizona Quality Municipal Income Fund +NVGS 11.25 11.2 120300 Navigator Holdings Ltd. +IFF 149.59 148.47 208300 Internationa Flavors & Fragrances, Inc. +IFN 27.99 27.96 125200 India Fund, Inc. (The) +SAFE 18.32 18.16 79300 Safety, Income and Growth, Inc. +NBB 21.88 21.817 36600 Nuveen Build America Bond Fund +NBD 22.36 22.33 8300 Nuveen Build America Bond Opportunity Fund +NBL 27.92 27.66 4778100 Noble Energy Inc. +VRS 5.89 5.77 130000 Verso Corporation +RFTA 20.84 19.62 72200 RAIT Financial Trust +NBR 7.24 7.15 5821000 Nabors Industries Ltd. +VRX 13 12.62 10741300 Valeant Pharmaceuticals International, Inc. +DKL 31.45 30.6 16000 Delek Logistics Partners, L.P. +DKS 24.74 24.69 2202300 Dick's Sporting Goods Inc +DKT 26.37 26.27 120200 Deutsch Bk Contingent Cap Tr V +TVPT 15.78 15.68 561500 Travelport Worldwide Limited +CELP 8.3 8.075 4700 Cypress Energy Partners, L.P. +IGA 11.37 11.31 69200 Voya Global Advantage and Premium Opportunity Fund +IGD 8.07 8.03 287000 Voya Global Equity Dividend and Premium Opportunity Fund +TLYS 11.89 11.88 98600 Tilly's, Inc. +ITGR 54.35 53.75 98100 Integer Holdings Corporation +IGI 21.04 21.04 15600 Western Asset Investment Grade Defined Opportunity Trust Inc. +SSNI 16.19 16.175 1123100 Silver Spring Networks, Inc. +IGR 7.94 7.92 431400 CBRE Clarion Global Real Estate Income Fund +IGT 23.96 23.2 2840900 International Game Technology +NCA 10.6 10.57 35800 Nuveen California Municipal Value Fund, Inc. +NCB 17.75 17.52 3600 Nuveen California Municipal Value Fund 2 +VSH 20.95 20.9 1740300 Vishay Intertechnology, Inc. +VSI 5.35 5.15 611100 Vitamin Shoppe, Inc +NGVC 5.15 4.79 422500 Natural Grocers by Vitamin Cottage, Inc. +TIER 19.8 19.51 196000 TIER REIT, Inc. +NCI 16.93 16.86 125100 Navigant Consulting, Inc. +VSM 39.49 39.421 227300 Versum Materials, Inc. +CODI 18.25 18.05 203600 Compass Diversified Holdings +VST 19.03 18.85 1915800 Vistra Energy Corp. +DLB 59.69 59.01 156000 Dolby Laboratories +NCR 37.43 37.15 1014100 NCR Corporation +NCS 15.65 15.25 915100 NCI Building Systems, Inc. +NCV 7.13 7.1 217200 AllianzGI Convertible & Income Fund +NGVT 69.36 69.07 195900 Ingevity Corporation +NCZ 6.22 6.2 169300 AllianzGI Convertible & Income Fund II +DLR 121.58 121.46 1201900 Digital Realty Trust, Inc. +ALSN 37.54 37.3 1184600 Allison Transmission Holdings, Inc. +DLX 72.42 71.98 164800 Deluxe Corporation +IHC 28 27.5 35700 Independence Holding Company +IHD 9.49 9.44 49800 Voya Emerging Markets High Income Dividend Equity Fund +IHG 54.06 54.01 46100 Intercontinental Hotels Group +MSGN 20.8 20.65 857600 MSG Networks Inc. +VTA 11.9 11.86 164300 Invesco Credit Opportunities Fund +EBR.B 7.45 7.32 15200 Centrais Electricas Brasileiras S.A.- Eletrobras +VTN 13.73 13.73 19300 Invesco Trust for Investment Grade New York Municipal +VTR 63 62.58 1684800 Ventas, Inc. +NDP 13.12 13.01 62800 Tortoise Energy Independence Fund, Inc. +DMB 13.33 13.22 78900 Dreyfus Municipal Bond Infrastructure Fund, Inc. +DMO 26.15 26.14 49200 Western Asset Mortgage Defined Opportunity Fund Inc +CTAA 27.04 27.04 12600 Qwest Corporation +DCUD 51.5 51.17 9100 Dominion Energy, Inc. +ECCA 25.83 25.8 500 Eagle Point Credit Company Inc. +ECCB 26.49 26.49 400 Eagle Point Credit Company Inc. +NLSN 39.58 39.48 1898300 Nielsen N.V. +IID 7.79 7.75 25900 Voya International High Dividend Equity Income Fund +IIF 36.47 36.34 11200 Morgan Stanley India Investment Fund, Inc. +IIM 14.9 14.89 82500 Invesco Value Municipal Income Trust +ECCY 25.6 25.46 1200 Eagle Point Credit Company Inc. +SAIC 68.65 67.78 298700 SCIENCE APPLICATIONS INTERNATIONAL CORPORATION +ECCZ 25.36 25.36 3200 Eagle Point Credit Company Inc. diff --git a/lab12-code/text2bin b/lab12-code/text2bin new file mode 100755 index 0000000..a934f31 Binary files /dev/null and b/lab12-code/text2bin differ diff --git a/lab12-code/text2bin.c b/lab12-code/text2bin.c new file mode 100644 index 0000000..5a44ce9 --- /dev/null +++ b/lab12-code/text2bin.c @@ -0,0 +1,47 @@ +// Program to read a text version of stocks such as in stocks.txt and +// write it to a binary file. + +#include "header.h" + + +int main(int argc, char *argv[]){ + if(argc > 1 && strcmp("-h",argv[1])==1){ + printf("usage: %s stocks.txt out.dat\n",argv[0]); + printf(" cat stocks.txt | %s > out.dat\n",argv[0]); + return 0; + } + + FILE *in_file = stdin; // read from standard in by default + if(argc >= 2){ // if arg is given, read from named file + in_file = fopen(argv[1], "r"); + } + int out_fd = STDOUT_FILENO; // write to standard output by default + if(argc >= 3){ // or write to file if given as an argument + out_fd = open(argv[2],O_CREAT | O_WRONLY,S_IRUSR | S_IWUSR); + } + + int line_num = 0; + while(1){ // repeat reading text lines and writing binary + line_num++; + char line[MAXLINE]; + char *ret = fgets(line,MAXLINE,in_file); // get a line of text + if(ret == NULL || strlen(line)==0){ // check for end of input + break; + } + if(line_num==1){ // skip first line which should contain header + continue; + } + + stock_t stock = {}; // stock to be filled + str2stock(line, &stock, line_num); // fill stock from text info + write(out_fd, &stock, sizeof(stock_t)); // write binary version to a file + } + + if(argc >=2){ + fclose(in_file); + } + if(argc >= 3){ + close(out_fd); + } + return 0; +} diff --git a/lab12-code/text2bin.o b/lab12-code/text2bin.o new file mode 100644 index 0000000..c86df8a Binary files /dev/null and b/lab12-code/text2bin.o differ diff --git a/lab12-code/x.dat b/lab12-code/x.dat new file mode 100644 index 0000000..4ab671e Binary files /dev/null and b/lab12-code/x.dat differ diff --git a/notes/01-introduction-code.zip b/notes/01-introduction-code.zip new file mode 100644 index 0000000..ff34aa4 Binary files /dev/null and b/notes/01-introduction-code.zip differ diff --git a/notes/01-introduction-code/max_memory.c b/notes/01-introduction-code/max_memory.c new file mode 100644 index 0000000..44a643c --- /dev/null +++ b/notes/01-introduction-code/max_memory.c @@ -0,0 +1,28 @@ +// Test the total memory available in a single malloc by repeatedly +// increasing the limit of the request + +#include +#include + +int main(){ + long n = 1; // int cannot hold large enough numbes + void *mem = NULL; // Pointer to memory + while( (mem = malloc(n)) != NULL){ // allocate and check result + printf("%12ld bytes: Success\n",n); // %ld to print a long, %d for int + free(mem); // free last allocation + n *= 2; // double size of next request + } // + printf("%12ld bytes: Fail\n",n); // failed last allocation, no need to free + n /= 2; // back up one step for max success + + long kb = n / 1024; // sizes of allocations + long mb = kb / 1024; + long gb = mb / 1024; + + printf("\n"); + printf("%12ld b limit\n",n); // Output human readable sizes + printf("%12ld KB limit\n",kb); + printf("%12ld MB limit\n",mb); + printf("%12ld GB limit\n",gb); + return 0; // return 0 to indicate succesful completion +} diff --git a/notes/01-introduction-code/nums.txt b/notes/01-introduction-code/nums.txt new file mode 100644 index 0000000..535d2b0 --- /dev/null +++ b/notes/01-introduction-code/nums.txt @@ -0,0 +1,8 @@ +1 +2 +3 +4 +5 +6 +7 +8 diff --git a/notes/01-introduction-code/read_all_numbers_file.c b/notes/01-introduction-code/read_all_numbers_file.c new file mode 100644 index 0000000..ec111dc --- /dev/null +++ b/notes/01-introduction-code/read_all_numbers_file.c @@ -0,0 +1,32 @@ +// Simple demonstration of reading user input using a linked list with +// dynamic memory allocation. +#include +#include + +typedef struct int_node_struct { // Definition of a node + int data; // integer data + struct int_node_struct *next; // link to another node +} int_node; + +int_node* head = NULL; // global variable, front of list + +int main(int argc, char **argv){ + int x; + FILE *input = fopen(argv[1], "r"); // open input file named on command line + while(fscanf(input,"%d",&x) != EOF){ // read a number, check for end of input + int_node *new = malloc(sizeof(int_node)); // allocate space for a node + new->data = x; // set data, -> derefernces and sets + new->next = head; // point at previous front of list + head = new; // make this node the new front + } + int_node *ptr = head; // prepare to iterate through list + int i=0; + printf("\nEntire list\n"); + while(ptr != NULL){ // iterate until out of nodes + printf("list(%d) = %d\n",i,ptr->data); // print data for one node + ptr = ptr->next; // move pointer forward one node + i++; + } + fclose(input); // close the input file + return 0; // Should free list but program is ending +} // so memory will automatically return to system diff --git a/notes/01-introduction-code/read_all_numbers_user.c b/notes/01-introduction-code/read_all_numbers_user.c new file mode 100644 index 0000000..3fd8ed7 --- /dev/null +++ b/notes/01-introduction-code/read_all_numbers_user.c @@ -0,0 +1,31 @@ +// Simple demonstration of reading user input using a linked list with +// dynamic memory allocation. +#include +#include + +typedef struct int_node_struct { // Definition of a node + int data; // integer data + struct int_node_struct *next; // link to another node +} int_node; + +int_node* head = NULL; // global variable, front of list + +int main(int argc, char **argv){ + int x; + printf("Enter numbers; Ctrl-D to end input:\n"); + while(fscanf(stdin,"%d",&x) != EOF){ // read a number, check for end of input + int_node *new = malloc(sizeof(int_node)); // allocate space for a node + new->data = x; // set data, -> derefernces and sets + new->next = head; // point at previous front of list + head = new; // make this node the new front + } + int_node *ptr = head; // prepare to iterate through list + int i=0; + printf("\nEntire list\n"); + while(ptr != NULL){ // iterate until out of nodes + printf("list(%d) = %d\n",i,ptr->data); // print data for one node + ptr = ptr->next; // move pointer forward one node + i++; + } + return 0; // Should free list but program is ending +} // so memory will automatically return to system diff --git a/notes/01-introduction.pdf b/notes/01-introduction.pdf new file mode 100644 index 0000000..4fe398a Binary files /dev/null and b/notes/01-introduction.pdf differ diff --git a/notes/02-unix-basics.pdf b/notes/02-unix-basics.pdf new file mode 100644 index 0000000..61698ec Binary files /dev/null and b/notes/02-unix-basics.pdf differ diff --git a/notes/03-process-basics-code.zip b/notes/03-process-basics-code.zip new file mode 100644 index 0000000..f457d7b Binary files /dev/null and b/notes/03-process-basics-code.zip differ diff --git a/notes/03-process-basics-code/badmemory-comments.c b/notes/03-process-basics-code/badmemory-comments.c new file mode 100644 index 0000000..96203a0 --- /dev/null +++ b/notes/03-process-basics-code/badmemory-comments.c @@ -0,0 +1,30 @@ +// Includes some bad memory problems which are identified by valgrind +#include +#include +int main(int argc, char **argv){ + int i,j; + int k = i + j; + printf("Uninitialized memory\n"); + if(k <200){ + printf("%d\n",k); // Caught + } + + printf("Out of bounds on heap\n"); + int *ptr = malloc(sizeof(int)*4); + for(i=0; i<= 4; i++){ + ptr[i] = i*i; // Caught + printf("%d\n",ptr[i]); + } + + printf("Out of bounds on stack\n"); + int a[4]; + for(i=0; i<=(1<<3); i++){ // 1<<3 == 8, avoids compiler catch + a[i] = i; + printf("%d\n",a[i]); // Not caught + } + + int *ip = NULL; + printf("Last Num: %d\n",*ip); // Cause a crash + + return 0; +} diff --git a/notes/03-process-basics-code/badmemory.c b/notes/03-process-basics-code/badmemory.c new file mode 100644 index 0000000..ef7ea02 --- /dev/null +++ b/notes/03-process-basics-code/badmemory.c @@ -0,0 +1,22 @@ +#include +#include +int main(int argc, char **argv){ + int i,j; + int k = i + j; + if(k <200){ + printf("%d\n",k); + } + int *ptr = malloc(sizeof(int)*4); + for(i=0; i<= 4; i++){ + ptr[i] = i*i; + printf("%d\n",ptr[i]); + } + int a[4]; + for(i=0; i<=(1<<3); i++){ + a[i] = i; + printf("%d\n",a[i]); + } + int *ip = NULL; + printf("Last Num: %d\n",*ip); + return 0; +} diff --git a/notes/03-process-basics-code/environment_vars.c b/notes/03-process-basics-code/environment_vars.c new file mode 100644 index 0000000..c13d51d --- /dev/null +++ b/notes/03-process-basics-code/environment_vars.c @@ -0,0 +1,27 @@ +#include +#include + +int main(int argc, char *argv[]){ + + char *verbosity = getenv("ROCK"); + if(verbosity == NULL){ + printf("ROCK not set\n"); + } + else{ + printf("ROCK is %s\n",verbosity); + printf("Turning VOLUME to 11\n"); + int fail = setenv("VOLUME","11",1); + if(fail){ + printf("Couldn't change VOLUME\n"); + } + } + char *volume = getenv("VOLUME"); + if(volume == NULL){ + volume = "not set"; + } + printf("VOLUME is %s\n",volume); + return 0; +} + + + diff --git a/notes/03-process-basics-code/environment_vars.c~ b/notes/03-process-basics-code/environment_vars.c~ new file mode 100644 index 0000000..fa76cf7 --- /dev/null +++ b/notes/03-process-basics-code/environment_vars.c~ @@ -0,0 +1,18 @@ +#include + +int main(int argc, char *argv[]){ + + char *verbosity = getenv("VERBOSITY"); + if(verbosity == NULL){ + printf("VERBOSITY not set\n"); + return 0; + } + else{ + printf("VERBOSITY is %s\n\n",verbosity); + printf("Turning VOLUME to 11\n"); + int fail = setenv("VOLUME","11",0); + if(fail){ + printf("Couldn't change VOLUME + + + diff --git a/notes/03-process-basics-code/no_interruptions.c b/notes/03-process-basics-code/no_interruptions.c new file mode 100644 index 0000000..561cd72 --- /dev/null +++ b/notes/03-process-basics-code/no_interruptions.c @@ -0,0 +1,41 @@ +// A C program that does not terminate from an interrupt signal is sent +// Usually pressing Ctrl+C sends this to the foreground program +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGINT(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGINT, handle_SIGINT); + printf("\nNo SIGINT-erruptions allowed.\n"); + fflush(stdout); +} + +// Function run when a SIGTERM is sent to the program +void handle_SIGTERM(int sig_num) { + // Reset handler to catch SIGTERM next time. + signal(SIGTERM, handle_SIGTERM); + printf("\nTry to SIGTERM me? Piss off!\n"); + fflush(stdout); +} + +int main () { + // Set handling functions for programs + signal(SIGINT, handle_SIGINT); + signal(SIGTERM, handle_SIGTERM); + + /* Infinite loop */ + unsigned int count = 0; + while(1) { + if(count == 0){ + printf("Ma-na na-na!\n"); + } + count++; + } + return 0; +} diff --git a/notes/03-process-basics-code/overflow.c b/notes/03-process-basics-code/overflow.c new file mode 100644 index 0000000..6c64970 --- /dev/null +++ b/notes/03-process-basics-code/overflow.c @@ -0,0 +1,16 @@ +#include + +// This program traverses stuff that it really ought not to... + +int main(int argc, char *argv[]){ + char a[3] = {'A','B','C'}; + int i = 0; + while(1){ + printf("%c",a[i]); + i++; + if(i%40 == 0){ + printf("\n"); + } + } + return 0; +} diff --git a/notes/03-process-basics-code/overflow.c~ b/notes/03-process-basics-code/overflow.c~ new file mode 100644 index 0000000..c91219f --- /dev/null +++ b/notes/03-process-basics-code/overflow.c~ @@ -0,0 +1,9 @@ +#include + +int main(int argc, char *argv[]){ + char *a[3] = {'A','B','C'}; + for(int i=1; ; i++){ + printf("%c",a[i]); + if(i%40 == 0){ + printf("\n"); + } diff --git a/notes/03-process-basics-code/print13.c b/notes/03-process-basics-code/print13.c new file mode 100644 index 0000000..143d771 --- /dev/null +++ b/notes/03-process-basics-code/print13.c @@ -0,0 +1,7 @@ +// Prints 1st and 3rd command line arguments without check they are +// there. May kersplode if insufficient args are provided. +#include +int main(int argc, char *argv[]){ + printf("%s\n",argv[1]); + printf("%s\n",argv[3]); +} diff --git a/notes/03-process-basics-code/print_args.c b/notes/03-process-basics-code/print_args.c new file mode 100644 index 0000000..8c1ade9 --- /dev/null +++ b/notes/03-process-basics-code/print_args.c @@ -0,0 +1,11 @@ +// Print all the arguments in the argv array + +#include + +int main(int argc, char *argv[]){ + printf("%d args received\n",argc); + for(int i=0; i +#include +#include +#include + +int main(int argc, char* argv){ + + // char *child_argv[] = {"ls","-l","-ah",NULL}; // argument array to child, must end with NULL + // char *child_cmd = "ls"; // actual command to run, must be on path + + char *child_argv[] = {"./complain",NULL}; // alternative commands + char *child_cmd = "complain"; + + printf("I'm %d, and I really don't feel like '%s'ing\n", + getpid(),child_cmd); + printf("I have a solution\n"); + + pid_t child_pid = fork(); + + if(child_pid == 0){ + printf(" I'm %d My pa '%d' wants me to '%s'. This sucks.\n", + getpid(), getppid(), child_cmd); + execvp(child_cmd, child_argv); + printf(" I don't feel like myself anymore...\n"); // unreachable + } + else{ + int status; + wait(&status); // wait for child to finish, collect status + if(WIFEXITED(status)){ + int retval = WEXITSTATUS(status); // decode status to 0-255 + printf("Great, junior %d did that and told me '%d'\n", + child_pid, retval); + if(retval != 0){ // nonzero exit codes usually indicate failure + printf("That little punk gave me a non-zero return. I'm glad he's dead\n"); + } + } + } + return 0; +} + diff --git a/notes/04-making-processes-code/child-labor.c b/notes/04-making-processes-code/child-labor.c new file mode 100644 index 0000000..6bcbafe --- /dev/null +++ b/notes/04-making-processes-code/child-labor.c @@ -0,0 +1,33 @@ +// Demonstrate the basics of fork/exec to launch a child process to do +// "labor". +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"ls","-l","-ah",NULL}; // argument array to child, must end with NULL + char *child_cmd = "ls"; // actual command to run, must be on path + + printf("I'm %d, and I really don't feel like '%s'ing\n", + getpid(),child_cmd); // use of getpid() to get current PID + printf("I have a solution\n"); + + pid_t child_pid = fork(); // clone a child + + if(child_pid == 0){ // child will have a 0 here + printf(" I'm %d My pa '%d' wants me to '%s'. This sucks.\n", + getpid(), getppid(), child_cmd); // use of getpid() and getppid() + + execvp(child_cmd, child_argv); // replace running image with child_cmd + + printf(" I don't feel like myself anymore...\n"); // unreachable statement + } + else{ // parent will see nonzero in child_pid + printf("Great, junior %d is taking care of that\n", + child_pid); + } + return 0; +} + diff --git a/notes/04-making-processes-code/child-wait.c b/notes/04-making-processes-code/child-wait.c new file mode 100644 index 0000000..625765a --- /dev/null +++ b/notes/04-making-processes-code/child-wait.c @@ -0,0 +1,35 @@ +// fork/exec plus parent waits for child and sees their status + +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"ls","-l","-ah",NULL}; // argument array to child, must end with NULL + char *child_cmd = "ls"; // actual command to run, must be on path + + // char *child_argv[] = {"./complain",NULL}; // alternative commands + // char *child_cmd = "complain"; + + printf("I'm %d, and I really don't feel like '%s'ing\n", + getpid(),child_cmd); + printf("I have a solution\n"); + + pid_t child_pid = fork(); + + if(child_pid == 0){ + printf(" I'm %d My pa '%d' wants me to '%s'. This sucks.\n", + getpid(), getppid(), child_cmd); + execvp(child_cmd, child_argv); + printf(" I don't feel like myself anymore...\n"); // unreachable + } + else{ + int status; + wait(&status); // wait for child to finish, collect status + printf("Great, junior %d did that\n", child_pid); + } + return 0; +} + diff --git a/notes/04-making-processes-code/complain b/notes/04-making-processes-code/complain new file mode 100755 index 0000000..f6857b1 Binary files /dev/null and b/notes/04-making-processes-code/complain differ diff --git a/notes/04-making-processes-code/complain.c b/notes/04-making-processes-code/complain.c new file mode 100644 index 0000000..fd7ed81 --- /dev/null +++ b/notes/04-making-processes-code/complain.c @@ -0,0 +1,9 @@ +// Simple program that can be run with the the child-labor or +// child-wait programs. Returns a nonzero exti code. + +#include + +int main(){ + printf("COMPLAIN: God this sucks. On a scale of 0 to 10 I hate pa ...\n"); + return 10; +} diff --git a/notes/04-making-processes-code/faster-child.c b/notes/04-making-processes-code/faster-child.c new file mode 100644 index 0000000..7524d37 --- /dev/null +++ b/notes/04-making-processes-code/faster-child.c @@ -0,0 +1,40 @@ +// demonstrate multiple children with wait(), detect which child returns + +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *children[][5] = { + {"./sleep_print","1","wait for me",NULL}, + {"./complain",NULL}, + {"ls","-l","-d",NULL}, + }; + + + for(int i=0; i<3; i++){ + pid_t child_pid = fork(); + if(child_pid == 0){ + execvp(children[i][0],children[i]); + perror("Failed to execvp()"); + } + else{ + printf("PARENT: Started '%s' in child proc %d\n", + children[i][0], child_pid); + } + } + // parent waits for each child + for(int i=0; i<3; i++){ + int status; + int child_pid = wait(&status); + if(WIFEXITED(status)){ + int retval = WEXITSTATUS(status); + printf("PARENT: Finished child proc %d, retval: %d\n", + child_pid, retval); + } + } + return 0; +} + diff --git a/notes/04-making-processes-code/helicopter-parent.c b/notes/04-making-processes-code/helicopter-parent.c new file mode 100644 index 0000000..7e39deb --- /dev/null +++ b/notes/04-making-processes-code/helicopter-parent.c @@ -0,0 +1,38 @@ +// demonstrate non-blocking waitpid() in excess +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"./complain",NULL}; + char *child_cmd = "complain"; + + printf("PARENT: Junior is about to '%s', I'll keep an eye on him\n", + child_cmd); + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("CHILD: I'm %d and I'm about to '%s'\n", + getpid(), child_cmd); + execvp(child_cmd, child_argv); + } + + // PARENT CODE + int status; + int checked = 0; + while(1){ + int cpid = waitpid(child_pid,&status,WNOHANG); // Check if child done, but don't actually wait + if(cpid == child_pid){ // Child did finish + break; + } + printf("Oh, junior's taking so long. Is he among the 50%% of people that are below average?\n"); + checked++; + } + printf("PARENT: Good job junior. I only checked on you %d times.\n",checked); + return 0; +} + diff --git a/notes/04-making-processes-code/helicopter-parent.c~ b/notes/04-making-processes-code/helicopter-parent.c~ new file mode 100644 index 0000000..a6695ba --- /dev/null +++ b/notes/04-making-processes-code/helicopter-parent.c~ @@ -0,0 +1,38 @@ +// demonstrate non-blocking waitpid() in excess +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"./complain",NULL}; // alternative commands + char *child_cmd = "complain"; + + printf("PARENT: Junior is about to '%s', I'll keep an eye on him\n", + child_cmd); + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("CHILD: I'm %d and I'm about to '%s'\n", + getpid(), child_cmd); + execvp(child_cmd, child_argv); + } + + // PARENT CODE + int status; + int checked = 0; + while(1){ + int cpid = waitpid(child_pid,&status,WNOHANG); // Check if child done, but don't actually wait + if(cpid == child_pid){ // Child did finish + break; + } + printf("Oh, junior's taking so long. Is he among the 50%% of people that are below average?\n"); + checked++; + } + printf("PARENT: Good job junior. I only checked on you %d times.\n",checked); + return 0; +} + diff --git a/notes/04-making-processes-code/impatient-parent.c b/notes/04-making-processes-code/impatient-parent.c new file mode 100644 index 0000000..3480466 --- /dev/null +++ b/notes/04-making-processes-code/impatient-parent.c @@ -0,0 +1,38 @@ +// demonstrate non-blocking waitpid() + +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"./complain",NULL}; + char *child_cmd = "complain"; + + printf("PARENT: Junior is about to '%s', I'll keep an eye on him\n", + child_cmd); + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("CHILD: I'm %d and I'm about to '%s'\n", + getpid(), child_cmd); + execvp(child_cmd, child_argv); + } + + // PARENT CODE + int status; + int pid = waitpid(child_pid,&status,WNOHANG); // Check if child done, but don't actually wait + if(pid == child_pid && WIFEXITED(status)){ // Child did finish + printf("PARENT: Good job junior. You told me %d\n",WEXITSTATUS(status)); + return 0; + } + else{ // Child not done yet + printf("PARENT: %d? The kid's not done yet. I'm bored\n",pid); + return -1; + } + return 0; +} + diff --git a/notes/04-making-processes-code/impatient-parent.c~ b/notes/04-making-processes-code/impatient-parent.c~ new file mode 100644 index 0000000..e63bee3 --- /dev/null +++ b/notes/04-making-processes-code/impatient-parent.c~ @@ -0,0 +1,38 @@ +// demonstrate non-blocking waitpid() + +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"./complain",NULL}; // alternative commands + char *child_cmd = "complain"; + + printf("PARENT: Junior is about to '%s', I'll keep an eye on him\n", + child_cmd); + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("CHILD: I'm %d and I'm about to '%s'\n", + getpid(), child_cmd); + execvp(child_cmd, child_argv); + } + + // PARENT CODE + int status; + int pid = waitpid(child_pid,&status,WNOHANG); // Check if child done, but don't actually wait + if(pid == child_pid && WIFEXITED(status)){ // Child did finish + printf("PARENT: Good job junior. You told me %d\n",WEXITSTATUS(status)); + return 0; + } + else{ // Child not done yet + printf("PARENT: %d? The kid's not done yet. I'm bored\n",pid); + return -1; + } + return 0; +} + diff --git a/notes/04-making-processes-code/in-class/a.out b/notes/04-making-processes-code/in-class/a.out new file mode 100755 index 0000000..1e844d7 Binary files /dev/null and b/notes/04-making-processes-code/in-class/a.out differ diff --git a/notes/04-making-processes-code/in-class/child-labor.c b/notes/04-making-processes-code/in-class/child-labor.c new file mode 100644 index 0000000..500729c --- /dev/null +++ b/notes/04-making-processes-code/in-class/child-labor.c @@ -0,0 +1,37 @@ +// Demonstrate the basics of fork/exec to launch a child process to do +// "labor". +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"ls","-l","-ah",NULL}; // argument array to child, must end with NULL + char *child_cmd = "ls"; // actual command to run, must be on path + + printf("I'm %d, and I really don't feel like '%s'ing\n", + getpid(),child_cmd); // use of getpid() to get current PID + printf("I have a solution\n"); + + pid_t child_pid = fork(); // clone a child + // wait(NULL); + + if(child_pid == 0){ // child will have a 0 here + printf(" I'm %d My pa '%d' wants me to '%s'. This sucks.\n", + getpid(), getppid(), child_cmd); // use of getpid() and getppid() + + execvp(child_cmd, child_argv); // replace running image with child_cmd + + printf(" I don't feel like myself anymore...\n"); // unreachable statement + } + else{ // parent will see nonzero in child_pid + int status; + wait(&status); + // waitpid(child_pid, NULL, 0); + printf("Great, junior %d is taking care of that\n", + child_pid); + } + return 0; +} + diff --git a/notes/04-making-processes-code/in-class/child-labor.c~ b/notes/04-making-processes-code/in-class/child-labor.c~ new file mode 100644 index 0000000..6bcbafe --- /dev/null +++ b/notes/04-making-processes-code/in-class/child-labor.c~ @@ -0,0 +1,33 @@ +// Demonstrate the basics of fork/exec to launch a child process to do +// "labor". +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"ls","-l","-ah",NULL}; // argument array to child, must end with NULL + char *child_cmd = "ls"; // actual command to run, must be on path + + printf("I'm %d, and I really don't feel like '%s'ing\n", + getpid(),child_cmd); // use of getpid() to get current PID + printf("I have a solution\n"); + + pid_t child_pid = fork(); // clone a child + + if(child_pid == 0){ // child will have a 0 here + printf(" I'm %d My pa '%d' wants me to '%s'. This sucks.\n", + getpid(), getppid(), child_cmd); // use of getpid() and getppid() + + execvp(child_cmd, child_argv); // replace running image with child_cmd + + printf(" I don't feel like myself anymore...\n"); // unreachable statement + } + else{ // parent will see nonzero in child_pid + printf("Great, junior %d is taking care of that\n", + child_pid); + } + return 0; +} + diff --git a/notes/04-making-processes-code/in-class/complain.c b/notes/04-making-processes-code/in-class/complain.c new file mode 100644 index 0000000..fd7ed81 --- /dev/null +++ b/notes/04-making-processes-code/in-class/complain.c @@ -0,0 +1,9 @@ +// Simple program that can be run with the the child-labor or +// child-wait programs. Returns a nonzero exti code. + +#include + +int main(){ + printf("COMPLAIN: God this sucks. On a scale of 0 to 10 I hate pa ...\n"); + return 10; +} diff --git a/notes/04-making-processes-code/in-class/sleep_print.c b/notes/04-making-processes-code/in-class/sleep_print.c new file mode 100644 index 0000000..96353a4 --- /dev/null +++ b/notes/04-making-processes-code/in-class/sleep_print.c @@ -0,0 +1,22 @@ +#include +#include +#include + +// usage: sleep_print secs message +int main(int argc, char *argv[]){ + + int secs = atoi(argv[1]); + + struct timespec tm = { + .tv_nsec = 0, + .tv_sec = secs, + }; + nanosleep(&tm,NULL); + for(int i=2; i +#include +#include + +// usage: sleep_print secs message +int main(int argc, char *argv[]){ + + int secs = atoi(argv[1]); + + struct timespec tm = { + .tv_nsec = 0, + .tv_sec = secs, + }; + nanosleep(&tm,NULL); + for(int i=2; i +#include +#include +#include + +int main(int argc, char* argv){ + + // char *child_argv[] = {"zombie",NULL}; + // char *child_cmd = "zombie"; + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("ZOMBIE %d: Brains...\n", getpid()); + sleep(1); + exit(0); + // execvp(child_cmd, child_argv); + } + + // PARENT CODE + printf("NECROMANCER: Go forth my servant #%d...\n",child_pid); + printf("NECROMANCER: Now for a nap...\n"); + sleep(10); + + wait(NULL); + // printf("NECROMANCER: I'm not waiting around to see what happens\n"); + return 0; +} + diff --git a/notes/04-making-processes-code/spawn-undead.c~ b/notes/04-making-processes-code/spawn-undead.c~ new file mode 100644 index 0000000..d850405 --- /dev/null +++ b/notes/04-making-processes-code/spawn-undead.c~ @@ -0,0 +1,38 @@ +// demonstrate creation of zombie processes: children that outlive +// their parent +#include +#include +#include +#include + +int main(int argc, char* argv){ + + char *child_argv[] = {"./sleep_print","10","Brains...",NULL}; // alternative commands + char *child_cmd = "complain"; + + printf("PARENT: Junior is about to '%s', I'll keep an eye on him\n", + child_cmd); + + pid_t child_pid = fork(); + + // CHILD CODE + if(child_pid == 0){ + printf("CHILD: I'm %d and I'm about to '%s'\n", + getpid(), child_cmd); + execvp(child_cmd, child_argv); + } + + // PARENT CODE + int status; + int pid = waitpid(child_pid,&status,WNOHANG); // Check if child done, but don't actually wait + if(pid == child_pid && WIFEXITED(status)){ // Child did finish + printf("PARENT: Good job junior. You told me %d\n",WEXITSTATUS(status)); + return 0; + } + else{ // Child not done yet + printf("PARENT: %d? The kid's not done yet. I'm bored\n",pid); + return -1; + } + return 0; +} + diff --git a/notes/04-making-processes-code/zombie b/notes/04-making-processes-code/zombie new file mode 100755 index 0000000..9b9322e Binary files /dev/null and b/notes/04-making-processes-code/zombie differ diff --git a/notes/04-making-processes-code/zombie.c b/notes/04-making-processes-code/zombie.c new file mode 100644 index 0000000..4c254cc --- /dev/null +++ b/notes/04-making-processes-code/zombie.c @@ -0,0 +1,41 @@ +// A C program that does not terminate from an interrupt signal is sent +// Usually pressing Ctrl+C sends this to the foreground program +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGINT(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGINT, handle_SIGINT); + printf("\nNo SIGINT-erruptions allowed.\n"); + fflush(stdout); +} + +// Function run when a SIGTERM is sent to the program +void handle_SIGTERM(int sig_num) { + // Reset handler to catch SIGTERM next time. + signal(SIGTERM, handle_SIGTERM); + printf("\nTry to SIGTERM me? Piss off!\n"); + fflush(stdout); +} + +int main () { + // Set handling functions for programs + signal(SIGINT, handle_SIGINT); + signal(SIGTERM, handle_SIGTERM); + + /* Infinite loop */ + unsigned int count = 0; + while(1) { + if(count == 0){ + printf("Brains...\n"); + } + count++; + } + return 0; +} diff --git a/notes/04-making-processes-code/zombie.c~ b/notes/04-making-processes-code/zombie.c~ new file mode 100644 index 0000000..561cd72 --- /dev/null +++ b/notes/04-making-processes-code/zombie.c~ @@ -0,0 +1,41 @@ +// A C program that does not terminate from an interrupt signal is sent +// Usually pressing Ctrl+C sends this to the foreground program +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGINT(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGINT, handle_SIGINT); + printf("\nNo SIGINT-erruptions allowed.\n"); + fflush(stdout); +} + +// Function run when a SIGTERM is sent to the program +void handle_SIGTERM(int sig_num) { + // Reset handler to catch SIGTERM next time. + signal(SIGTERM, handle_SIGTERM); + printf("\nTry to SIGTERM me? Piss off!\n"); + fflush(stdout); +} + +int main () { + // Set handling functions for programs + signal(SIGINT, handle_SIGINT); + signal(SIGTERM, handle_SIGTERM); + + /* Infinite loop */ + unsigned int count = 0; + while(1) { + if(count == 0){ + printf("Ma-na na-na!\n"); + } + count++; + } + return 0; +} diff --git a/notes/04-making-processes.pdf b/notes/04-making-processes.pdf new file mode 100644 index 0000000..69a911c Binary files /dev/null and b/notes/04-making-processes.pdf differ diff --git a/notes/05-io-files-pipes-code.zip b/notes/05-io-files-pipes-code.zip new file mode 100644 index 0000000..9fa476a Binary files /dev/null and b/notes/05-io-files-pipes-code.zip differ diff --git a/notes/05-io-files-pipes-code/capture_stdout.c b/notes/05-io-files-pipes-code/capture_stdout.c new file mode 100644 index 0000000..689b0d0 --- /dev/null +++ b/notes/05-io-files-pipes-code/capture_stdout.c @@ -0,0 +1,30 @@ +// Redirect standard output temporarily to a pipe, then restore +// standard output and retrieve the captured output +#include +#include +#include + +#define PREAD 0 // index of read end of pipe +#define PWRITE 1 // index of write end of pipe + +int main(){ + setvbuf(stdout, NULL, _IONBF, 0); // Turn off buffering + + printf("Piping\n"); + int my_pipe[2]; + pipe(my_pipe); + int stdout_bak = dup(STDOUT_FILENO); + // int stderr_bak = dup(STDERR_FILENO); + dup2(my_pipe[PWRITE],STDOUT_FILENO); + printf("In the my_pipe, five by five"); + dup2(stdout_bak, STDOUT_FILENO); + close(my_pipe[PWRITE]); + printf("Read from the my_pipe\n"); + char buf[2048]; + int bytes_read = read(my_pipe[PREAD], buf, 2048); + buf[bytes_read] = '\0'; + close(my_pipe[PREAD]); + printf("Read: '%s'\n",buf); + + return 0; +} diff --git a/notes/05-io-files-pipes-code/existing.txt b/notes/05-io-files-pipes-code/existing.txt new file mode 100644 index 0000000..ad16f40 Binary files /dev/null and b/notes/05-io-files-pipes-code/existing.txt differ diff --git a/notes/05-io-files-pipes-code/gettysburg.txt b/notes/05-io-files-pipes-code/gettysburg.txt new file mode 100644 index 0000000..ce35ad5 --- /dev/null +++ b/notes/05-io-files-pipes-code/gettysburg.txt @@ -0,0 +1,28 @@ +Four score and seven years ago our fathers brought forth on this +continent, a new nation, conceived in Liberty, and dedicated to the +proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, +or any nation so conceived and so dedicated, can long endure. We are +met on a great battle-field of that war. We have come to dedicate a +portion of that field, as a final resting place for those who here +gave their lives that that nation might live. It is altogether fitting +and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate +-- we can not hallow -- this ground. The brave men, living and dead, +who struggled here, have consecrated it, far above our poor power to +add or detract. The world will little note, nor long remember what we +say here, but it can never forget what they did here. It is for us the +living, rather, to be dedicated here to the unfinished work which they +who fought here have thus far so nobly advanced. It is rather for us +to be here dedicated to the great task remaining before us -- that +from these honored dead we take increased devotion to that cause for +which they gave the last full measure of devotion -- that we here +highly resolve that these dead shall not have died in vain -- that +this nation, under God, shall have a new birth of freedom -- and that +government of the people, by the people, for the people, shall not +perish from the earth. + +Abraham Lincoln +November 19, 1863 diff --git a/notes/05-io-files-pipes-code/integers.dat b/notes/05-io-files-pipes-code/integers.dat new file mode 100644 index 0000000..9dbd273 Binary files /dev/null and b/notes/05-io-files-pipes-code/integers.dat differ diff --git a/notes/05-io-files-pipes-code/low_level_interactions.c b/notes/05-io-files-pipes-code/low_level_interactions.c new file mode 100644 index 0000000..a805ce2 --- /dev/null +++ b/notes/05-io-files-pipes-code/low_level_interactions.c @@ -0,0 +1,30 @@ +// Demonstrate low-level interaction with user with read/write, much +// more painful than standard C functions + +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char buffer[BUFSIZE] = "Wubba lubba dub dub!\n"; + int length = strlen(buffer); + write(STDOUT_FILENO, buffer, length); // must write corrent number of bytes + + snprintf(buffer, BUFSIZE, "Enter # Mortys: "); // create output buffer + write(STDOUT_FILENO, buffer, strlen(buffer)); // write to the screen + + int bytes_read = read(STDIN_FILENO, buffer, BUFSIZE-1); // read into buffer + buffer[bytes_read] = '\0'; // null-terminate string read + int mortys = atoi(buffer); // use atoi() to convert to inteber + + snprintf(buffer, BUFSIZE, "%d Mortys requested\n",mortys);// output message + write(STDOUT_FILENO, buffer, strlen(buffer)); // write to screen + + return 0; +} diff --git a/notes/05-io-files-pipes-code/quote.txt b/notes/05-io-files-pipes-code/quote.txt new file mode 100644 index 0000000..fbca09a --- /dev/null +++ b/notes/05-io-files-pipes-code/quote.txt @@ -0,0 +1,4 @@ +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra diff --git a/notes/05-io-files-pipes-code/read_some.c b/notes/05-io-files-pipes-code/read_some.c new file mode 100644 index 0000000..2d930b3 --- /dev/null +++ b/notes/05-io-files-pipes-code/read_some.c @@ -0,0 +1,46 @@ +// Basic demonstration of reading data from a file usin open(), +// read(), close() system calls. +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + if(argc < 2){ // check command line for arguments + printf("usage: %s \n",argv[0]); // usage and exit if not given + return 0; + } + + char *infile = argv[1]; // will read from file named on argv[1] + + printf("Opening %s\n",infile); + int in_fd = open(infile,O_RDONLY); // open file for reading + if(in_fd == -1){ // check result and fail if not opened + perror("Couldn't open file"); + exit(1); + } + + printf("Reading up to %d bytes from %s\n",BUFSIZE,infile); + char buffer[BUFSIZE+1]; // someplace to read into + int bytes_read = read(in_fd, buffer, BUFSIZE); // read from file, max BUFSIZE + if(bytes_read == -1){ // check for errors + perror("Failed to read from file"); + return 1; + } + + buffer[bytes_read] = '\0'; // null terminate string + printf("Read %d chars which are:\n",bytes_read); // print bytes read + printf("====\n%s\n====\n", buffer); // print what was read + + int result = close(in_fd); + if(result == -1){ + perror("Failed to close file"); + return 1; + } + + return 0; +} diff --git a/notes/05-io-files-pipes-code/write_read_ints.c b/notes/05-io-files-pipes-code/write_read_ints.c new file mode 100644 index 0000000..367b28e --- /dev/null +++ b/notes/05-io-files-pipes-code/write_read_ints.c @@ -0,0 +1,70 @@ +// Demonstration of writing integer data to a file the reading it back +#include +#include +#include +#include +#include +#include + +#define COUNT 16 + +int main(int argc, char *argv[]){ + char *outfile = "integers.dat"; // make sure this file exists + + printf("Opening file %s\n",outfile); + int out_fd = open(outfile,O_WRONLY); // open for writing, must exist + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Filling output buffer\n"); + int out_ints[COUNT]; + for(int i=0; i +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char *outfile = "readable.txt"; + + printf("Opening file %s\n",outfile); + mode_t mode = S_IRUSR | S_IWUSR; + int out_fd = open(outfile,O_WRONLY | O_CREAT, mode); // open for writing and create if needed, WITH PERMISSIONS + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Writing to file %s\n",outfile); + char outbuf[BUFSIZE] = "here is some text to write"; // what to write + int bytes_written = write(out_fd, outbuf, BUFSIZE); // do th write + if(bytes_written == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + printf("Wrote %d bytes to %s\n",bytes_written,outfile); + + if(close(out_fd) == -1){ // check for errors on close + perror("Couldn't close file"); + } + + return 0; +} diff --git a/notes/05-io-files-pipes-code/write_then_read.c b/notes/05-io-files-pipes-code/write_then_read.c new file mode 100644 index 0000000..9a3e621 --- /dev/null +++ b/notes/05-io-files-pipes-code/write_then_read.c @@ -0,0 +1,61 @@ +// Basic demonstration of writing data to a file the reading it back +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char *outfile = "existing.txt"; // make sure this file exists + + printf("Opening file %s\n",outfile); + int out_fd = open(outfile,O_WRONLY); // open for writing, must exist + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Writing to file %s\n",outfile); + char outbuf[BUFSIZE] = "here is some text to write"; // what to write + int bytes_written = write(out_fd, outbuf, BUFSIZE); // do th write + if(bytes_written == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + printf("Wrote %d bytes to %s\n",bytes_written,outfile); + + if(close(out_fd) == -1){ // check for errors on close + perror("Couldn't close file"); + } + + int in_fd = open(outfile,O_RDONLY); // open file for reading + if(in_fd == -1){ // check result and fail if not opened + perror("Couldn't open file"); + exit(1); + } + + printf("Opening %s\n",outfile); + + printf("Reading up to %d bytes from %s\n",BUFSIZE,outfile); + char buffer[BUFSIZE+1]; // someplace to read into + int bytes_read = read(in_fd, buffer, BUFSIZE); // read from file, max BUFSIZE + if(bytes_read == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + + buffer[bytes_read] = '\0'; // null terminate string + printf("Read %d chars which are:\n",bytes_read); // print bytes read + printf("====\n%s\n====\n", buffer); // print what was read + + int result = close(in_fd); + if(result == -1){ + perror("Failed to close file"); + exit(1); + } + + return 0; +} diff --git a/notes/05-io-files-pipes-code/write_unreadable.c b/notes/05-io-files-pipes-code/write_unreadable.c new file mode 100644 index 0000000..db4591f --- /dev/null +++ b/notes/05-io-files-pipes-code/write_unreadable.c @@ -0,0 +1,36 @@ +// Writes data to a file which is unreadable/unwritable by everyone +// due to missing permissions +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char *outfile = "unreadable.txt"; + + printf("Opening file %s\n",outfile); + int out_fd = open(outfile,O_WRONLY | O_CREAT); // open for writing and create if needed, NO PERMISSIONS + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Writing to file %s\n",outfile); + char outbuf[BUFSIZE] = "here is some text to write"; // what to write + int bytes_written = write(out_fd, outbuf, BUFSIZE); // do th write + if(bytes_written == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + printf("Wrote %d bytes to %s\n",bytes_written,outfile); + + if(close(out_fd) == -1){ // check for errors on close + perror("Couldn't close file"); + } + + return 0; +} diff --git a/notes/05-io-files-pipes.pdf b/notes/05-io-files-pipes.pdf new file mode 100644 index 0000000..d2b08a5 Binary files /dev/null and b/notes/05-io-files-pipes.pdf differ diff --git a/notes/06-files-dirs-code.zip b/notes/06-files-dirs-code.zip new file mode 100644 index 0000000..e7e4087 Binary files /dev/null and b/notes/06-files-dirs-code.zip differ diff --git a/notes/06-files-dirs-code/3K.txt b/notes/06-files-dirs-code/3K.txt new file mode 100644 index 0000000..f849b98 --- /dev/null +++ b/notes/06-files-dirs-code/3K.txt @@ -0,0 +1,139 @@ + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 +70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 +102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 +127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 +152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 +177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 +202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 +227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 +252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 +277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 +302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 +327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 +352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 +377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 +402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 +427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 +452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 +477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 +502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 +527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 +552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 +577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 +602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 +627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 +652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 +677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 +702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 +727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 +752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 +777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 +802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 +827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 +852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 +877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 +902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 +927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 +952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 +977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 +1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 +1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 +1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 +1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 +1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 +1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 +1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 +1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 +1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 +1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 +1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 +1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 +1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 +1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 +1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 +1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 +1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 +1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 +1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 +1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 +1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 +1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 +1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 +1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 +1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 +1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 +1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 +1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 +1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 +1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 +1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 +1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 +1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 +1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 +1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 +1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 +1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 +1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 +1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 +1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 +1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 +1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 +1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 +1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 +1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 +1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 +1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 +1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 +1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 +1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 +2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 +2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 +2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 +2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 +2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 +2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 +2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 +2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 +2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 +2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 +2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 +2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 +2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 +2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 +2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 +2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 +2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 +2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 +2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 +2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 +2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 +2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 +2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 +2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 +2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 +2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 +2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 +2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 +2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 +2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 +2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 +2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 +2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 +2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 +2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 +2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 +2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 +2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 +2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 +2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 +2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 +2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 +2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 +2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 +2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 +2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 +2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 +2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 +2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 +2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 diff --git a/notes/06-files-dirs-code/a.out b/notes/06-files-dirs-code/a.out new file mode 100755 index 0000000..489dc53 Binary files /dev/null and b/notes/06-files-dirs-code/a.out differ diff --git a/notes/06-files-dirs-code/buffered-output-input.c b/notes/06-files-dirs-code/buffered-output-input.c new file mode 100644 index 0000000..8d4de11 --- /dev/null +++ b/notes/06-files-dirs-code/buffered-output-input.c @@ -0,0 +1,33 @@ +// Demonstrate that full buffering can make output/input trickier: the +// prompt will not display under full buffering +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + char outbuf[1024] = {}; + setvbuf(stdout, outbuf, _IOFBF, 1024); // set full buffering for stdout + // setvbuf(stdout, outbuf, _IOLBF, 1024); // set line buffering for stdout + + fprintf(stdout,"Enter number: "); + int num = -1; + fscanf(stdin,"%d",&num); + fprintf(stdout,"Number is %d\n",num); + + + char outbuf2[1024] = {}; + setvbuf(stdout, outbuf2, _IOFBF, 1024); // set full buffering for stdout + fprintf(stdout,"BUFFER IS:\n"); + for(int i=0; i<1024; i++){ + fprintf(stdout,"%c",outbuf[i]); + } + fprintf(stdout,"\n"); + return 0; +} + +// char *msg = "Enter number: "; +// int len = strlen(msg); +// for(int i=0; i +#include +#include +#include +#include + +#define SIZE 2048 +#define TMPDIR "tmpdir" + +int main(int argc, char *argv[]){ + int ret; + char buf[SIZE]; + mode_t perms = S_IRUSR | S_IWUSR | S_IXUSR; + + getcwd(buf,SIZE); + printf("WORKING DIRECTORY: %s\n\n",buf); + + mkdir(TMPDIR,perms); + printf("MADE %s\n\n",TMPDIR); + + printf("CHANGING TO %s\n\n",TMPDIR); + chdir(TMPDIR); + + getcwd(buf,SIZE); + printf("WORKING DIRECTORY: %s\n\n",buf); + + printf("CHANGING TO ..\n\n",TMPDIR); + chdir(".."); + + getcwd(buf,SIZE); + printf("WORKING DIRECTORY: %s\n\n",buf); + + printf("DIRECTORY LISTING\n\n"); + DIR *dir = opendir("."); + struct dirent *file = NULL; + while( (file = readdir(dir)) != NULL){ + printf("%s\n", file->d_name); + } + closedir(dir); + + printf("\nREMOVING %s\n\n",TMPDIR); + rmdir(TMPDIR); + + printf("DIRECTORY LISTING\n\n"); + dir = opendir("."); + while( (file = readdir(dir)) != NULL){ + printf("%s\n", file->d_name); + } + closedir(dir); + + return 0; +} diff --git a/notes/06-files-dirs-code/dir-demo.c.bk b/notes/06-files-dirs-code/dir-demo.c.bk new file mode 100644 index 0000000..a562d78 --- /dev/null +++ b/notes/06-files-dirs-code/dir-demo.c.bk @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +#define SIZE 2048 + +int main(int argc, char *argv[]){ + int ret; + char buf[SIZE]; + mode_t perms = S_IRUSR | S_IWUSR | S_IXUSR; + + // Get working directory + if( getcwd(buf,SIZE) == NULL ){ + perror("Can't get working directory"); + exit(1); + } + printf("Working directory: %s\n",buf); + + // Create a directory + if( mkdir("tmpdir",perms) == -1 ){ + perror("Couldn't create directory"); + exit(1); + } + printf("Made tmpdir\n"); + + // Change to new directory + if( chdir("tmpdir") == -1 ){ + perror("Couldn't change directory"); + exit(1); + } + if( getcwd(buf,SIZE) == NULL ){ + perror("Can't get working directory"); + exit(1); + } + printf("Working directory: %s\n",buf); + + // Change back + if( chdir("..") == -1 ){ + perror("Couldn't change back"); + exit(1); + } + + return 0; +} diff --git a/notes/06-files-dirs-code/fail-to-write.c b/notes/06-files-dirs-code/fail-to-write.c new file mode 100644 index 0000000..a4d43bb --- /dev/null +++ b/notes/06-files-dirs-code/fail-to-write.c @@ -0,0 +1,22 @@ +// Program demonstrating buffering effects of C stdio: printing +// functions may buffer output for later writing. If files aren't +// closed and proper exit doesn't occur, may truncate output. +#include +#include +#include + +int main(int argc, char *argv[]){ + FILE *out = fopen("out.txt","w"); + for(int i=1; i<=1000; i++){ // Expect 1000 lines of output + fprintf(out,"%04d\n",i); + } + + // Any of the following will ensure full output makes it to the file + // fflush(out); // flush file, don't close + // fclose(out); // flush buffers and close file + // exit(0); // exit normally + + // This however may cause data loss: less than 1000 lines in file + _exit(0); // exit without any cleanup + +} diff --git a/notes/06-files-dirs-code/file-hole.c b/notes/06-files-dirs-code/file-hole.c new file mode 100644 index 0000000..1a7a584 --- /dev/null +++ b/notes/06-files-dirs-code/file-hole.c @@ -0,0 +1,28 @@ +// Create a file with a gap. Examine contents of holey.txt to see a +// gap created by text. +// +// Inspired by Stevens/Rago Fig 3.2 +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + int flags = O_WRONLY | O_CREAT; + mode_t perms = S_IRUSR | S_IWUSR; + char buf1[] = "abcdefghij"; + char buf2[] = "ABCDEFGHIJ"; + + int fd = open("holey.txt", flags,perms); + write(fd, buf1, strlen(buf1)); // offset now = 10 + lseek(fd, 20, SEEK_CUR); // offset now = 10+20 + write(fd, buf1, strlen(buf1)); // write data from 30-39 + lseek(fd, 50, SEEK_SET); // offset now = 50 + write(fd, buf2, strlen(buf2)); // write from 50-59 + close(fd); + exit(0); +} + diff --git a/notes/06-files-dirs-code/file-hole2.c b/notes/06-files-dirs-code/file-hole2.c new file mode 100644 index 0000000..48bcbd9 --- /dev/null +++ b/notes/06-files-dirs-code/file-hole2.c @@ -0,0 +1,24 @@ +// Create a file with a gap. Examine contents of holey.txt to see a +// gap created by text. +// +// Inspired by Stevens/Rago Fig 3.2 +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + int flags = O_WRONLY | O_CREAT; + mode_t perms = S_IRUSR | S_IWUSR; + char buf1[] = "ZYXW"; + + int fd = open("holey.txt", flags,perms); + lseek(fd, 20, SEEK_SET); // offset now = 20 + write(fd, buf1, strlen(buf1)); // write data from 30-39 + close(fd); + exit(0); +} + diff --git a/notes/06-files-dirs-code/file0.txt b/notes/06-files-dirs-code/file0.txt new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/file1.txt b/notes/06-files-dirs-code/file1.txt new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/file2.txt b/notes/06-files-dirs-code/file2.txt new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/file3.txt b/notes/06-files-dirs-code/file3.txt new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/holey.txt b/notes/06-files-dirs-code/holey.txt new file mode 100644 index 0000000..e242c6f Binary files /dev/null and b/notes/06-files-dirs-code/holey.txt differ diff --git a/notes/06-files-dirs-code/linkdir/fileW b/notes/06-files-dirs-code/linkdir/fileW new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/linkdir/fileX b/notes/06-files-dirs-code/linkdir/fileX new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/linkdir/fileY b/notes/06-files-dirs-code/linkdir/fileY new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/linkdir/fileZ b/notes/06-files-dirs-code/linkdir/fileZ new file mode 100644 index 0000000..e69de29 diff --git a/notes/06-files-dirs-code/mixed-std-low.c b/notes/06-files-dirs-code/mixed-std-low.c new file mode 100644 index 0000000..5d52ba8 --- /dev/null +++ b/notes/06-files-dirs-code/mixed-std-low.c @@ -0,0 +1,24 @@ +// Program demonstrating strange effects of mixing C std and Unix +// system I/O. Typical output is +// +// FIRST: 1 +// NEXT: 41 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 +// +// which is explainable with internal buffering of C std I/O +#include +#include +int main(int argc, char *argv[]){ + + FILE *input = fopen("3K.txt","r"); + int first; + fscanf(input, "%d", &first); + printf("FIRST: %d\n",first); + + int fd = fileno(input); + char *buf[64]; + read(fd, buf, 63); + buf[127] = '\0'; + printf("NEXT: %s\n",buf); + + return 0; +} diff --git a/notes/06-files-dirs-code/myprog b/notes/06-files-dirs-code/myprog new file mode 100755 index 0000000..9f14f8b Binary files /dev/null and b/notes/06-files-dirs-code/myprog differ diff --git a/notes/06-files-dirs-code/out.txt b/notes/06-files-dirs-code/out.txt new file mode 100644 index 0000000..46fb6a5 --- /dev/null +++ b/notes/06-files-dirs-code/out.txt @@ -0,0 +1,1000 @@ +0001 +0002 +0003 +0004 +0005 +0006 +0007 +0008 +0009 +0010 +0011 +0012 +0013 +0014 +0015 +0016 +0017 +0018 +0019 +0020 +0021 +0022 +0023 +0024 +0025 +0026 +0027 +0028 +0029 +0030 +0031 +0032 +0033 +0034 +0035 +0036 +0037 +0038 +0039 +0040 +0041 +0042 +0043 +0044 +0045 +0046 +0047 +0048 +0049 +0050 +0051 +0052 +0053 +0054 +0055 +0056 +0057 +0058 +0059 +0060 +0061 +0062 +0063 +0064 +0065 +0066 +0067 +0068 +0069 +0070 +0071 +0072 +0073 +0074 +0075 +0076 +0077 +0078 +0079 +0080 +0081 +0082 +0083 +0084 +0085 +0086 +0087 +0088 +0089 +0090 +0091 +0092 +0093 +0094 +0095 +0096 +0097 +0098 +0099 +0100 +0101 +0102 +0103 +0104 +0105 +0106 +0107 +0108 +0109 +0110 +0111 +0112 +0113 +0114 +0115 +0116 +0117 +0118 +0119 +0120 +0121 +0122 +0123 +0124 +0125 +0126 +0127 +0128 +0129 +0130 +0131 +0132 +0133 +0134 +0135 +0136 +0137 +0138 +0139 +0140 +0141 +0142 +0143 +0144 +0145 +0146 +0147 +0148 +0149 +0150 +0151 +0152 +0153 +0154 +0155 +0156 +0157 +0158 +0159 +0160 +0161 +0162 +0163 +0164 +0165 +0166 +0167 +0168 +0169 +0170 +0171 +0172 +0173 +0174 +0175 +0176 +0177 +0178 +0179 +0180 +0181 +0182 +0183 +0184 +0185 +0186 +0187 +0188 +0189 +0190 +0191 +0192 +0193 +0194 +0195 +0196 +0197 +0198 +0199 +0200 +0201 +0202 +0203 +0204 +0205 +0206 +0207 +0208 +0209 +0210 +0211 +0212 +0213 +0214 +0215 +0216 +0217 +0218 +0219 +0220 +0221 +0222 +0223 +0224 +0225 +0226 +0227 +0228 +0229 +0230 +0231 +0232 +0233 +0234 +0235 +0236 +0237 +0238 +0239 +0240 +0241 +0242 +0243 +0244 +0245 +0246 +0247 +0248 +0249 +0250 +0251 +0252 +0253 +0254 +0255 +0256 +0257 +0258 +0259 +0260 +0261 +0262 +0263 +0264 +0265 +0266 +0267 +0268 +0269 +0270 +0271 +0272 +0273 +0274 +0275 +0276 +0277 +0278 +0279 +0280 +0281 +0282 +0283 +0284 +0285 +0286 +0287 +0288 +0289 +0290 +0291 +0292 +0293 +0294 +0295 +0296 +0297 +0298 +0299 +0300 +0301 +0302 +0303 +0304 +0305 +0306 +0307 +0308 +0309 +0310 +0311 +0312 +0313 +0314 +0315 +0316 +0317 +0318 +0319 +0320 +0321 +0322 +0323 +0324 +0325 +0326 +0327 +0328 +0329 +0330 +0331 +0332 +0333 +0334 +0335 +0336 +0337 +0338 +0339 +0340 +0341 +0342 +0343 +0344 +0345 +0346 +0347 +0348 +0349 +0350 +0351 +0352 +0353 +0354 +0355 +0356 +0357 +0358 +0359 +0360 +0361 +0362 +0363 +0364 +0365 +0366 +0367 +0368 +0369 +0370 +0371 +0372 +0373 +0374 +0375 +0376 +0377 +0378 +0379 +0380 +0381 +0382 +0383 +0384 +0385 +0386 +0387 +0388 +0389 +0390 +0391 +0392 +0393 +0394 +0395 +0396 +0397 +0398 +0399 +0400 +0401 +0402 +0403 +0404 +0405 +0406 +0407 +0408 +0409 +0410 +0411 +0412 +0413 +0414 +0415 +0416 +0417 +0418 +0419 +0420 +0421 +0422 +0423 +0424 +0425 +0426 +0427 +0428 +0429 +0430 +0431 +0432 +0433 +0434 +0435 +0436 +0437 +0438 +0439 +0440 +0441 +0442 +0443 +0444 +0445 +0446 +0447 +0448 +0449 +0450 +0451 +0452 +0453 +0454 +0455 +0456 +0457 +0458 +0459 +0460 +0461 +0462 +0463 +0464 +0465 +0466 +0467 +0468 +0469 +0470 +0471 +0472 +0473 +0474 +0475 +0476 +0477 +0478 +0479 +0480 +0481 +0482 +0483 +0484 +0485 +0486 +0487 +0488 +0489 +0490 +0491 +0492 +0493 +0494 +0495 +0496 +0497 +0498 +0499 +0500 +0501 +0502 +0503 +0504 +0505 +0506 +0507 +0508 +0509 +0510 +0511 +0512 +0513 +0514 +0515 +0516 +0517 +0518 +0519 +0520 +0521 +0522 +0523 +0524 +0525 +0526 +0527 +0528 +0529 +0530 +0531 +0532 +0533 +0534 +0535 +0536 +0537 +0538 +0539 +0540 +0541 +0542 +0543 +0544 +0545 +0546 +0547 +0548 +0549 +0550 +0551 +0552 +0553 +0554 +0555 +0556 +0557 +0558 +0559 +0560 +0561 +0562 +0563 +0564 +0565 +0566 +0567 +0568 +0569 +0570 +0571 +0572 +0573 +0574 +0575 +0576 +0577 +0578 +0579 +0580 +0581 +0582 +0583 +0584 +0585 +0586 +0587 +0588 +0589 +0590 +0591 +0592 +0593 +0594 +0595 +0596 +0597 +0598 +0599 +0600 +0601 +0602 +0603 +0604 +0605 +0606 +0607 +0608 +0609 +0610 +0611 +0612 +0613 +0614 +0615 +0616 +0617 +0618 +0619 +0620 +0621 +0622 +0623 +0624 +0625 +0626 +0627 +0628 +0629 +0630 +0631 +0632 +0633 +0634 +0635 +0636 +0637 +0638 +0639 +0640 +0641 +0642 +0643 +0644 +0645 +0646 +0647 +0648 +0649 +0650 +0651 +0652 +0653 +0654 +0655 +0656 +0657 +0658 +0659 +0660 +0661 +0662 +0663 +0664 +0665 +0666 +0667 +0668 +0669 +0670 +0671 +0672 +0673 +0674 +0675 +0676 +0677 +0678 +0679 +0680 +0681 +0682 +0683 +0684 +0685 +0686 +0687 +0688 +0689 +0690 +0691 +0692 +0693 +0694 +0695 +0696 +0697 +0698 +0699 +0700 +0701 +0702 +0703 +0704 +0705 +0706 +0707 +0708 +0709 +0710 +0711 +0712 +0713 +0714 +0715 +0716 +0717 +0718 +0719 +0720 +0721 +0722 +0723 +0724 +0725 +0726 +0727 +0728 +0729 +0730 +0731 +0732 +0733 +0734 +0735 +0736 +0737 +0738 +0739 +0740 +0741 +0742 +0743 +0744 +0745 +0746 +0747 +0748 +0749 +0750 +0751 +0752 +0753 +0754 +0755 +0756 +0757 +0758 +0759 +0760 +0761 +0762 +0763 +0764 +0765 +0766 +0767 +0768 +0769 +0770 +0771 +0772 +0773 +0774 +0775 +0776 +0777 +0778 +0779 +0780 +0781 +0782 +0783 +0784 +0785 +0786 +0787 +0788 +0789 +0790 +0791 +0792 +0793 +0794 +0795 +0796 +0797 +0798 +0799 +0800 +0801 +0802 +0803 +0804 +0805 +0806 +0807 +0808 +0809 +0810 +0811 +0812 +0813 +0814 +0815 +0816 +0817 +0818 +0819 +0820 +0821 +0822 +0823 +0824 +0825 +0826 +0827 +0828 +0829 +0830 +0831 +0832 +0833 +0834 +0835 +0836 +0837 +0838 +0839 +0840 +0841 +0842 +0843 +0844 +0845 +0846 +0847 +0848 +0849 +0850 +0851 +0852 +0853 +0854 +0855 +0856 +0857 +0858 +0859 +0860 +0861 +0862 +0863 +0864 +0865 +0866 +0867 +0868 +0869 +0870 +0871 +0872 +0873 +0874 +0875 +0876 +0877 +0878 +0879 +0880 +0881 +0882 +0883 +0884 +0885 +0886 +0887 +0888 +0889 +0890 +0891 +0892 +0893 +0894 +0895 +0896 +0897 +0898 +0899 +0900 +0901 +0902 +0903 +0904 +0905 +0906 +0907 +0908 +0909 +0910 +0911 +0912 +0913 +0914 +0915 +0916 +0917 +0918 +0919 +0920 +0921 +0922 +0923 +0924 +0925 +0926 +0927 +0928 +0929 +0930 +0931 +0932 +0933 +0934 +0935 +0936 +0937 +0938 +0939 +0940 +0941 +0942 +0943 +0944 +0945 +0946 +0947 +0948 +0949 +0950 +0951 +0952 +0953 +0954 +0955 +0956 +0957 +0958 +0959 +0960 +0961 +0962 +0963 +0964 +0965 +0966 +0967 +0968 +0969 +0970 +0971 +0972 +0973 +0974 +0975 +0976 +0977 +0978 +0979 +0980 +0981 +0982 +0983 +0984 +0985 +0986 +0987 +0988 +0989 +0990 +0991 +0992 +0993 +0994 +0995 +0996 +0997 +0998 +0999 +1000 diff --git a/notes/06-files-dirs-code/readable1.txt b/notes/06-files-dirs-code/readable1.txt new file mode 100644 index 0000000..87377c7 --- /dev/null +++ b/notes/06-files-dirs-code/readable1.txt @@ -0,0 +1 @@ +here is some text to write \ No newline at end of file diff --git a/notes/06-files-dirs-code/readable2.txt b/notes/06-files-dirs-code/readable2.txt new file mode 100644 index 0000000..1f3ce24 --- /dev/null +++ b/notes/06-files-dirs-code/readable2.txt @@ -0,0 +1 @@ +more text for writing \ No newline at end of file diff --git a/notes/06-files-dirs-code/stat-demo.c b/notes/06-files-dirs-code/stat-demo.c new file mode 100644 index 0000000..9942ee1 --- /dev/null +++ b/notes/06-files-dirs-code/stat-demo.c @@ -0,0 +1,59 @@ +// This program is taken directly from the manual page +// +// man 2 stat +// +// and demonstrates typical fields available via a stat calls. Minor +// modifications have been made to focus attention on important +// facets. + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + struct stat sb; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + if (stat(argv[1], &sb) == -1) { // call to stat(), fills sb + perror("stat"); + exit(EXIT_FAILURE); + } + + printf("Filename: %s\n",argv[1]); + printf("File type: "); + if(0){} // checks to determine file type + else if S_ISBLK (sb.st_mode) { printf("block device\n"); } + else if S_ISCHR (sb.st_mode) { printf("character device\n"); } + else if S_ISDIR (sb.st_mode) { printf("directory\n"); } + else if S_ISFIFO(sb.st_mode) { printf("FIFO/pipe\n"); } + else if S_ISLNK (sb.st_mode) { printf("symlink\n"); } + else if S_ISREG (sb.st_mode) { printf("regular file\n"); } + else if S_ISSOCK(sb.st_mode) { printf("socket\n"); } + else{ printf("unknown?\n"); } + + // Use various fields to display information + printf("I-node number: %ld\n" , (long) sb.st_ino); + printf("Permissions: %lo (octal)\n" , (unsigned long) sb.st_mode); + printf("Link count: %ld\n" , (long) sb.st_nlink); + printf("Ownership: UID=%ld GID=%ld\n" , (long) sb.st_uid, (long) sb.st_gid); + printf("Preferred I/O block size: %ld bytes\n" , (long) sb.st_blksize); + printf("File size: %lld bytes\n" , (long long) sb.st_size); + printf("Blocks allocated: %lld\n" , (long long) sb.st_blocks); + + // Print times of last access + printf("Last status change: %s", ctime(&sb.st_ctime)); // formats time as a string + printf("Last file access: %s", ctime(&sb.st_atime)); // fields like st_atime are of + printf("Last file modification: %s", ctime(&sb.st_mtime)); // type time_t taken by ctime() + + // Optionally report device number + // printf("ID of containing device: [%lx,%lx]\n", (long) major(sb.st_dev), (long) minor(sb.st_dev)); + + exit(EXIT_SUCCESS); +} diff --git a/notes/06-files-dirs-code/stat-demo.c.old b/notes/06-files-dirs-code/stat-demo.c.old new file mode 100644 index 0000000..d1e52b8 --- /dev/null +++ b/notes/06-files-dirs-code/stat-demo.c.old @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + if(argc < 2){ + printf("usage: %s \n",argv[0]); + exit(1); + } + + char *filename = argv[1]; + struct stat statbuf = {}; + int ret = stat(filename, &statbuf); + if(ret == -1){ + perror("Could not stat file"); + exit(1); + } + + printf("Stats for file %s\n",filename); + printf("Perms: %o\n",statbuf.st_mode & 0777); + + exit(1); +} diff --git a/notes/06-files-dirs-code/watch-files.c b/notes/06-files-dirs-code/watch-files.c new file mode 100644 index 0000000..639535a --- /dev/null +++ b/notes/06-files-dirs-code/watch-files.c @@ -0,0 +1,73 @@ +// Broken example of trying to watch 4 files using select +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXFILES 4 + +int main(int argc, char *argv[]) { + + char *filenames[MAXFILES] = { + "file0.txt", + "file1.txt", + "file2.txt", + "file3.txt", + }; + + + int fds[MAXFILES] = {}; + int maxfd = 0; + int flags = O_RDONLY | O_CREAT; + mode_t perms = S_IRUSR | S_IWUSR; + for(int i=0; i +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char *outfile = "readable.txt"; + + printf("Opening file %s\n",outfile); + mode_t mode = S_IRUSR | S_IWUSR; + int out_fd = open(outfile,O_WRONLY | O_CREAT, mode); // open for writing and create if needed, WITH PERMISSIONS + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Writing to file %s\n",outfile); + char outbuf[BUFSIZE] = "here is some text to write"; // what to write + int bytes_written = write(out_fd, outbuf, BUFSIZE); // do th write + if(bytes_written == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + printf("Wrote %d bytes to %s\n",bytes_written,outfile); + + if(close(out_fd) == -1){ // check for errors on close + perror("Couldn't close file"); + } + + return 0; +} diff --git a/notes/06-files-dirs-code/write_umask.c b/notes/06-files-dirs-code/write_umask.c new file mode 100644 index 0000000..1e47ea2 --- /dev/null +++ b/notes/06-files-dirs-code/write_umask.c @@ -0,0 +1,40 @@ +// Demonstrate umask: restrictions on permissions for freshly created +// files with open()/creat() files +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + + mode_t new_mask = 0000; // allow any permissions + mode_t old_mask = umask(new_mask); // set umask to + + int perms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;; + int flags = O_WRONLY | O_CREAT; + int out_fd = -1; + char *message = NULL; + // Write to first file + out_fd = open("readable1.txt",flags,perms ); // create file + message = "here is some text to write"; // what to write + write(out_fd, message, strlen(message)); // do the write + close(out_fd); // sloppy close + + // readable1.txt should have perms: -rw-rw---- + + new_mask = 0077; // don't allow permissions to be set for group or other + old_mask = umask(new_mask); + + // Write to first file + out_fd = open("readable2.txt",flags,perms); // open for writing and create if needed, PERMISSIONS + message = "more text for writing"; // what to write + write(out_fd, message, strlen(message)); // do the write + close(out_fd); // sloppy close + + // readable1.txt should have perms: -rw------- + // No group perms as umask stopped this + + return 0; +} diff --git a/notes/06-files-dirs-code/write_unreadable.c b/notes/06-files-dirs-code/write_unreadable.c new file mode 100644 index 0000000..db4591f --- /dev/null +++ b/notes/06-files-dirs-code/write_unreadable.c @@ -0,0 +1,36 @@ +// Writes data to a file which is unreadable/unwritable by everyone +// due to missing permissions +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 128 + +int main(int argc, char *argv[]){ + char *outfile = "unreadable.txt"; + + printf("Opening file %s\n",outfile); + int out_fd = open(outfile,O_WRONLY | O_CREAT); // open for writing and create if needed, NO PERMISSIONS + if(out_fd == -1){ // check result and fail if not opened + perror("Couldn't open output file"); + exit(1); + } + + printf("Writing to file %s\n",outfile); + char outbuf[BUFSIZE] = "here is some text to write"; // what to write + int bytes_written = write(out_fd, outbuf, BUFSIZE); // do th write + if(bytes_written == -1){ // check for errors + perror("Failed to read from file"); + exit(1); + } + printf("Wrote %d bytes to %s\n",bytes_written,outfile); + + if(close(out_fd) == -1){ // check for errors on close + perror("Couldn't close file"); + } + + return 0; +} diff --git a/notes/06-files-dirs-code/xyz b/notes/06-files-dirs-code/xyz new file mode 100755 index 0000000..e69de29 diff --git a/notes/06-files-dirs.pdf b/notes/06-files-dirs.pdf new file mode 100644 index 0000000..3f4a4c5 Binary files /dev/null and b/notes/06-files-dirs.pdf differ diff --git a/notes/08-signals-code.zip b/notes/08-signals-code.zip new file mode 100644 index 0000000..e026b62 Binary files /dev/null and b/notes/08-signals-code.zip differ diff --git a/notes/08-signals-code/a.out b/notes/08-signals-code/a.out new file mode 100755 index 0000000..c512a6c Binary files /dev/null and b/notes/08-signals-code/a.out differ diff --git a/notes/08-signals-code/in-class/non-reentrant.c b/notes/08-signals-code/in-class/non-reentrant.c new file mode 100644 index 0000000..5ce7423 --- /dev/null +++ b/notes/08-signals-code/in-class/non-reentrant.c @@ -0,0 +1,62 @@ +// Shows dangers of using a non-reentrant function with signal +// handling. Strange things can happen due to the use of the +// non-reentrant function getpwnam() being called both in the main +// loop and signal handler. Uncommenting the getpwnam() in the signal +// handler causes unpredictable things to happen like a permanent +// stall of the program on Linux boxes. +// +// Adapted from Stevens and Rago Fig 10.5. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERNAME "kauffman" + +static void alarm_handler(int signo) { + printf("in signal handler\n"); + struct passwd *rootptr = NULL; + + // NON-REENTRANT FUNCTION CALL IN SIGNAL HANDLER + rootptr = getpwnam("root"); // fetch record associated with root password + + if (rootptr == NULL){ // check for presence of root + printf("no root, that's weird...\n"); + } + else{ + printf("root looks okay\n"); + } + alarm(1); // reset the alarm + printf("leaving signal handler\n"); +} + +int main(void) { + signal(SIGALRM, alarm_handler); // handle alarms in with the above function + alarm(1); + + int successes = 0; + printf("Repeatedly checking on user '%s'\n",USERNAME); + while(1){ + struct passwd *ptr = getpwnam(USERNAME); // non-reentrant call + if(ptr == NULL){ + perror("couldn't find user"); + exit(1); + } + if(strcmp(ptr->pw_name, USERNAME) != 0){ // should always be equal to USERNAME + printf("return value corrupted!, pw_name = %s\n", + ptr->pw_name); + exit(1); + } + successes++; // Show progress of loop + if(successes % 100000 == 0){ + printf("%d successes so far\n",successes); + } + } + exit(0); +} diff --git a/notes/08-signals-code/interrupted-read.c b/notes/08-signals-code/interrupted-read.c new file mode 100644 index 0000000..880ce4b --- /dev/null +++ b/notes/08-signals-code/interrupted-read.c @@ -0,0 +1,63 @@ +// Shows how one would write code for a system where the read() call +// could be interrupted by a signal. This does not happen by default +// on most modern unix systems so this is for demo purposes only. +// +// Easiest to run this program using a fifo as in +// > mkfifo not-there-yet.fifo +// > gcc interrupted-read.c +// > a.out not-there-yet.fifo +// +// In a separate terminal send signals to the process such as SIGUSR1 +// then echo data into the fifo. +// +// > pkill -USR1 a.out +// > pkill -USR2 a.out +// > echo 'Here is some text' > not-there-yet.fifo + +#include +#include +#include +#include +#include +#include +#include +#include + +void handle_usr_signals(int signo) { // argument is signal number + if (signo == SIGUSR1){ // check for signal type 1 + printf("received SIGUSR1\n"); + } + else if (signo == SIGUSR2){ // check for signal type 2 + printf("received SIGUSR2\n"); + } + else{ // this should not be reachable + printf("signo %d: Wait, how did I get here?\n",signo); + exit(1); + } +} + +int main(int argc, char *argv[]) { + signal(SIGUSR1, handle_usr_signals); + signal(SIGUSR2, handle_usr_signals); + + char *fname = argv[1]; + + int fd = open(fname,O_RDONLY); + int nread; + char buf[512]; + while( (nread = read(fd, buf, 512)) == -1){ // Keep reading + if(errno == EINTR){ // Check whether we were interrupted + printf("Interrupted while reading.\n"); + } + else{ + perror("reading failed due to error"); + exit(1); + } + } + + printf("Read the following: "); + fflush(stdout); + write(STDOUT_FILENO, buf, nread); + printf("\n"); + exit(0); +} diff --git a/notes/08-signals-code/multi-signal.c b/notes/08-signals-code/multi-signal.c new file mode 100644 index 0000000..27968a8 --- /dev/null +++ b/notes/08-signals-code/multi-signal.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +int signal_received = 0; + +// Handle multiple different signals in a single handler. Note that +// the signal handler is NOT reset in the function but still +// works. This is the behavior of most modern implementations. + +void handle_usr_signals(int signo) { // argument is signal number + signal_received = 1; + if (signo == SIGUSR1){ // check for signal type 1 + printf("received SIGUSR1\n"); + } + else if (signo == SIGUSR2){ // check for signal type 2 + printf("received SIGUSR2\n"); + } + else{ // this should not be reachable + printf("signo %d: Wait, how did I get here?\n",signo); + exit(1); + } +} + +// Required to check the result of using the signal() function +typedef void (*sighandler_t)(int); + + +// main() function: set up signal handlers then sleep for an +// interval. Can be woken up by some signals. +// +// Note also default disposition for signals like CONT which are +// ignored while the program is running. +int main(void) { + // Set signal handler and check result + sighandler_t result = signal(SIGUSR1, handle_usr_signals); + if(result == SIG_ERR){ + perror("couldn't set handler for SIGUSR1"); + exit(1); + } + + // Short hand for set/check result + if (signal(SIGUSR2, handle_usr_signals) == SIG_ERR){ + perror("couldn't set handler for SIGUSR2"); + exit(1); + } + + while(1){ + sleep(4); // Sleep until a woken by a signal or 4 seconds passes + if(signal_received == 1){ + printf("Signalled! Back to sleep now\n"); + signal_received = 0; + } + else{ + printf("Woke up after sleeping. Back to bed\n"); + } + } + +} + diff --git a/notes/08-signals-code/no-interruptions-block.c b/notes/08-signals-code/no-interruptions-block.c new file mode 100644 index 0000000..af1c6a3 --- /dev/null +++ b/notes/08-signals-code/no-interruptions-block.c @@ -0,0 +1,31 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. This +// version ignores signals silently for a while, then restores the +// default signal handlers so the program can be terminated normally. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +int main () { + sigset_t block_all, defaults; + sigfillset( &block_all ); // set contains all signals + sigprocmask(SIG_SETMASK, &block_all, &defaults); // set the mask to all signals + // and save defaults for later + // infinite loop + int count = 0; + while(1) { + sleep(1); + printf("Ma-na na-na!\n"); + fflush(stdout); + count++; + if(count == 5){ + printf("Restoring default signal disposition\n"); + sigprocmask(SIG_SETMASK, &defaults, NULL); // restore defaults, pending signals delivered + } + } + return 0; +} diff --git a/notes/08-signals-code/no-interruptions-ignore.c b/notes/08-signals-code/no-interruptions-ignore.c new file mode 100644 index 0000000..090d926 --- /dev/null +++ b/notes/08-signals-code/no-interruptions-ignore.c @@ -0,0 +1,32 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. This +// version ignores signals silently for a while, then restores the +// default signal handlers so the program can be terminated normally. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +int main () { + // Set handling functions for programs + signal(SIGINT, SIG_IGN); // Ignore these signals silently + signal(SIGTERM, SIG_IGN); + + // Infinite loop + int count = 0; + while(1) { + sleep(1); + printf("Ma-na na-na!\n"); + fflush(stdout); + count++; + if(count == 5){ + printf("Restoring default signal disposition\n"); + signal(SIGINT, SIG_DFL); // restore default signal disposition + signal(SIGTERM, SIG_DFL); + } + } + return 0; +} diff --git a/notes/08-signals-code/no-interruptions-sigaction.c b/notes/08-signals-code/no-interruptions-sigaction.c new file mode 100644 index 0000000..8456e1d --- /dev/null +++ b/notes/08-signals-code/no-interruptions-sigaction.c @@ -0,0 +1,41 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +// +// This version uses portable signal handler setup +#include +#include +#include + +// Function run when a signals are caught +void handle_signals(int sig_num) { + if(sig_num == SIGINT){ + printf("\nNo SIGINT-erruptions allowed.\n"); + } + else if(sig_num == SIGTERM){ + printf("\nTry to SIGTERM me? Piss off!\n"); + } + fflush(stdout); +} + +int main () { + // Set handling functions for programs using portable handler setup + // with sigaction() + struct sigaction my_sa = {}; // carries information about handler and options + my_sa.sa_handler = handle_signals; // run function handle_signals + sigemptyset(&my_sa.sa_mask); // don't block any other signals during handling + my_sa.sa_flags = SA_RESTART; // restart system calls on signals if possible + sigaction(SIGTERM, &my_sa, NULL); // register SIGTERM with given action + sigaction(SIGINT, &my_sa, NULL); // register SIGINT with given action + + // Infinite loop + while(1) { + sleep(1); + printf("Ma-na na-na!\n"); + fflush(stdout); + } + return 0; +} diff --git a/notes/08-signals-code/no-interruptions-sigaction.c~ b/notes/08-signals-code/no-interruptions-sigaction.c~ new file mode 100644 index 0000000..4eb7f5d --- /dev/null +++ b/notes/08-signals-code/no-interruptions-sigaction.c~ @@ -0,0 +1,39 @@ +// A C program that does not terminate from an interrupt signal. +// Usually pressing Ctrl-C sends this to the foreground program. +// +// To stop this program from running, open another terminal and try +// > pkill -9 a.out +// assuming you named the output program a.out +#include +#include +#include + +// Function run when a SIGINT is sent to the program +void handle_SIGINT(int sig_num) { + // Reset handler to catch SIGINT next time. + signal(SIGINT, handle_SIGINT); + printf("\nNo SIGINT-erruptions allowed.\n"); + fflush(stdout); +} + +// Function run when a SIGTERM is sent to the program +void handle_SIGTERM(int sig_num) { + // Reset handler to catch SIGTERM next time. + signal(SIGTERM, handle_SIGTERM); + printf("\nTry to SIGTERM me? Piss off!\n"); + fflush(stdout); +} + +int main () { + // Set handling functions for programs + signal(SIGINT, handle_SIGINT); + signal(SIGTERM, handle_SIGTERM); + + /* Infinite loop */ + while(1) { + sleep(1); + printf("Ma-na na-na!\n"); + fflush(stdout); + } + return 0; +} diff --git a/notes/08-signals-code/non-reentrant.c b/notes/08-signals-code/non-reentrant.c new file mode 100644 index 0000000..5ce7423 --- /dev/null +++ b/notes/08-signals-code/non-reentrant.c @@ -0,0 +1,62 @@ +// Shows dangers of using a non-reentrant function with signal +// handling. Strange things can happen due to the use of the +// non-reentrant function getpwnam() being called both in the main +// loop and signal handler. Uncommenting the getpwnam() in the signal +// handler causes unpredictable things to happen like a permanent +// stall of the program on Linux boxes. +// +// Adapted from Stevens and Rago Fig 10.5. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERNAME "kauffman" + +static void alarm_handler(int signo) { + printf("in signal handler\n"); + struct passwd *rootptr = NULL; + + // NON-REENTRANT FUNCTION CALL IN SIGNAL HANDLER + rootptr = getpwnam("root"); // fetch record associated with root password + + if (rootptr == NULL){ // check for presence of root + printf("no root, that's weird...\n"); + } + else{ + printf("root looks okay\n"); + } + alarm(1); // reset the alarm + printf("leaving signal handler\n"); +} + +int main(void) { + signal(SIGALRM, alarm_handler); // handle alarms in with the above function + alarm(1); + + int successes = 0; + printf("Repeatedly checking on user '%s'\n",USERNAME); + while(1){ + struct passwd *ptr = getpwnam(USERNAME); // non-reentrant call + if(ptr == NULL){ + perror("couldn't find user"); + exit(1); + } + if(strcmp(ptr->pw_name, USERNAME) != 0){ // should always be equal to USERNAME + printf("return value corrupted!, pw_name = %s\n", + ptr->pw_name); + exit(1); + } + successes++; // Show progress of loop + if(successes % 100000 == 0){ + printf("%d successes so far\n",successes); + } + } + exit(0); +} diff --git a/notes/08-signals-code/non-reentrant.c~ b/notes/08-signals-code/non-reentrant.c~ new file mode 100644 index 0000000..3dd0f3e --- /dev/null +++ b/notes/08-signals-code/non-reentrant.c~ @@ -0,0 +1,60 @@ +// Shows dangers of using a non-reentrant function with signal +// handling. Strange things can happen due to the use of the +// non-reentrant function getpwnam() being called both in the main +// loop and signal handler. Uncommenting the getpwnam() in the signal +// handler causes unpredictable things to happen like a permanent +// stall of the program on Linux boxes. +// +// Adapted from Stevens and Rago Fig 10.5. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERNAME "kauffman" + +static void alarm_handler(int signo) { + printf("in signal handler\n"); + struct passwd *rootptr = NULL; + + // NON-REENTRANT FUNCTION CALL IN SIGNAL HANDLER + rootptr = getpwnam("root"); // fetch record associated with root password + + if (rootptr == NULL){ // check for presence of root + printf("no root, that's weird...\n"); + } + else{ + printf("root looks okay\n"); + } + alarm(1); // reset the alarm + printf("leaving signal handler\n"); +} + +int main(void) { + signal(SIGALRM, alarm_handler); // xhandle alarms in with the above function + alarm(1); + + printf("Repeatedly checking on user '%s'\n",USERNAME); + while(1){ + struct passwd *ptr = getpwnam(USERNAME); // non-reentrant call + if(ptr == NULL){ + perror("couldn't find user"); + exit(1); + } + if(strcmp(ptr->pw_name, USERNAME) != 0){ // should always be equal to USERNAME + printf("return value corrupted!, pw_name = %s\n", + ptr->pw_name); + exit(1); + } + // else{ + // printf("%s looks okay\n",USERNAME); // verbose output + // } + } + exit(0); +} diff --git a/notes/08-signals-code/protected-reentrant.c b/notes/08-signals-code/protected-reentrant.c new file mode 100644 index 0000000..6ede4d5 --- /dev/null +++ b/notes/08-signals-code/protected-reentrant.c @@ -0,0 +1,73 @@ +// In-class exercise: protect non-reentrant function using signal +// blocking. This prevents stalls but NOT may yield incorrect results +// if the signals are unblocked before the CRITICAL section can be +// completed. +// +// Adapted from Stevens and Rago Fig 10.5. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USERNAME "kauffman" + +static void alarm_handler(int signo) { + printf("in signal handler\n"); + sigset_t block_all, defaults; // two sets of signals + sigfillset( &block_all ); // contains all signals + sigprocmask(SIG_SETMASK, &block_all, &defaults); // block all signals + struct passwd *rootptr = NULL; + + // NON-REENTRANT FUNCTION CALL IN SIGNAL HANDLER + rootptr = getpwnam("root"); // fetch record associated with root password + + if (rootptr == NULL){ // check for presence of root + printf("no root, that's weird...\n"); + } + else{ + printf("root looks okay\n"); + } + alarm(1); // reset the alarm + sigprocmask(SIG_SETMASK, &defaults, NULL); // un-block signals + printf("leaving signal handler\n"); +} + +int main(void) { + signal(SIGALRM, alarm_handler); // handle alarms in with the above function + alarm(1); + + int successes = 0; + printf("Repeatedly checking on user '%s'\n",USERNAME); + while(1){ + // Block signals while calling non-reentrant function + sigset_t block_all, defaults; // two sets of signals + sigfillset( &block_all ); // contains all signals + sigprocmask(SIG_SETMASK, &block_all, &defaults); // block all signals + struct passwd *ptr = getpwnam(USERNAME); // non-reentrant call + // sigprocmask(SIG_SETMASK, &defaults, NULL); // un-block signals, incorrect position + + if(ptr == NULL){ + perror("couldn't find user"); + exit(1); + } + if(strcmp(ptr->pw_name, USERNAME) != 0){ // should always be equal to USERNAME + printf("return value corrupted! pw_name = %s\n", + ptr->pw_name); + exit(1); + } + + sigprocmask(SIG_SETMASK, &defaults, NULL); // un-block signals, correct position + + successes++; // Show progress of loop + if(successes % 100000 == 0){ + printf("%d successes so far\n",successes); + } + } + exit(0); +} diff --git a/notes/08-signals-code/sigsets-demo.c b/notes/08-signals-code/sigsets-demo.c new file mode 100644 index 0000000..927b5ef --- /dev/null +++ b/notes/08-signals-code/sigsets-demo.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + sigset_t set; + sigemptyset( &set ); + sigaddset( &set, SIGINT); + sigaddset( &set, SIGTERM); + sigaddset( &set, SIGUSR1); + + if( sigismember( &set, SIGINT ) ){ + printf("This set contains SIGINT\n"); + } + + sigdelset( &set, SIGUSR1); + if( sigismember( &set, SIGUSR1 ) ){ + printf("This set contains SIGUSR1\n"); + } + exit(0); +} diff --git a/notes/08-signals.pdf b/notes/08-signals.pdf new file mode 100644 index 0000000..4884f66 Binary files /dev/null and b/notes/08-signals.pdf differ diff --git a/notes/09-pipes-fifos-code.zip b/notes/09-pipes-fifos-code.zip new file mode 100644 index 0000000..d986356 Binary files /dev/null and b/notes/09-pipes-fifos-code.zip differ diff --git a/notes/09-pipes-fifos-code/fill_pipe.c b/notes/09-pipes-fifos-code/fill_pipe.c new file mode 100644 index 0000000..ab226a5 --- /dev/null +++ b/notes/09-pipes-fifos-code/fill_pipe.c @@ -0,0 +1,34 @@ +// Demonstrates fillling a pipe which only occasionally gets read from +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1024 + +int main(int argc, char *argv[]){ + int pip[2]; + pipe(pip); + + int pid = fork(); + if(pid == 0){ // CHILD + char buf[BUFSIZE]; + while(1){ + sleep(1); // sleep then... + printf("Reading ...\n"); + fflush(stdout); + read(pip[0], buf, BUFSIZE); // empty the pipe a bit + } + } + else{ // PARENT + for(int i=1; ; i++){ // keep writing to the pipe + char c = '-'; + write(pip[1], &c, 1); // blocks when pipe is full + printf("Wrote %d so far\n",i); + fflush(stdout); + } + } + return 0; +} diff --git a/notes/09-pipes-fifos-code/multiple_writes.c b/notes/09-pipes-fifos-code/multiple_writes.c new file mode 100644 index 0000000..600facd --- /dev/null +++ b/notes/09-pipes-fifos-code/multiple_writes.c @@ -0,0 +1,70 @@ +// Demonstrate 4 scenarios for writing to files versus FIFOs +// +// > a.out prefork file tmpt.txt 20 +// +// 1. Process opens normal file, forks, Parent / Child write. File position +// in file is shared. +// +// > a.out postfork file tmpt.txt 20 +// +// 2. Process forks, opens file, Parent / Child write. File position +// is NOT shared so will overwrite each other in file. +// +// > a.out prefork fifo tmpt.fifo 20 +// +// 3. Process opens a FIFO, forks, Parent / Child write. Both hang +// until something reads the pipe but all data is present. +// +// > a.out postfork fifo tmpt.fifo 20 +// +// 4. Proccess forks, opens FIFO, Parent / Child write. Both hang +// until something reads the pipe but all data is present. +#include +#include +#include +#include +#include +#include +#include + +#define MAXSIZE 1024 + +int main(int argc, char *argv[]){ + if(argc < 5){ + printf("usage: %s {prefork,postfork} {file,fifo} \n",argv[0]); + exit(1); + } + + char *open_prefork = argv[1]; // open file before or after fork + char *use_fifo = argv[2]; // whether to create a fifo or a normal file + char *fname = argv[3]; // name of file to write + int iters = atoi(argv[4]); // number of iterations to write + char msg[MAXSIZE]; // buffer for message + int fd; + + remove(fname); // get rid of file for creation + if(strcmp(use_fifo,"fifo")==0){ + mkfifo(fname, S_IRUSR | S_IWUSR); // create the fifo if needed + } + + if(strcmp(open_prefork,"prefork")==0){ // open pre-fork, processes share position + fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); // create if needed + } + char *id = "PPPP"; + int pid = fork(); // child inherits file descriptor + if(pid == 0){ // child changes message + id = "CCCC"; + } + if(strcmp(open_prefork,"postfork")==0){ // Open post-fork, each process has its own position + fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); // create if needed + } + + for(int i=0; i +#include +#include +#include + +#define MAXLINE 1024 +#define PAGER "less" // environment variable, or default +// #define PAGER "${PAGER:-more}" // environment variable, or default + +int main(int argc, char *argv[]) { + char line[MAXLINE]; + FILE *fpin, *fpout; + + if (argc != 2){ + printf("usage: a.out \n"); + exit(1); + } + + if ((fpin = fopen(argv[1], "r")) == NULL){ + perror("can′t open input file"); + exit(1); + } + + if ((fpout = popen(PAGER, "w")) == NULL){ + perror("popen error"); + exit(1); + } + + // copy argv[1] to pager + while (fgets(line, MAXLINE, fpin) != NULL) { + if (fputs(line, fpout) == EOF){ + perror("fputs error to pipe"); + exit(1); + } + } + if (ferror(fpin)){ + perror("fgets error"); + exit(1); + } + if (pclose(fpout) == -1){ + perror("pclose error"); + exit(1); + } + + return 0; +} diff --git a/notes/09-pipes-fifos-code/sources_sinks.c b/notes/09-pipes-fifos-code/sources_sinks.c new file mode 100644 index 0000000..d8674fc --- /dev/null +++ b/notes/09-pipes-fifos-code/sources_sinks.c @@ -0,0 +1,84 @@ +// Demonstrate how a FIFO coordinates reads/writes between multiple processes +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1024 + +typedef struct { + int from; + int index; +} msg_t; + +// Write from to source fd +void write_source(int fd, int source_num, int delay){ + int count = 0; + while(1){ + msg_t msg = {.from=source_num, .index=count}; + int nbytes = write(fd, &msg, sizeof(msg_t)); + assert(nbytes == sizeof(msg_t)); + printf("SEND %d: Proc %d sent %d\n", + source_num, getpid(), count); + count++; + sleep(delay); + } +} + +// Write to the source fd +void read_source(int fd, int sink_num, int delay){ + while(1){ + msg_t msg; + int nbytes = read(fd, &msg, sizeof(msg_t)); + assert(nbytes == sizeof(msg_t)); + printf("RECV %d: Proc %d got {from=%3d, index=%3d}\n", + sink_num, getpid(), msg.from, msg.index); + sleep(delay); + } +} + + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); // Turn off output buffering + + if(argc < 3){ + printf("usage: %s \n", argv[0]); + exit(1); + } + + int n_sources = atoi(argv[1]); + int n_sinks = atoi(argv[2]); + + // Create FIFO to coordinate + remove("queue.fifo"); // remove if already present + mkfifo("queue.fifo", S_IRUSR | S_IWUSR); + int fifo_fd = open("queue.fifo", O_RDWR); + printf("queue.fifo fd: %d\n",fifo_fd); + + // Create writing processes + for(int i=1; i<=n_sources; i++){ + int pid=fork(); + if(pid==0){ + write_source(fifo_fd, i, 1); + } + } + + // Create reading processes + for(int i=1; i<=n_sinks; i++){ + int pid=fork(); + if(pid==0){ + read_source(fifo_fd, i, 1); + } + } + + // Not likely to ever get beyond first wait + for(int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1024 + +typedef struct { + int from; + int index; +} msg_t; + +// Write from to source fd +void write_source(int fd, int source_num, int limit){ + for(int count=1; count<=limit; count++){ + msg_t msg = {.from=source_num, .index=count}; + int nbytes = write(fd, &msg, sizeof(msg_t)); + assert(nbytes == sizeof(msg_t)); + printf("SEND %d: Proc %d sent %d\n", + source_num, getpid(), count); + } +} + +// Write to the source fd +void read_source(int fd, int sink_num){ + while(1){ + msg_t msg; + int nbytes = read(fd, &msg, sizeof(msg_t)); + assert(nbytes == sizeof(msg_t)); + printf("RECV %d: Proc %d got {from=%3d, index=%3d}\n", + sink_num, getpid(), msg.from, msg.index); + } +} + + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); // Turn off output buffering + + if(argc < 4){ + printf("usage: %s \n", argv[0]); + exit(1); + } + + int n_sources = atoi(argv[1]); + int n_sinks = atoi(argv[2]); + int limit = atoi(argv[3]); + + // Create FIFO to coordinate + remove("queue.fifo"); // remove if already present + mkfifo("queue.fifo", S_IRUSR | S_IWUSR); + int fifo_fd = open("queue.fifo", O_RDWR); + printf("queue.fifo fd: %d\n",fifo_fd); + + // Create writing processes + for(int i=1; i<=n_sources; i++){ + int pid=fork(); + if(pid==0){ + write_source(fifo_fd, i, limit); + } + } + + // Create reading processes + for(int i=1; i<=n_sinks; i++){ + int pid=fork(); + if(pid==0){ + read_source(fifo_fd, i); + } + } + + // Not likely to ever get beyond first wait + for(int i=0; i a.out file.txt 10 'AAA' & a.out file.txt 10 'BBB' & +// +// which will lead to either all AAA or all BBB messages in +// file.txt. Alternatively run with a fifo/named pipe as in +// +// $> mkfifo some.fifo +// $> a.out some.fifo 10 'AAA' & a.out some.fifo 10 'BBB' & +// +// Doing a cat some.fifo will complete both processes and show output +// intermingled from both. +#include +#include +#include +#include +#include +#include +#include + +#define MAXSIZE 1024 + +int main(int argc, char *argv[]){ + if(argc < 4){ + printf("usage: %s file iters message\n",argv[0]); + exit(1); + } + + char *fname = argv[1]; // name of file to write + int iters = atoi(argv[2]); // number of iterations to write + char *cmd_msg = argv[3]; // message to write each time + char msg[MAXSIZE]; // buffer for message + + int fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); // create if needed + for(int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NRECS 21 +#define STRSIZE 128 +#define SHM_SIZE (NRECS * sizeof(lookup_t)) + +// structure to store a lookup_t of name-to-email association +typedef struct { + char name [STRSIZE]; + char email[STRSIZE]; +} lookup_t; + +lookup_t original_data[NRECS] = { + {"Chris Kauffman" ,"kauffman@umn.edu"}, + {"Christopher Jonathan" ,"jonat003@umn.edu"}, + {"Amy Larson" ,"larson@cs.umn.edu"}, + {"Chris Dovolis" ,"dovolis@cs.umn.edu"}, + {"Dan Knights" ,"knights@cs.umn.edu"}, + {"George Karypis" ,"karypis@cs.umn.edu"}, + {"Steven Jensen" ,"sjensen@cs.umn.edu"}, + {"Daniel Keefe" ,"dfk@umn.edu"}, + {"Michael W. Whalen" ,"whalen@cs.umn.edu"}, + {"Catherine Qi Zhao" ,"qzhao@umn.edu"}, + {"Dan Challou" ,"challou@cs.umn.edu"}, + {"Steven Wu" ,"zsw@umn.edu"}, + {"Michael Steinbach" ,"steinbac@cs.umn.edu"}, + {"Jon Weissman" ,"jon@cs.umn.edu"}, + {"Victoria Interrante" ,"interran@cs.umn.edu"}, + {"Shana Watters" ,"watt0087@umn.edu"}, + {"James Parker" ,"jparker@cs.umn.edu"}, + {"James Moen" ,"moen0017@cs.umn.edu"}, + {"Daniel Giesel" ,"giese138@umn.edu"}, + {"Jon Read" ,"readx028@umn.edu"}, + {"Sara Stokowski" ,"stoko004@umn.edu"}, +}; + + +int main(int argc, char *argv[]) { + if(argc < 2){ + printf("usage: %s restore\n",argv[0]); + printf(" %s lookup \n",argv[0]); + printf(" %s change \n",argv[0]); + exit(1); + } + + key_t key = ftok("shmdemo.c", 'R'); // make the SysV IPC key + int shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT); // connect to (and possibly create) the segment: + lookup_t *data = (lookup_t *) shmat(shmid, (void *)0, 0); // attach to the segment to get a pointer to it: + + if( strcmp("restore",argv[1])==0 ){ + printf("Restoring\n"); + for(int i=0; i +#include +#include +#include +#include +#include +#include + +// Custom struct to hold messages in the message queue +struct my_msgbuf { + long mtype; // tag allowing filtering of messages + char mtext[200]; // Contents of message +}; + +int main(){ + // Get a unique IPC key based on a file name + key_t key = ftok("kirk.c", 'B'); + if(key == -1){ + perror("ftok"); + exit(1); + } + + // Get a message queue based on the key provided + int msqid = msgget(key, 0644 | IPC_CREAT); + if(msqid == -1) { + perror("msgget"); + exit(1); + } + + struct my_msgbuf buf; + buf.mtype = 1; // all messages have the same tag, no filtering done in this program + + printf("Enter lines of text, ^D to quit:\n"); + + // Repeatedly read a line of text into the message buffer and put it into the queue + while(fgets(buf.mtext, sizeof(buf.mtext), stdin) != NULL) { + int len = strlen(buf.mtext); + + // ditch newline at end, if it exists + if (buf.mtext[len-1] == '\n'){ + buf.mtext[len-1] = '\0'; + } + int sent = msgsnd(msqid, &buf, len+1, 0); + if (sent == -1){ + perror("msgsnd"); + } + + // Expect an acknowledgement + int received = msgrcv(msqid, &buf, sizeof buf.mtext, 0, 0); + if (received == -1) { + perror("msgrcv"); + exit(1); + } + printf("Got back: %s\n",buf.mtext); + } + + // Eliminate the message queue + int removal = msgctl(msqid, IPC_RMID, NULL); + if (removal == -1) { + perror("msgctl"); + exit(1); + } + + return 0; +} + diff --git a/notes/10-ipc-code/old/kirk.c b/notes/10-ipc-code/old/kirk.c new file mode 100644 index 0000000..a9be5d4 --- /dev/null +++ b/notes/10-ipc-code/old/kirk.c @@ -0,0 +1,62 @@ +/* +** kirk.c -- writes to a message queue +*/ + +#include +#include +#include +#include +#include +#include +#include + +// Custom struct to hold messages in the message queue +struct my_msgbuf { + long mtype; // tag allowing filtering of messages + char mtext[200]; // Contents of message +}; + +int main(){ + // Get a unique IPC key based on a file name + key_t key = ftok("kirk.c", 'B'); + if(key == -1){ + perror("ftok"); + exit(1); + } + + // Get a message queue based on the key provided + int msqid = msgget(key, 0644 | IPC_CREAT); + if(msqid == -1) { + perror("msgget"); + exit(1); + } + + struct my_msgbuf buf; + buf.mtype = 1; // all messages have the same tag, no filtering done in this program + + printf("Enter lines of text, ^D to quit:\n"); + + // Repeatedly read a line of text into the message buffer and put it into the queue + while(fgets(buf.mtext, sizeof(buf.mtext), stdin) != NULL) { + int len = strlen(buf.mtext); + + // ditch newline at end, if it exists + if (buf.mtext[len-1] == '\n'){ + buf.mtext[len-1] = '\0'; + } + int sent = msgsnd(msqid, &buf, len+1, 0); + if (sent == -1){ + perror("msgsnd"); + } + } + + // Eliminate the message queue + int removal = msgctl(msqid, IPC_RMID, NULL); + if (removal == -1) { + perror("msgctl"); + exit(1); + } + + return 0; +} + diff --git a/notes/10-ipc-code/old/spock.c b/notes/10-ipc-code/old/spock.c new file mode 100644 index 0000000..3aea4c4 --- /dev/null +++ b/notes/10-ipc-code/old/spock.c @@ -0,0 +1,48 @@ +/* +** spock.c -- reads from a message queue +*/ + +#include +#include +#include +#include +#include +#include +#include + +struct my_msgbuf { + long mtype; + char mtext[200]; +}; + +int main(void){ + // Get a unique IPC key based on a file name + key_t key = ftok("kirk.c", 'B'); + if(key == -1){ + perror("ftok"); + exit(1); + } + + // Connect to message queue based on the key provided + int msqid = msgget(key, 0644 | IPC_CREAT); + if(msqid == -1) { + perror("msgget"); + exit(1); + } + + printf("spock: ready to receive messages, captain.\n"); + + // Spock never quits: forever wait for messages in the queue + struct my_msgbuf buf; + for(;;) { + int received = msgrcv(msqid, &buf, sizeof buf.mtext, 0, 0); + if (received == -1) { + perror("msgrcv"); + exit(1); + } + printf("spock: \"%s\"\n", buf.mtext); + } + + return 0; +} + diff --git a/notes/10-ipc-code/philosophers.c b/notes/10-ipc-code/philosophers.c new file mode 100644 index 0000000..ea76f0b --- /dev/null +++ b/notes/10-ipc-code/philosophers.c @@ -0,0 +1,141 @@ +// Dining philosophers (swansons) using System V Semaphores +// Original: http://www.lisha.ufsc.br/~guto/teaching/os/exercise/phil.html +// Modified by Chris Kauffman +// +// Short random delays are added between each philosophers +// thinking/eating cycle to generate some variance in execution order +// +// To see the multiple processes, run the following commands +// > gcc -o philosophers philosophers.c +// > philosophers > xxx & watch -d -n 0.1 'ps ux | grep philosophers' +// Ctrl-c to stop the "watch" command (may screw up the terminal display) + +#include +#include +#include +#include +#include +#include +#include +#include + +const int N_PHILOSOPHERS = 5; // Number of philosophers +const int MEALS_TO_FINISH = 10; // Number of iterations before philosophers finish +const int MAX_DELAY = 50000; // Maximum delay in nanos between meal iterations + +// Semaphore ids +int utensils; // ID for array of IPC semaphores +int not_at_table; // Start dinner when semaphore reaches 0 + +int philosopher(int n); // Defined after main() + +int main(){ + setvbuf(stdout, NULL, _IONBF, 0); + int i, status; + pid_t phil[N_PHILOSOPHERS]; + printf("The Dining Swansons (Philosophers) Problem\n"); + + // Parent process only: + // + // Allocate utensils: semaphores which are initially set to value + // one. 5 utensils total in an array. Private semaphore array for + // parent/children. + utensils = semget(IPC_PRIVATE, N_PHILOSOPHERS, IPC_CREAT | 0600); + for(i=0; i 0 + phil[i] = pid; // parent tracks children + } + } + + // Parent waits on all children to finish + for(i = 0; i < N_PHILOSOPHERS; i++) { + waitpid(phil[i], &status, 0); + } + + // Eliminate the utensils and table semaphores + semctl(utensils, 0, IPC_RMID, 0); + semctl(not_at_table, 0, IPC_RMID, 0); + return 0; +} + +// Code for dining philosopher child processes +int philosopher(int n){ + int i, j, first, second; + struct sembuf op; // Used to perform semaphore operations + op.sem_flg = 0; + srand(time(NULL)); // Seed random number generator + + // Avoid deadlock via slightly different order of utensil requests + // for last philospher + + // first utensil to get, most go for n first, last philospher goes for 0 first + first = (n != N_PHILOSOPHERS-1)? n : 0; + // second utensil to get, last philopher goes for n second + second = (n != N_PHILOSOPHERS-1)? n + 1 : n; + + printf("Swanson %d wants utensils %d and %d\n",n,first,second); + + // Check in for dinner by decrementing the not_at_table value. + op.sem_op = -1; + op.sem_num = 0; + semop(not_at_table, &op, 1); + printf("Swanson %d at the table\n", n); + + // Wait for everyone to check in before start the meal. Passing 0 as + // the sem_op means wait until the not_at_table counter is 0 to + // proceed. + op.sem_op = 0; + op.sem_num = 0; + semop(not_at_table, &op, 1); + + // Main loop of thinking/eating cycles + for(i = 0; i < MEALS_TO_FINISH; i++) { + int sleep_time = rand() % MAX_DELAY; + usleep(sleep_time); // sleep for for a short time + + printf("%2d: Swanson %d is contemplating his awesomeness ...\n", i,n); + + // get first utensil + op.sem_op = -1; + op.sem_num = first; + semop(utensils, &op, 1); + printf("%2d: Swanson %d got utensil %d\n",i,n,first); + + // get second utensil + op.sem_op = -1; + op.sem_num = second; + semop(utensils, &op, 1); + printf("%2d: Swanson %d got utensil %d\n",i,n,second); + + printf("%2d: Swanson %d is eating an egg ...\n", i,n); + + // release first utensil + op.sem_op = +1; + op.sem_num = first; + semop(utensils, &op, 1); + + // release second utensil + op.sem_op = +1; + op.sem_num = second; + semop(utensils, &op, 1); + } + + printf("Swanson %d leaving the diner\n",n); + exit(n); +} diff --git a/notes/10-ipc-code/philosophers_a.c b/notes/10-ipc-code/philosophers_a.c new file mode 100644 index 0000000..b1d97d7 --- /dev/null +++ b/notes/10-ipc-code/philosophers_a.c @@ -0,0 +1,98 @@ +// Original version of dining philosphers. Rather that using a single +// semaphore of size 5 to control the chopsticks, this version uses a +// C array of 5 singular semaphores to control chopstick access +// +// Source: http://www.lisha.ufsc.br/~guto/teaching/os/exercise/phil.html + +#include +#include +#include +#include +#include +#include +#include + +const int ITERATIONS = 50; + +int chopstick[5]; + +int philosopher(int n) +{ + int i, j, first, second; + struct sembuf op; + op.sem_num = 0; + op.sem_flg = 0; + + printf("Philosopher %d was born!\n", n); + srand(n); + + first = (n < 4)? n : 0; /* left for phil 0 .. 3, right for phil 4 */ + second = (n < 4)? n + 1 : 4; /* right for phil 0 .. 3, left for phil 4 */ + + for(i = 0; i < ITERATIONS; i++) { + printf("%2d: Philosopher %d is thinking ...\n", i,n); + /* get first chopstick */ + op.sem_op = -1; + semop(chopstick[first], &op, 1); + /* get second chopstick */ + op.sem_op = -1; + semop(chopstick[second], &op, 1); + + printf("%2d: Philosopher %d is eating ...\n", i,n); + /* release first chopstick */ + op.sem_op = +1; + semop(chopstick[first], &op, 1); + /* release second chopstick */ + op.sem_op = +1; + semop(chopstick[second], &op, 1); + int sleep_time = rand() % 10; + usleep(sleep_time); // sleep for 0-9 microseconds + } + + exit(n); +} + +int main(){ + int i, status; + pid_t phil[5]; + + printf("The Dining-Philosophers Problem\n"); + + // Parent process only: + // + // Allocate chopsticks: semaphores which are initially set to value + // 1. 5 chopsticks total in an array. + for(i = 0; i < 5; i++) { + if((chopstick[i] = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600)) < 0) + return -1; + if(semctl(chopstick[i], 0, SETVAL, 1) < 0) + return -1; + } + + // Parent generates child processes + for(i = 0; i < 5; i++){ + int pid = fork(); + if(pid == 0){ // child has pid 0 + int ret = philosopher(i); // child acts as philosopher + exit(ret); // then exits + } + else{ // parent gets pid > 0 + phil[i] = pid; // parent tracks children + } + } + + // Parent waits on all children to finish + for(i = 0; i < 5; i++) { + waitpid(phil[i], &status, 0); + if(WEXITSTATUS(status) == i) + printf("Philosopher %d went to heaven!\n", i); + else + printf("Philosopher %d went to hell!\n", i); + } + + // Eliminate the chopsticks semaphores + for(i = 0; i < 5; i++) + semctl(chopstick[i], 0, IPC_RMID, 0); + + return 0; +} diff --git a/notes/10-ipc-code/semdemo.c b/notes/10-ipc-code/semdemo.c new file mode 100644 index 0000000..1e2e0d7 --- /dev/null +++ b/notes/10-ipc-code/semdemo.c @@ -0,0 +1,122 @@ +/* +** semdemo.c -- demonstrates semaphore use as a file locking mechanism +*/ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RETRIES 10 + +union semun { + int val; + struct semid_ds *buf; + ushort *array; +}; + +/* +** initsem() -- more-than-inspired by W. Richard Stevens' UNIX Network +** Programming 2nd edition, volume 2, lockvsem.c, page 295. +*/ +int initsem(key_t key, int nsems) /* key from ftok() */ +{ + int i; + union semun arg; + struct semid_ds buf; + struct sembuf sb; + int semid; + + semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666); + + if (semid >= 0) { /* we got it first */ + sb.sem_op = 1; sb.sem_flg = 0; + arg.val = 1; + + printf("press return\n"); getchar(); + + for(sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) { + /* do a semop() to "free" the semaphores. */ + /* this sets the sem_otime field, as needed below. */ + if (semop(semid, &sb, 1) == -1) { + int e = errno; + semctl(semid, 0, IPC_RMID); /* clean up */ + errno = e; + return -1; /* error, check errno */ + } + } + + } else if (errno == EEXIST) { /* someone else got it first */ + int ready = 0; + + semid = semget(key, nsems, 0); /* get the id */ + if (semid < 0) return semid; /* error, check errno */ + + /* wait for other process to initialize the semaphore: */ + arg.buf = &buf; + for(i = 0; i < MAX_RETRIES && !ready; i++) { + semctl(semid, nsems-1, IPC_STAT, arg); + if (arg.buf->sem_otime != 0) { + ready = 1; + } else { + sleep(1); + } + } + if (!ready) { + errno = ETIME; + return -1; + } + } else { + return semid; /* error, check errno */ + } + + return semid; +} + +int main(void) +{ + key_t key; + int semid; + struct sembuf sb; + + sb.sem_num = 0; + sb.sem_op = -1; /* set to allocate resource */ + sb.sem_flg = SEM_UNDO; + + if ((key = ftok("semdemo.c", 'J')) == -1) { + perror("ftok"); + exit(1); + } + + /* grab the semaphore set created by seminit.c: */ + if ((semid = initsem(key, 1)) == -1) { + perror("initsem"); + exit(1); + } + + printf("Press return to lock: "); + getchar(); + printf("Trying to lock...\n"); + + if (semop(semid, &sb, 1) == -1) { + perror("semop"); + exit(1); + } + + printf("Locked.\n"); + printf("Press return to unlock: "); + getchar(); + + sb.sem_op = 1; /* free resource */ + if (semop(semid, &sb, 1) == -1) { + perror("semop"); + exit(1); + } + + printf("Unlocked\n"); + + return 0; +} diff --git a/notes/10-ipc-code/shmdemo.c b/notes/10-ipc-code/shmdemo.c new file mode 100644 index 0000000..8fd34fa --- /dev/null +++ b/notes/10-ipc-code/shmdemo.c @@ -0,0 +1,38 @@ +// System V Shared Memory demo. Create a piece of shared memory, write +// to it or retrive from it. +// +// usage: shmdemo - prints current contents +// shmdemo - changes contents to be the argument given +// +// Based on 9.6 of http://beej.us/guide/bgipc/output/html/multipage/shm.html +#include +#include +#include +#include +#include +#include + +#define SHM_SIZE 1024 // size of shared memory, 1K + +int main(int argc, char *argv[]) { + if (argc > 2) { + fprintf(stderr, "usage: shmdemo [data_to_write]\n"); + exit(1); + } + + // All error handling in the below has been eliminated + key_t key = ftok("shmdemo.c", 'R'); // make the SysV IPC key + int shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT); // connect to (and possibly create) the segment: + char *data = shmat(shmid, (void *)0, 0); // attach to the segment to get a pointer to it: + + if (argc == 2) { + printf("writing to segment: \"%s\"\n", argv[1]); // modify the segment based on the command line + strncpy(data, argv[1], SHM_SIZE); // copy characters into the shared memeory + } + else{ + printf("segment contains: \"%s\"\n", data); // retrieve current contents + } + shmdt(data); // detach from the shared meory + + return 0; +} diff --git a/notes/10-ipc-code/shmtest.c b/notes/10-ipc-code/shmtest.c new file mode 100644 index 0000000..87d027f --- /dev/null +++ b/notes/10-ipc-code/shmtest.c @@ -0,0 +1,59 @@ +/* +** shmdemo.c -- read and write to a shared memory segment +*/ + +#include +#include +#include +#include +#include +#include + +#define SHM_SIZE 1024 /* make it a 1K shared memory segment */ + +int main(int argc, char *argv[]) +{ + key_t key; + int shmid; + char *data; + int mode; + + if (argc > 2) { + fprintf(stderr, "usage: shmdemo [data_to_write]\n"); + exit(1); + } + + /* make the key: */ + if ((key = ftok("shmdemo.c", 'R')) == -1) { + perror("ftok"); + exit(1); + } + + /* connect to (and possibly create) the segment: */ + if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) { + perror("shmget"); + exit(1); + } + + /* attach to the segment to get a pointer to it: */ + data = shmat(shmid, (void *)0, 0); + if (data == (char *)(-1)) { + perror("shmat"); + exit(1); + } + + /* read or modify the segment, based on the command line: */ + if (argc == 2) { + printf("writing to segment: \"%s\"\n", argv[1]); + strncpy(data, argv[1], SHM_SIZE); + } else + printf("segment contains: \"%s\"\n", data); + + /* detach from the segment: */ + if (shmdt(data) == -1) { + perror("shmdt"); + exit(1); + } + + return 0; +} diff --git a/notes/10-ipc-code/spock.c b/notes/10-ipc-code/spock.c new file mode 100644 index 0000000..28ce7b7 --- /dev/null +++ b/notes/10-ipc-code/spock.c @@ -0,0 +1,58 @@ +// System V message queues: reads from a message queue, sends back +// response +// +// Based on: http://beej.us/guide/bgipc/output/html/multipage/mq.html + +#include +#include +#include +#include +#include +#include +#include + +struct my_msgbuf { + long mtype; + char mtext[200]; +}; + +int main(void){ + // Get a unique IPC key based on a file name + key_t key = ftok("kirk.c", 'B'); + if(key == -1){ + perror("ftok"); + exit(1); + } + + // Connect to message queue based on the key provided + int msqid = msgget(key, 0644 | IPC_CREAT); + if(msqid == -1) { + perror("msgget"); + exit(1); + } + + printf("spock: ready to receive messages, captain.\n"); + + // Spock never quits: forever wait for messages in the queue + struct my_msgbuf buf; + for(;;) { + int received = msgrcv(msqid, &buf, sizeof buf.mtext, 0, 0); + if (received == -1) { + perror("msgrcv"); + exit(1); + } + printf("spock: \"%s\"\n", buf.mtext); + + // Respond to the message + strcpy(buf.mtext,"Acknowledged, Captain."); + int len = strlen(buf.mtext); + int sent = msgsnd(msqid, &buf, len+1, 0); + if (sent == -1){ + perror("msgsnd"); + } + + } + + return 0; +} + diff --git a/notes/10-ipc.pdf b/notes/10-ipc.pdf new file mode 100644 index 0000000..dfd4a82 Binary files /dev/null and b/notes/10-ipc.pdf differ diff --git a/notes/11-threads-code.zip b/notes/11-threads-code.zip new file mode 100644 index 0000000..9ec7d9e Binary files /dev/null and b/notes/11-threads-code.zip differ diff --git a/notes/11-threads-code/Makefile b/notes/11-threads-code/Makefile new file mode 100644 index 0000000..656d2e5 --- /dev/null +++ b/notes/11-threads-code/Makefile @@ -0,0 +1,39 @@ +# Makefile build/run experiments using odds_evens_* programs and +# compare timings of variants. + +# print only when lock acquired +CC = gcc -Wall -lpthread -DTHREAD_ITERS=5000 -DVPRINTF=ignore + +# # don't sleep at all +# CC = gcc -Wall -Wno-unused-value -lpthread -DTHREAD_ITERS=5000 -DVPRINTF=ignore -DSLEEPFUN=0 + +# also print when failing to acquire +# CC = gcc -Wall -lpthread -DTHREAD_ITERS=5000 + +PROGS = busy nested_if triple_if condvar two_condvars + +all : $(PROGS) + +experiment : all + for prog in $(PROGS); do echo "time $$prog:"; time $$prog > /tmp/$$prog.out; echo "-----"; done + for prog in $(PROGS); do wc -l /tmp/$$prog.out; done + +busy : odds_evens_busy.c odds_evens.h + $(CC) -o $@ $< + +condvar : odds_evens_condvar.c odds_evens.h + $(CC) -o $@ $< + +nested_if : odds_evens_busy_nested_if.c odds_evens.h + $(CC) -o $@ $< + +triple_if : odds_evens_busy_triple_if.c odds_evens.h + $(CC) -o $@ $< + +two_condvars : odds_evens_two_condvars.c odds_evens.h + $(CC) -o $@ $< + + +clean : + rm -f $(PROGS) + diff --git a/notes/11-threads-code/busy b/notes/11-threads-code/busy new file mode 100755 index 0000000..c9d52fc Binary files /dev/null and b/notes/11-threads-code/busy differ diff --git a/notes/11-threads-code/condvar b/notes/11-threads-code/condvar new file mode 100755 index 0000000..978954c Binary files /dev/null and b/notes/11-threads-code/condvar differ diff --git a/notes/11-threads-code/condvar.c b/notes/11-threads-code/condvar.c new file mode 100644 index 0000000..f0452ec --- /dev/null +++ b/notes/11-threads-code/condvar.c @@ -0,0 +1,115 @@ +/****************************************************************************** +* FILE: condvar.c +* DESCRIPTION: +* Example code for using Pthreads condition variables. The main thread +* creates three threads. Two of those threads increment a "count" variable, +* while the third thread watches the value of "count". When "count" +* reaches a predefined limit, the waiting thread is signaled by one of the +* incrementing threads. The waiting thread "awakens" and then modifies +* count. The program continues until the incrementing threads reach +* TCOUNT. The main program prints the final value of count. +* SOURCE: Adapted from example code in "Pthreads Programming", B. Nichols +* et al. O'Reilly and Associates. +* LAST REVISED: 10/14/10 Blaise Barney +******************************************************************************/ +#include +#include +#include + +#define NUM_THREADS 3 +#define TCOUNT 10 +#define COUNT_LIMIT 12 + +int count = 0; +pthread_mutex_t count_mutex; +pthread_cond_t count_threshold_cv; + +void *inc_count(void *t) +{ + int i; + long my_id = (long)t; + + for (i=0; i < TCOUNT; i++) { + pthread_mutex_lock(&count_mutex); + count++; + + /* + Check the value of count and signal waiting thread when condition is + reached. Note that this occurs while mutex is locked. + */ + if (count == COUNT_LIMIT) { + printf("inc_count(): thread %ld, count = %d Threshold reached. ", + my_id, count); + pthread_cond_signal(&count_threshold_cv); + printf("Just sent signal.\n"); + } + printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", + my_id, count); + pthread_mutex_unlock(&count_mutex); + + /* Do some work so threads can alternate on mutex lock */ + sleep(1); + } + pthread_exit(NULL); +} + +void *watch_count(void *t) +{ + long my_id = (long)t; + + printf("Starting watch_count(): thread %ld\n", my_id); + + /* + Lock mutex and wait for signal. Note that the pthread_cond_wait routine + will automatically and atomically unlock mutex while it waits. + Also, note that if COUNT_LIMIT is reached before this routine is run by + the waiting thread, the loop will be skipped to prevent pthread_cond_wait + from never returning. + */ + pthread_mutex_lock(&count_mutex); + while (count < COUNT_LIMIT) { + printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count); + pthread_cond_wait(&count_threshold_cv, &count_mutex); + printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count); + printf("watch_count(): thread %ld Updating the value of count...\n", my_id,count); + count += 125; + printf("watch_count(): thread %ld count now = %d.\n", my_id, count); + } + printf("watch_count(): thread %ld Unlocking mutex.\n", my_id); + pthread_mutex_unlock(&count_mutex); + pthread_exit(NULL); +} + +int main(int argc, char *argv[]) +{ + int i, rc; + long t1=1, t2=2, t3=3; + pthread_t threads[3]; + pthread_attr_t attr; + + /* Initialize mutex and condition variable objects */ + pthread_mutex_init(&count_mutex, NULL); + pthread_cond_init (&count_threshold_cv, NULL); + + /* For portability, explicitly create threads in a joinable state */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_create(&threads[0], &attr, watch_count, (void *)t1); + pthread_create(&threads[1], &attr, inc_count, (void *)t2); + pthread_create(&threads[2], &attr, inc_count, (void *)t3); + + /* Wait for all threads to complete */ + for (i = 0; i < NUM_THREADS; i++) { + pthread_join(threads[i], NULL); + } + printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n", + NUM_THREADS, count); + + /* Clean up and exit */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&count_mutex); + pthread_cond_destroy(&count_threshold_cv); + pthread_exit (NULL); + +} + diff --git a/notes/11-threads-code/mutex_busy.c b/notes/11-threads-code/mutex_busy.c new file mode 100644 index 0000000..41bb604 --- /dev/null +++ b/notes/11-threads-code/mutex_busy.c @@ -0,0 +1,39 @@ +// Demonstrates that pthread_mutex_lock() is not a busy wait. Two +// threads obtain a lock and then sleep for a second. The total +// runtime should be about 2 seconds as only one thread can have the +// lock at a time. If lock waiting was busy, the user time should be +// about 1s as one thread busily waits for the lock. However user time +// is usually measured in the thousandths of seconds as threads sleep +// then wake up when the the lock is available. +#include +#include +#include + +int glob = 1; +pthread_mutex_t glob_lock; + +void *doit(void *param){ + pthread_mutex_lock(&glob_lock); + glob = glob*2; + sleep(1); + pthread_mutex_unlock(&glob_lock); + return NULL; +} + +int main(){ + printf("BEFORE glob: %d\n",glob); + + pthread_mutex_init(&glob_lock, NULL); + pthread_t thread_1; + pthread_create(&thread_1, NULL, doit, NULL); + pthread_t thread_2; + pthread_create(&thread_2, NULL, doit, NULL); + + pthread_join(thread_1, (void **) NULL); + pthread_join(thread_2, (void **) NULL); + + printf("AFTER glob: %d\n",glob); + pthread_mutex_destroy(&glob_lock); + + return 0; +} diff --git a/notes/11-threads-code/nested_if b/notes/11-threads-code/nested_if new file mode 100755 index 0000000..809bd19 Binary files /dev/null and b/notes/11-threads-code/nested_if differ diff --git a/notes/11-threads-code/odd-even-experiment.txt b/notes/11-threads-code/odd-even-experiment.txt new file mode 100644 index 0000000..0dcf39f --- /dev/null +++ b/notes/11-threads-code/odd-even-experiment.txt @@ -0,0 +1,52 @@ +Programs run were +- busy: always lock, then check +- nested_if: check, the lock, then check again +- triple_if: check, check again, then lock, then check +- condvar: check then sleep on a single condvar, broadcast to sleepers +- two_condvars: check odd_cv or even_cv, sleep, signal opposite CV + +Run on laptop with 4 cores (phaedrus) + +5000 increments, output only when updating + +Simulate work in critical region with usleep(1): 1 microsecond sleep + +time busy: +real 0m2.113s +user 0m1.032s +sys 0m0.596s +----- + +time nested_if: +real 0m2.982s +user 0m3.239s +sys 0m0.330s + +----- +time triple_if: +real 0m2.514s +user 0m2.494s +sys 0m0.378s + +----- +time condvar: +real 0m1.635s +user 0m0.261s +sys 0m0.820s + +----- +time two_condvars: +real 0m1.581s +user 0m0.126s +sys 0m0.405s + +The condition variable(s) leads to much more efficient system CPU +utilization as evidenced by the smaller user times. Using two +condition variables means only waking up a single sleeper that should +wake up. + +Between the busy, nested_if, and triple_if, more checks of the +variable happen with the nested_if/triple_if leading to higher CPU +utilization for checks which is not useful work. The busy variant +causes threads to sleep more often lowering user time. + diff --git a/notes/11-threads-code/odds_evens.h b/notes/11-threads-code/odds_evens.h new file mode 100644 index 0000000..8151833 --- /dev/null +++ b/notes/11-threads-code/odds_evens.h @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +#define NUM_THREADS 2 // number of odd/evens threads +#define TOT_THREADS (2*NUM_THREADS) // total threads + +#ifndef THREAD_ITERS +#define THREAD_ITERS 5 // total iterations each thread will add on +#endif + +#ifndef VPRINTF +#define VPRINTF printf +#endif +void ignore(char *s, int i, int j, int k){} // ignore requests to print + +#ifndef SLEEPFUN +#define SLEEPFUN usleep(1) +#endif + +void update(int *x){ + *x = *x+1; + SLEEPFUN; // simulate some "work" done while locked +} diff --git a/notes/11-threads-code/odds_evens_busy.c b/notes/11-threads-code/odds_evens_busy.c new file mode 100644 index 0000000..773bf17 --- /dev/null +++ b/notes/11-threads-code/odds_evens_busy.c @@ -0,0 +1,72 @@ +// odd/even thread coordination on incrementing an global +// variable. This version involves busy waiting on the odd/even +// condition by locking the single mutex every time, checking, and +// releasing if oddness/evenness is not appropriate. +#include "odds_evens.h" + +int count = 0; // global variable all threads are modifiying +pthread_mutex_t count_mutex; // mutex to check count + +// Run by even child threads, increment count when it is even +void *even_work(void *t) { + int tid = *( (int *) t); + for(int i=0; i +// num_samples: int, how many sample points to try, higher gets closer to pi + +#include +#include + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s \n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + return 1; + } + + unsigned int rstate = 123456789; // seed state for random num generator + + int npoints = atoi(argv[1]); + int total_hits=0; + + for (int i = 0; i < npoints; i++) { + double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + total_hits++; + } + } + + double pi_est = ((double)total_hits) / npoints * 4.0; + printf("npoints: %8d\n",npoints); + printf("hits: %8d\n",total_hits); + printf("pi_est: %f\n",pi_est); + return 0; +} diff --git a/notes/11-threads-code/picalc_rand.c b/notes/11-threads-code/picalc_rand.c new file mode 100644 index 0000000..bb5f8a3 --- /dev/null +++ b/notes/11-threads-code/picalc_rand.c @@ -0,0 +1,42 @@ +// This version uses the rand() function which is NOT thread safe but +// is usable as there is only a single thread in this case. +// +// Sample program to estimate PI = 3.14159... by randomly generating +// points in the positive quadrant and testing whether they are +// distance <= 1.0 from the origin. The ratio of "hits" to tries is +// an approximation for the area of the quarter circle with radius 1 +// so multiplying the ratio by 4 estimates pi. +// +// usage: picalc +// num_samples: int, how many sample points to try, higher gets closer to pi + +#include +#include + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s \n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + return 1; + } + + unsigned int rstate = 123456789; // seed state for random num generator + srand(rstate); // seed the random number gen + + int npoints = atoi(argv[1]); + int total_hits=0; + + for (int i = 0; i < npoints; i++) { + double x = ((double) rand()) / ((double) RAND_MAX); + double y = ((double) rand()) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + total_hits++; + } + } + + double pi_est = ((double)total_hits) / npoints * 4.0; + printf("npoints: %8d\n",npoints); + printf("hits: %8d\n",total_hits); + printf("pi_est: %f\n",pi_est); + return 0; +} diff --git a/notes/11-threads-code/pthread_ids.c b/notes/11-threads-code/pthread_ids.c new file mode 100644 index 0000000..b5ea078 --- /dev/null +++ b/notes/11-threads-code/pthread_ids.c @@ -0,0 +1,23 @@ +// Small example showing non-portable printing of thread IDs which are + // often just unsigned long +#include +#include + +void *doit(void *param){ + pthread_t tid = pthread_self(); + printf("doit: I am thread %ld\n",tid); + int *var = (int *) param; + *var = (*var) * 2; + return NULL; +} + +int main(){ + pthread_t thread_1; + int stackvar = 42; + pthread_create(&thread_1, NULL, doit, &stackvar); + pthread_t tid = pthread_self(); + printf("main: I am thread %ld\n",tid); + pthread_join(thread_1, NULL); + printf("stack var is: %d\n",stackvar); + return 0; +} diff --git a/notes/11-threads-code/pthreads_minimal_example.c b/notes/11-threads-code/pthreads_minimal_example.c new file mode 100644 index 0000000..6a9fe5a --- /dev/null +++ b/notes/11-threads-code/pthreads_minimal_example.c @@ -0,0 +1,19 @@ +// Minimal example of starting a pthread, passing a parameter to the +// thread function, then waiting for it to finish +#include +#include + +void *doit(void *param){ + int p=(int) param; + p = p*2; + return (void *) p; +} + +int main(){ + pthread_t thread_1; + pthread_create(&thread_1, NULL, doit, (void *) 42); + int xres; + pthread_join(thread_1, (void **) &xres); + printf("result is: %d\n",xres); + return 0; +} diff --git a/notes/11-threads-code/pthreads_picalc_broken.c b/notes/11-threads-code/pthreads_picalc_broken.c new file mode 100644 index 0000000..2f98572 --- /dev/null +++ b/notes/11-threads-code/pthreads_picalc_broken.c @@ -0,0 +1,54 @@ +// Broken version of threaded picalc computation. Trouble is access to +// global variable total_hits is not controlled so it may be increased +// incorrectly. The results for this program will vary from run to run +// due to race conditions. + +#include +#include +#include + +// Global variables shared by all threads +int total_hits = 0; +int points_per_thread = -1; + +void *compute_pi(void *arg){ + long thread_id = (long) arg; + unsigned int rstate = 123456789 * thread_id; // give each thread its own starting point + for (int i = 0; i < points_per_thread; i++) { + double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + total_hits++; + } + } + return NULL; +} + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s [num_threads]\n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + printf(" num_threads: int, number of threads to use for the computation, default 4\n"); + return -1; + } + + int npoints = atoi(argv[1]); // number of samples + int num_threads = argc>2 ? atoi(argv[2]) : 4; // number of threads + + points_per_thread = npoints / num_threads; // init global variables + + pthread_t threads[num_threads]; // track each thread + + for(long p=0; p +#include +#include + +// Global variables shared by all threads +int total_hits=0; +int points_per_thread = -1; +pthread_mutex_t lock; + +void *compute_pi(void *arg){ + long thread_id = (long) arg; + unsigned int rstate = 123456789 * thread_id; // give each thread its own starting point + for (int i = 0; i < points_per_thread; i++) { + double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + pthread_mutex_lock(&lock); // lock global variable + total_hits++; // update + pthread_mutex_unlock(&lock); // unlock global variable + } + } + return NULL; +} + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s [num_threads]\n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + printf(" num_threads: int, number of threads to use for the computation, default 4\n"); + return -1; + } + + int npoints = atoi(argv[1]); // number of samples + int num_threads = argc>2 ? atoi(argv[2]) : 4; // number of threads + + points_per_thread = npoints / num_threads; // init global variables + pthread_mutex_init(&lock, NULL); // create a lock + + pthread_t threads[num_threads]; // track each thread + + for(long p=0; p +#include +#include + +// Global variables shared by all threads +int total_hits=0; +int points_per_thread = -1; +pthread_mutex_t lock; + +void *compute_pi(void *arg){ + long thread_id = (long) arg; + int my_hits = 0; // private count for this thread + unsigned int rstate = 123456789 * thread_id; // give each thread its own starting point + for (int i = 0; i < points_per_thread; i++) { + double x = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + double y = ((double) rand_r(&rstate)) / ((double) RAND_MAX); + if (x*x + y*y <= 1.0){ + my_hits++; // update local + } + } + pthread_mutex_lock(&lock); // lock global variable + total_hits += my_hits; // update global hits + pthread_mutex_unlock(&lock); // unlock global variable + return NULL; +} + +int main(int argc, char **argv) { + if(argc < 2){ + printf("usage: %s [num_threads]\n",argv[0]); + printf(" num_samples: int, how many sample points to try, higher gets closer to pi\n"); + printf(" num_threads: int, number of threads to use for the computation, default 4\n"); + return -1; + } + + int npoints = atoi(argv[1]); // number of samples + int num_threads = argc>2 ? atoi(argv[2]) : 4; // number of threads + + points_per_thread = npoints / num_threads; // init global variables + pthread_mutex_init(&lock, NULL); // create a lock + + pthread_t threads[num_threads]; // track each thread + + for(long p=0; p +#include +#include +#include + +#define NUM_THREADS 3 +#define TCOUNT 10 +#define COUNT_LIMIT 12 + +int count = 0; +pthread_mutex_t count_mutex; +pthread_cond_t count_threshold_cv; + +// Run by two child threads +void *inc_count(void *t) +{ + int i; + long my_id = (long)t; + + for (i=0; i < TCOUNT; i++) { + pthread_mutex_lock(&count_mutex); + count++; + + /* Check the value of count and signal waiting thread when + condition is reached. Note that this occurs while mutex is + locked. */ + if (count == COUNT_LIMIT) { + printf("inc_count(): thread %ld, count = %d Threshold reached. ", + my_id, count); + pthread_cond_signal(&count_threshold_cv); + printf("Just sent signal.\n"); + } + printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", + my_id, count); + pthread_mutex_unlock(&count_mutex); + + /* Do some work so threads can alternate on mutex lock */ + sleep(1); + } + pthread_exit(NULL); +} + +// Run by 1 child thread +void *watch_count(void *t) +{ + long my_id = (long)t; + + printf("Starting watch_count(): thread %ld\n", my_id); + + /* Lock mutex and wait for signal. Note that the pthread_cond_wait + routine will automatically and atomically unlock mutex while it + waits. Also, note that if COUNT_LIMIT is reached before this + routine is run by the waiting thread, the loop will be skipped to + prevent pthread_cond_wait from never returning. */ + pthread_mutex_lock(&count_mutex); + while (count < COUNT_LIMIT) { + printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count); + pthread_cond_wait(&count_threshold_cv, &count_mutex); + printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count); + printf("watch_count(): thread %ld Updating the value of count...\n", my_id,count); + // count += 125; + printf("watch_count(): thread %ld count now = %d.\n", my_id, count); + } + printf("watch_count(): thread %ld Unlocking mutex.\n", my_id); + pthread_mutex_unlock(&count_mutex); + pthread_exit(NULL); +} + +int main(int argc, char *argv[]) +{ + int i, rc; + long t1=1, t2=2, t3=3; + pthread_t threads[3]; + pthread_attr_t attr; + + /* Initialize mutex and condition variable objects */ + pthread_mutex_init(&count_mutex, NULL); + pthread_cond_init (&count_threshold_cv, NULL); + + /* For portability, explicitly create threads in a joinable state */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + pthread_create(&threads[0], &attr, watch_count, (void *)t1); + pthread_create(&threads[1], &attr, inc_count, (void *)t2); + pthread_create(&threads[2], &attr, inc_count, (void *)t3); + + /* Wait for all threads to complete */ + for (i = 0; i < NUM_THREADS; i++) { + pthread_join(threads[i], NULL); + } + printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n", + NUM_THREADS, count); + + /* Clean up and exit */ + pthread_attr_destroy(&attr); + pthread_mutex_destroy(&count_mutex); + pthread_cond_destroy(&count_threshold_cv); + pthread_exit (NULL); + +} + diff --git a/notes/11-threads-code/triple_if b/notes/11-threads-code/triple_if new file mode 100755 index 0000000..7bbc711 Binary files /dev/null and b/notes/11-threads-code/triple_if differ diff --git a/notes/11-threads-code/two_condvars b/notes/11-threads-code/two_condvars new file mode 100755 index 0000000..d6ef6bb Binary files /dev/null and b/notes/11-threads-code/two_condvars differ diff --git a/notes/11-threads.pdf b/notes/11-threads.pdf new file mode 100644 index 0000000..ed60aa9 Binary files /dev/null and b/notes/11-threads.pdf differ diff --git a/notes/12-exam2-review.pdf b/notes/12-exam2-review.pdf new file mode 100644 index 0000000..c859b6d Binary files /dev/null and b/notes/12-exam2-review.pdf differ diff --git a/notes/13-sockets-code.zip b/notes/13-sockets-code.zip new file mode 100644 index 0000000..e3858f5 Binary files /dev/null and b/notes/13-sockets-code.zip differ diff --git a/notes/13-sockets-code/Makefile b/notes/13-sockets-code/Makefile new file mode 100644 index 0000000..66cd51c --- /dev/null +++ b/notes/13-sockets-code/Makefile @@ -0,0 +1,17 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) +# LIBS = -lpthread + +all : simple-server simple-client pause-server + +simple-server : simple-server.c + $(CC) -o $@ $^ + +simple-client : simple-client.c + $(CC) -o $@ $^ + +pause-server : pause-server.c + $(CC) -o $@ $^ + +clean : + rm -f *.o simple-server simple-client pause-server diff --git a/notes/13-sockets-code/pause-server.c b/notes/13-sockets-code/pause-server.c new file mode 100644 index 0000000..7b787bf --- /dev/null +++ b/notes/13-sockets-code/pause-server.c @@ -0,0 +1,153 @@ +// pause-server.c: get 4 client connections then tell them inform them +// of shutdown + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void get_address_string(struct addrinfo *addr, char buffer[]); +void get_sock_address_string(struct sockaddr *addr, char buffer[]); +void get_sock_fd_address_string(int sockfd, char buffer[]); + +int main(void) { + int ret; + char address_str[INET6_ADDRSTRLEN+16]; // fill in a string version of the addresses for printing + + struct addrinfo hints = { // hints allow a specific kind of socket + .ai_family = AF_UNSPEC, // to be set up for the server + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_PASSIVE, + }; + + #define PORT "3490" // port number clients will connect to + struct addrinfo *serv_addr; // address of the server + ret = getaddrinfo(NULL, PORT, &hints, &serv_addr); // find server (my) address + assert(ret == 0); + + int listen_fd = socket(serv_addr->ai_family, // fd of socket on which the server will listen + serv_addr->ai_socktype, + serv_addr->ai_protocol); + assert(listen_fd != -1); + + int yes = 1; + ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, // set socket options to allow re-use of address + &yes, sizeof(int)); // avoids "Address already in use" errors on bind + assert(ret != -1); + + ret = bind(listen_fd, // bind the socket to the server address given + serv_addr->ai_addr, // allows listening for connections later on + serv_addr->ai_addrlen); + if(ret == -1){ perror("bind failed"); exit(1); } + + + get_address_string(serv_addr, address_str); + printf("SERVER: address is %s\n", address_str); + + freeaddrinfo(serv_addr); // no longer need the server address once bind completes + + printf("SERVER: waiting for connections on port %s\n", PORT); + + + #define MAX_CLIENTS 4 + int client_fds[MAX_CLIENTS]; + + #define BACKLOG 10 // number of pending connections to queue before refusing + ret = listen(listen_fd, BACKLOG); // block until a client tries to connect + + struct sockaddr_storage client_addr_storage; // info on clients that may connect and + struct sockaddr *client_addr = // structs to store the connection data + (struct sockaddr *) &client_addr_storage; + socklen_t client_addr_size = sizeof(client_addr); + + for(int i=0; iai_family == AF_INET){ // ipv4 address + ip_address = (void *) &((struct sockaddr_in*)addr->ai_addr)->sin_addr; + } + else if(addr->ai_family == AF_INET6){ // ipv6 address + ip_address = (void *) &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr; + } + inet_ntop(addr->ai_family, ip_address, buffer, INET6_ADDRSTRLEN); +} + +// Same as above but takes a socket address as an argument rather than +// a full addrinfo. Also adds the port number to the string. +// Called like the below: +// +// get_sock_address_string(serv_addr->ai_addr, address_str); +void get_sock_address_string(struct sockaddr *addr, char buffer[]){ + void *ip_address = NULL; + if(addr->sa_family == AF_INET){ // ipv4 address + ip_address = (void *) &(((struct sockaddr_in *) addr)->sin_addr); + } + else if(addr->sa_family == AF_INET6){ // ipv6 address + ip_address = (void *) &(((struct sockaddr_in6 *) addr)->sin6_addr); + } + inet_ntop(addr->sa_family, ip_address, buffer, INET6_ADDRSTRLEN); + int len = strlen(buffer); + struct sockaddr_in *addr_in = (struct sockaddr_in *) addr; + sprintf(buffer+len,":%d",addr_in->sin_port); // add on the port for printing +} + +void get_sock_fd_address_string(int sockfd, char buffer[]){ + struct sockaddr_storage client_addr_storage; // info on clients that may connect and + struct sockaddr *client_addr = // structs to store the connection data + (struct sockaddr *) &client_addr_storage; + socklen_t client_addr_size = sizeof(client_addr); + int ret = getpeername(sockfd, // recover the address of the the peer side of the socket + client_addr, + &client_addr_size); + assert(ret != -1); + get_sock_address_string(client_addr, buffer); +} diff --git a/notes/13-sockets-code/simple-client.c b/notes/13-sockets-code/simple-client.c new file mode 100644 index 0000000..f1257a5 --- /dev/null +++ b/notes/13-sockets-code/simple-client.c @@ -0,0 +1,113 @@ +// simple-client.c: contact server and receive a "hello world" +// Adapted from http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#syscalls +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT "3490" // the port client will be connecting to + +#define MAXDATASIZE 100 // max number of bytes we can get at once + +void get_address_string(struct addrinfo *addr, char buffer[]); +void get_sock_address_string(struct sockaddr *addr, char buffer[]); + +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr,"usage: client hostname\n"); + exit(1); + } + char *hostname = argv[1]; + int ret; + + struct addrinfo *serv_addr; // translate the hostname specified to binary + ret = getaddrinfo(hostname, PORT, // and look up its internet address using DNS + NULL, &serv_addr); + assert(ret == 0); + + // Note: there may be several addresses in the linked list assocated + // serv_addr, some of which work and others of which don't. The + // remaining code assumes the first one pointed to directly by + // serv_addr will work. More robust code should cycle through the + // list tring to connect() to each one until successful. + + int sockfd = socket(serv_addr->ai_family, // create a socket with the appropriate params + serv_addr->ai_socktype, // to the server + serv_addr->ai_protocol); + assert(ret != -1); + + ret = connect(sockfd, // connect the socket to the server so that + serv_addr->ai_addr, // writes will send over the network + serv_addr->ai_addrlen); + assert(ret != -1); + + + char address_str[INET6_ADDRSTRLEN]; // fill in a string version of the addrss which was resolved + get_address_string(serv_addr, address_str); // defined below, fills in buffer with printable address + printf("client: connecting to %s\n", address_str); + + freeaddrinfo(serv_addr); // all done with this structure + + char buf[MAXDATASIZE]; + int nbytes = read(sockfd, buf, MAXDATASIZE-1); // receive data data from the server + assert(nbytes != -1); + buf[nbytes] = '\0'; + printf("client: received '%s'\n",buf); + + // int numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0); // alternative to read() is recv() with additional options + + close(sockfd); + + return 0; +} + +// Fill in the given buffer with a string version of the address from +// the given addrinfo. This involves some nasty casting. addrinfo +// structs have the member. +// +// struct sockaddr *ai_addr; /* Socket address for socket. */ +// +// which may be either a sockaddr_in (IPv4) or sockaddr_in6 (IPv6). +// The exact type is defined in the sin_family which is supposed be +// identical to the ai_family field of the addrinfo. +// +// The main workhorse is inet_ntop() which does the actual fill-in of +// the buffer with the translated address. +void get_address_string(struct addrinfo *addr, char buffer[]){ + get_sock_address_string((struct sockaddr *)addr->ai_addr, buffer); + + // void *ip_address = NULL; + // if(addr->ai_family == AF_INET){ // ipv4 address + // ip_address = (void *) &((struct sockaddr_in*)addr->ai_addr)->sin_addr; + // } + // else if(addr->ai_family == AF_INET6){ // ipv6 address + // ip_address = (void *) &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr; + // } + // inet_ntop(addr->ai_family, ip_address, buffer, INET6_ADDRSTRLEN); +} + +// Same as above but takes a socket address as an argument rather than +// a full addrinfo. Also adds the port number to the string. +// Called like the below: +// +// get_sock_address_string(serv_addr->ai_addr, address_str); +void get_sock_address_string(struct sockaddr *addr, char buffer[]){ + void *ip_address = NULL; + if(addr->sa_family == AF_INET){ // ipv4 address + ip_address = (void *) &(((struct sockaddr_in *) addr)->sin_addr); + } + else if(addr->sa_family == AF_INET6){ // ipv6 address + ip_address = (void *) &(((struct sockaddr_in6 *) addr)->sin6_addr); + } + inet_ntop(addr->sa_family, ip_address, buffer, INET6_ADDRSTRLEN); + int len = strlen(buffer); + struct sockaddr_in *addr_in = (struct sockaddr_in *) addr; + sprintf(buffer+len,":%d",addr_in->sin_port); // add on the port for printing +} diff --git a/notes/13-sockets-code/simple-server.c b/notes/13-sockets-code/simple-server.c new file mode 100644 index 0000000..68ca1b3 --- /dev/null +++ b/notes/13-sockets-code/simple-server.c @@ -0,0 +1,124 @@ +// server.c -- a stream socket server demo + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +void get_address_string(struct addrinfo *addr, char buffer[]); +void get_sock_address_string(struct sockaddr *addr, char buffer[]); + +int main(void) { + int ret; + + struct addrinfo hints = { // hints allow a specific kind of socket + .ai_family = AF_UNSPEC, // to be set up for the server + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_PASSIVE, + }; + + #define PORT "3490" // port number clients will connect to + struct addrinfo *serv_addr; // address of the server + ret = getaddrinfo(NULL, PORT, &hints, &serv_addr); // find server (my) address + assert(ret == 0); + + int listen_fd = socket(serv_addr->ai_family, // fd of socket on which the server will listen + serv_addr->ai_socktype, + serv_addr->ai_protocol); + assert(listen_fd != -1); + + int yes = 1; + ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, // set socket options to allow re-use of address + &yes, sizeof(int)); // avoids "Address already in use" errors on bind + assert(ret != -1); + + ret = bind(listen_fd, // bind the socket to the server address given + serv_addr->ai_addr, // allows listening for connections later on + serv_addr->ai_addrlen); + if(ret == -1){ perror("bind failed"); exit(1); } + + + char address_str[INET6_ADDRSTRLEN]; // fill in a string version of the server address for printing + get_address_string(serv_addr, address_str); + printf("SERVER: address is %s\n", address_str); + + freeaddrinfo(serv_addr); // no longer need the server address once bind completes + + printf("SERVER: waiting for connections on port %s\n", PORT); + + #define BACKLOG 10 // number of pending connections to queue before refusing + ret = listen(listen_fd, BACKLOG); // block until a client tries to connect + + while(1){ // server listens forever + struct sockaddr_storage client_addr_storage; // info on clients that may connect and + struct sockaddr *client_addr = // structs to store the connection data + (struct sockaddr *) &client_addr_storage; + socklen_t client_addr_size = sizeof(client_addr); + + int client_fd = accept(listen_fd, // accept a connection from the open port from a client + client_addr, // produces a new file descriptor for socket created to communicate + &client_addr_size); // with the client and fills in client addrss info + assert(client_fd != -1); + + char address_str[INET6_ADDRSTRLEN]; // fill in a string version of the client address for printing + get_sock_address_string(client_addr, address_str); + printf("SERVER: connection from %s\n", address_str); + + ret = write(client_fd, "Hello, world!", 13); + assert(ret != -1); + + close(client_fd); // done with client, release its socket + } + + close(listen_fd); // should close socket on shutdown though this is unreachable + return 0; +} + +// Fill in the given buffer with a string version of the address from +// the given addrinfo. This involves some nasty casting. addrinfo +// structs have the member. +// +// struct sockaddr *ai_addr; /* Socket address for socket. */ +// +// which may be either a sockaddr_in (IPv4) or sockaddr_in6 (IPv6). +// The exact type is defined in the sin_family which is supposed be +// identical to the ai_family field of the addrinfo. +// +// The main workhorse is inet_ntop() which does the actual fill-in of +// the buffer with the translated address. +void get_address_string(struct addrinfo *addr, char buffer[]){ + void *ip_address = NULL; + if(addr->ai_family == AF_INET){ // ipv4 address + ip_address = (void *) &((struct sockaddr_in*)addr->ai_addr)->sin_addr; + } + else if(addr->ai_family == AF_INET6){ // ipv6 address + ip_address = (void *) &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr; + } + inet_ntop(addr->ai_family, ip_address, buffer, INET6_ADDRSTRLEN); +} + +// Same as above but takes a socket address as an argument rather than a full addrinfo. +// Called like the below: +// +// get_sock_address_string(serv_addr->ai_addr, address_str); +void get_sock_address_string(struct sockaddr *addr, char buffer[]){ + void *ip_address = NULL; + if(addr->sa_family == AF_INET){ // ipv4 address + ip_address = (void *) &(((struct sockaddr_in *) addr)->sin_addr); + } + else if(addr->sa_family == AF_INET6){ // ipv6 address + ip_address = (void *) &(((struct sockaddr_in6 *) addr)->sin6_addr); + } + inet_ntop(addr->sa_family, ip_address, buffer, INET6_ADDRSTRLEN); +} diff --git a/notes/13-sockets.pdf b/notes/13-sockets.pdf new file mode 100644 index 0000000..d753cbd Binary files /dev/null and b/notes/13-sockets.pdf differ diff --git a/notes/14-virtual-memory-code.zip b/notes/14-virtual-memory-code.zip new file mode 100644 index 0000000..3437eec Binary files /dev/null and b/notes/14-virtual-memory-code.zip differ diff --git a/notes/14-virtual-memory-code/Makefile b/notes/14-virtual-memory-code/Makefile new file mode 100644 index 0000000..8925e46 --- /dev/null +++ b/notes/14-virtual-memory-code/Makefile @@ -0,0 +1,23 @@ +CFLAGS = -Wall -g +CC = gcc $(CFLAGS) +# LIBS = -lpthread + +all : mmap-specific-stock mmap-tr mmap-print-file mmap-demo page-size + +page-size : page-size.c + $(CC) -o $@ $^ + +mmap-demo : mmap-demo.c + $(CC) -o $@ $^ + +mmap-print-file : mmap-print-file.c + $(CC) -o $@ $^ + +mmap-tr : mmap-tr.c + $(CC) -o $@ $^ + +mmap-specific-stock : mmap-specific-stock.c + $(CC) -o $@ $^ + +clean : + rm -f *.o mmap-specific-stock mmap-tr mmap-print-file mmap-demo page-size diff --git a/notes/14-virtual-memory-code/gettysburg-mod.txt b/notes/14-virtual-memory-code/gettysburg-mod.txt new file mode 100644 index 0000000..83af5a3 --- /dev/null +++ b/notes/14-virtual-memory-code/gettysburg-mod.txt @@ -0,0 +1,25 @@ +Pour score and seven years ago our pathers brought porth on this continent, a +new nation, conceived in Liberty, and dedicated to the proposition that all men +are created equal. + +Now we are engaged in a great civil war, testing whether that nation, or any +nation so conceived and so dedicated, can long endure. We are met on a great +battle-pield op that war. We have come to dedicate a portion op that pield, as a +pinal resting place por those who here gave their lives that that nation might +live. It is altogether pitting and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate -- we can +not hallow -- this ground. The brave men, living and dead, who struggled here, +have consecrated it, par above our poor power to add or detract. The world will +little note, nor long remember what we say here, but it can never porget what +they did here. It is por us the living, rather, to be dedicated here to the +unpinished work which they who pought here have thus par so nobly advanced. It +is rather por us to be here dedicated to the great task remaining bepore us -- +that prom these honored dead we take increased devotion to that cause por which +they gave the last pull measure op devotion -- that we here highly resolve that +these dead shall not have died in vain -- that this nation, under God, shall +have a new birth op preedom -- and that government op the people, by the people, +por the people, shall not perish prom the earth. + +Abraham Lincoln +November 19, 1863 diff --git a/notes/14-virtual-memory-code/gettysburg.txt b/notes/14-virtual-memory-code/gettysburg.txt new file mode 100644 index 0000000..317abed --- /dev/null +++ b/notes/14-virtual-memory-code/gettysburg.txt @@ -0,0 +1,25 @@ +Four score and seven years ago our fathers brought forth on this continent, a +new nation, conceived in Liberty, and dedicated to the proposition that all men +are created equal. + +Now we are engaged in a great civil war, testing whether that nation, or any +nation so conceived and so dedicated, can long endure. We are met on a great +battle-field of that war. We have come to dedicate a portion of that field, as a +final resting place for those who here gave their lives that that nation might +live. It is altogether fitting and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate -- we can +not hallow -- this ground. The brave men, living and dead, who struggled here, +have consecrated it, far above our poor power to add or detract. The world will +little note, nor long remember what we say here, but it can never forget what +they did here. It is for us the living, rather, to be dedicated here to the +unfinished work which they who fought here have thus far so nobly advanced. It +is rather for us to be here dedicated to the great task remaining before us -- +that from these honored dead we take increased devotion to that cause for which +they gave the last full measure of devotion -- that we here highly resolve that +these dead shall not have died in vain -- that this nation, under God, shall +have a new birth of freedom -- and that government of the people, by the people, +for the people, shall not perish from the earth. + +Abraham Lincoln +November 19, 1863 diff --git a/notes/14-virtual-memory-code/gettysburg.txt.bk b/notes/14-virtual-memory-code/gettysburg.txt.bk new file mode 100644 index 0000000..317abed --- /dev/null +++ b/notes/14-virtual-memory-code/gettysburg.txt.bk @@ -0,0 +1,25 @@ +Four score and seven years ago our fathers brought forth on this continent, a +new nation, conceived in Liberty, and dedicated to the proposition that all men +are created equal. + +Now we are engaged in a great civil war, testing whether that nation, or any +nation so conceived and so dedicated, can long endure. We are met on a great +battle-field of that war. We have come to dedicate a portion of that field, as a +final resting place for those who here gave their lives that that nation might +live. It is altogether fitting and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate -- we can +not hallow -- this ground. The brave men, living and dead, who struggled here, +have consecrated it, far above our poor power to add or detract. The world will +little note, nor long remember what we say here, but it can never forget what +they did here. It is for us the living, rather, to be dedicated here to the +unfinished work which they who fought here have thus far so nobly advanced. It +is rather for us to be here dedicated to the great task remaining before us -- +that from these honored dead we take increased devotion to that cause for which +they gave the last full measure of devotion -- that we here highly resolve that +these dead shall not have died in vain -- that this nation, under God, shall +have a new birth of freedom -- and that government of the people, by the people, +for the people, shall not perish from the earth. + +Abraham Lincoln +November 19, 1863 diff --git a/notes/14-virtual-memory-code/mmap-demo.c b/notes/14-virtual-memory-code/mmap-demo.c new file mode 100644 index 0000000..03f6844 --- /dev/null +++ b/notes/14-virtual-memory-code/mmap-demo.c @@ -0,0 +1,24 @@ +// Demonstrate use of mmap() to print the first 128 characters of a +// text file +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + int fd = open("gettysburg.txt", O_RDONLY); // open file to get file descriptor + int size = 128; // size for mmap()'ed memory + char *file_chars = // pointer to file contents + mmap(NULL, size, PROT_READ, MAP_SHARED, // call mmap with given size and file descriptor + fd, 0); // read only, potentially share, offset 0 + + for(int i=0; i +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + if(argc < 2){ + printf("usage: %s \n",argv[0]); + return 0; + } + + int fd = open(argv[1], O_RDONLY); // open file to get file descriptor + + struct stat stat_buf; + fstat(fd, &stat_buf); // get stats on the open file such as size + + + int size = stat_buf.st_size; // size for mmap()'ed memory is size of file + char *file_chars = // pointer to file contents + mmap(NULL, size, PROT_READ, MAP_SHARED, // call mmap with given size and file descriptor + fd, 0); // read only, potentially share, offset 0 + + for(int i=0; i \n",argv[0]); + exit(1); + } + + int in_fd = open(argv[1], O_RDONLY); + int stock_num = atoi(argv[2]); // index of stock to retrieve + + struct stat stat_buf; + fstat(in_fd, &stat_buf); // get stats on the open file such as size + int size = stat_buf.st_size; // size for mmap()'ed memory is size of file + + stock_t *stocks = // pointer to file contents as stock_array + mmap(NULL, size, PROT_READ, // call mmap with given size and file descriptor + MAP_SHARED, in_fd, 0); // read/write, potentially share, offset 0 + + printf("%s\n",stocks[stock_num].symbol); // access indicated stock via mapped mem + + munmap(stocks, size); // unmap and close file + close(in_fd); + return 0; +} diff --git a/notes/14-virtual-memory-code/mmap-tr.c b/notes/14-virtual-memory-code/mmap-tr.c new file mode 100644 index 0000000..8adb6f1 --- /dev/null +++ b/notes/14-virtual-memory-code/mmap-tr.c @@ -0,0 +1,44 @@ +// Demonstrate use of mmap() and fstat() to print all characters in a +// file without use of read() +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + if(argc < 4){ + printf("usage: %s \n",argv[0]); + printf(" Transforms all in-char to out-char in file\n"); + return 0; + } + char *filename = argv[1]; // filename to operate on + char in_char = argv[2][0]; // in character to match + char out_char = argv[3][0]; // out char to transform + + printf("Transforming '%c' to '%c' in %s\n", + in_char, out_char, filename); + + int fd = open(filename, O_RDWR); // open file to get file descriptor + + struct stat stat_buf; + fstat(fd, &stat_buf); // get stats on the open file such as size + int size = stat_buf.st_size; // size for mmap()'ed memory is size of file + + + char *file_chars = // pointer to file contents + mmap(NULL, size, PROT_READ | PROT_WRITE, // call mmap with given size and file descriptor + MAP_SHARED, fd, 0); // read/write, potentially share, offset 0 + + for(int i=0; i +#include /* sysconf(3) */ + +int main(void) { + printf("The page size for this system is %ld bytes.\n", + sysconf(_SC_PAGESIZE)); /* _SC_PAGE_SIZE is OK too. */ + + return 0; +} diff --git a/notes/14-virtual-memory-code/stock.h b/notes/14-virtual-memory-code/stock.h new file mode 100644 index 0000000..b31a671 --- /dev/null +++ b/notes/14-virtual-memory-code/stock.h @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLINE 4096 // max length of lines + +// stock structure +typedef struct { + char symbol[16]; // ticker symbol like GOOG + double open; // price at market open + double close; // price at market close + long volume; // quantity of shares exchanged during day + char name[128]; // name of company +} stock_t; diff --git a/notes/14-virtual-memory-code/stocks-10.dat b/notes/14-virtual-memory-code/stocks-10.dat new file mode 100644 index 0000000..4ab671e Binary files /dev/null and b/notes/14-virtual-memory-code/stocks-10.dat differ diff --git a/notes/14-virtual-memory-code/stocks-10.txt b/notes/14-virtual-memory-code/stocks-10.txt new file mode 100644 index 0000000..10bf54a --- /dev/null +++ b/notes/14-virtual-memory-code/stocks-10.txt @@ -0,0 +1,11 @@ +Symbol Open Low Volume Name +NEA 13.79 13.77 304100 Nuveen AMT-Free Quality Municipal Income Fund +NEE 151.5 151.03 1291000 NextEra Energy, Inc. +NEM 37.72 37.55 3923700 Newmont Mining Corporation +NEP 43.09 41 553600 NextEra Energy Partners, LP +DNB 120.38 119.54 217100 Dun & Bradstreet Corporation (The) +NEU 429.3 425.86 17000 NewMarket Corporation +NEV 14.71 14.64 41000 Nuveen Enhanced Municipal Value Fund +DWDP 70.8 70.53 5606700 DowDuPont Inc. +DNI 13.1 13.05 13600 Dividend and Income Fund +DNP 11.45 11.39 202000 Duff & Phelps Utilities Income, Inc. diff --git a/notes/14-virtual-memory.pdf b/notes/14-virtual-memory.pdf new file mode 100644 index 0000000..44db1db Binary files /dev/null and b/notes/14-virtual-memory.pdf differ diff --git a/p1-code/.gitignore b/p1-code/.gitignore new file mode 100644 index 0000000..9cc90a6 --- /dev/null +++ b/p1-code/.gitignore @@ -0,0 +1,10 @@ +.vscode +*.o +commando +actual.txt +actual.std +expect.txt +expect.std +valgrind.txt +binary_tests +test_args diff --git a/p1-code/3K.txt b/p1-code/3K.txt new file mode 100644 index 0000000..a1b28de --- /dev/null +++ b/p1-code/3K.txt @@ -0,0 +1,139 @@ +1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 +37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 +70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 +102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 +127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 +152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 +177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 +202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 +227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 +252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 +277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 +302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 +327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 +352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 +377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 +402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 +427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 +452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 +477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 +502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 +527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 +552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 +577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 +602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 +627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 +652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 +677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 +702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 +727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 +752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 +777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 +802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 +827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 +852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 +877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 +902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 +927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 +952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 +977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 +1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 +1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 +1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 +1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 +1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 +1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 +1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 +1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 +1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 +1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 +1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 +1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 +1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 +1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 +1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 +1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 +1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 +1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 +1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 +1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 +1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 +1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 +1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 +1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 +1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 +1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 +1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 +1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 +1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 +1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 +1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 +1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 +1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 +1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 +1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 +1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 +1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 +1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 +1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 +1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 +1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 +1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 +1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 +1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 +1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 +1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 +1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 +1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 +1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 +1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 +2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 +2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 +2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 +2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 +2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 +2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 +2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 +2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 +2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 +2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 +2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 +2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 +2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 +2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 +2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 +2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 +2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 +2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 +2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 +2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 +2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 +2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 +2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 +2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 +2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 +2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 +2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 +2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 +2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 +2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 +2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 +2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 +2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 +2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 +2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 +2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 +2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 +2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 +2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 +2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 +2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 +2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 +2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 +2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 +2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 +2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 +2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 +2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 +2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 +2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 diff --git a/p1-code/GROUP-MEMBERS.txt b/p1-code/GROUP-MEMBERS.txt new file mode 100644 index 0000000..6ded15f --- /dev/null +++ b/p1-code/GROUP-MEMBERS.txt @@ -0,0 +1,9 @@ +These 1 or 2 people worked on this project together and will share a +grade for it. + +PARTNER 1: +Michael Zhang +zhan4854 +PARTNER 2: +John Eidum +eidum003 diff --git a/p1-code/Makefile b/p1-code/Makefile new file mode 100644 index 0000000..073e2d9 --- /dev/null +++ b/p1-code/Makefile @@ -0,0 +1,35 @@ +CFLAGS = -Wall -g +CC = gcc + +commando: commando.o cmd.o cmdctl.o util.o + $(CC) $(CFLAGS) -o commando $^ + +commando.o: commando.c commando.h + $(CC) $(CFLAGS) -c $< + +cmd.o: cmd.c commando.h + $(CC) $(CFLAGS) -c $< + +cmdctl.o: cmdctl.c commando.h + $(CC) $(CFLAGS) -c $< + +util.o: util.c commando.h + $(CC) $(CFLAGS) -c $< + +clean: + rm -f *.o actual.txt expect.txt valgrind.txt + +binary_tests.o : binary_tests.c commando.h tests.h + $(CC) -c $< + +test_utils.o : test_utils.c tests.h + $(CC) -c $< + +binary_tests : binary_tests.o cmd.o cmdctl.o test_utils.o + $(CC) -o $@ $^ + +test-binary : binary_tests + valgrind ./binary_tests + +test-shell : commando + ./shell_tests.sh diff --git a/p1-code/a b/p1-code/a new file mode 100644 index 0000000..81195ab --- /dev/null +++ b/p1-code/a @@ -0,0 +1,1001 @@ +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +./table.sh +list diff --git a/p1-code/binary_tests.c b/p1-code/binary_tests.c new file mode 100644 index 0000000..1d6b602 --- /dev/null +++ b/p1-code/binary_tests.c @@ -0,0 +1,783 @@ +#include "commando.h" +#include "tests.h" +#include +#include + +// from cmd.c, but neglected in the distributed commando.h +char *read_all(int fd, int *nread); + +static int TESTS_RUN = 0; +static int PASSED = 0; + +#define BEGTEST(NAME) \ + void NAME(){ \ + TESTS_RUN++; \ + printf("TEST %2d %-18s : ",TESTS_RUN, #NAME); + +#define ENDTEST() \ + printf("OK\n"); \ + PASSED++; \ + } + + +// Tests creation and init of a cmd_t along with cmd_free() to deallocate it +BEGTEST(cmd_new_1){ + char *argv[] = {"cat","quote.txt","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + if( assert_str_equals("cmd->name wrong","cat",cmd->name) ) return; + if( assert_str_equals("cmd->argv[0] wrong","cat",cmd->argv[0]) ) return; + if( assert_str_equals("cmd->argv[1] wrong","quote.txt",cmd->argv[1]) ) return; + if( assert_str_equals("cmd->argv[2] wrong","gettysburg.txt",cmd->argv[2]) ) return; + if( assert_null("cmd->argv[3] wrong",cmd->argv[3]) ) return; + if( assert_str_equals("cmd->str_status wrong","INIT",cmd->str_status) ) return; + if( assert_int_equals("cmd->finished wrong",0,cmd->finished) ) return; + if( assert_int_equals("cmd->status wrong",-1,cmd->status) ) return; + if( assert_int_equals("cmd->pid wrong",-1,cmd->pid) ) return; + if( assert_null("cmd->output wrong",cmd->output) ) return; + if( assert_unique_pointers("cmd->argv[0] not strdup()'d",argv[0],cmd->argv[0]) ) return; + if( assert_unique_pointers("cmd->argv[1] not strdup()'d",argv[1],cmd->argv[1]) ) return; + if( assert_unique_pointers("cmd->argv[2] not strdup()'d",argv[2],cmd->argv[2]) ) return; + cmd_free(cmd); + ENDTEST(); +} + +BEGTEST(cmd_new_2){ + char *argv[] = {"grep","-i", "the ","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + if( assert_str_equals("cmd->name wrong","grep",cmd->name) ) return; + if( assert_str_equals("cmd->argv[0] wrong","grep",cmd->argv[0]) ) return; + if( assert_str_equals("cmd->argv[1] wrong","-i",cmd->argv[1]) ) return; + if( assert_str_equals("cmd->argv[2] wrong","the ",cmd->argv[2]) ) return; + if( assert_str_equals("cmd->argv[3] wrong","gettysburg.txt",cmd->argv[3]) ) return; + if( assert_null("cmd->argv[4] wrong",cmd->argv[4]) ) return; + if( assert_str_equals("cmd->str_status wrong","INIT",cmd->str_status) ) return; + if( assert_int_equals("cmd->finished wrong",0,cmd->finished) ) return; + if( assert_int_equals("cmd->status wrong",-1,cmd->status) ) return; + if( assert_int_equals("cmd->pid wrong",-1,cmd->pid) ) return; + if( assert_null("cmd->output wrong",cmd->output) ) return; + if( assert_unique_pointers("cmd->argv[0] not strdup()'d",argv[0],cmd->argv[0]) ) return; + if( assert_unique_pointers("cmd->argv[1] not strdup()'d",argv[1],cmd->argv[1]) ) return; + if( assert_unique_pointers("cmd->argv[2] not strdup()'d",argv[2],cmd->argv[2]) ) return; + if( assert_unique_pointers("cmd->argv[3] not strdup()'d",argv[3],cmd->argv[3]) ) return; + cmd_free(cmd); + ENDTEST(); +} + +BEGTEST(cmd_new_3){ + char *argv[] = {"ls","-F", "-a","-1","stuff",NULL}; + cmd_t *cmd = cmd_new(argv); + if( assert_str_equals("cmd->name wrong","ls",cmd->name) ) return; + if( assert_str_equals("cmd->argv[0] wrong","ls",cmd->argv[0]) ) return; + if( assert_str_equals("cmd->argv[1] wrong","-F",cmd->argv[1]) ) return; + if( assert_str_equals("cmd->argv[2] wrong","-a",cmd->argv[2]) ) return; + if( assert_str_equals("cmd->argv[3] wrong","-1",cmd->argv[3]) ) return; + if( assert_str_equals("cmd->argv[4] wrong","stuff",cmd->argv[4]) ) return; + if( assert_null("cmd->argv[5] wrong",cmd->argv[5]) ) return; + if( assert_str_equals("cmd->str_status wrong","INIT",cmd->str_status) ) return; + if( assert_int_equals("cmd->finished wrong",0,cmd->finished) ) return; + if( assert_int_equals("cmd->status wrong",-1,cmd->status) ) return; + if( assert_int_equals("cmd->pid wrong",-1,cmd->pid) ) return; + if( assert_null("cmd->output wrong",cmd->output) ) return; + if( assert_unique_pointers("cmd->argv[0] not strdup()'d",argv[0],cmd->argv[0]) ) return; + if( assert_unique_pointers("cmd->argv[1] not strdup()'d",argv[1],cmd->argv[1]) ) return; + if( assert_unique_pointers("cmd->argv[2] not strdup()'d",argv[2],cmd->argv[2]) ) return; + if( assert_unique_pointers("cmd->argv[3] not strdup()'d",argv[3],cmd->argv[3]) ) return; + if( assert_unique_pointers("cmd->argv[4] not strdup()'d",argv[4],cmd->argv[4]) ) return; + cmd_free(cmd); + ENDTEST(); +} + +// Tests creation and init of a cmd_t along with cmd_free() to deallocate it +BEGTEST(cmd_start_1){ + char *argv[] = {"cat","quote.txt","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + cmd_start(cmd); + if( assert_str_equals("cmd->str_status wrong","RUN",cmd->str_status) ) return; + if( assert_int_positive("cmd->pid", cmd->pid) ) return; + if( assert_int_positive("cmd->out_pipe[PREAD]", cmd->out_pipe[PREAD]) ) return; + if( assert_int_positive("cmd->out_pipe[PWRITE]",cmd->out_pipe[PWRITE]) ) return; + if( assert_int_equals("cmd->finished",0,cmd->finished) ) return; + cmd_free(cmd); + ENDTEST(); +} + +BEGTEST(cmd_start_2){ + char *argv[] = {"grep","-i", "the ","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + cmd_start(cmd); + if( assert_str_equals("cmd->str_status wrong","RUN",cmd->str_status) ) return; + if( assert_int_positive("cmd->pid", cmd->pid) ) return; + if( assert_int_positive("cmd->out_pipe[PREAD]", cmd->out_pipe[PREAD]) ) return; + if( assert_int_positive("cmd->out_pipe[PWRITE]",cmd->out_pipe[PWRITE]) ) return; + if( assert_int_equals("cmd->finished",0,cmd->finished) ) return; + cmd_free(cmd); + ENDTEST(); +} +BEGTEST(cmd_start_3){ + char *argv[] = {"ls","-F", "-a","-1","stuff",NULL}; + cmd_t *cmd = cmd_new(argv); + cmd_start(cmd); + if( assert_str_equals("cmd->str_status wrong","RUN",cmd->str_status) ) return; + if( assert_int_positive("cmd->pid", cmd->pid) ) return; + if( assert_int_positive("cmd->out_pipe[PREAD]", cmd->out_pipe[PREAD]) ) return; + if( assert_int_positive("cmd->out_pipe[PWRITE]",cmd->out_pipe[PWRITE]) ) return; + if( assert_int_equals("cmd->finished",0,cmd->finished) ) return; + cmd_free(cmd); + ENDTEST(); +} + +// Tests read_all() function to read all input from an open file +// descriptor +BEGTEST(read_all_1){ + int fd = open("./quote.txt", O_RDONLY); + char *expect_read = + "Object-oriented programming is an exceptionally bad idea which could\n" + "only have originated in California.\n" + "\n" + "-- Edsger Dijkstra\n" + ""; + int bytes_read = -1; + char *actual_read = read_all(fd, &bytes_read); + int result = close(fd); + if( result == -1 ){ fail("fd already closed, should not be"); return; } + if( assert_int_equals("bytes_read wrong:",125,bytes_read) ) return; + actual_read[bytes_read] = '\0'; + if( assert_strn_equals("string read wrong", expect_read, actual_read) ) return; + free(actual_read); + ENDTEST(); +} + +BEGTEST(read_all_2){ + int fd = open("./gettysburg.txt", O_RDONLY); + char *expect_read = + "Four score and seven years ago our fathers brought forth on this\n" + "continent, a new nation, conceived in Liberty, and dedicated to the\n" + "proposition that all men are created equal.\n" + "\n" + "Now we are engaged in a great civil war, testing whether that nation,\n" + "or any nation so conceived and so dedicated, can long endure. We are\n" + "met on a great battle-field of that war. We have come to dedicate a\n" + "portion of that field, as a final resting place for those who here\n" + "gave their lives that that nation might live. It is altogether fitting\n" + "and proper that we should do this.\n" + "\n" + "But, in a larger sense, we can not dedicate -- we can not consecrate\n" + "-- we can not hallow -- this ground. The brave men, living and dead,\n" + "who struggled here, have consecrated it, far above our poor power to\n" + "add or detract. The world will little note, nor long remember what we\n" + "say here, but it can never forget what they did here. It is for us the\n" + "living, rather, to be dedicated here to the unfinished work which they\n" + "who fought here have thus far so nobly advanced. It is rather for us\n" + "to be here dedicated to the great task remaining before us -- that\n" + "from these honored dead we take increased devotion to that cause for\n" + "which they gave the last full measure of devotion -- that we here\n" + "highly resolve that these dead shall not have died in vain -- that\n" + "this nation, under God, shall have a new birth of freedom -- and that\n" + "government of the people, by the people, for the people, shall not\n" + "perish from the earth.\n" + "\n" + "Abraham Lincoln\n" + "November 19, 1863\n" + ""; + int bytes_read = -1; + char *actual_read = read_all(fd, &bytes_read); + int result = close(fd); + if( result == -1 ){ fail("fd already closed, should not be"); return; } + if( assert_int_equals("bytes_read wrong:",1511,bytes_read) ) return; + actual_read[bytes_read] = '\0'; + if( assert_strn_equals("string read wrong", expect_read, actual_read) ) return; + free(actual_read); + ENDTEST(); +} + +BEGTEST(read_all_3){ + int fd = open("./3K.txt", O_RDONLY); + char *expect_read = + "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36\n" + "37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69\n" + "70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101\n" + "102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126\n" + "127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151\n" + "152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176\n" + "177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201\n" + "202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226\n" + "227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251\n" + "252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276\n" + "277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301\n" + "302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326\n" + "327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351\n" + "352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376\n" + "377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401\n" + "402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426\n" + "427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451\n" + "452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476\n" + "477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501\n" + "502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526\n" + "527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551\n" + "552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576\n" + "577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601\n" + "602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626\n" + "627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651\n" + "652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676\n" + "677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701\n" + "702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726\n" + "727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751\n" + "752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776\n" + "777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801\n" + "802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826\n" + "827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851\n" + "852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876\n" + "877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901\n" + "902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926\n" + "927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951\n" + "952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976\n" + "977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000\n" + "1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020\n" + "1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040\n" + "1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060\n" + "1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080\n" + "1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100\n" + "1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120\n" + "1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140\n" + "1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160\n" + "1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180\n" + "1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200\n" + "1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220\n" + "1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240\n" + "1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260\n" + "1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280\n" + "1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300\n" + "1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320\n" + "1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340\n" + "1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360\n" + "1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380\n" + "1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400\n" + "1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420\n" + "1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440\n" + "1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460\n" + "1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480\n" + "1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500\n" + "1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520\n" + "1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540\n" + "1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560\n" + "1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580\n" + "1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600\n" + "1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620\n" + "1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640\n" + "1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660\n" + "1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680\n" + "1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700\n" + "1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720\n" + "1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740\n" + "1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760\n" + "1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780\n" + "1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800\n" + "1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820\n" + "1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840\n" + "1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860\n" + "1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880\n" + "1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900\n" + "1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920\n" + "1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940\n" + "1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960\n" + "1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980\n" + "1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000\n" + "2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020\n" + "2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040\n" + "2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060\n" + "2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080\n" + "2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100\n" + "2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120\n" + "2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140\n" + "2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160\n" + "2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180\n" + "2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200\n" + "2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220\n" + "2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240\n" + "2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260\n" + "2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280\n" + "2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300\n" + "2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320\n" + "2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340\n" + "2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360\n" + "2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380\n" + "2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400\n" + "2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420\n" + "2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440\n" + "2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460\n" + "2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480\n" + "2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500\n" + "2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520\n" + "2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540\n" + "2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560\n" + "2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580\n" + "2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600\n" + "2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620\n" + "2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640\n" + "2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660\n" + "2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680\n" + "2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700\n" + "2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720\n" + "2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740\n" + "2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760\n" + "2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780\n" + "2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800\n" + "2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820\n" + "2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840\n" + "2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860\n" + "2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880\n" + "2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900\n" + "2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920\n" + "2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940\n" + "2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960\n" + "2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980\n" + "2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000\n" + ""; + int bytes_read = -1; + char *actual_read = read_all(fd, &bytes_read); + int result = close(fd); + if( result == -1 ){ fail("fd already closed, should not be"); return; } + if( assert_int_equals("bytes_read wrong:",13893,bytes_read) ) return; + actual_read[bytes_read] = '\0'; + if( assert_strn_equals("string read wrong", expect_read, actual_read) ) return; + free(actual_read); + ENDTEST(); +} + + +// Tests creation and init of a cmd_t along with cmd_free() to deallocate it +BEGTEST(cmd_update_1){ + char *argv[] = {"cat","quote.txt","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + char *expect_output = + "Object-oriented programming is an exceptionally bad idea which could\n" + "only have originated in California.\n" + "\n" + "-- Edsger Dijkstra\n" + "Four score and seven years ago our fathers brought forth on this\n" + "continent, a new nation, conceived in Liberty, and dedicated to the\n" + "proposition that all men are created equal.\n" + "\n" + "Now we are engaged in a great civil war, testing whether that nation,\n" + "or any nation so conceived and so dedicated, can long endure. We are\n" + "met on a great battle-field of that war. We have come to dedicate a\n" + "portion of that field, as a final resting place for those who here\n" + "gave their lives that that nation might live. It is altogether fitting\n" + "and proper that we should do this.\n" + "\n" + "But, in a larger sense, we can not dedicate -- we can not consecrate\n" + "-- we can not hallow -- this ground. The brave men, living and dead,\n" + "who struggled here, have consecrated it, far above our poor power to\n" + "add or detract. The world will little note, nor long remember what we\n" + "say here, but it can never forget what they did here. It is for us the\n" + "living, rather, to be dedicated here to the unfinished work which they\n" + "who fought here have thus far so nobly advanced. It is rather for us\n" + "to be here dedicated to the great task remaining before us -- that\n" + "from these honored dead we take increased devotion to that cause for\n" + "which they gave the last full measure of devotion -- that we here\n" + "highly resolve that these dead shall not have died in vain -- that\n" + "this nation, under God, shall have a new birth of freedom -- and that\n" + "government of the people, by the people, for the people, shall not\n" + "perish from the earth.\n" + "\n" + "Abraham Lincoln\n" + "November 19, 1863\n" + ""; + cmd_start(cmd); + catch_stdout(); + cmd_update_state(cmd,DOBLOCK); + restore_stdout(); + char expect_alert[BUFSIZE]; + snprintf(expect_alert, BUFSIZE, "@!!! cat[#%d]: EXIT(0)\n", cmd->pid); + if( assert_int_equals("cmd->finished",1,cmd->finished) ) return; + if( assert_int_equals("cmd->status",0,cmd->status) ) return; + if( assert_str_equals("cmd->str_status wrong","EXIT(0)",cmd->str_status) ) return; + if( assert_int_equals("cmd->output_size wrong", 1636, cmd->output_size) ) return; + if( assert_strn_equals("cmd->output wrong", expect_output, cmd->output) ) return; + if( assert_strn_equals("Alert message does not match", expect_alert, captured_stdout()) ) return; + cmd_free(cmd); + ENDTEST(); +} + +BEGTEST(cmd_update_2){ + char *argv[] = {"grep","-i", "the ","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + char *expect_output = + "-- we can not hallow -- this ground. The brave men, living and dead,\n" + "add or detract. The world will little note, nor long remember what we\n" + "living, rather, to be dedicated here to the unfinished work which they\n" + "to be here dedicated to the great task remaining before us -- that\n" + "which they gave the last full measure of devotion -- that we here\n" + "government of the people, by the people, for the people, shall not\n" + "perish from the earth.\n" + ""; + cmd_start(cmd); + catch_stdout(); + cmd_update_state(cmd,DOBLOCK); + restore_stdout(); + char expect_alert[BUFSIZE]; + snprintf(expect_alert, BUFSIZE, "@!!! grep[#%d]: EXIT(0)\n", cmd->pid); + if( assert_int_equals("cmd->finished",1,cmd->finished) ) return; + if( assert_int_equals("cmd->status",0,cmd->status) ) return; + if( assert_str_equals("cmd->str_status wrong","EXIT(0)",cmd->str_status) ) return; + if( assert_int_equals("cmd->output_size wrong", 433, cmd->output_size) ) return; + if( assert_strn_equals("cmd->output wrong", expect_output, cmd->output) ) return; + if( assert_strn_equals("Alert message does not match", expect_alert, captured_stdout()) ) return; + cmd_free(cmd); + ENDTEST(); +} + +BEGTEST(cmd_update_3){ + char *argv[] = {"grep","-i", "shmeckles","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + char *expect_output = + ""; + cmd_start(cmd); + catch_stdout(); + cmd_update_state(cmd,DOBLOCK); + restore_stdout(); + char expect_alert[BUFSIZE]; + snprintf(expect_alert, BUFSIZE, "@!!! grep[#%d]: EXIT(1)\n", cmd->pid); + if( assert_int_equals("cmd->finished",1,cmd->finished) ) return; + if( assert_int_equals("cmd->status",1,cmd->status) ) return; + if( assert_str_equals("cmd->str_status wrong","EXIT(1)",cmd->str_status) ) return; + if( assert_int_equals("cmd->output_size wrong", 0, cmd->output_size) ) return; + if( assert_strn_equals("cmd->output wrong", expect_output, cmd->output) ) return; + if( assert_strn_equals("Alert message does not match", expect_alert, captured_stdout()) ) return; + cmd_free(cmd); + ENDTEST(); +} + +// Tests creation and init of a cmd_t along with cmd_free() to deallocate it +BEGTEST(cmd_print_1){ + char *argv[] = {"cat","quote.txt","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + char *expect_output = + "Object-oriented programming is an exceptionally bad idea which could\n" + "only have originated in California.\n" + "\n" + "-- Edsger Dijkstra\n" + "Four score and seven years ago our fathers brought forth on this\n" + "continent, a new nation, conceived in Liberty, and dedicated to the\n" + "proposition that all men are created equal.\n" + "\n" + "Now we are engaged in a great civil war, testing whether that nation,\n" + "or any nation so conceived and so dedicated, can long endure. We are\n" + "met on a great battle-field of that war. We have come to dedicate a\n" + "portion of that field, as a final resting place for those who here\n" + "gave their lives that that nation might live. It is altogether fitting\n" + "and proper that we should do this.\n" + "\n" + "But, in a larger sense, we can not dedicate -- we can not consecrate\n" + "-- we can not hallow -- this ground. The brave men, living and dead,\n" + "who struggled here, have consecrated it, far above our poor power to\n" + "add or detract. The world will little note, nor long remember what we\n" + "say here, but it can never forget what they did here. It is for us the\n" + "living, rather, to be dedicated here to the unfinished work which they\n" + "who fought here have thus far so nobly advanced. It is rather for us\n" + "to be here dedicated to the great task remaining before us -- that\n" + "from these honored dead we take increased devotion to that cause for\n" + "which they gave the last full measure of devotion -- that we here\n" + "highly resolve that these dead shall not have died in vain -- that\n" + "this nation, under God, shall have a new birth of freedom -- and that\n" + "government of the people, by the people, for the people, shall not\n" + "perish from the earth.\n" + "\n" + "Abraham Lincoln\n" + "November 19, 1863\n" + ""; + cmd_start(cmd); + catch_stdout(); + cmd_update_state(cmd,DOBLOCK); + restore_stdout(); + if( assert_strn_equals("cmd->output wrong", expect_output, cmd->output) ) return; + catch_stdout(); + cmd_print_output(cmd); + restore_stdout(); + if( assert_strn_equals("printed output wrong", expect_output, captured_stdout()) ) return; + cmd_free(cmd); + ENDTEST(); +} +BEGTEST(cmd_print_2){ + char *argv[] = {"grep","-i", "the ","gettysburg.txt",NULL}; + cmd_t *cmd = cmd_new(argv); + char *expect_output = + "-- we can not hallow -- this ground. The brave men, living and dead,\n" + "add or detract. The world will little note, nor long remember what we\n" + "living, rather, to be dedicated here to the unfinished work which they\n" + "to be here dedicated to the great task remaining before us -- that\n" + "which they gave the last full measure of devotion -- that we here\n" + "government of the people, by the people, for the people, shall not\n" + "perish from the earth.\n" + ""; + cmd_start(cmd); + catch_stdout(); + cmd_update_state(cmd,DOBLOCK); + restore_stdout(); + if( assert_strn_equals("cmd->output wrong", expect_output, cmd->output) ) return; + catch_stdout(); + cmd_print_output(cmd); + restore_stdout(); + if( assert_strn_equals("printed output wrong", expect_output, captured_stdout()) ) return; + cmd_free(cmd); + ENDTEST(); +} + +// Check for adding a cmd to a cmdctl +BEGTEST(cmdctl_add_1){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"./sleep_print","1","wait for me",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmdctl_add(ctl, cmd); + } + cmdctl_freeall(ctl); + ENDTEST(); +} + +BEGTEST(cmdctl_add_2){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"ls","-a","stuff",NULL}, + {"ls","-a","-F","stuff",NULL}, + {"gcc","-o","test_args","test_args.c",NULL}, + {"grep","-i", "flurbo ","gettysburg.txt",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmdctl_add(ctl, cmd); + } + cmdctl_freeall(ctl); + ENDTEST(); +} + +// Check for cmdctl's update +BEGTEST(cmdctl_update_1){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"ls","-a","stuff",NULL}, + {"ls","-a","-F","stuff",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmd_start(cmd); + cmdctl_add(ctl, cmd); + } + catch_stdout(); + cmdctl_update_state(ctl,DOBLOCK); + restore_stdout(); + char expect_alert[BUFSIZE]; + char *fmt = + "@!!! cat[#%d]: EXIT(0)\n" + "@!!! ls[#%d]: EXIT(0)\n" + "@!!! ls[#%d]: EXIT(0)\n" + ""; + snprintf(expect_alert, BUFSIZE, fmt, ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid); + if( assert_strn_equals("Alert messages do not match", expect_alert, captured_stdout()) ) return; + cmdctl_freeall(ctl); + ENDTEST(); +} + +BEGTEST(cmdctl_update_2){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"ls","-a","stuff",NULL}, + {"grep","-i", "flurbo ","gettysburg.txt",NULL}, + {"ls","-a","-F","stuff",NULL}, + {"gcc","-o","test_args","test_args.c",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmd_start(cmd); + cmdctl_add(ctl, cmd); + } + catch_stdout(); + cmdctl_update_state(ctl,DOBLOCK); + restore_stdout(); + char expect_alert[BUFSIZE]; + char *fmt = + "@!!! cat[#%d]: EXIT(0)\n" + "@!!! ls[#%d]: EXIT(0)\n" + "@!!! grep[#%d]: EXIT(1)\n" + "@!!! ls[#%d]: EXIT(0)\n" + "@!!! gcc[#%d]: EXIT(0)\n" + ""; + snprintf(expect_alert, BUFSIZE, fmt, + ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid, ctl->cmd[3]->pid, ctl->cmd[4]->pid); + if( assert_strn_equals("Alert messages do not match", expect_alert, captured_stdout()) ) return; + cmdctl_freeall(ctl); + ENDTEST(); +} + +BEGTEST(cmdctl_print_1){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"ls","-a","stuff",NULL}, + {"ls","-a","-F","stuff",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmdctl_add(ctl, cmd); + } + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_init = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #-1 -1 INIT -1 cat quote.txt \n" + "1 #-1 -1 INIT -1 ls -a stuff \n" + "2 #-1 -1 INIT -1 ls -a -F stuff \n" + ""; + if( assert_strn_equals("print doesn't match", expect_init, captured_stdout()) ) return; + for(int i=0; children[i][0] != NULL; i++){ + cmd_start(ctl->cmd[i]); + } + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_start_fmt = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #%-8d -1 RUN -1 cat quote.txt \n" + "1 #%-8d -1 RUN -1 ls -a stuff \n" + "2 #%-8d -1 RUN -1 ls -a -F stuff \n" + ""; + char expect_start[BUFSIZE]; + snprintf(expect_start, BUFSIZE, expect_start_fmt, + ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid); + if( assert_strn_equals("print doesn't match", expect_start, captured_stdout()) ) return; + catch_stdout(); + cmdctl_update_state(ctl,DOBLOCK); + restore_stdout(); + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_done_fmt = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #%-8d 0 EXIT(0) 125 cat quote.txt \n" + "1 #%-8d 0 EXIT(0) 33 ls -a stuff \n" + "2 #%-8d 0 EXIT(0) 36 ls -a -F stuff \n" + ""; + char expect_done[BUFSIZE]; + snprintf(expect_done, BUFSIZE, expect_done_fmt, + ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid); + if( assert_strn_equals("print doesn't match", expect_done, captured_stdout()) ) return; + cmdctl_freeall(ctl); + ENDTEST(); +} + +BEGTEST(cmdctl_print_2){ + char *children[][5] = { + {"cat","quote.txt",NULL}, + {"ls","-a","stuff",NULL}, + {"grep","-i", "flurbo","gettysburg.txt",NULL}, + {"ls","-a","-F","stuff",NULL}, + {"gcc","-o","test_args","test_args.c",NULL}, + {NULL}, + }; + cmdctl_t cmdctl = {}; + cmdctl_t *ctl = &cmdctl; + for(int i=0; children[i][0] != NULL; i++){ + cmd_t *cmd = cmd_new(children[i]); + cmdctl_add(ctl, cmd); + } + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_init = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #-1 -1 INIT -1 cat quote.txt \n" + "1 #-1 -1 INIT -1 ls -a stuff \n" + "2 #-1 -1 INIT -1 grep -i flurbo gettysburg.txt \n" + "3 #-1 -1 INIT -1 ls -a -F stuff \n" + "4 #-1 -1 INIT -1 gcc -o test_args test_args.c \n" + ""; + if( assert_strn_equals("print doesn't match", expect_init, captured_stdout()) ) return; + for(int i=0; children[i][0] != NULL; i++){ + cmd_start(ctl->cmd[i]); + } + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_start_fmt = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #%-8d -1 RUN -1 cat quote.txt \n" + "1 #%-8d -1 RUN -1 ls -a stuff \n" + "2 #%-8d -1 RUN -1 grep -i flurbo gettysburg.txt \n" + "3 #%-8d -1 RUN -1 ls -a -F stuff \n" + "4 #%-8d -1 RUN -1 gcc -o test_args test_args.c \n" + ""; + char expect_start[BUFSIZE]; + snprintf(expect_start, BUFSIZE, expect_start_fmt, + ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid, ctl->cmd[3]->pid, ctl->cmd[4]->pid); + if( assert_strn_equals("print doesn't match", expect_start, captured_stdout()) ) return; + catch_stdout(); + cmdctl_update_state(ctl,DOBLOCK); + restore_stdout(); + catch_stdout(); + cmdctl_print(ctl); + restore_stdout(); + char *expect_done_fmt = + "JOB #PID STAT STR_STAT OUTB COMMAND\n" + "0 #%-8d 0 EXIT(0) 125 cat quote.txt \n" + "1 #%-8d 0 EXIT(0) 33 ls -a stuff \n" + "2 #%-8d 1 EXIT(1) 0 grep -i flurbo gettysburg.txt \n" + "3 #%-8d 0 EXIT(0) 36 ls -a -F stuff \n" + "4 #%-8d 0 EXIT(0) 0 gcc -o test_args test_args.c \n" + ""; + char expect_done[BUFSIZE]; + snprintf(expect_done, BUFSIZE, expect_done_fmt, + ctl->cmd[0]->pid, ctl->cmd[1]->pid, ctl->cmd[2]->pid, ctl->cmd[3]->pid, ctl->cmd[4]->pid); + if( assert_strn_equals("print doesn't match", expect_done, captured_stdout()) ) return; + cmdctl_freeall(ctl); + ENDTEST(); +} + + +int main(int argc, char *argv[]){ + setvbuf(stdout, NULL, _IONBF, 0); // Turn off buffering + printf("Running tests\n"); + + // grep 'BEGTEST(' binary_tests.c |sed 's/BEGTEST(//g; s/){/();/g;'|grep -v NAME + cmd_new_1(); + cmd_new_2(); + cmd_new_3(); + cmd_start_1(); + cmd_start_2(); + cmd_start_3(); + read_all_1(); + read_all_2(); + read_all_3(); + cmd_update_1(); + cmd_update_2(); + cmd_update_3(); + cmd_print_1(); + cmd_print_2(); + cmdctl_add_1(); + cmdctl_add_2(); + cmdctl_update_1(); + cmdctl_update_2(); + cmdctl_print_1(); + cmdctl_print_2(); + + printf("================\n"); + printf("Finished: %d / %d passed\n",PASSED,TESTS_RUN); + + return 0; +} diff --git a/p1-code/cmd.c b/p1-code/cmd.c new file mode 100644 index 0000000..8c43ba6 --- /dev/null +++ b/p1-code/cmd.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include "commando.h" + +// Allocate a new cmd_t with the given argv[] array. Make string +// copies of each of the strings contained within argv[] using +// strdup() as they likely come from a source that will be +// altered. Ensure that cmd->argv[] is ended with NULL. Set the name +// field to be the argv[0]. Set finished to 0 (not finished yet). Set +// str_status to be "INIT" using snprintf(). Initialize the remaining +// fields to obvious default values such as -1s, and NULLs. +cmd_t *cmd_new(char *argv[]) { + cmd_t *cmd = malloc(sizeof(cmd_t)); + strcpy(cmd->name, argv[0]); + int i; + for (i = 0; i < ARG_MAX; ++i) { + if (!argv[i]) break; + cmd->argv[i] = strdup(argv[i]); + } + cmd->pid = -1; + cmd->status = -1; + cmd->output = NULL; + cmd->output_size = -1; + cmd->argv[i] = NULL; + cmd->finished = 0; + snprintf(cmd->str_status, 5, "INIT"); + return cmd; +} + +// Deallocate a cmd structure. Deallocate the strings in the argv[] +// array. Also deallocat the output buffer if it is not NULL. Finally, +// deallocate cmd itself. +void cmd_free(cmd_t *cmd) { + for (int i = 0; cmd->argv[i]; ++i) { + free(cmd->argv[i]); + } + if (cmd->output) free(cmd->output); + free(cmd); +} + +// Fork a process and start the command in cmd in it. Change the +// str_status field to "RUN" using snprintf(). Create a pipe for +// out_pipe to capture standard output. In the parent process, ensure +// that the pid field is set to the child PID. In the child process, +// direct standard output to the pipe using the dup2() command. For +// both parent and child, ensure that unused file descriptors for the +// pipe are closed (write in the parent, read in the child). +void cmd_start(cmd_t *cmd) { + snprintf(cmd->str_status, 4, "RUN"); + if (pipe(cmd->out_pipe)) { + printf("pipe failed: %d\n", errno); + exit(1); + // immediately cause a kernel panic!!1! + } + pid_t child_pid = fork(); + if (child_pid == 0) { + // child + close(cmd->out_pipe[PREAD]); + // dup2(cmd->out_pipe[PWRITE], STDOUT_FILENO); + FILE *fp = fopen("lol", "r"); + dup2(cmd->out_pipe[PWRITE], fileno(fp)); + execvp(cmd->name, cmd->argv); + } else { + // parent + cmd->pid = child_pid; + close(cmd->out_pipe[PWRITE]); + } +} + +// If the finished flag is 1, do nothing. Otherwise, update the state +// of cmd. Use waitpid() and the pid field of command to wait +// selectively for the given process. Pass the block argumnent, one of +// DOBLOCK or NOBLOCK, to waitpid() to cause either non-blocking or +// blocking waits. Use the macro WIFEXITED to check the returned +// status for whether the command has exited. If so, set the finished +// field to 1 and set the cmd->status field to the exit status of the +// cmd using the WEXITSTATUS macro. Call cmd_fetch_output() to fill up +// the output buffer for later printing. +// +// When a command finishes (the first time), print a status update +// message of the form +// +// @!!! ls[#17331]: EXIT(0) +// +// which includes the command name, PID, and exit status. +void cmd_update_state(cmd_t *cmd, int block) { + if (cmd->finished) return; + int status = 0; + int val = waitpid(cmd->pid, &status, block); + if (val > 0) { + if (WIFEXITED(status)) { + cmd->status = WEXITSTATUS(status); + snprintf(cmd->str_status, STATUS_LEN, "EXIT(%d)", + WEXITSTATUS(status)); + cmd->finished = 1; + cmd_fetch_output(cmd); + printf("@!!! %s[#%d]: EXIT(%d)\n", cmd->name, cmd->pid, + cmd->status); + } + } + // printf("status of %d is %d\n", cmd->pid, status); +} + +// Read all input from the open file descriptor fd. Store the results +// in a dynamically allocated buffer which may need to grow as more +// data is read. Use an efficient grown scheme such as doubling the +// size of the buffer when additional space is needed. Use realloc() +// for resizing. When no data is left in fd, set the integer pointed +// to by nread to the number of bytes read and return a pointer to the +// allocated buffer. +void *read_all(int fd, int *nread) { + int size = BUFSIZE, total = 0, bytes; + char *buf = (char *)malloc(size + 1); + bytes = read(fd, buf, size / 2); + total += bytes; + while (bytes == size / 2) { + size *= 2; + buf = (char *)realloc(buf, size + 1); + bytes = read(fd, buf + total, size / 2); + if (!bytes) break; + total += bytes; + } + buf[total] = '\0'; + *nread = total; + return buf; +} + +// If cmd->finished is zero, print an error message with the format +// +// ls[#12341] not finished yet +// +// Otherwise retrieves output from the cmd->out_pipe and fills +// cmd->output setting cmd->output_size to number of bytes in +// output. Data should be read() from the cmd's out_pipe into +// cmd->out_buf (allocated in this function). If out_buf runs out of +// space, realloc() it to a larger size and continue reading. Using a +// temporary buffer may help with this. +void cmd_fetch_output(cmd_t *cmd) { + if (!cmd->finished) { + printf("%s[#%d] not finished yet\n", cmd->name, (int)cmd->pid); + return; + } + int nread; + void *buf = read_all(cmd->out_pipe[PREAD], &nread); + cmd->output = buf; + cmd->output_size = nread; + close(cmd->out_pipe[PREAD]); +} + +// Print the output of the cmd contained in the output field if it is +// non-null. Print an error message like +// +// ls[#17251] has no output yet +// +// if output is NULL. The message includes the command name and PID. +void cmd_print_output(cmd_t *cmd) { + if (!cmd->output) { + printf("%s[#%d] has no output yet\n", cmd->name, (int)cmd->pid); + return; + } + write(STDOUT_FILENO, cmd->output, cmd->output_size); +} diff --git a/p1-code/cmdctl.c b/p1-code/cmdctl.c new file mode 100644 index 0000000..ac04c00 --- /dev/null +++ b/p1-code/cmdctl.c @@ -0,0 +1,51 @@ +#include "commando.h" + +// Add the given cmd to the ctl structure. update the cmd[] array and +// size field. +void cmdctl_add(cmdctl_t *ctl, cmd_t *cmd) { ctl->cmd[ctl->size++] = cmd; } + +// Print all cmd elements in the given ctl structure. The format of +// the table is +// +// JOB #PID STAT STR_STAT OUTB COMMAND +// 0 #17434 0 EXIT(0) 2239 ls -l -a -F +// 1 #17435 0 EXIT(0) 3936 gcc --help +// 2 #17436 -1 RUN -1 sleep 2 +// 3 #17437 0 EXIT(0) 921 cat Makefile +// +// Widths of the fields and justification are as follows +// +// JOB #PID STAT STR_STAT OUTB COMMAND +// 1234 12345678 1234 1234567890 1234 Remaining +// left left right right rigt left +// int int int string int string +// +// The final field should be the contents of cmd->argv[] with a space +// between each element of the array. +void cmdctl_print(cmdctl_t *ctl) { + printf("JOB #PID STAT STR_STAT OUTB COMMAND\n"); + for (int i = 0, l = ctl->size; i < l; ++i) { + printf("%-4d #%-8d %4d %10s %4d ", i, ctl->cmd[i]->pid, + ctl->cmd[i]->status, ctl->cmd[i]->str_status, + ctl->cmd[i]->output_size); + for (int j = 0; ctl->cmd[i]->argv[j]; ++j) { + printf("%s ", ctl->cmd[i]->argv[j]); + } + printf("\n"); + } +} + +// Update each cmd in ctl by calling cmd_update_state() which is also +// passed the block argument (either NOBLOCK or DOBLOCK) +void cmdctl_update_state(cmdctl_t *ctl, int block) { + for (int i = 0, l = ctl->size; i < l; ++i) { + cmd_update_state(ctl->cmd[i], block); + } +} + +// Call cmd_free() on all of the constituent cmd_t's. +void cmdctl_freeall(cmdctl_t *ctl) { + for (int i = 0, l = ctl->size; i < l; ++i) { + cmd_free(ctl->cmd[i]); + } +} diff --git a/p1-code/commando.c b/p1-code/commando.c new file mode 100644 index 0000000..0215e63 --- /dev/null +++ b/p1-code/commando.c @@ -0,0 +1,151 @@ +#include "commando.h" +#include +#include +#include + +cmdctl_t commands; + +const char *HELP_CONTENTS = + "COMMANDO COMMANDS\n" + "help : show this message\n" + "exit : exit the program\n" + "list : list all jobs that have been started giving " + "information on each\n" + "pause nanos secs : pause for the given number of nanseconds and " + "seconds\n" + "output-for int : print the output for given job number\n" + "output-all : print output for all jobs\n" + "wait-for int : wait until the given job number finishes\n" + "wait-all : wait for all jobs to finish\n" + "command arg1 ... : non-built-in is run as a job"; + +void cleanup() { cmdctl_freeall(&commands); } + +// define command handlers + +void exit_handler(char **tokens, int ntok) { + cleanup(); + exit(0); +} +void help_handler(char **tokens, int ntok) { printf("%s\n", HELP_CONTENTS); } +void list_handler(char **tokens, int ntok) { cmdctl_print(&commands); } +void pause_handler(char **tokens, int ntok) { + if (ntok < 3) return; + long nsec = atol(tokens[1]); + int sec = atoi(tokens[2]); + pause_for(nsec, sec); +} + +void output_cmd(cmd_t *command) { + printf("@<<< Output for %s[#%d] (%d bytes):\n", command->name, command->pid, + command->output_size); + printf("----------------------------------------\n"); + cmd_print_output(command); + printf("----------------------------------------\n"); +} + +void output_for_handler(char **tokens, int ntok) { + if (ntok < 2) return; + int id = atoi(tokens[1]); + if (id > commands.size) return; + output_cmd(commands.cmd[id]); +} +void output_all_handler(char **tokens, int ntok) { + for (int i = 0, l = commands.size; i < l; ++i) { + output_cmd(commands.cmd[i]); + } +} + +void wait_for_handler(char **tokens, int ntok) { + if (ntok < 2) return; + int id = atoi(tokens[1]); + if (id > commands.size) return; + cmd_update_state(commands.cmd[id], DOBLOCK); +} + +void wait_all_handler(char **tokens, int ntok) { + for (int i = 0, l = commands.size; i < l; ++i) { + cmd_update_state(commands.cmd[i], DOBLOCK); + } +} + +const char *COMMANDS[8] = {"help", "exit", "list", "pause", + "output-for", "output-all", "wait-for", "wait-all"}; +void (*HANDLERS[8])(char **, int); + +int main(int argc, char **argv) { + setvbuf(stdout, NULL, _IONBF, 0); + char input[MAX_LINE + 1]; + char *tokens[ARG_MAX]; + char cmd_flag; + int ntok = 0; + + commands.size = 0; + + HANDLERS[0] = (void *)help_handler; + HANDLERS[1] = (void *)exit_handler; + HANDLERS[2] = (void *)list_handler; + HANDLERS[3] = (void *)pause_handler; + HANDLERS[4] = (void *)output_for_handler; + HANDLERS[5] = (void *)output_all_handler; + HANDLERS[6] = (void *)wait_for_handler; + HANDLERS[7] = (void *)wait_all_handler; + + // echoing option + char echoing = 0; + if ((argc > 1 && !strncmp(argv[1], "--echo", 6)) || getenv("COMMANDO_ECHO")) + echoing = 1; + + while (1) { + // Print the prompt @> + printf("@> "); + + // Use a call to fgets() to read a whole line of text from the user. The + // #define MAX_LINE limits the length of what will be read. If no input + // remains, print End of input and break out of the loop. + char *result = fgets(input, MAX_LINE, stdin); + if (!result) { + printf("\nEnd of input\n"); + break; + } + + // Echo (print) given input if echoing is enabled. + if (echoing) { + printf("%s", input); + } + + // Use a call to parse_into_tokens() from util.c to break the line up by + // spaces. If there are no tokens, jump to the end of the loop (the use + // just + // hit enter). + parse_into_tokens(input, tokens, &ntok); + if (!ntok) { + continue; + } + + // Examine the 0th token for built-ins like help, list, and so forth. + // Use strncmp() to determine if any match and make appropriate calls. + // This will be a long if/else chain of statements. (why?) + cmd_flag = 0; + for (int i = 0; i < 8; ++i) { + if (!strncmp(tokens[0], COMMANDS[i], strlen(COMMANDS[i]))) { + cmd_flag = 1; + HANDLERS[i](tokens, ntok); + break; + } + } + + // If no built-ins match, create a new cmd_t instance where the tokens + // are the argv[] for it and start it running. + if (!cmd_flag) { + cmd_t *cmd = cmd_new(tokens); + cmdctl_add(&commands, cmd); + cmd_start(cmd); + } + + // At the end of each loop, update the state of all child processes via + // a call to cmdctl_update_state(). + cmdctl_update_state(&commands, NOBLOCK); + } + cleanup(); +} diff --git a/p1-code/commando.h b/p1-code/commando.h new file mode 100644 index 0000000..778999f --- /dev/null +++ b/p1-code/commando.h @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1024 // size of read/write buffers +#define PREAD 0 // index of read end of pipe +#define PWRITE 1 // index of write end of pipe +#define NAME_MAX 255 // max len of commands and args +#define ARG_MAX 255 // max number of arguments +#define MAX_LINE 1024 // maximum length of input lines +#define MAX_CHILD 1024 // maximum number of children in commando +#define STATUS_LEN 10 // length of the str_status field in childcmd + +// block options to update_cmd_status() indicating whether to block or +// not on waiting for child; passed to wait() +#define NOBLOCK (WCONTINUED | WUNTRACED | WNOHANG) +#define DOBLOCK (WCONTINUED | WUNTRACED) + +#define eprintf(...) fprintf(stderr, __VA_ARGS__) + +// cmd_t: struct to represent a running command/child process. +typedef struct { + char name[NAME_MAX + 1]; // name of command like "ls" or "gcc" + char *argv[ARG_MAX + 1]; // argv for running child, NULL terminated + pid_t pid; // PID of child + int out_pipe[2]; // pipe for child output + int finished; // 1 if child process finished, 0 otherwise + int status; // return value of child, -1 if not finished + char str_status[STATUS_LEN + + 1]; // describes child status such as RUN or EXIT(..) + void *output; // saved output from child, NULL initially + int output_size; // number of bytes in output +} cmd_t; + +// cmdctl_t: struct for tracking multiple commands +typedef struct { + cmd_t *cmd[MAX_CHILD]; // array of pointers to cmd_t + int size; // number of cmds in the array +} cmdctl_t; + +// util.c +void parse_into_tokens(char input_command[], char *tokens[], int *ntok); +void pause_for(long nanos, int secs); + +// cmd.c +cmd_t *cmd_new(char *argv[]); +void cmd_free(cmd_t *cmd); +void cmd_info(cmd_t *cmd); +void cmd_start(cmd_t *cmd); +void cmd_fetch_output(cmd_t *cmd); +void cmd_print_output(cmd_t *cmd); +void cmd_update_state(cmd_t *cmd, int nohang); + +// cmdctl.c +void cmdctl_print(cmdctl_t *ctl); +void cmdctl_add(cmdctl_t *ctl, cmd_t *cmd); +void cmdctl_update_state(cmdctl_t *ctl, int nohang); +void cmdctl_freeall(cmdctl_t *ctl); diff --git a/p1-code/gettysburg.txt b/p1-code/gettysburg.txt new file mode 100644 index 0000000..ce35ad5 --- /dev/null +++ b/p1-code/gettysburg.txt @@ -0,0 +1,28 @@ +Four score and seven years ago our fathers brought forth on this +continent, a new nation, conceived in Liberty, and dedicated to the +proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, +or any nation so conceived and so dedicated, can long endure. We are +met on a great battle-field of that war. We have come to dedicate a +portion of that field, as a final resting place for those who here +gave their lives that that nation might live. It is altogether fitting +and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate +-- we can not hallow -- this ground. The brave men, living and dead, +who struggled here, have consecrated it, far above our poor power to +add or detract. The world will little note, nor long remember what we +say here, but it can never forget what they did here. It is for us the +living, rather, to be dedicated here to the unfinished work which they +who fought here have thus far so nobly advanced. It is rather for us +to be here dedicated to the great task remaining before us -- that +from these honored dead we take increased devotion to that cause for +which they gave the last full measure of devotion -- that we here +highly resolve that these dead shall not have died in vain -- that +this nation, under God, shall have a new birth of freedom -- and that +government of the people, by the people, for the people, shall not +perish from the earth. + +Abraham Lincoln +November 19, 1863 diff --git a/p1-code/quote.txt b/p1-code/quote.txt new file mode 100644 index 0000000..fbca09a --- /dev/null +++ b/p1-code/quote.txt @@ -0,0 +1,4 @@ +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra diff --git a/p1-code/shell_tests.sh b/p1-code/shell_tests.sh new file mode 100755 index 0000000..78163fa --- /dev/null +++ b/p1-code/shell_tests.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +printf "Loading tests... " +source shell_tests_data.sh +printf "%d tests loaded\n" "$T" + +NTESTS=$T +NPASS=0 + +all_tests=$(seq $NTESTS) + +# Check whether a single test is being run +single_test=$1 +if ((single_test > 0 && single_test <= NTESTS)); then + printf "Running single TEST %d\n" "$single_test" + all_tests=$single_test + NTESTS=1 +else + printf "Running %d tests\n" "$NTESTS" +fi + +# printf "tests: %s\n" "$all_tests" +printf "\n" + +for i in $all_tests; do + printf "TEST %2d %-18s : " "$i" "${tnames[i]}" + + # Run the test + printf "%s\n" "${input[i]}" | ./commando --echo >& actual.txt + ./standardize actual.txt > actual.std + printf "%s\n" "${output[i]}" > expect.std + printf "%s\n" "${input[i]}" | valgrind $VALGRIND_OPTS ./commando --echo |& cat > valgrind.txt + + # Check for failure, print side-by-side diff if problems + if ! cmp -s expect.std actual.std; + then + printf "FAIL: Output Incorrect\n" + printf "================================\n" + printf "INPUT:\n%s\n" "${input[i]}" + printf "OUTPUT: EXPECT vs ACTUAL\n" + diff -y expect.std actual.std + # sdiff expect.txt actual.txt + printf "================================\n" + + # Check various outputs from valgrind + elif ! grep -q 'ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)' valgrind.txt || + ! grep -q 'in use at exit: 0 bytes in 0 blocks' valgrind.txt || + grep -q 'definitely lost: 0 bytes in 0 blocks' valgrind.txt; + then + printf "FAIL: Valgrind detected problems\n" + printf "================================\n" + cat valgrind.txt + printf "================================\n" + else + printf "OK\n" + ((NPASS++)) + fi +done +printf "================================\n" +printf "Finished: %d / %d passed\n" "$NPASS" "$NTESTS" + diff --git a/p1-code/shell_tests_data.sh b/p1-code/shell_tests_data.sh new file mode 100755 index 0000000..6af30c6 --- /dev/null +++ b/p1-code/shell_tests_data.sh @@ -0,0 +1,1206 @@ +#!/bin/bash +T=0 # global test number + +# Basic test to check for help and exit +((T++)) +tnames[T]="help-exit" +read -r -d '' input[$T] <<"ENDIN" +help +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> help +COMMANDO COMMANDS +help : show this message +exit : exit the program +list : list all jobs that have been started giving information on each +pause nanos secs : pause for the given number of nanseconds and seconds +output-for int : print the output for given job number +output-all : print output for all jobs +wait-for int : wait until the given job number finishes +wait-all : wait for all jobs to finish +command arg1 ... : non-built-in is run as a job +@> exit +ALERTS: +ENDOUT + +# Check for presence of list +((T++)) +tnames[T]="list-exit" +read -r -d '' input[$T] <<"ENDIN" +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> exit +ALERTS: +ENDOUT + +# Check for proper handling of end of input +((T++)) +tnames[T]="end-of-input" +read -r -d '' input[$T] <<"ENDIN" +help +list +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> help +COMMANDO COMMANDS +help : show this message +exit : exit the program +list : list all jobs that have been started giving information on each +pause nanos secs : pause for the given number of nanseconds and seconds +output-for int : print the output for given job number +output-all : print output for all jobs +wait-for int : wait until the given job number finishes +wait-all : wait for all jobs to finish +command arg1 ... : non-built-in is run as a job +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> +End of input +ALERTS: +ENDOUT + +# Check for proper handling of blank lines +((T++)) +tnames[T]="blank-lines" +read -r -d '' input[$T] <<"ENDIN" +list + + +help + +list + +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> +@> +@> help +COMMANDO COMMANDS +help : show this message +exit : exit the program +list : list all jobs that have been started giving information on each +pause nanos secs : pause for the given number of nanseconds and seconds +output-for int : print the output for given job number +output-all : print output for all jobs +wait-for int : wait until the given job number finishes +wait-all : wait for all jobs to finish +command arg1 ... : non-built-in is run as a job +@> +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> +@> exit +ALERTS: +ENDOUT + +# Simple test which runs an ls of a directory, waits for it, lists and +# outputs it +((T++)) +tnames[T]="ls-stuff" +read -r -d '' input[$T] <<"ENDIN" +ls -a -F stuff/ +wait-for 0 +list +output-for 0 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -a -F stuff/ +@> wait-for 0 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +@> output-for 0 +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@> exit +ALERTS: +@!!! ls[%0]: EXIT(0) +ENDOUT + +# Simple test which cats output of quote.txt +((T++)) +tnames[T]="cat-quote" +read -r -d '' input[$T] <<"ENDIN" +cat quote.txt +wait-for 0 +output-for 0 +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> cat quote.txt +@> wait-for 0 +@> output-for 0 +@<<< Output for cat[%0] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +@> exit +ALERTS: +@!!! cat[%0]: EXIT(0) +ENDOUT + +# Simple sleeps 1 second, no output +((T++)) +tnames[T]="sleep-1" +read -r -d '' input[$T] <<"ENDIN" +sleep 1 +wait-for 0 +output-for 0 +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> sleep 1 +@> wait-for 0 +@> output-for 0 +@<<< Output for sleep[%0] (0 bytes): +---------------------------------------- +---------------------------------------- +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 0 sleep 1 +@> exit +ALERTS: +@!!! sleep[%0]: EXIT(0) +ENDOUT + + +# Run two ls calls, should have identical output but distinct pids +((T++)) +tnames[T]="ls-multiple" +read -r -d '' input[$T] <<"ENDIN" +ls -a -F stuff/ +ls -a -F stuff/ +wait-for 0 +wait-for 1 +list +output-for 0 +output-for 1 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -a -F stuff/ +@> ls -a -F stuff/ +@> wait-for 0 +@> wait-for 1 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +1 %1 0 EXIT(0) 36 ls -a -F stuff/ +@> output-for 0 +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@> output-for 1 +@<<< Output for ls[%1] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@> exit +ALERTS: +@!!! ls[%0]: EXIT(0) +@!!! ls[%1]: EXIT(0) +ENDOUT + +# Run two calls, ls stuff/ and table.sh +((T++)) +tnames[T]="ls-table" +read -r -d '' input[$T] <<"ENDIN" +ls -a -F stuff/ +./table.sh +wait-for 0 +wait-for 1 +list +output-for 0 +output-for 1 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -a -F stuff/ +@> ./table.sh +@> wait-for 0 +@> wait-for 1 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +1 %1 0 EXIT(0) 1140 ./table.sh +@> output-for 0 +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@> output-for 1 +@<<< Output for ./table.sh[%1] (1140 bytes): +---------------------------------------- +i^1= 1 i^2= 1 i^3= 1 +i^1= 2 i^2= 4 i^3= 8 +i^1= 3 i^2= 9 i^3= 27 +i^1= 4 i^2= 16 i^3= 64 +i^1= 5 i^2= 25 i^3= 125 +i^1= 6 i^2= 36 i^3= 216 +i^1= 7 i^2= 49 i^3= 343 +i^1= 8 i^2= 64 i^3= 512 +i^1= 9 i^2= 81 i^3= 729 +i^1= 10 i^2= 100 i^3= 1000 +i^1= 11 i^2= 121 i^3= 1331 +i^1= 12 i^2= 144 i^3= 1728 +i^1= 13 i^2= 169 i^3= 2197 +i^1= 14 i^2= 196 i^3= 2744 +i^1= 15 i^2= 225 i^3= 3375 +i^1= 16 i^2= 256 i^3= 4096 +i^1= 17 i^2= 289 i^3= 4913 +i^1= 18 i^2= 324 i^3= 5832 +i^1= 19 i^2= 361 i^3= 6859 +i^1= 20 i^2= 400 i^3= 8000 +i^1= 21 i^2= 441 i^3= 9261 +i^1= 22 i^2= 484 i^3= 10648 +i^1= 23 i^2= 529 i^3= 12167 +i^1= 24 i^2= 576 i^3= 13824 +i^1= 25 i^2= 625 i^3= 15625 +i^1= 26 i^2= 676 i^3= 17576 +i^1= 27 i^2= 729 i^3= 19683 +i^1= 28 i^2= 784 i^3= 21952 +i^1= 29 i^2= 841 i^3= 24389 +i^1= 30 i^2= 900 i^3= 27000 +---------------------------------------- +@> exit +ALERTS: +@!!! ls[%0]: EXIT(0) +@!!! ./table.sh[%1]: EXIT(0) +ENDOUT + + +# Remove an executabl if present, compile it, then run it +((T++)) +tnames[T]="compile-run" +read -r -d '' input[$T] <<"ENDIN" +rm -f ./test_args +wait-for 0 +gcc -o test_args ./test_args.c +wait-for 1 +./test_args hello goodbye so long +wait-for 2 +list +output-for 0 +output-for 1 +output-for 2 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> rm -f ./test_args +@> wait-for 0 +@> gcc -o test_args ./test_args.c +@> wait-for 1 +@> ./test_args hello goodbye so long +@> wait-for 2 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 0 rm -f ./test_args +1 %1 0 EXIT(0) 0 gcc -o test_args ./test_args.c +2 %2 5 EXIT(5) 65 ./test_args hello goodbye so long +@> output-for 0 +@<<< Output for rm[%0] (0 bytes): +---------------------------------------- +---------------------------------------- +@> output-for 1 +@<<< Output for gcc[%1] (0 bytes): +---------------------------------------- +---------------------------------------- +@> output-for 2 +@<<< Output for ./test_args[%2] (65 bytes): +---------------------------------------- +5 args received +0: ./test_args +1: hello +2: goodbye +3: so +4: long +---------------------------------------- +@> exit +ALERTS: +@!!! rm[%0]: EXIT(0) +@!!! gcc[%1]: EXIT(0) +@!!! ./test_args[%2]: EXIT(5) +ENDOUT + +# Same as above but uses output-all +((T++)) +tnames[T]="output-all" +read -r -d '' input[$T] <<"ENDIN" +rm -f ./test_args +wait-for 0 +gcc -o test_args ./test_args.c +wait-for 1 +./test_args hello goodbye so long +wait-for 2 +list +output-all +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> rm -f ./test_args +@> wait-for 0 +@> gcc -o test_args ./test_args.c +@> wait-for 1 +@> ./test_args hello goodbye so long +@> wait-for 2 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 0 rm -f ./test_args +1 %1 0 EXIT(0) 0 gcc -o test_args ./test_args.c +2 %2 5 EXIT(5) 65 ./test_args hello goodbye so long +@> output-all +@<<< Output for rm[%0] (0 bytes): +---------------------------------------- +---------------------------------------- +@<<< Output for gcc[%1] (0 bytes): +---------------------------------------- +---------------------------------------- +@<<< Output for ./test_args[%2] (65 bytes): +---------------------------------------- +5 args received +0: ./test_args +1: hello +2: goodbye +3: so +4: long +---------------------------------------- +@> exit +ALERTS: +@!!! rm[%0]: EXIT(0) +@!!! gcc[%1]: EXIT(0) +@!!! ./test_args[%2]: EXIT(5) +ENDOUT + +# Start several independent jobs then wait-all for them +((T++)) +tnames[T]="wait-all" +read -r -d '' input[$T] <<"ENDIN" +ls -a -F stuff/ +gcc -o test_args test_args.c +cat quote.txt +cat gettysburg.txt +wait-all +list +output-all +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -a -F stuff/ +@> gcc -o test_args test_args.c +@> cat quote.txt +@> cat gettysburg.txt +@> wait-all +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +1 %1 0 EXIT(0) 0 gcc -o test_args test_args.c +2 %2 0 EXIT(0) 125 cat quote.txt +3 %3 0 EXIT(0) 1511 cat gettysburg.txt +@> output-all +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@<<< Output for gcc[%1] (0 bytes): +---------------------------------------- +---------------------------------------- +@<<< Output for cat[%2] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@<<< Output for cat[%3] (1511 bytes): +---------------------------------------- +Four score and seven years ago our fathers brought forth on this +continent, a new nation, conceived in Liberty, and dedicated to the +proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, +or any nation so conceived and so dedicated, can long endure. We are +met on a great battle-field of that war. We have come to dedicate a +portion of that field, as a final resting place for those who here +gave their lives that that nation might live. It is altogether fitting +and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate +-- we can not hallow -- this ground. The brave men, living and dead, +who struggled here, have consecrated it, far above our poor power to +add or detract. The world will little note, nor long remember what we +say here, but it can never forget what they did here. It is for us the +living, rather, to be dedicated here to the unfinished work which they +who fought here have thus far so nobly advanced. It is rather for us +to be here dedicated to the great task remaining before us -- that +from these honored dead we take increased devotion to that cause for +which they gave the last full measure of devotion -- that we here +highly resolve that these dead shall not have died in vain -- that +this nation, under God, shall have a new birth of freedom -- and that +government of the people, by the people, for the people, shall not +perish from the earth. + +Abraham Lincoln +November 19, 1863 +---------------------------------------- +@> exit +ALERTS: +@!!! ls[%0]: EXIT(0) +@!!! gcc[%1]: EXIT(0) +@!!! cat[%2]: EXIT(0) +@!!! cat[%3]: EXIT(0) +ENDOUT + +# Initially output should be empty for jobs but filled in later after +# a wait-for; this test may be a little shakey +((T++)) +tnames[T]="output-checks" +read -r -d '' input[$T] <<"ENDIN" +cat quote.txt +list +output-for 0 +wait-for 0 +list +output-for 0 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> cat quote.txt +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 -1 RUN -1 cat quote.txt +@> output-for 0 +@<<< Output for cat[%0] (-1 bytes): +---------------------------------------- +cat[%0] has no output yet +---------------------------------------- +@> wait-for 0 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +@> output-for 0 +@<<< Output for cat[%0] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@> exit +ALERTS: +@!!! cat[%0]: EXIT(0) +ENDOUT + + +# Check that pause is implemented +((T++)) +tnames[T]="pause-present" +read -r -d '' input[$T] <<"ENDIN" +list +pause 10000 0 +pause 0 1 +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> pause 10000 0 +@> pause 0 1 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +@> exit +ALERTS: +ENDOUT + +# Pause should allow short jobs to finish +((T++)) +tnames[T]="pause-works" +read -r -d '' input[$T] <<"ENDIN" +cat quote.txt +pause 10000000 0 +list +output-for 0 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> cat quote.txt +@> pause 10000000 0 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +@> output-for 0 +@<<< Output for cat[%0] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@> exit +ALERTS: +@!!! cat[%0]: EXIT(0) +ENDOUT + +# Multiple jobs should finish after a medium pause +((T++)) +tnames[T]="pause-medium" +read -r -d '' input[$T] <<"ENDIN" +cat quote.txt +cat gettysburg.txt +grep printf test_args.c +pause 10000000 0 +list +output-all +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> cat quote.txt +@> cat gettysburg.txt +@> grep printf test_args.c +@> pause 10000000 0 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +1 %1 0 EXIT(0) 1511 cat gettysburg.txt +2 %2 0 EXIT(0) 71 grep printf test_args.c +@> output-all +@<<< Output for cat[%0] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@<<< Output for cat[%1] (1511 bytes): +---------------------------------------- +Four score and seven years ago our fathers brought forth on this +continent, a new nation, conceived in Liberty, and dedicated to the +proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, +or any nation so conceived and so dedicated, can long endure. We are +met on a great battle-field of that war. We have come to dedicate a +portion of that field, as a final resting place for those who here +gave their lives that that nation might live. It is altogether fitting +and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate +-- we can not hallow -- this ground. The brave men, living and dead, +who struggled here, have consecrated it, far above our poor power to +add or detract. The world will little note, nor long remember what we +say here, but it can never forget what they did here. It is for us the +living, rather, to be dedicated here to the unfinished work which they +who fought here have thus far so nobly advanced. It is rather for us +to be here dedicated to the great task remaining before us -- that +from these honored dead we take increased devotion to that cause for +which they gave the last full measure of devotion -- that we here +highly resolve that these dead shall not have died in vain -- that +this nation, under God, shall have a new birth of freedom -- and that +government of the people, by the people, for the people, shall not +perish from the earth. + +Abraham Lincoln +November 19, 1863 +---------------------------------------- +@<<< Output for grep[%2] (71 bytes): +---------------------------------------- + printf("%d args received\n",argc); + printf("%d: %s\n",i,argv[i]); +---------------------------------------- +@> exit +ALERTS: +@!!! cat[%0]: EXIT(0) +@!!! cat[%1]: EXIT(0) +@!!! grep[%2]: EXIT(0) +ENDOUT + +# Longer jobs should not finish during the pause +((T++)) +tnames[T]="pause-not-done" +read -r -d '' input[$T] <<"ENDIN" +cat quote.txt +./table.sh 20 2 +cat gettysburg.txt +grep printf test_args.c +pause 10000000 0 +list +output-all +wait-all +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> cat quote.txt +@> ./table.sh 20 2 +@> cat gettysburg.txt +@> grep printf test_args.c +@> pause 10000000 0 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +1 %3 -1 RUN -1 ./table.sh 20 2 +2 %1 0 EXIT(0) 1511 cat gettysburg.txt +3 %2 0 EXIT(0) 71 grep printf test_args.c +@> output-all +@<<< Output for cat[%0] (125 bytes): +---------------------------------------- +Object-oriented programming is an exceptionally bad idea which could +only have originated in California. + +-- Edsger Dijkstra +---------------------------------------- +@<<< Output for ./table.sh[%3] (-1 bytes): +---------------------------------------- +./table.sh[%3] has no output yet +---------------------------------------- +@<<< Output for cat[%1] (1511 bytes): +---------------------------------------- +Four score and seven years ago our fathers brought forth on this +continent, a new nation, conceived in Liberty, and dedicated to the +proposition that all men are created equal. + +Now we are engaged in a great civil war, testing whether that nation, +or any nation so conceived and so dedicated, can long endure. We are +met on a great battle-field of that war. We have come to dedicate a +portion of that field, as a final resting place for those who here +gave their lives that that nation might live. It is altogether fitting +and proper that we should do this. + +But, in a larger sense, we can not dedicate -- we can not consecrate +-- we can not hallow -- this ground. The brave men, living and dead, +who struggled here, have consecrated it, far above our poor power to +add or detract. The world will little note, nor long remember what we +say here, but it can never forget what they did here. It is for us the +living, rather, to be dedicated here to the unfinished work which they +who fought here have thus far so nobly advanced. It is rather for us +to be here dedicated to the great task remaining before us -- that +from these honored dead we take increased devotion to that cause for +which they gave the last full measure of devotion -- that we here +highly resolve that these dead shall not have died in vain -- that +this nation, under God, shall have a new birth of freedom -- and that +government of the people, by the people, for the people, shall not +perish from the earth. + +Abraham Lincoln +November 19, 1863 +---------------------------------------- +@<<< Output for grep[%2] (71 bytes): +---------------------------------------- + printf("%d args received\n",argc); + printf("%d: %s\n",i,argv[i]); +---------------------------------------- +@> wait-all +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 125 cat quote.txt +1 %3 0 EXIT(0) 760 ./table.sh 20 2 +2 %1 0 EXIT(0) 1511 cat gettysburg.txt +3 %2 0 EXIT(0) 71 grep printf test_args.c +@> exit +ALERTS: +@!!! cat[%0]: EXIT(0) +@!!! cat[%1]: EXIT(0) +@!!! grep[%2]: EXIT(0) +@!!! ./table.sh[%3]: EXIT(0) +ENDOUT + + +# Check that wait-for waits for individual jobs +((T++)) +tnames[T]="wait-coord" +read -r -d '' input[$T] <<"ENDIN" +sleep 1 +sleep 3 +sleep 2 +wait-for 0 +output-for 0 +output-for 1 +wait-for 2 +output-for 2 +output-for 1 +wait-all +output-for 1 +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> sleep 1 +@> sleep 3 +@> sleep 2 +@> wait-for 0 +@> output-for 0 +@<<< Output for sleep[%0] (0 bytes): +---------------------------------------- +---------------------------------------- +@> output-for 1 +@<<< Output for sleep[%1] (-1 bytes): +---------------------------------------- +sleep[%1] has no output yet +---------------------------------------- +@> wait-for 2 +@> output-for 2 +@<<< Output for sleep[%2] (0 bytes): +---------------------------------------- +---------------------------------------- +@> output-for 1 +@<<< Output for sleep[%1] (-1 bytes): +---------------------------------------- +sleep[%1] has no output yet +---------------------------------------- +@> wait-all +@> output-for 1 +@<<< Output for sleep[%1] (0 bytes): +---------------------------------------- +---------------------------------------- +@> exit +ALERTS: +@!!! sleep[%0]: EXIT(0) +@!!! sleep[%2]: EXIT(0) +@!!! sleep[%1]: EXIT(0) +ENDOUT + +# Somewhat involved test with a variety of commands +((T++)) +tnames[T]="stress1" +read -r -d '' input[$T] <<"ENDIN" +ls -a -F stuff/ +./table.sh 50 2 +sleep 2 +list +cat test_args.c +pause 0 1 +output-for 1 +output-all +list +wait-all +list +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -a -F stuff/ +@> ./table.sh 50 2 +@> sleep 2 +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 -1 RUN -1 ls -a -F stuff/ +1 %1 -1 RUN -1 ./table.sh 50 2 +2 %2 -1 RUN -1 sleep 2 +@> cat test_args.c +@> pause 0 1 +@> output-for 1 +@<<< Output for ./table.sh[%1] (-1 bytes): +---------------------------------------- +./table.sh[%1] has no output yet +---------------------------------------- +@> output-all +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@<<< Output for ./table.sh[%1] (-1 bytes): +---------------------------------------- +./table.sh[%1] has no output yet +---------------------------------------- +@<<< Output for sleep[%2] (-1 bytes): +---------------------------------------- +sleep[%2] has no output yet +---------------------------------------- +@<<< Output for cat[%3] (175 bytes): +---------------------------------------- +#include + +int main(int argc, char *argv[]){ + printf("%d args received\n",argc); + for(int i=0; i list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +1 %1 -1 RUN -1 ./table.sh 50 2 +2 %2 -1 RUN -1 sleep 2 +3 %3 0 EXIT(0) 175 cat test_args.c +@> wait-all +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -a -F stuff/ +1 %1 0 EXIT(0) 1900 ./table.sh 50 2 +2 %2 0 EXIT(0) 0 sleep 2 +3 %3 0 EXIT(0) 175 cat test_args.c +@> exit +ALERTS: +@!!! ls[%0]: EXIT(0) +@!!! cat[%3]: EXIT(0) +@!!! ./table.sh[%1]: EXIT(0) +@!!! sleep[%2]: EXIT(0) +ENDOUT + +# Somewhat involved test with a variety of commands +((T++)) +tnames[T]="stress2" +read -r -d '' input[$T] <<"ENDIN" +ls -1 -a -F stuff/ +./table.sh 100 2 +./table.sh 50 3 +grep flurbo gettysburg.txt +list +cat test_args.c +pause 0 1 +output-all +grep -n the gettysburg.txt +grep -n the quote.txt +list +wait-all +list +output-all +exit +ENDIN + +read -r -d '' output[$T] <<"ENDOUT" +@> ls -1 -a -F stuff/ +@> ./table.sh 100 2 +@> ./table.sh 50 3 +@> grep flurbo gettysburg.txt +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 -1 RUN -1 ls -1 -a -F stuff/ +1 %1 -1 RUN -1 ./table.sh 100 2 +2 %2 -1 RUN -1 ./table.sh 50 3 +3 %3 -1 RUN -1 grep flurbo gettysburg.txt +@> cat test_args.c +@> pause 0 1 +@> output-all +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@<<< Output for ./table.sh[%1] (-1 bytes): +---------------------------------------- +./table.sh[%1] has no output yet +---------------------------------------- +@<<< Output for ./table.sh[%2] (-1 bytes): +---------------------------------------- +./table.sh[%2] has no output yet +---------------------------------------- +@<<< Output for grep[%3] (0 bytes): +---------------------------------------- +---------------------------------------- +@<<< Output for cat[%4] (175 bytes): +---------------------------------------- +#include + +int main(int argc, char *argv[]){ + printf("%d args received\n",argc); + for(int i=0; i grep -n the gettysburg.txt +@> grep -n the quote.txt +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -1 -a -F stuff/ +1 %1 -1 RUN -1 ./table.sh 100 2 +2 %2 -1 RUN -1 ./table.sh 50 3 +3 %3 1 EXIT(1) 0 grep flurbo gettysburg.txt +4 %4 0 EXIT(0) 175 cat test_args.c +5 %5 -1 RUN -1 grep -n the gettysburg.txt +6 %6 -1 RUN -1 grep -n the quote.txt +@> wait-all +@> list +JOB #PID STAT STR_STAT OUTB COMMAND +0 %0 0 EXIT(0) 36 ls -1 -a -F stuff/ +1 %1 0 EXIT(0) 3801 ./table.sh 100 2 +2 %2 0 EXIT(0) 1900 ./table.sh 50 3 +3 %3 1 EXIT(1) 0 grep flurbo gettysburg.txt +4 %4 0 EXIT(0) 175 cat test_args.c +5 %5 0 EXIT(0) 879 grep -n the gettysburg.txt +6 %6 1 EXIT(1) 0 grep -n the quote.txt +@> output-all +@<<< Output for ls[%0] (36 bytes): +---------------------------------------- +./ +../ +a.out* +expect.txt +util.o +xxx +---------------------------------------- +@<<< Output for ./table.sh[%1] (3801 bytes): +---------------------------------------- +i^1= 1 i^2= 1 i^3= 1 +i^1= 2 i^2= 4 i^3= 8 +i^1= 3 i^2= 9 i^3= 27 +i^1= 4 i^2= 16 i^3= 64 +i^1= 5 i^2= 25 i^3= 125 +i^1= 6 i^2= 36 i^3= 216 +i^1= 7 i^2= 49 i^3= 343 +i^1= 8 i^2= 64 i^3= 512 +i^1= 9 i^2= 81 i^3= 729 +i^1= 10 i^2= 100 i^3= 1000 +i^1= 11 i^2= 121 i^3= 1331 +i^1= 12 i^2= 144 i^3= 1728 +i^1= 13 i^2= 169 i^3= 2197 +i^1= 14 i^2= 196 i^3= 2744 +i^1= 15 i^2= 225 i^3= 3375 +i^1= 16 i^2= 256 i^3= 4096 +i^1= 17 i^2= 289 i^3= 4913 +i^1= 18 i^2= 324 i^3= 5832 +i^1= 19 i^2= 361 i^3= 6859 +i^1= 20 i^2= 400 i^3= 8000 +i^1= 21 i^2= 441 i^3= 9261 +i^1= 22 i^2= 484 i^3= 10648 +i^1= 23 i^2= 529 i^3= 12167 +i^1= 24 i^2= 576 i^3= 13824 +i^1= 25 i^2= 625 i^3= 15625 +i^1= 26 i^2= 676 i^3= 17576 +i^1= 27 i^2= 729 i^3= 19683 +i^1= 28 i^2= 784 i^3= 21952 +i^1= 29 i^2= 841 i^3= 24389 +i^1= 30 i^2= 900 i^3= 27000 +i^1= 31 i^2= 961 i^3= 29791 +i^1= 32 i^2= 1024 i^3= 32768 +i^1= 33 i^2= 1089 i^3= 35937 +i^1= 34 i^2= 1156 i^3= 39304 +i^1= 35 i^2= 1225 i^3= 42875 +i^1= 36 i^2= 1296 i^3= 46656 +i^1= 37 i^2= 1369 i^3= 50653 +i^1= 38 i^2= 1444 i^3= 54872 +i^1= 39 i^2= 1521 i^3= 59319 +i^1= 40 i^2= 1600 i^3= 64000 +i^1= 41 i^2= 1681 i^3= 68921 +i^1= 42 i^2= 1764 i^3= 74088 +i^1= 43 i^2= 1849 i^3= 79507 +i^1= 44 i^2= 1936 i^3= 85184 +i^1= 45 i^2= 2025 i^3= 91125 +i^1= 46 i^2= 2116 i^3= 97336 +i^1= 47 i^2= 2209 i^3= 103823 +i^1= 48 i^2= 2304 i^3= 110592 +i^1= 49 i^2= 2401 i^3= 117649 +i^1= 50 i^2= 2500 i^3= 125000 +i^1= 51 i^2= 2601 i^3= 132651 +i^1= 52 i^2= 2704 i^3= 140608 +i^1= 53 i^2= 2809 i^3= 148877 +i^1= 54 i^2= 2916 i^3= 157464 +i^1= 55 i^2= 3025 i^3= 166375 +i^1= 56 i^2= 3136 i^3= 175616 +i^1= 57 i^2= 3249 i^3= 185193 +i^1= 58 i^2= 3364 i^3= 195112 +i^1= 59 i^2= 3481 i^3= 205379 +i^1= 60 i^2= 3600 i^3= 216000 +i^1= 61 i^2= 3721 i^3= 226981 +i^1= 62 i^2= 3844 i^3= 238328 +i^1= 63 i^2= 3969 i^3= 250047 +i^1= 64 i^2= 4096 i^3= 262144 +i^1= 65 i^2= 4225 i^3= 274625 +i^1= 66 i^2= 4356 i^3= 287496 +i^1= 67 i^2= 4489 i^3= 300763 +i^1= 68 i^2= 4624 i^3= 314432 +i^1= 69 i^2= 4761 i^3= 328509 +i^1= 70 i^2= 4900 i^3= 343000 +i^1= 71 i^2= 5041 i^3= 357911 +i^1= 72 i^2= 5184 i^3= 373248 +i^1= 73 i^2= 5329 i^3= 389017 +i^1= 74 i^2= 5476 i^3= 405224 +i^1= 75 i^2= 5625 i^3= 421875 +i^1= 76 i^2= 5776 i^3= 438976 +i^1= 77 i^2= 5929 i^3= 456533 +i^1= 78 i^2= 6084 i^3= 474552 +i^1= 79 i^2= 6241 i^3= 493039 +i^1= 80 i^2= 6400 i^3= 512000 +i^1= 81 i^2= 6561 i^3= 531441 +i^1= 82 i^2= 6724 i^3= 551368 +i^1= 83 i^2= 6889 i^3= 571787 +i^1= 84 i^2= 7056 i^3= 592704 +i^1= 85 i^2= 7225 i^3= 614125 +i^1= 86 i^2= 7396 i^3= 636056 +i^1= 87 i^2= 7569 i^3= 658503 +i^1= 88 i^2= 7744 i^3= 681472 +i^1= 89 i^2= 7921 i^3= 704969 +i^1= 90 i^2= 8100 i^3= 729000 +i^1= 91 i^2= 8281 i^3= 753571 +i^1= 92 i^2= 8464 i^3= 778688 +i^1= 93 i^2= 8649 i^3= 804357 +i^1= 94 i^2= 8836 i^3= 830584 +i^1= 95 i^2= 9025 i^3= 857375 +i^1= 96 i^2= 9216 i^3= 884736 +i^1= 97 i^2= 9409 i^3= 912673 +i^1= 98 i^2= 9604 i^3= 941192 +i^1= 99 i^2= 9801 i^3= 970299 +i^1= 100 i^2= 10000 i^3= 1000000 +---------------------------------------- +@<<< Output for ./table.sh[%2] (1900 bytes): +---------------------------------------- +i^1= 1 i^2= 1 i^3= 1 +i^1= 2 i^2= 4 i^3= 8 +i^1= 3 i^2= 9 i^3= 27 +i^1= 4 i^2= 16 i^3= 64 +i^1= 5 i^2= 25 i^3= 125 +i^1= 6 i^2= 36 i^3= 216 +i^1= 7 i^2= 49 i^3= 343 +i^1= 8 i^2= 64 i^3= 512 +i^1= 9 i^2= 81 i^3= 729 +i^1= 10 i^2= 100 i^3= 1000 +i^1= 11 i^2= 121 i^3= 1331 +i^1= 12 i^2= 144 i^3= 1728 +i^1= 13 i^2= 169 i^3= 2197 +i^1= 14 i^2= 196 i^3= 2744 +i^1= 15 i^2= 225 i^3= 3375 +i^1= 16 i^2= 256 i^3= 4096 +i^1= 17 i^2= 289 i^3= 4913 +i^1= 18 i^2= 324 i^3= 5832 +i^1= 19 i^2= 361 i^3= 6859 +i^1= 20 i^2= 400 i^3= 8000 +i^1= 21 i^2= 441 i^3= 9261 +i^1= 22 i^2= 484 i^3= 10648 +i^1= 23 i^2= 529 i^3= 12167 +i^1= 24 i^2= 576 i^3= 13824 +i^1= 25 i^2= 625 i^3= 15625 +i^1= 26 i^2= 676 i^3= 17576 +i^1= 27 i^2= 729 i^3= 19683 +i^1= 28 i^2= 784 i^3= 21952 +i^1= 29 i^2= 841 i^3= 24389 +i^1= 30 i^2= 900 i^3= 27000 +i^1= 31 i^2= 961 i^3= 29791 +i^1= 32 i^2= 1024 i^3= 32768 +i^1= 33 i^2= 1089 i^3= 35937 +i^1= 34 i^2= 1156 i^3= 39304 +i^1= 35 i^2= 1225 i^3= 42875 +i^1= 36 i^2= 1296 i^3= 46656 +i^1= 37 i^2= 1369 i^3= 50653 +i^1= 38 i^2= 1444 i^3= 54872 +i^1= 39 i^2= 1521 i^3= 59319 +i^1= 40 i^2= 1600 i^3= 64000 +i^1= 41 i^2= 1681 i^3= 68921 +i^1= 42 i^2= 1764 i^3= 74088 +i^1= 43 i^2= 1849 i^3= 79507 +i^1= 44 i^2= 1936 i^3= 85184 +i^1= 45 i^2= 2025 i^3= 91125 +i^1= 46 i^2= 2116 i^3= 97336 +i^1= 47 i^2= 2209 i^3= 103823 +i^1= 48 i^2= 2304 i^3= 110592 +i^1= 49 i^2= 2401 i^3= 117649 +i^1= 50 i^2= 2500 i^3= 125000 +---------------------------------------- +@<<< Output for grep[%3] (0 bytes): +---------------------------------------- +---------------------------------------- +@<<< Output for cat[%4] (175 bytes): +---------------------------------------- +#include + +int main(int argc, char *argv[]){ + printf("%d args received\n",argc); + for(int i=0; i exit +ALERTS: +@!!! ls[%0]: EXIT(0) +@!!! grep[%3]: EXIT(1) +@!!! cat[%4]: EXIT(0) +@!!! ./table.sh[%1]: EXIT(0) +@!!! ./table.sh[%2]: EXIT(0) +@!!! grep[%5]: EXIT(0) +@!!! grep[%6]: EXIT(1) +ENDOUT diff --git a/p1-code/sleep_print.c b/p1-code/sleep_print.c new file mode 100644 index 0000000..96353a4 --- /dev/null +++ b/p1-code/sleep_print.c @@ -0,0 +1,22 @@ +#include +#include +#include + +// usage: sleep_print secs message +int main(int argc, char *argv[]){ + + int secs = atoi(argv[1]); + + struct timespec tm = { + .tv_nsec = 0, + .tv_sec = secs, + }; + nanosleep(&tm,NULL); + for(int i=2; i= 1)); then + limit=$1 +fi + +sleeptime=0 +if (($# >= 2)); then + sleeptime=$2 +fi + +for i in `seq $limit`; do + printf "i^1= %6d i^2= %6d i^3= %6d\n" $((i)) $((i*i)) $((i*i*i)) +done + +sleep $sleeptime diff --git a/p1-code/test_args.c b/p1-code/test_args.c new file mode 100644 index 0000000..427880e --- /dev/null +++ b/p1-code/test_args.c @@ -0,0 +1,9 @@ +#include + +int main(int argc, char *argv[]){ + printf("%d args received\n",argc); + for(int i=0; i= BUFSZ){ + printf("Warning: could not capture all of standard output: insufficient buffer size\n"); + } + STDOUT_BUF[bytes_read] = '\0'; + close(STDOUT_PIPE[PREAD]); +} + +// Get a pointer to the output captured from stdout. Uses an internal +// buffer so overwritten each call to catch/restore, do not free(). +char *captured_stdout(){ + return STDOUT_BUF; +} + + diff --git a/p1-code/tests.h b/p1-code/tests.h new file mode 100644 index 0000000..f402c96 --- /dev/null +++ b/p1-code/tests.h @@ -0,0 +1,39 @@ +void fail(char *msg); +// Fail with given message + +int assert_int_equals(char *msg, int expect, int actual); +// Utility to check if two ints are equal; if unequal print errors and +// return 1 + +int assert_int_positive(char *msg, int actual); +// Utility to check if two ints are equal; if unequal print errors and +// return 1 + +int assert_str_equals(char *msg, char *expect, char *actual); +// Utility to check if two strings are equal; if unequal print errors +// and return 1 + +int assert_strn_equals(char *msg, char *expect, char *actual); +// Utility to check if two strings are equal; if unequal print errors +// and return 1; prints expect and actual on their own lines for +// multiline strings + +int assert_null(char *msg, void *actual); +// Utility to check if pointer is null; if not print errors +// and return 1 + +int assert_unique_pointers(char *msg, void *x, void *y); +// Utility to check if pointers are unique or point at the same +// location; if not print errors and return 1 + +// Temporarily direct stdout to a pipe which is captured for later +// use. +void catch_stdout(); + +// Restore stdout redirected via catch_stdout(); fill internal buffer +// to allow captured output to be retrieved +void restore_stdout(); + +// Get a pointer to the output captured from stdout. Uses an internal +// buffer so overwritten each call to catch/restore, do not free(). +char *captured_stdout(); diff --git a/p1-code/util.c b/p1-code/util.c new file mode 100644 index 0000000..82fa47c --- /dev/null +++ b/p1-code/util.c @@ -0,0 +1,26 @@ +#include "commando.h" + +// Parse the contents of input_command so that tokens[i] will point to +// the ith space-separated string in it. Set ntok to the number of +// tokens that are found. +void parse_into_tokens(char input_command[], char *tokens[], int *ntok) { + int i = 0; + char *tok = strtok(input_command, " \n"); + while (tok != NULL && i < ARG_MAX) { + tokens[i] = tok; // assign tokens to found string + i++; + tok = strtok(NULL, " \n"); + } + tokens[i] = NULL; // null terminate tokens to ease argv[] work + *ntok = i; + return; +} + +// Sleep the running program for the given number of nanoseconds and +// seconds. +void pause_for(long nanos, int secs) { + struct timespec tm = { + .tv_nsec = nanos, .tv_sec = secs, + }; + nanosleep(&tm, NULL); +} diff --git a/p2-code.zip b/p2-code.zip new file mode 100644 index 0000000..2a1ca8d Binary files /dev/null and b/p2-code.zip differ diff --git a/p2-code/.clang-format b/p2-code/.clang-format new file mode 100644 index 0000000..80d3293 --- /dev/null +++ b/p2-code/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +IndentWidth: 4 diff --git a/p2-code/.gitignore b/p2-code/.gitignore new file mode 100644 index 0000000..ac5db3a --- /dev/null +++ b/p2-code/.gitignore @@ -0,0 +1,4 @@ +bin +*.o +handin.zip +test-* \ No newline at end of file diff --git a/p2-code/GROUP-MEMBERS.txt b/p2-code/GROUP-MEMBERS.txt new file mode 100644 index 0000000..a0a072f --- /dev/null +++ b/p2-code/GROUP-MEMBERS.txt @@ -0,0 +1,6 @@ +These 1 or 2 people worked on this project together and will share a +grade for it. + +PARTNER 1: Michael Zhang + +PARTNER 2: John Eidum diff --git a/p2-code/Makefile b/p2-code/Makefile new file mode 100644 index 0000000..4f226e1 --- /dev/null +++ b/p2-code/Makefile @@ -0,0 +1,51 @@ +CC = gcc +CFLAGS = -g -Wall -Werror + +.PHONY: all handin clean clean-tests + +all: bindir bl-server bl-client bl-showlog + +bindir: + mkdir -p bin + +bl-server: server.o util.o bl-server.o + $(CC) $(CFLAGS) -o bin/bl-server $^ + +bl-server.o: bl-server.c + $(CC) $(CFLAGS) -c -o $@ $< + +server.o: server.c + $(CC) $(CFLAGS) -c -o $@ $< + +bl-client: util.o simpio.o bl-client.o + $(CC) $(CFLAGS) -o bin/bl-client $^ -lpthread + +bl-client.o: bl-client.c + $(CC) $(CFLAGS) -c -o $@ $< + +bl-showlog: bl-showlog.o + $(CC) $(CFLAGS) -o bin/bl-showlog $< + +bl-showlog.o: bl-showlog.c + $(CC) $(CFLAGS) -c -o $@ $< + +simpio.o: simpio.c + $(CC) $(CFLAGS) -c -o $@ $< + +util.o: util.c + $(CC) $(CFLAGS) -c -o $@ $< + +handin: + zip handin GROUP-MEMBERS.txt Makefile bl-client.c bl-server.c bl-showlog.c blather.h server.c simpio.c util.c + +clean: + rm -f bin/{bl-server,bl-client} *.o *.fifo + +shell-tests: shell_tests.sh shell_tests_data.sh clean-tests + chmod u+rx shell_tests.sh shell_tests_data.sh normalize.awk filter-semopen-bug.awk + ./shell_tests.sh + +clean-tests: + rm -f test-*.{log,out,expect,diff,valgrindout} + rm -f *.fifo + diff --git a/p2-code/add-to-makefile.txt b/p2-code/add-to-makefile.txt new file mode 100644 index 0000000..7e8b18b --- /dev/null +++ b/p2-code/add-to-makefile.txt @@ -0,0 +1,10 @@ +Add the below lines to your Makefile and run with +> make +> make shell-tests + +make shell-tests : shell_tests.sh shell_tests_data.sh clean-tests + chmod u+rx shell_tests.sh shell_tests_data.sh normalize.awk filter-semopen-bug.awk + ./shell_tests.sh + +clean-tests : + rm -f test-*.{log,out,expect,diff,valgrindout} diff --git a/p2-code/bl-client.c b/p2-code/bl-client.c new file mode 100644 index 0000000..e4e6e7c --- /dev/null +++ b/p2-code/bl-client.c @@ -0,0 +1,167 @@ +#include "blather.h" + +simpio_t simpio; +char username[MAXNAME]; +int to_server_fd, to_client_fd; +pthread_t client_thread, server_thread; + +void *client_thread_fn(void *arg) { + // user thread{ + // repeat: + // read input using simpio + // when a line is ready + // create a mesg_t with the line and write it to the to-server FIFO + // until end of input + // write a DEPARTED mesg_t into to-server + // cancel the server thread + while (!simpio.end_of_input) { + simpio_reset(&simpio); + iprintf(&simpio, ""); + while (!simpio.line_ready && + !simpio.end_of_input) { // read until line is complete + simpio_get_char(&simpio); + } + if (simpio.line_ready) { + // iprintf(&simpio, "You entered: %s\n", simpio.buf); + mesg_t payload = {.kind = BL_MESG}; + strncpy(payload.name, username, MAXNAME); + strncpy(payload.body, simpio.buf, MAXLINE); + write(to_server_fd, &payload, sizeof(mesg_t)); + } + } + pthread_cancel(server_thread); + return NULL; +} + +void *server_thread_fn(void *arg) { + // server thread{ + // repeat: + // read a mesg_t from to-client FIFO + // print appropriate response to terminal with simpio + // until a SHUTDOWN mesg_t is read + // cancel the user thread + mesg_t payload, response; + while (read(to_client_fd, &payload, sizeof(mesg_t))) { + switch (payload.kind) { + case BL_MESG: + iprintf(&simpio, "[%s] : %s\n", payload.name, payload.body); + break; + case BL_JOINED: + iprintf(&simpio, "-- %s JOINED --\n", payload.name); + break; + case BL_DEPARTED: + iprintf(&simpio, "-- %s DEPARTED --\n", payload.name); + break; + case BL_SHUTDOWN: + goto server_shutdown; + case BL_DISCONNECTED: + iprintf(&simpio, " -- '%s' has disconnected.\n", payload.name); + break; + case BL_PING: + response.kind = BL_PING; + write(to_server_fd, &response, sizeof(mesg_t)); + break; + } + } +server_shutdown: + iprintf(&simpio, "!!! server is shutting down !!!\n"); + pthread_cancel(client_thread); + return NULL; +} + +int main(int argc, char **argv) { + setvbuf(stdout, NULL, _IONBF, 0); + + // variables used + char *servername; + int server_join_fd; + + // read name of server and name of user from command line args + if (argc < 3) { + fprintf(stderr, "Usage: %s [server] [username]\n", argv[0]); + exit(1); + } + servername = argv[1]; + strncpy(username, argv[2], MAXNAME); + if (strlen(username) > MAXNAME) { + fprintf(stderr, "Username '%s' is too long.\n", username); + exit(1); + } + + // TODO + (void)(username); + (void)(server_join_fd); + + // create to-server and to-client FIFOs + int len = strlen(servername) + strlen(username); + char to_server_fifo_name[len + 10]; + snprintf(to_server_fifo_name, len + 10, "%s.to.%s.fifo", username, + servername); + char to_client_fifo_name[len + 10]; + snprintf(to_client_fifo_name, len + 10, "%s.to.%s.fifo", servername, + username); + + remove(to_server_fifo_name); + remove(to_client_fifo_name); + + mkfifo(to_server_fifo_name, S_IRUSR | S_IWUSR); + mkfifo(to_client_fifo_name, S_IRUSR | S_IWUSR); + + to_server_fd = open(to_server_fifo_name, O_RDWR); + to_client_fd = open(to_client_fifo_name, O_RDWR); + + // write a join_t request to the server FIFO + len = strlen(servername); + char server_fifo_name[len + 6]; + snprintf(server_fifo_name, len + 6, "%s.fifo", servername); + server_join_fd = open(server_fifo_name, O_RDWR); + + join_t request; + strncpy(request.name, username, MAXPATH); + strncpy(request.to_client_fname, to_client_fifo_name, MAXPATH); + strncpy(request.to_server_fname, to_server_fifo_name, MAXPATH); + write(server_join_fd, &request, sizeof(join_t)); + + // write join message + mesg_t payload = {.kind = BL_JOINED}; + strncpy(payload.name, username, MAXNAME); + write(to_server_fd, &payload, sizeof(mesg_t)); + + // configure simpio + len = strlen(username); + char prompt[len + 4]; + snprintf(prompt, len + 4, "%s>> ", username); + simpio_set_prompt(&simpio, prompt); + simpio_reset(&simpio); + simpio_noncanonical_terminal_mode(); + + // start a user thread to read input + if (pthread_create(&client_thread, NULL, &client_thread_fn, NULL)) { + fprintf(stderr, "Error creating client thread.\n"); + exit(1); + } + + // start a server thread to listen to the server + if (pthread_create(&server_thread, NULL, &server_thread_fn, NULL)) { + fprintf(stderr, "Error creating server thread.\n"); + exit(1); + } + + // wait for threads to return + pthread_join(client_thread, NULL); + pthread_join(server_thread, NULL); + + // write depart message + payload.kind = BL_DEPARTED; + strncpy(payload.name, username, MAXNAME); + write(to_server_fd, &payload, sizeof(mesg_t)); + + // close file descriptors + close(to_server_fd); + close(to_client_fd); + + // restore standard terminal output + simpio_reset_terminal_mode(); + printf("\n"); + return 0; +} diff --git a/p2-code/bl-server.c b/p2-code/bl-server.c new file mode 100644 index 0000000..f372330 --- /dev/null +++ b/p2-code/bl-server.c @@ -0,0 +1,40 @@ +#include "blather.h" + +server_t server; + +void signal_handler(int signum) { + server_shutdown(&server); + exit(0); +} + +int main(int argc, char **argv) { + setvbuf(stdout, NULL, _IONBF, 0); + client_t *client; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [name]\n", argv[0]); + exit(1); + } + + // set up signals + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + server_start(&server, argv[1], S_IRUSR | S_IWUSR); + + // main loop + while (1) { + // check all sources + server_check_sources(&server); + + // handle a join request if one is ready + if (server_join_ready(&server)) + server_handle_join(&server); + + for (int i = 0; i < server.n_clients; ++i) { + client = server_get_client(&server, i); + if (client->data_ready) + server_handle_client(&server, i); + } + } +} diff --git a/p2-code/bl-showlog b/p2-code/bl-showlog new file mode 100644 index 0000000..0841fea Binary files /dev/null and b/p2-code/bl-showlog differ diff --git a/p2-code/bl-showlog.c b/p2-code/bl-showlog.c new file mode 100644 index 0000000..96e9834 --- /dev/null +++ b/p2-code/bl-showlog.c @@ -0,0 +1 @@ +int main(int argc, char const *argv[]) { return 0; } \ No newline at end of file diff --git a/p2-code/blather.h b/p2-code/blather.h new file mode 100644 index 0000000..930d076 --- /dev/null +++ b/p2-code/blather.h @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 1 // turn of/off debug printing +#define PROMPT ">> " // prompt for client UI + +#define MAXLINE 1024 // max length of line that can be typed for messages +#define MAXNAME 256 // max length of user name for clients +#define MAXPATH 1024 // max length filename paths +#define MAXCLIENTS 256 // max number of clients accepted + +#define EOT 4 // ascii code of typical EOF character +#define DEL 127 // ascii code of typical backspace key + +#define DEFAULT_PERMS S_IRUSR | S_IWUSR // default permissions for fifos +#define ALARM_INTERVAL 1 // seconds between alarm rings and pings to clients +#define DISCONNECT_SECS \ + 5 // seconds before clients are dropped due to lack of contact + +// client_t: data on a client connected to the server +typedef struct { + char name[MAXPATH]; // name of the client + int to_client_fd; // file descriptor to write to to send to client + int to_server_fd; // file descriptor to read from to receive from client + char to_client_fname[MAXPATH]; // name of file (FIFO) to write into send to + // client + char to_server_fname[MAXPATH]; // name of file (FIFO) to read from receive + // from client + int data_ready; // flag indicating a mesg_t can be read from to_server_fd + int last_contact_time; // ADVANCED: server time at which last contact was + // made with client +} client_t; + +// server_t: data pertaining to server operations +typedef struct { + char server_name[MAXPATH]; // name of server which dictates file names for + // joining and logging + int join_fd; // file descriptor of join file/FIFO + int join_ready; // flag indicating if a join is available + int n_clients; // number of clients communicating with server + client_t client[MAXCLIENTS]; // array of clients populated up to n_clients + int time_sec; // ADVANCED: time in seconds since server started + int log_fd; // ADVANCED: file descriptor for log + sem_t *log_sem; // ADVANCED: posix semaphore to control who_t section of + // log file +} server_t; + +// join_t: structure for requests to join the chat room +typedef struct { + char name[MAXPATH]; // name of the client joining the server + char to_client_fname[MAXPATH]; // name of file server writes to to send to + // client + char to_server_fname[MAXPATH]; // name of file client writes to to send to + // server +} join_t; + +// mesg_kind_t: Kinds of messages between server/client +typedef enum { + BL_MESG = 10, // normal messasge from client with name/body + BL_JOINED = 20, // client joined the server, name only + BL_DEPARTED = 30, // client leaving/left server normally, name only + BL_SHUTDOWN = + 40, // server to client : server is shutting down, no name/body + BL_DISCONNECTED = 50, // ADVANCED: client disconnected abnormally, name only + BL_PING = 60, // ADVANCED: ping to ask or show liveness +} mesg_kind_t; + +// mesg_t: struct for messages between server/client +typedef struct { + mesg_kind_t kind; // kind of message + char name[MAXNAME]; // name of sending client or subject of event + char body[MAXLINE]; // body text, possibly empty depending on kind +} mesg_t; + +// who_t: data to write into server log for current clients (ADVANCED) +typedef struct { + int n_clients; // number of clients on server + char names[MAXCLIENTS][MAXNAME]; // names of clients +} who_t; + +// simpio_t: data structure to manage terminal input/output for clients +typedef struct { + char buf[MAXLINE]; // line of text to read + char prompt[MAXNAME]; // prompt to be printed ahead of input + int pos; // position in buf + int line_ready; // flag determining if a line in buf is ready for + // processing + int end_of_input; // flag determining if end of input has been indicated + FILE *infile; // FILE to read from for input, usually stdin + FILE *outfile; // FILE to write to for output, usually stdout +} simpio_t; + +// server.c +client_t *server_get_client(server_t *server, int idx); +void server_start(server_t *server, char *server_name, int perms); +void server_shutdown(server_t *server); +int server_add_client(server_t *server, join_t *join); +int server_remove_client(server_t *server, int idx); +int server_broadcast(server_t *server, mesg_t *mesg); +void server_check_sources(server_t *server); +int server_join_ready(server_t *server); +int server_handle_join(server_t *server); +int server_client_ready(server_t *server, int idx); +int server_handle_client(server_t *server, int idx); +void server_tick(server_t *server); +void server_ping_clients(server_t *server); +void server_remove_disconnected(server_t *server, int disconnect_secs); +void server_write_who(server_t *server); +void server_log_message(server_t *server, mesg_t *mesg); + +// simpio.c +void simpio_noncanonical_terminal_mode(); +void simpio_reset_terminal_mode(); +void simpio_reset(simpio_t *simpio); +void simpio_set_prompt(simpio_t *simpio, char *prompt); +void simpio_get_char(simpio_t *simpio); +void iprintf(simpio_t *simpio, char *fmt, ...); + +// util.c +void check_fail(int condition, int perr, char *fmt, ...); +void dbg_printf(char *fmt, ...); +void pause_for(long nanos, int secs); diff --git a/p2-code/cat-sig.sh b/p2-code/cat-sig.sh new file mode 100755 index 0000000..8631545 --- /dev/null +++ b/p2-code/cat-sig.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Works like cat but handles SIGTERM gracefully + +handle_term() { + exit 0 +} + +trap 'handle_term' TERM + +while read line +do + echo "$line" +done < "${1:-/dev/stdin}" diff --git a/p2-code/filter-semopen-bug.awk b/p2-code/filter-semopen-bug.awk new file mode 100755 index 0000000..eced687 --- /dev/null +++ b/p2-code/filter-semopen-bug.awk @@ -0,0 +1,17 @@ +#!/usr/bin/awk -f + +/: sem_open /{ + sem_err=1 +} + +/ERROR SUMMARY/{ + if(sem_err==1){ + nerrors=$4 + ncontexts=$7 + $4 = nerrors-1 + $7 = ncontexts-1 + print "NOTE: FILTERED sem_open BUG" + } +} + +{print} diff --git a/p2-code/normalize.awk b/p2-code/normalize.awk new file mode 100755 index 0000000..d94729f --- /dev/null +++ b/p2-code/normalize.awk @@ -0,0 +1,15 @@ +#!/usr/bin/awk -f + +# Normalize output of a client transcript so that it has a standard +# format. Splits each line based on the + +BEGIN{ +# Full binary for control signals but gawk chokes on this +# FS="\x1b\x5b\x32\x4b\x0d" +# Hex code for ASCII Carriage Return +# FS="\x0d" + FS="\r" +} +{ + print $NF +} diff --git a/p2-code/p2-tests.zip b/p2-code/p2-tests.zip new file mode 100644 index 0000000..741d9e4 Binary files /dev/null and b/p2-code/p2-tests.zip differ diff --git a/p2-code/readme.html b/p2-code/readme.html new file mode 100644 index 0000000..f9fbfe9 --- /dev/null +++ b/p2-code/readme.html @@ -0,0 +1,2535 @@ + + + +CSCI 4061 Project 2: Blather Chat Server/Client + + + + + + + + + + +
+Last Updated: 2017-11-29 Wed 17:46 +
+
+

CSCI 4061 Project 2: Blather Chat Server/Client

+
    +
  • Due: 11:59pm Tue 12/12/2017 +
  • +
  • Approximately 20.0% of total grade +
  • +
  • Submit to Canvas +
  • +
  • Projects may be done in groups of 1 or 2. Indicate groups in the +GROUP-MEMBERS.txt file. +
  • +
  • No additional collaboration with other students is allowed. Seek +help from course staff if you get stuck for too long. +
  • +
+ +
+

CODE DISTRIBUTION: p2-code.zip

+
+
+

TEST CODE: Not posted

+
+
+
+ + + +
+

1 Introduction: A Chat Service

+
+

+Systems programming is often associated with communication as this +invariably requires coordinating multiple entities that are related +only based on their desire to share information. This project focuses +on developing a simple chat server and client called blather. The +basic usage is in two parts. +

+
+
Server
Some user starts bl-server which manages the chat "room". The +server is non-interactive and will likely only print debugging +output as it runs. +
+
Client
Any user who wishes to chat runs bl-client which takes input +typed on the keyboard and sends it to the server. The server +broadcasts the input to all other clients who can respond by +typing their own input. +
+
+ +

+Chat servers are an old idea dating to the late 1970's and if you have +never used one previously, get online a bit more or read about them on +Wikipedia. Even standard Unix terminals have a built-in ability to +communicate with other users through commands like write, wall, +and talk. +

+ +

+Unlike standard internet chat services, blather will be restricted +to a single Unix machine and to users with permission to read related +files. However, extending the programs to run via the internet will +be the subject of some discussion. +

+ +

+Like most interesting projects, blather utilizes a combination of +many different system tools. Look for the following items to arise. +

+
    +
  • Multiple communicating processes: clients to servers +
  • +
  • Communication through FIFOs +
  • +
  • Signal handling for graceful server shutdown +
  • +
  • Alarm signals for periodic behavior +
  • +
  • Input multiplexing with select() +
  • +
  • Multiple threads in the client to handle typed input versus info +from the server +
  • +
+ +

+Finally, this project includes some advanced features which may be +implemented for extra credit. +

+
+ +
+

1.1 Basic Features

+
+

+The specification below is mainly concerned with basic features of the +blather server and client. Implementing these can garner full credit +for the assignment. +

+
+
+ +
+

1.2 ADVANCED Features : Extra Credit

+
+

+Some portions of the specification and code are marked ADVANCED to +indicate optional features that can be implemented for extra +credit. Some of these have dependencies so take care to read +carefully. +

+ +

+ADVANCED features may be evaluated using tests and manual inspection +criteria that are made available after the standard tests are +distributed. +

+
+
+
+ +
+

2 Download Code and Setup

+
+

+As in labs, download the code pack linked at the top of the +page. Unzip this which will create a folder and create your files in +that folder. +

+ + + + +++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStateNotes
GROUP-MEMBERS.txtEditFill in names of group members to indicate partnerships
MakefileCreateBuild project, run tests
server.cCreateService routines for the server
bl-server.cCreateMain function for bl-server executable
bl-client.cCreateMain function for bl-client executable
blather.hProvidedHeader file which contains required structs, defines, and prototypes
util.cProvidedUtility methods debug messages and checking system call returns
simpio.cProvidedSimplified terminal I/O to get nice interactive sessions
simpio-demo.cProvidedDemonstrates simpio features, model for bl-client.c
+
+
+ + +
+

3 Demo / ScreenShot

+
+

+Demonstrating an interactive, dynamic chat session between multiple +users is difficult but the screenshot below attempts to do so. It +shows the server and several clients mid-chat. +

+
    +
  • The server bl-server is started in the large terminal on the left +and shows output about what is going on. There is no specific output +required and that shown is for debugging purposes. +
  • +
  • There are 4 bl-client instances run by various users who log into +the server and specify their name. The lower-right user Barbara +joins later while the upper left user Bruce logs out near the end +of the session. +
  • +
+ +
+ +
+

blather-demo.png +

+

Figure 1: Sample blather server and client runs.

+
+
+
+
+ +
+

4 Overall Architecture

+
+
+

4.1 What Needs to be Implemented

+
+

+blather has two parts: the server and client. Both need to be +written along with service routines in server.c +

+
+
+

server.c data structure manipulations

+
+

+Implement the functions in this file to manipulate the server_t and +client_t data that will ultimately be used by the server to fulfill +its role. +

+
+
+ +
+

bl-server.c main function and signal handlers

+
+

+Implement the server which manages the interactions between clients in +this file making use of the service functions in server.c to get the +job done. +

+
+
+ +
+

bl-client.c main function and thread workers

+
+

+Implement the client which allows a single user to communicate with +the server in this file. The client must have multiple threads so you +will need to implement some worker functions as thread entry points +here. +

+
+
+
+ +
+

4.2 What's Already Done

+
+

+Examine the provided files closely as they give some insight into what +work is already done. +

+
    +
  • blather.h can be included in most files to make programs aware of +the data structures and required functions. It contains +documentation of the central data structures. +
  • +
  • util.c contains a few functions for debugging and checking system +calls. +
  • +
  • simpio.c and simpio-demo.c provide a small library and data +structure to do terminal I/O nicely. The demo program shows how it +works. +
  • +
+
+
+ +
+

4.3 Provide a Makefile

+
+

+Provide a Makefile which has at least the following targets. +

+
    +
  • bl-server : builds the server executable, be included in the +default targets. +
  • +
  • bl-client : builds the client executable, be included in the +default targets. +
  • +
  • test-binary : compile and run the binary tests +
  • +
  • test-shell : run the shell scripts associated with integration +tests +
  • +
+
+
+ +
+

4.4 No malloc() / free() required

+
+

+It may come as a surprise, but this set of programs is specifically +oriented so that no dynamic memory allocation is required. All of the +data structures are fixed size, strings have a maximum length, and +communication is done through FIFOs. Keep this in mind as you code +and avoid malloc() unless you see no other way around it as it will +likely make things harder than they need to be. +

+
+
+
+ + +
+

5 Basic Protocol and Architecture

+
+

+Clients communicate with the server along the following lines. +

+
    +
  • bl-server creates a FIFO at startup time. The FIFO is created with +a name specified according to naming convention at startup. Examples: +
    + +
    $> bl-server server1               # creates the server1.fifo
    +$> bl-server batcave               # creates the batcave.fifo
    +$> bl-server fortress-of-solitude  # creates the fortress-of-solitude.fifo
    +
    +
    +

    +This FIFO is only for join requests to the server. The name of +this file must be known for the clients to connect to server. +

    +
  • +
  • The server then waits for clients to write join requests to join +FIFO. +
  • +
  • bl-client creates two FIFOs on startup: +
      +
    • A to-client FIFO for the server to write data intended for the +client. The client reads this FIFO. +
    • +
    • A to-server FIFO to which the client writes and from which the +server reads. +
    • +
    • The names of these files are inconsequential so long as they are +fairly unique. Basing names for the FIFOs on the PID of the client +is an easy way to do this. This avoids multiple clients in the +same directory mistakenly using each other's FIFOs. +
    • +
    +
  • +
  • A client writes a join request to the server which includes the +names of its to-client and to-server FIFOs. All subsequent +communication between client and server is done through the +to-client and to-server FIFOs. +
  • +
  • A client reads typed input from users. When input is ready, it is +sent as a mesgt to the server. +
  • +
  • As a server receives messages from clients, it will broadcast the +message to all clients including the sender. +
  • +
  • The server sends notices of other kinds to the clients such as when +a new client joins. Clients may send departure notices which are +re-broadcast by the server. +
  • +
+ +

+The sections below give graphical depictions of some of the ideas of +the protocols. +

+
+ +
+

5.1 Server and Clients

+
+

+The following diagram illustrates the single server server1 with 2 +clients connected. Each client has its own FIFOs for communication +with the server and the server knows about these FIFOs. +

+
+ +
+

schematic.svg +

+

Figure 2: Schematic of server data which has been joined by 2 clients.

+
+
+
+
+ +
+

5.2 Joining

+
+

+This diagram illustrates how a new client can join the server. It +creates FIFOs for communication and then writes a join_t request on +the server's FIFO. The server then adds the client information to its +array and broadcasts the join to all clients. +

+ +
+ +
+

join-request.svg +

+

Figure 3: New client joining the server which has two existing clients.

+
+
+
+
+ +
+

5.3 Normal Messages

+
+

+A client wanting to communicate with others sends a normal mesg_t to +the server with its name and body filled in. The client's to-server +FIFO is used for this. The server then broadcasts the same message to +all clients including the sender. +

+ +
+ +
+

broadcast.svg +

+

Figure 4: Client sending a message which is broadcast to all other clients.

+
+
+
+
+ +
+

5.4 Departures and Removing Clients

+
+

+A client can indicate it is leaving by sending an appropriate +message. The server will remove its FIFOs and shift all elements in +its clients array. The departure is broadcast to all clients. +

+ +
+ +
+

depart.svg +

+

Figure 5: Client sending a message which is broadcast to all other clients.

+
+
+
+
+ +
+

5.5 Protocol Data Types

+
+

+The header file blather.h describes several data types associated +with basic communication operations. One of these is the mesg_t +struct which is used to convey information between clients and server. +

+
// mesg_t: struct for messages between server/client
+typedef struct {
+  mesg_kind_t kind;               // kind of message
+  char name[MAXNAME];             // name of sending client or subject of event
+  char body[MAXLINE];             // body text, possibly empty depending on kind
+} mesg_t;
+
+ +

+Each message has a kind which helps determine what to do with the +messages. The kinds are defined in the mesg_kind_t enumeration which +sets up specific integers associated with each kind. +

+
// mesg_kind_t: Kinds of messages between server/client
+typedef enum {
+  BL_MESG         = 10,         // normal messasge from client with name/body
+  BL_JOINED       = 20,         // client joined the server, name only
+  BL_DEPARTED     = 30,         // client leaving/left server normally, name only
+  BL_SHUTDOWN     = 40,         // server to client : server is shutting down, no name/body
+  BL_DISCONNECTED = 50,         // ADVANCED: client disconnected abnormally, name only
+  BL_PING         = 60,         // ADVANCED: ping to ask or show liveness
+} mesg_kind_t;
+
+ +

+Messages are sent both from client to server and from server to client +through the FIFOs that connect them. The specification below will +describe what actions need be taken on receiving messages. +

+ +

+Finally, when the a client wishes to initially join the server, it +fills in and sends a join_t. +

+
// join_t: structure for requests to join the chat room
+typedef struct {
+  char name[MAXPATH];            // name of the client joining the server
+  char to_client_fname[MAXPATH]; // name of file server writes to to send to client
+  char to_server_fname[MAXPATH]; // name of file client writes to to send to server
+} join_t;
+
+
+
+
+ + + +
+

6 The Server

+
+

+The bl-server.c program is responsible for allowing clients to +connect, become aware of one another, and communicate. It's main +functionality is to broadcast messages from one client to all others +and to broadcast status changes such as new clients that join or +depart. +

+
+ + +
+

6.1 Server and Client Data

+
+

+To that end, the server process should maintain a server_t data +structure which is defined in blather.h as below +

+ +
// server_t: data pertaining to server operations
+typedef struct {
+  char server_name[MAXPATH];    // name of server which dictates file names for joining and logging
+  int join_fd;                  // file descriptor of join file/FIFO
+  int join_ready;               // flag indicating if a join is available
+  int n_clients;                // number of clients communicating with server
+  client_t client[MAXCLIENTS];  // array of clients populated up to n_clients
+  int time_sec;                 // ADVANCED: time in seconds since server started
+  int log_fd;                   // ADVANCED: file descriptor for log
+  sem_t *log_sem;               // ADVANCED: posix semaphore to control who_t section of log file
+} server_t;
+
+ +

+The most prominent features of this structure are as follows. +

+
    +
  • The server_name which determines the name of the FIFO filename for +joining and a few other things. +
  • +
  • A join_fd file descriptor which should be attached to a FIFO to +read requests from clients to join the server. +
  • +
  • The client[][ array of client_t structs that track clients +connected to the server. The field n_clients determines how full +this array is. +
  • +
+ +

+Associated closely with the server_t is the client_t struct which +contains data on each client. +

+
// client_t: data on a client connected to the server
+typedef struct {
+  char name[MAXPATH];             // name of the client
+  int to_client_fd;               // file descriptor to write to to send to client
+  int to_server_fd;               // file descriptor to read from to receive from client
+  char to_client_fname[MAXPATH];  // name of file (FIFO) to write into send to client
+  char to_server_fname[MAXPATH];  // name of file (FIFO) to read from receive from client
+  int data_ready;                 // flag indicating a mesg_t can be read from to_server_fd
+  int last_contact_time;          // ADVANCED: server time at which last contact was made with client
+} client_t;
+
+ +

+While the client program bl-client may make use of this struct as +well its main purpose is to help track data for the server. Prominent +features are as follows. +

+
    +
  • The user name of the client which is provided when it joins. +
  • +
  • Names and file descriptors of the to-client and to-server FIFOs. The +file descriptors are opened by the server based on the file names +the provided by the client and used for communication between them. +
  • +
  • A data_ready flag which is set and cleared by the server as +messages are available. +
  • +
+
+
+ +
+

6.2 Server Operations: server.c

+
+

+To facilitate operations of bl-server main program, complete the +server.c file which provides service routines that mainly manipulate +server_t structures. Each of these has a purpose to serve in the +ultimate goal of the server. +

+ +
client_t *server_get_client(server_t *server, int idx);
+// Gets a pointer to the client_t struct at the given index. If the
+// index is beyond n_clients, the behavior of the function is
+// unspecified and may cause a program crash.
+
+void server_start(server_t *server, char *server_name, int perms);
+// Initializes and starts the server with the given name. A join fifo
+// called "server_name.fifo" should be created. Removes any existing
+// file of that name prior to creation. Opens the FIFO and stores its
+// file descriptor in join_fd._
+//
+// ADVANCED: create the log file "server_name.log" and write the
+// initial empty who_t contents to its beginning. Ensure that the
+// log_fd is position for appending to the end of the file. Create the
+// POSIX semaphore "/server_name.sem" and initialize it to 1 to
+// control access to the who_t portion of the log.
+
+void server_shutdown(server_t *server);
+// Shut down the server. Close the join FIFO and unlink (remove) it so
+// that no further clients can join. Send a BL_SHUTDOWN message to all
+// clients and proceed to remove all clients in any order.
+//
+// ADVANCED: Close the log file. Close the log semaphore and unlink
+// it.
+
+int server_add_client(server_t *server, join_t *join);
+// Adds a client to the server according to the parameter join which
+// should have fileds such as name filed in.  The client data is
+// copied into the client[] array and file descriptors are opened for
+// its to-server and to-client FIFOs. Initializes the data_ready field
+// for the client to 0. Returns 0 on success and non-zero if the
+// server as no space for clients (n_clients == MAXCLIENTS).
+
+int server_remove_client(server_t *server, int idx);
+// Remove the given client likely due to its having departed or
+// disconnected. Close fifos associated with the client and remove
+// them.  Shift the remaining clients to lower indices of the client[]
+// array and decrease n_clients.
+
+int server_broadcast(server_t *server, mesg_t *mesg);
+// Send the given message to all clients connected to the server by
+// writing it to the file descriptors associated with them.
+//
+// ADVANCED: Log the broadcast message unless it is a PING which
+// should not be written to the log.
+
+void server_check_sources(server_t *server);
+// Checks all sources of data for the server to determine if any are
+// ready for reading. Sets the servers join_ready flag and the
+// data_ready flags of each of client if data is ready for them.
+// Makes use of the select() system call to efficiently determine
+// which sources are ready.
+
+int server_join_ready(server_t *server);
+// Return the join_ready flag from the server which indicates whether
+// a call to server_handle_join() is safe.
+
+int server_handle_join(server_t *server);
+// Call this function only if server_join_ready() returns true. Read a
+// join request and add the new client to the server. After finishing,
+// set the servers join_ready flag to 0.
+
+int server_client_ready(server_t *server, int idx);
+// Return the data_ready field of the given client which indicates
+// whether the client has data ready to be read from it.
+
+int server_handle_client(server_t *server, int idx);
+// Process a message from the specified client. This function should
+// only be called if server_client_ready() returns true. Read a
+// message from to_server_fd and analyze the message kind. Departure
+// and Message types should be broadcast to all other clients.  Ping
+// responses should only change the last_contact_time below. Behavior
+// for other message types is not specified. Clear the client's
+// data_ready flag so it has value 0.
+//
+// ADVANCED: Update the last_contact_time of the client to the current
+// server time_sec.
+
+void server_tick(server_t *server);
+// ADVANCED: Increment the time for the server
+
+void server_ping_clients(server_t *server);
+// ADVANCED: Ping all clients in the server by broadcasting a ping.
+
+void server_remove_disconnected(server_t *server, int disconnect_secs);
+// ADVANCED: Check all clients to see if they have contacted the
+// server recently. Any client with a last_contact_time field equal to
+// or greater than the parameter disconnect_secs should be
+// removed. Broadcast that the client was disconnected to remaining
+// clients.  Process clients from lowest to highest and take care of
+// loop indexing as clients may be removed during the loop
+// necessitating index adjustments.
+
+void server_write_who(server_t *server);
+// ADVANCED: Write the current set of clients logged into the server
+// to the BEGINNING the log_fd. Ensure that the write is protected by
+// locking the semaphore associated with the log file. Since it may
+// take some time to complete this operation (acquire semaphore then
+// write) it should likely be done in its own thread to preven the
+// main server operations from stalling.  For threaded I/O, consider
+// using the pwrite() function to write to a specific location in an
+// open file descriptor which will not alter the position of log_fd so
+// that appends continue to write to the end of the file.
+
+void server_log_message(server_t *server, mesg_t *mesg);
+// ADVANCED: Write the given message to the end of log file associated
+// with the server.
+
+
+
+ +
+

6.3 Messages Handled by the Server

+
+

+The function server_handle_client() is a workhorse that will read a +message from a client and respond take appropriate action. Here are +the messages that the server should accept and respond to. +

+ + + + +++ ++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + +
kindNameBody?Action
BL_MESGYesYesBroadcast message to all clients.
BL_DEPARTEDYesNoBroadcast message to all clients.
+
+
+ +
+

6.4 Other Messages Sent by the Server

+
+

+The server will broadcast several other kinds of messages to clients +under the following circumstances. +

+ + + +++ ++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
kindNameBody?Circumstance
BL_JOINEDYesNoBroadcast when a new client joins the server
BL_SHUTDOWNNoNoBroadcast when the server starts shutting down
ADVANCED   
BL_PINGNoNoBroadcast periodically, clients should respond with a ping to indicate liveness
BL_DISCONNECTEDYesNoBroadcast when a client has not pinged in a while to indicate disconnection.
+
+
+ + +
+

6.5 bl-server.c main function

+
+

+Define a main() entry point in bl-server that ties all of the +server operations together into a function unit. +

+
+ +
+

Listen, Select, Respond

+
+

+The server main() function in its simplest form boils down to the +following pseudocode. +

+
+ +
REPEAT:
+  check all sources
+  handle a join request if on is ready
+  for each client{
+    if the client is ready handle data from it
+  }
+}
+
+
+ +

+The advanced features build somewhat on this but not by much. +

+
+
+ +
+

Signal Handling

+
+

+The server should run indefinitely without interaction from an +interactive user. To stop it, send signals. The server should handle +SIGTERM and SIGINT by shutting down gracefully: exit the main +computation, call server_shutdown() and return 0. +

+
+
+
+
+ + + +
+

7 The Client

+
+

+While bl-server is a perpetual, non-interactive program, it is not +interesting with clients to connect to it allowing users to +communicate. bl-client is such a program. It allows a user to type +into the terminal to send text to the server and receive text back +from the server which is printed to the screen. The sections below +describe how to build it. +

+
+ +
+

7.1 Simplified Terminal I/O

+
+

+Standard terminal input and output work well in many situations but +the bl-client must intermingle the user typing while data may be +printed to the screen. This calls for somewhat finer control. To +simplify the murky area that is terminal control, the file simpio.c +provides functions which have the following net effect. +

+
    +
  • A prompt can be set that is always displayed as the last final +advancing line in the terminal. +
  • +
  • Text can be typed and deleted by the user. +
  • +
  • Any thread printing with the iprintf() function will advance the +prompt forwards without disrupting the text a user may be typing. +
  • +
+ +

+The program simpio-demo.c demonstrates this facility by spinning up +a user and background thread which both print to the screen. Text +printed by the background thread using iprintf() does not disrupt +text being typed by the user at the prompt. +

+ +

+Use simpio-demo.c as a template to begin you development on +bl-client.c noting the following. +

+
    +
  • Initialize the simplified terminal I/O with the following sequence +
    + +
    simpio_set_prompt(simpio, prompt);         // set the prompt
    +simpio_reset(simpio);                      // initialize io
    +simpio_noncanonical_terminal_mode();       // set the terminal into a compatible mode
    +
    +
    +
  • +
  • When threads want to print, use the iprintf() function. It works +like printf() but takes as its first argument a simpio_t object +which manages the prompt and typed text. +
  • +
  • Analyze the input loop in simpio-demo.c to see how to read +characters from the prompt, detect a completed line, and end of +input. +
  • +
+
+
+ +
+

7.2 bl-client.c Features

+
+

+Unlike the server, there are no required C functions for the +client. Instead, there are a series of required features and +suggestions on how to implement them. +

+
+ +
+

Client Name and FIFO Creation

+
+

+The client program is run as follows +

+
+ +
$> bl-client server1 Lois
+# join the server1 as a user Lois
+
+$> bl-client dc-serv Bruce
+# join the dc-serv server as user Bruce
+
+
+ +

+The first argument is the server to join and corresponds to a FIFO +name that is owned by the server. +

+ +

+The client should create its own to-client and to-server FIFOs which +become part of the join request to the server. The names of these +FIFOs can be selected arbitrarily so long as they do not conflict with +other user FIFO names. Examples are to create temporary file names or +use the PID of the client process to choose the FIFO names. +

+
+
+ +
+

Joining the Server

+
+

+The client should construct a join_t with its name and the names of +its to-client and to-server FIFOs. This should be written to the name +of the server's FIFO which will notify the server and other clients of +the new user's arrival. +

+
+
+ +
+

Messages Handled by Client

+
+

+The client should handle the following kinds of messages from the server. +

+ + + +++ ++ ++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
kindNameBody?ActionPrint Format / Example
BL_MESGYesYesPrint[Bruce] : check this out
BL_JOINEDYesNoPrint-- Bruce JOINED --
BL_DEPARTEDYesNoPrint-- Clark DEPARTED --
BL_SHUTDOWNNoNoPrint!!! server is shutting down !!!
ADVANCED    
BL_DISCONNECTEDYesNoPrint-- Clark DISCONNECTED --
BL_PINGNoNoReplySend BL_PING message back to server
+
+
+ +
+

User Input and Messages from the Server

+
+

+To make the user experience reasonable, server messages should be +received and printed to the screen as soon as they are available. +Printing server messages should not disrupt the text input too +much. This combination of requirements suggests the following. +

+
    +
  • Use two threads, one for user interactions and the other for +server interactions. +
  • +
  • The user thread performs an input loop until the user has completed +a line. It then writes message data into the to-server FIFO to get +it to the server and goes back to reading user input. +
  • +
  • The server thread reads data from the to-client FIFO and prints to +the screen as data is read. +
  • +
  • Both user and server threads use the iprintf() function to ensure +that data appears correctly on the screen and cooperates with input +being typed. +
  • +
+ +

+A few additional notes are in order on the interaction of these two +threads. +

+
    +
  • Should the user thread receive and end of input, it should send a +message to the server with kind BL_DEPARTED to indicate the client +is shutting down. This will notify other users of the departure. The +user thread should cancel the server thread and return. +
  • +
  • If the server thread receives a BL_SHUTDOWN message, the server is +shutting down. This means the client should exit as well. The server +thread should cancel the user thread and return. +
  • +
+
+
+ +
+

Typed Input is Sent to the Server, not Printed

+
+

+When users type input, it is echoed onto the screen by simpio at the +prompt. However, on hitting enter, the data is sent immediately to the +server as a mesg_t with kind MESG, name filled in with the +user's name and body filled in with the text line typed. +

+ +

+Though the message body is known by the client which just sent it, the +body is not printed to the screen. Instead, the client waits for the +server to broadcast the message back and prints its own message just +as if it were a message from another user. This ensures that no +special actions need to be taken to avoid duplicate messages. +

+ +

+This "print only what the server sends" feature restriction is +somewhat modified by some of the advanced features described later. +

+
+
+
+ +
+

7.3 Client Main Approach

+
+

+To summarize, bl-client will roughly take the following steps. +

+
+ +
read name of server and name of user from command line args
+create to-server and to-client FIFOs
+write a join_t request to the server FIFO
+start a user thread to read inpu
+start a server thread to listen to the server
+wait for threads to return
+restore standard terminal output
+
+user thread{
+  repeat:
+    read input using simpio
+    when a line is ready
+    create a mesg_t with the line and write it to the to-server FIFO
+  until end of input
+  write a DEPARTED mesg_t into to-server
+  cancel the server thread
+
+server thread{
+  repeat:
+    read a mesg_t from to-client FIFO
+    print appropriate response to terminal with simpio
+  until a SHUTDOWN mesg_t is read
+  cancel the user thread
+
+
+
+
+
+ +
+

8 Manual Inspection Criteria (50%)

+
+

+The following criteria will be examined during manual inspection of +code by graders. Use this as a guide to avoid omitting important steps +or committing bad style fouls. +

+ + + + +++ ++ ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LocationWgtCriteria
Makefile5A Makefile is provided which compiles commando
  Any required test targets are present.
server.c  
server_start()5creates and opens FIFO correctly for joins, removes existing FIFO
server_shutdown() closes and removes FIFO to prevent additional joins
  broadcasts a shutdown message
  does basic error checking of system calls
server_add_client()5does bounds checking to prevent overflow on add
  adds client to end of array and increments n_clients
  fills in fixed fields of client data based on join parameter
  makes use of strncpy() to prevent buffer overruns
  opens to-client and to-server FIFOs for reading
server_remove_client()5uses server_get_client() for readability
  closes to-client and from-client FIFOs
  correctly shifts array of clients to maintain contiguous client array
server_check_sources()5makes use of select() system call to detect ready clients/joins
  checks join FIFO and all clients in select() call
  does not read data but sets read flags for join and clients
  does basic error checking of system calls
server_handle_join()5reads a join_t from join FIFO correctly
  adds client with server_add_client()
  broadcasts join
server_handle_client() reads a mesg_t from the to-server FIFO
  processes message properly and broadcasts if needed
  does basic error checking of system calls
bl-server.c  
 5main loop makes use of the server.c routines extensively
  clear code to check input sources and handle ready input
  signal handling for graceful shutdown is clear
bl-client.c  
main and overall5proper setup of terminal with simpio
  use of simpio for input and output
  clear creation and joining of threads
  resets terminal at end of run
user thread5clear use of a user thread to handle typed input
  user thread sends data to server
  cancels server thread at end of input before returning
server thread5clear use of a server thread to listen data on to-client FIFO
  clear handling of different kinds of messages coming from server
  cancels user thread on receiving shutdown message and returns
 50Total
+
+
+ + +
+

9 ADVANCED Features

+
+

+The following advanced features may be implemented to garner extra +credit on the total project score for the semester. Each additional +feature is worth the extra credit indicated. +

+
+ +
+

9.1 Server Ping and Disconnected Clients (10%)

+
+

+Clients may terminate abruptly in the real world before they have a +chance to send a BL_DEPARTED message to the server. This additional +feature adds period pinging to the server and clients. A ping is a +short message just to establish whether a communication partner is +still present. In this case, it is a message with kind BL_PING. +

+ +

+Implementing this feature will cause the server broadcast a ping to +all clients every second. Clients should respond immediately by +sending a ping back. +

+ +

+To detect disconnected clients, the server should maintain its +time_sec incrementing it each second. Whenever a message is +received from a client, including BL_PING messages, the server +updates the client's last_contact_time to the current server +time. Any client that abruptly departs will eventually have a large +gap between its last_contact_time and the time_sec. +

+ +

+Every second, the server runs the function +server_remove_disconnected(server, disconnect_secs). If any client +with a difference in last_contact_time and +server_remove_disconnected that is larger than the argument +disconnect_secs should be removed. A BL_DISCONNECTED message +should be broadcast for this client to notify other clients of the +change. +

+ +

+A good way to implement periodic activity is to use the alarm() +function. This arranges for a periodic signal to be sent to the server +process. This should be done in main() for bl-server.c. The +signal handler for the SIGALRM that is raised can set a variable to +indicate that 1 second has passed. In the main loop of the server, a +condition checks this variable and performs the ping broadcast and +checks for disconnected clients. +

+ +

+All changes for this feature are on the server side. Additional +functions to write or modify are as follows. +

+
+ +
// server.c
+// Modify
+int server_handle_client(server_t *server, int idx)
+
+// Write 
+void server_tick(server_t *server)
+void server_ping_clients(server_t *server)
+void server_remove_disconnected(server_t *server, int disconnect_secs)
+
+// bl-server.c
+int main(int argc, char *argv[])
+
+
+
+
+ +
+

9.2 Binary Server Log File (10%)

+
+

+There is cause to want a log of all messages that pass through a +server. This feature will cause the server to write such a log in a +binary file. +

+ +

+The file should be named after the server name similarly to the join +FIFO. For example +

+
+ +
$> bl-server server1               
+# creates server1.fifo
+# creates server1.log
+
+$> bl-server batcave          
+# creates batcave.fifo
+# creates batcave.log
+
+
+ + +

+The format of this binary log file is as follows. +

+
    +
  • The first part should contain a binary who_t structure which has +the active users in it. To complete the logging feature, the +who_t does not need to be kept to date. +
  • +
  • After the who_t is a growing sequence of mesg_t structs in the +log file. Any message that is broadcast by the server EXCEPT for +pings is written to the end of this log, NOT in text format but as +the direct binary representation of a mesg_t. +
  • +
  • Each new message that is broadcast is appended to the end of the log +in binary format. +
  • +
+ +

+When the server starts up, the log file should be created and the +log_fd field filled with its file descriptor. A good place to write +log messages is during server_broadcast(). In it, any message that +is not a ping should be written to the end of log. +

+ +

+When the server shuts down, close the file descriptor of the log but +do not remove the file. On startup, re-open any existing log and +continue appending to it. +

+ +

+This feature is implemented entirely in the server and requires +modification of the following functions. +

+
+ +
// server.c
+void server_start(server_t *server, char *server_name, int perms)
+void server_shutdown(server_t *server)
+int server_broadcast(server_t *server, mesg_t *mesg)
+void server_write_who(server_t *server)
+void server_log_message(server_t *server, mesg_t *mesg)
+
+// bl-server.c
+int main(int argc, char *argv[])
+
+
+ +

+In addition, provide a file called bl-showlog.c which will read the +binary log file and print its output. This should include the who_t +at the beginning and all log messages. Here is a demo run including +the presumed Makefile target. Output is nearly identical to what is +shown in the client. +

+
+ +
> make bl-showlog
+gcc -Wall -g -c bl-showlog.c
+gcc -Wall -g -c util.c
+gcc -Wall -g -o bl-showlog bl-showlog.o util.o -lpthread
+
+> file server1.log
+server1.log: data
+
+> ./bl-showlog server1.log
+3 CLIENTS
+0: Batman
+1: Clark
+2: Barbara
+MESSAGES
+-- Bruce JOINED --
+-- Clark JOINED --
+-- Lois JOINED --
+[Bruce] : hey, want to know secret identity?
+[Clark] : dude, I have x-ray vision
+[Lois] : wait, you have x-ray vision
+[Clark] : ah, er, I mean...
+[Bruce] : ha ha. I'd never do something dumb like that.
+[Lois] : why not?
+[Clark] : oh boy, here it comes...
+[Bruce] : because...
+[Lois] : ??
+[Bruce] : AHYM BAAATMAN!!!
+[Clark] : walked into that one
+[Lois] : yup
+-- Barbara JOINED --
+[Barbara] : hey guys
+[Clark] : hey Barbara
+[Lois] : what up!
+[Barbara] : Did I miss anything important?
+[Clark] : the big "reveal" from Bruce...
+[Barbara] : what, that he's Batman?
+[Lois] : yup
+[Bruce] : wait, how did you know that?
+[Barbara] : you told me when we were dating
+[Lois] : me too
+[Bruce] : awkward. time for a SMOKE BOMB!!!
+-- Bruce DEPARTED --
+[Barbara] : that guy
+>
+
+
+
+
+ +
+

9.3 Last Messages for Client (10%)

+
+

+This feature requires the Binary Server Log File Feature. +

+ +

+Clients that recently join a server have no idea what has transpired +prior to their joining. This can be ameliorated if clients can access +the binary log to examine the last N messages. For example: +

+
+ +
$> bl-client server1 Lois
+-- Lois JOINED --
+[Clark] : eek!
+-- Clark DEPARTED --
+[Lois] : what's his deal?
+[Bruce] : um..
+
+Lois> %last 10
+====================
+LAST 10 MESSAGES
+[Bruce] : what up man?
+[Clark] : not much, just down in the fortress of solitude
+[Bruce] : with lois
+[Clark] : nope. lana
+[Bruce] : nice
+-- Lois JOINED --
+[Clark] : eek!
+-- Clark DEPARTED --
+[Lois] : what's his deal?
+[Bruce] : um..
+====================
+Lois>> wtf?!?
+
+
+ +

+To accomplish this bl-client should examine the typed line that is +entered to see if it starts with the string %last in which case it +will be followed by an integer which is the number of messages +requested. +

+ +

+On detecting this command request, client should open the binary log +file for the server and seek to the end of it using lseek(). Note +that the exact position in the binary log file can be calculated +immediately by using. +

+
    +
  • sizeof(mesg_t +
  • +
  • The number of messages requested +
  • +
  • The argument SEEK_END to lseek() +
  • +
+

+Thus no looping is required to find that position. +

+ +

+The client should then read off these messages and print them to the +screen. It is a good idea to write function that will print logged +messages to keep the main loop and thread loops simple in the client. +

+ +

+No server interaction is required for this feature so long as the +server is producing the binary log file. Modify only bl-client.c. +

+ +

+Modify the following code for this feature. +

+
+ +
// bl-client.c
+// helper functions and maybe main()
+int main(int argc, char *argv[])
+
+
+
+
+ +
+

9.4 who_t for Client and Server (10%)

+
+

+Users who log into the server have no way of knowing who is logged +in. This feature ameliorates that. +

+
    +
  • The server writes its active users as a who_t structure to the +beginning of its binary log every second at the same time as it +would check for disconnected users. +
  • +
  • Clients can read the who_t at the beginning of the log file to +determine which users are connected to the server. The client the +provides a %who command which prints active users. +
  • +
  • To prevent the server from writing the who_t structure while a +client is reading or vice versa, the server creates a semaphore +which must be acquired to access this part of the log. +
  • +
+ +

+The who_t structure is a simple, fixed size array of strings. +

+
// who_t: data to write into server log for current clients (ADVANCED)
+typedef struct {
+  int n_clients;                   // number of clients on server
+  char names[MAXCLIENTS][MAXNAME]; // names of clients
+} who_t;
+
+ +

+This fixed size means every time it is written it will overwrite the +same bytes. The server should write it every second in the same block +using the same approach as is used to check for disconnected clients +(alarm(1)). Use of pwrite() is suggested to allow the log_fd to +stay in position to write to the end of the log file. +

+ +

+The client should implement the %who command by checking the +simpio->buf for the string. It should then acquire the semaphore, +read the who_t and print the results the screen similar to the +following. +

+
+ +
-- Barbara JOINED --
+[Barbara] : Bruce?
+[Barbara] : Bruce, are you there?
+[Clark] : Ummm....
+[Barbara] : hang on
+
+Barbara>> %who
+====================
+3 CLIENTS
+0: Batman
+1: Clark
+2: Barbara
+====================
+[Barbara] : (sigh) Batman?
+[Batman] : I AM THE NIGHT!
+Barbara>>
+
+
+ +

+The server is responsible for creating the semaphore which controls +access to the who_t portion of the log. Follow the same naming +convention as before. +

+
+ +
$> bl-server server1               
+# creates server1.fifo  FIFO
+# creates server1.log   binary log file
+# creates /server1.sem  POSIX semaphore
+
+$> bl-server batcave          
+# creates batcave.fifo  FIFO
+# creates batcave.log   binary log file
+# creates /batcave.sem  POSIX semaphore
+
+
+

+A few notes on POSIX semaphores. +

+
    +
  • They are created / accessed with the sem_open() function which +takes a name which must start with a forward slash, thus the +/server1.sem convention. +
  • +
  • POSIX semaphores are singular, not arrays of semaphores like System +V semaphores. The have only sem_wait() (decrement) and +sem_post() (increment) operations. However, these are sufficient +for the present purpose. +
  • +
  • When the server wants to write a who_t into the log, it acquires +the semaphore with sem_wait(), writes, then releases with +sem_post(). +
  • +
  • Clients follow a similar protocol when reading the who_t. +
  • +
  • When shutting down the, server should unlink the semaphore with +sem_unlink(). +
  • +
+ +

+Modify the following code for this feature. +

+
+ +
// server.c
+void server_start(server_t *server, char *server_name, int perms)
+void server_shutdown(server_t *server)
+void server_write_who(server_t *server)
+
+// bl-server.c
+int main(int argc, char *argv[])
+
+
+// bl-client.c
+// helper functions and maybe main()
+int main(int argc, char *argv[])
+
+
+
+
+
+ +
+

10 Automatic Testing (50%)   grading

+
+

+Brewing +

+
+
+ +
+

11 Zip and Submit

+
+
+

11.1 Submit to Canvas

+
+

+Once your are confident your code is working, you are ready to +submit. Ensure your folder has all of the required files. Create a +zip archive of your lab folder and submit it to blackboard. +

+ +

+On Canvas: +

+
    +
  • Click on the Assignments section +
  • +
  • Click on the appropriate link for this lab +
  • +
  • Scroll down to "Attach a File" +
  • +
  • Click "Browse My Computer" +
  • +
  • Select you Zip file and press OK +
  • +
+
+
+ +
+

11.2 Late Policies

+
+

+You may wish to review the policy on late project submission which +will cost you late tokens to submit late or credit if you run out of +tokens. +

+ +

+http://www-users.cs.umn.edu/~kauffman/4061/syllabus.html#late-projects +

+ +

+No projects will be accepted more than 48 hours after the deadline. +

+
+
+
+
+
+
Author: Chris Kauffman (kauffman@umn.edu)
Date: 2017-11-29 Wed 17:46
+
+ + +
\ No newline at end of file diff --git a/p2-code/readme_files/blather-demo.png b/p2-code/readme_files/blather-demo.png new file mode 100644 index 0000000..c72716c Binary files /dev/null and b/p2-code/readme_files/blather-demo.png differ diff --git a/p2-code/readme_files/broadcast.svg b/p2-code/readme_files/broadcast.svg new file mode 100644 index 0000000..e43f80c --- /dev/null +++ b/p2-code/readme_files/broadcast.svg @@ -0,0 +1,711 @@ + + + + + + + + + + + + + + + + + + + + + Client 456 sends a normal message to server + through its to-server FIFO + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 3 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + + + + + + + Clark + + + + + + + Howdy! + name + body + + + + + + + BL_MSG + kind + mesg_t + + + + + + + + + + + Server broadcast normal message to all clients + through each of their to-client FIFOs + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 3 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + + + + + + + Clark + + + + + + + Howdy! + name + body + + + + + + + BL_MSG + kind + mesg_t + + + + + + + + + + + + + Clark + + + + + + + Howdy! + name + body + + + + + + + BL_MSG + kind + mesg_t + + + + + + + + + + + + + Clark + + + + + + + Howdy! + name + body + + + + + + + BL_MSG + kind + mesg_t + + + + + + + diff --git a/p2-code/readme_files/cmdline_frame.html b/p2-code/readme_files/cmdline_frame.html new file mode 100644 index 0000000..7895e96 --- /dev/null +++ b/p2-code/readme_files/cmdline_frame.html @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/p2-code/readme_files/depart.svg b/p2-code/readme_files/depart.svg new file mode 100644 index 0000000..bb1697f --- /dev/null +++ b/p2-code/readme_files/depart.svg @@ -0,0 +1,626 @@ + + + + + + + + + + + + + + + + + + + + + Client 123 indicates it is departing to the server + through its to-server FIFO + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 3 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + + + + + + + Bruce + + + + + + + name + body + + + + + + + DEPART + kind + mesg_t + + + + + + + + + + + Server removes the client including FIFOS shifting elements + of the clients[] array down then broadcasts the departure + + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 2 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + + + + + + + + + + + + + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + + + + + + + Bruce + + + + + + + name + body + + + + + + + DEPART + kind + mesg_t + + + + + + + + + + + + + Bruce + + + + + + + name + body + + + + + + + DEPART + kind + mesg_t + + + + + + + diff --git a/p2-code/readme_files/join-request.svg b/p2-code/readme_files/join-request.svg new file mode 100644 index 0000000..96a63fe --- /dev/null +++ b/p2-code/readme_files/join-request.svg @@ -0,0 +1,707 @@ + + + + + + + + + + + + + + + + + + + + + New Client 864 Creates FIFOS + Writes Request to server1 Join FIFO + + + + + + + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + to_client + to_server + + + + + + + server1 + name + join_t + + + + + + + + + + + + + + + Server Processes Join, Adds to client[] Array + Broadcasts Join to all clients through to_client FIFOs + + + + + + + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + 3 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + 864.client.fifo + + + + + + + 864.server.fifo + + + + + + + + + + + + + + + + + + + + + Client + Proc 864 + + + + + + + + + + + + + + + + + + + + Lois + + + + + + + Lois + + + + + + + name + body + + + + + + + BL_JOIN + kind + mesg_t + + + + + + + + + + + + + Lois + + + + + + + name + body + + + + + + + BL_JOIN + kind + mesg_t + + + + + + + + + + + + + Lois + + + + + + + name + body + + + + + + + BL_JOIN + kind + mesg_t + + + + + + + diff --git a/p2-code/readme_files/schematic.svg b/p2-code/readme_files/schematic.svg new file mode 100644 index 0000000..c2e9866 --- /dev/null +++ b/p2-code/readme_files/schematic.svg @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + Server with data, 2 clients, and FIFOs for communication + + + + + + + + 123.client.fifo + + + + + + + 123.server.fifo + + + + + + + Client + Proc 123 + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + 456.client.fifo + + + + + + + 456.server.fifo + + + + + + + + + + + Client + Proc 456 + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + server1.fifo + + + + + + + + + + + Server Proc 78 + + + + + + + + + + + + + + + + + + + + + + + + + + Bruce + + + + + + + + + + + + + + + + + + + + + + + + + Clark + + + + + + + join_fd + clients[] + clients[0] + clients[1] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + n_clients + + + + + + + server1 + name + + + + + + + ... + clients[2] + + + + + + + + + + + + + diff --git a/p2-code/server.c b/p2-code/server.c new file mode 100644 index 0000000..3e768e4 --- /dev/null +++ b/p2-code/server.c @@ -0,0 +1,266 @@ +#include + +#include "blather.h" + +// Gets a pointer to the client_t struct at the given index. If the +// index is beyond n_clients, the behavior of the function is +// unspecified and may cause a program crash. +client_t *server_get_client(server_t *server, int idx) { + if (idx > server->n_clients) { + // cause a kernel panic + raise(SIGSEGV); + } + return &server->client[idx]; +} + +// Initializes and starts the server with the given name. A join fifo +// called "server_name.fifo" should be created. Removes any existing +// file of that name prior to creation. Opens the FIFO and stores its +// file descriptor in join_fd._ +// +// ADVANCED: create the log file "server_name.log" and write the +// initial empty who_t contents to its beginning. Ensure that the +// log_fd is position for appending to the end of the file. Create the +// POSIX semaphore "/server_name.sem" and initialize it to 1 to +// control access to the who_t portion of the log. +void server_start(server_t *server, char *server_name, int perms) { + // add .fifo to the server name + int len = strlen(server_name); + strncpy(server->server_name, server_name, len + 1); + char server_fifo_name[len + 6]; + snprintf(server_fifo_name, len + 6, "%s.fifo", server_name); + + // remove existing fifo + remove(server_fifo_name); + if (mkfifo(server_fifo_name, perms) == -1) { + fprintf(stderr, "Error creating '%s': %s\n", server_fifo_name, + strerror(errno)); + exit(1); + } + + // open the fifo + if ((server->join_fd = open(server_fifo_name, O_RDWR)) == -1) { + fprintf(stderr, "Error opening '%s': %s\n", server_fifo_name, + strerror(errno)); + exit(1); + } +} + +// Shut down the server. Close the join FIFO and unlink (remove) it so +// that no further clients can join. Send a BL_SHUTDOWN message to all +// clients and proceed to remove all clients in any order. +// +// ADVANCED: Close the log file. Close the log semaphore and unlink +// it. +void server_shutdown(server_t *server) { + // close the fifo + close(server->join_fd); + + // get fifo name + int len = strlen(server->server_name); + char server_fifo_name[len + 6]; + snprintf(server_fifo_name, len + 6, "%s.fifo", server->server_name); + + // remove the fifo + remove(server_fifo_name); + + // send BL_SHUTDOWN + mesg_t msg = {.kind = BL_SHUTDOWN}; + server_broadcast(server, &msg); + + // remove clients + for (int i = 0; i < server->n_clients; ++i) { + server_remove_client(server, i); + } +} + +// Adds a client to the server according to the parameter join which +// should have fileds such as name filed in. The client data is +// copied into the client[] array and file descriptors are opened for +// its to-server and to-client FIFOs. Initializes the data_ready field +// for the client to 0. Returns 0 on success and non-zero if the +// server as no space for clients (n_clients == MAXCLIENTS). +int server_add_client(server_t *server, join_t *join) { + if (server->n_clients == MAXCLIENTS) + return 1; + + int to_server_fd, to_client_fd; + if ((to_server_fd = open(join->to_server_fname, O_RDWR)) == -1) { + fprintf(stderr, "Could not open connection '%s': %s\n", + join->to_server_fname, strerror(errno)); + exit(1); + } + if ((to_client_fd = open(join->to_client_fname, O_RDWR)) == -1) { + fprintf(stderr, "Could not open connection '%s': %s\n", + join->to_server_fname, strerror(errno)); + exit(1); + } + + client_t client = {.to_server_fd = to_server_fd, + .to_client_fd = to_client_fd, + .data_ready = 0}; + + strncpy(client.name, join->name, MAXPATH); + strncpy(client.to_server_fname, join->to_server_fname, MAXPATH); + strncpy(client.to_client_fname, join->to_client_fname, MAXPATH); + + server->client[server->n_clients++] = client; + return 0; +} + +// Remove the given client likely due to its having departed or +// disconnected. Close fifos associated with the client and remove +// them. Shift the remaining clients to lower indices of the client[] +// array and decrease n_clients. +int server_remove_client(server_t *server, int idx) { + // close fds + client_t *client = server_get_client(server, idx); + close(client->to_server_fd); + close(client->to_client_fd); + + for (int i = idx; i < server->n_clients - 1; ++i) + server->client[i] = server->client[i + 1]; + + server->n_clients--; + return 0; +} + +// Send the given message to all clients connected to the server by +// writing it to the file descriptors associated with them. +// +// ADVANCED: Log the broadcast message unless it is a PING which +// should not be written to the log. +int server_broadcast(server_t *server, mesg_t *mesg) { + client_t *client; + for (int i = 0; i < server->n_clients; ++i) { + client = server_get_client(server, i); + if ((write(client->to_client_fd, mesg, sizeof(mesg_t))) < 0) + return 1; + } + return 0; +} + +// Checks all sources of data for the server to determine if any are +// ready for reading. Sets the servers join_ready flag and the +// data_ready flags of each of client if data is ready for them. +// Makes use of the select() system call to efficiently determine +// which sources are ready. +void server_check_sources(server_t *server) { + fd_set readfds; + FD_ZERO(&readfds); + + int maxfd = server->join_fd; + FD_SET(server->join_fd, &readfds); + client_t *client; + for (int i = 0; i < server->n_clients; ++i) { + client = server_get_client(server, i); + client->data_ready = 0; + FD_SET(client->to_server_fd, &readfds); + if (client->to_server_fd > maxfd) + maxfd = client->to_server_fd; + } + + if (select(maxfd + 1, &readfds, NULL, NULL, NULL)) { + if (FD_ISSET(server->join_fd, &readfds)) + server->join_ready = 1; + for (int i = 0; i < server->n_clients; ++i) { + client = server_get_client(server, i); + if (FD_ISSET(client->to_server_fd, &readfds)) + client->data_ready = 1; + } + } +} + +// Return the join_ready flag from the server which indicates whether +// a call to server_handle_join() is safe. +int server_join_ready(server_t *server) { return server->join_ready; } + +// Call this function only if server_join_ready() returns true. Read a +// join request and add the new client to the server. After finishing, +// set the servers join_ready flag to 0. +int server_handle_join(server_t *server) { + // read join request + join_t request; + if (read(server->join_fd, &request, sizeof(join_t)) < 0) + return -1; + printf("name: %s\n", request.name); + + // add client + server_add_client(server, &request); + server->join_ready = 0; + return 0; +} + +// Return the data_ready field of the given client which indicates +// whether the client has data ready to be read from it. +int server_client_ready(server_t *server, int idx) { + client_t *client = server_get_client(server, idx); + return client->data_ready; +} + +// Process a message from the specified client. This function should +// only be called if server_client_ready() returns true. Read a +// message from to_server_fd and analyze the message kind. Departure +// and Message types should be broadcast to all other clients. Ping +// responses should only change the last_contact_time below. Behavior +// for other message types is not specified. Clear the client's +// data_ready flag so it has value 0. +// +// ADVANCED: Update the last_contact_time of the client to the current +// server time_sec. +int server_handle_client(server_t *server, int idx) { + client_t *client = server_get_client(server, idx); + + mesg_t payload; + read(client->to_server_fd, &payload, sizeof(mesg_t)); + + printf("received message: (%d) <%s> '%s'\n", payload.kind, payload.name, + payload.body); + switch (payload.kind) { + case BL_MESG: + case BL_JOINED: + case BL_DEPARTED: + server_broadcast(server, &payload); + break; + case BL_SHUTDOWN: + case BL_DISCONNECTED: + // shouldn't happen + break; + case BL_PING: + // TODO + break; + } + + client->data_ready = 0; + return 0; +} + +// ADVANCED: Increment the time for the server +void server_tick(server_t *server); + +// ADVANCED: Ping all clients in the server by broadcasting a ping. +void server_ping_clients(server_t *server); + +// ADVANCED: Check all clients to see if they have contacted the +// server recently. Any client with a last_contact_time field equal to +// or greater than the parameter disconnect_secs should be +// removed. Broadcast that the client was disconnected to remaining +// clients. Process clients from lowest to highest and take care of +// loop indexing as clients may be removed during the loop +// necessitating index adjustments. +void server_remove_disconnected(server_t *server, int disconnect_secs); + +// ADVANCED: Write the current set of clients logged into the server +// to the BEGINNING the log_fd. Ensure that the write is protected by +// locking the semaphore associated with the log file. Since it may +// take some time to complete this operation (acquire semaphore then +// write) it should likely be done in its own thread to preven the +// main server operations from stalling. For threaded I/O, consider +// using the pwrite() function to write to a specific location in an +// open file descriptor which will not alter the position of log_fd so +// that appends continue to write to the end of the file. +void server_write_who(server_t *server); + +// ADVANCED: Write the given message to the end of log file associated +// with the server. +void server_log_message(server_t *server, mesg_t *mesg); \ No newline at end of file diff --git a/p2-code/shell_tests.sh b/p2-code/shell_tests.sh new file mode 100755 index 0000000..b7800f3 --- /dev/null +++ b/p2-code/shell_tests.sh @@ -0,0 +1,174 @@ +#!/bin/bash + +generate=0 +run_norm=1 # run normal tests +run_valg=1 # run valgrind tests + +ticktime_norm=0.05 +ticktime_valg=0.5 +ticktime=$ticktime_valg + +function major_sep(){ + printf '%s\n' '=====================================' +} +function minor_sep(){ + printf '%s\n' '-------------------------------------' +} + +printf "Loading tests... " +source shell_tests_data.sh +printf "%d tests loaded\n" "$T" + +NTESTS=$T +VTESTS=$T +NPASS=0 +NVALG=0 + +all_tests=$(seq $NTESTS) + +# Check whether a single test is being run +single_test=$1 +if ((single_test > 0 && single_test <= NTESTS)); then + printf "Running single TEST %d\n" "$single_test" + all_tests=$single_test + NTESTS=1 + VTESTS=1 +else + printf "Running %d tests\n" "$NTESTS" +fi + +# printf "tests: %s\n" "$all_tests" +printf "\n" + +printf "RUNNING NORMAL TESTS\n" +export valg="" +ticktime=$ticktime_norm + + +if [ "$run_norm" = "1" ]; then + + for i in $all_tests; do + printf -v tid "test-%02d" "$i" # test id for various places + printf "TEST %2d %-18s : " "$i" "${tnames[i]}" + + # Run the test + outfiles=() + eval "${setup[i]}" + while read -r act; do + eval "$act" + tick + done <<< "${actions[i]}" + eval "${teardown[i]}" + + # Check each client for failure, print side-by-side diff if problems + failed=0 + for ((c=0; c<${#outfiles[*]}; c++)); do + outfile=${outfiles[c]} + printf "%s\n" "${expect_outs[i]}" | awk -F '\t' "{print \$$((c+1))}" > ${outfile}.expect + #printf "%s\n" "${expect_outs[i]}" > xxx + + # -b ignore whitespace + # -B ignore blank lines + # -y do side-by-side comparison + if ! diff -bBy ${outfile}.expect $outfile > ${outfile}.diff + then + printf "FAIL\n" + minor_sep + printf "Difference between '%s' and '%s'\n" "${outfile}.expect" "$outfile" + printf "OUTPUT: EXPECT vs ACTUAL\n" + cat ${outfile}.diff + minor_sep + failed=1 + else + rm ${outfile}.diff + # printf "'%s' OK " "${outfile}" + fi + done + + if [ "$failed" != "1" ]; then + printf "ALL OK\n" + ((NPASS++)) + elif [ "$generate" = "1" ]; then + printf "GENERATE\n" + echo "${outfiles[*]}" + paste ${outfiles[*]} + minor_sep + fi + # printf "\n" + + done + + printf "%s\n" "$major_sep" + printf "Finished:\n" + printf "%2d / %2d Normal correct\n" "$NPASS" "$NTESTS" + printf "\n" +fi + +# ================================================================================ + +if [ "$run_valg" = "1" ]; then + + printf "RUNNING VALGRIND TESTS\n" + export valg="valgrind" + export valg_opts="--leak-check=full --show-leak-kinds=all" + ticktime=$ticktime_valg + + for i in $all_tests; do + if [[ "${tnames[i]}" == *"shutdown"* ]]; then + printf "Skipping valgrind %s due to known bugs\n" "${tnames[i]}" + ((VTESTS--)) + continue + fi + + printf -v tid "test-%02d" "$i" # test id for various places + printf "TEST %2d %-18s : " "$i" "${tnames[i]}" + + # Run the test + outfiles=() + eval "${setup[i]}" + while read -r act; do + eval "$act" + tick + done <<< "${actions[i]}" + eval "${teardown[i]}" + + # Check each client for failure, print side-by-side diff if problems + failed=0 + + # Check each client for failure, print side-by-side diff if problems + failed=0 + for ((c=0; c<${#outfiles[*]}; c++)); do + outfile=${outfiles[c]} + ./filter-semopen-bug.awk $outfile > xxx # deal with apparent sem_open kernel bug + mv xxx $outfile + # Check various outputs from valgrind + if ! grep -q 'ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)' $outfile || + ! grep -q 'in use at exit: 0 bytes in 0 blocks' $outfile || + grep -q 'definitely lost: 0 bytes in 0 blocks' $outfile; + then + printf "FAIL\nValgrind detected problems in $outfile\n" + major_sep + cat $outfile + major_sep + failed=1 + fi + done + + if [ "$failed" != "1" ]; then + printf "ALL OK" + ((NVALG++)) + fi + printf "\n" + done + major_sep + printf "Finished:\n" + printf "%2d / %2d Valgrind correct\n" "$NVALG" "$VTESTS" + printf "\n" + +fi + +major_sep +printf "OVERALL:\n" +printf "%2d / %2d Normal correct\n" "$NPASS" "$NTESTS" +printf "%2d / %2d Valgrind correct\n" "$NVALG" "$VTESTS" + diff --git a/p2-code/shell_tests_data.sh b/p2-code/shell_tests_data.sh new file mode 100755 index 0000000..276c1dc --- /dev/null +++ b/p2-code/shell_tests_data.sh @@ -0,0 +1,857 @@ +#!/bin/bash + +function tick() { # command to pause input + sleep $ticktime +} + +function server_spawn () { + server="${tid}-serv" # set server name + server_out="${server}.${valg}out" # set server output name + if [ ! "$valg" = "" ]; then + outfiles+=("$server_out") + fi + $valg ${valg_opts} ./bin/bl-server $server >& ${server_out} & server_pid=$! +} + +function server_close () { + kill $server_pid + wait $server_pid +} + +function client_spawn () { + client=$1 +# echo spawning "$client" + client_out="${tid}-${client}.${valg}out" + client_fifo="${tid}-${client}.fifo" + outfiles+=("$client_out") + rm -f ${client_fifo} + mkfifo ${client_fifo} + ./cat-sig.sh <> $client_fifo > \ + >($valg ${valg_opts} ./bin/bl-client $server $client |& ./normalize.awk >& \ + ${client_out} ) & pid=$! + eval ${client}_pid=$pid +# echo client "$client $pid" spawned +} + +function client_print () { + client=$1 + mesg="$2" + echo -e "$mesg" > ${tid}-${client}.fifo +# echo -e "$mesg" ${tid}-${client}.fifo + # printf "%s\n" "$mesg" > ${client}.fifo +} + +function client_close () { + client=$1 +# echo closing "$client" + client_pid="${client}_pid" +# echo "$client_pid" ${!client_pid} + kill "${!client_pid}" + wait "${!client_pid}" + rm -f ${tid}-${client}.fifo +# echo client "$client" closed +} + + +T=0 # global test number + +# Server start/stop +((T++)) +tnames[T]="server-only" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +tick +tick +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +EOF + +# Server and single client, no messages +((T++)) +tnames[T]="1client-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- +Bruce>> +EOF + +# # Server and single client, single message +# ((T++)) +# tnames[T]="1client-2" +# read -r -d '' setup[$T] <<"EOF" +# EOF +# read -r -d '' actions[$T] <<"EOF" +# server_spawn +# client_spawn Bruce +# client_print Bruce "This is a test\n" +# client_close Bruce +# server_close +# EOF +# read -r -d '' teardown[$T] <<"EOF" +# EOF +# read -r -d '' expect_outs[$T] <<"EOF" +# -- Bruce JOINED -- +# [Bruce] : This is a test +# Bruce>> +# EOF + +# Server and single client, multiple messages +((T++)) +tnames[T]="1client-2" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_print Bruce "This is a test\n" +client_print Bruce "Is anyone there\n" +client_print Bruce "Alfreeeed!\n" +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- +[Bruce] : This is a test +[Bruce] : Is anyone there +[Bruce] : Alfreeeed! +Bruce>> +EOF + +# Server and two clients, no messages +((T++)) +tnames[T]="2client-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_close Bruce +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- -- Bruce DEPARTED -- +Bruce>> Clark>> +EOF + +# Server and two clients, single message +((T++)) +tnames[T]="2client-2" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hey big guy\n" +client_close Bruce +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- [Bruce] : Hey big guy +[Bruce] : Hey big guy -- Bruce DEPARTED -- +Bruce>> Clark>> +EOF + +# Server and two clients, multiple messages +((T++)) +tnames[T]="2client-3" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hey big guy\n" +client_print Bruce "What's happen'?\n" +client_print Clark "Not much, how about you?\n" +client_print Bruce "Hangin' out..." +client_print Bruce "In the BATCAVE" +client_print Clark "I figured..." +client_print Clark "I'm out" +client_close Clark +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- [Bruce] : Hey big guy +[Bruce] : Hey big guy [Bruce] : What's happen'? +[Bruce] : What's happen'? [Clark] : Not much, how about you? +[Clark] : Not much, how about you? [Bruce] : Hangin' out... +[Bruce] : Hangin' out... [Bruce] : In the BATCAVE +[Bruce] : In the BATCAVE [Clark] : I figured... +[Clark] : I figured... [Clark] : I'm out +[Clark] : I'm out Clark>> +-- Clark DEPARTED -- +Bruce>> +EOF + +# Server and two clients, multiple messages, one client remains +((T++)) +tnames[T]="2client-4" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hello\n" +client_print Clark "Yo\n" +client_print Bruce "bye\n" +client_close Bruce +client_print Clark "guess I'm all alone\n" +client_print Clark "this is lame\n" +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- [Bruce] : Hello +[Bruce] : Hello [Clark] : Yo +[Clark] : Yo [Bruce] : bye +[Bruce] : bye -- Bruce DEPARTED -- +Bruce>> [Clark] : guess I'm all alone + [Clark] : this is lame + Clark>> +EOF + + +# Server and two clients, multiple messages, one client remains +((T++)) +tnames[T]="2client-5" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hello\n" +client_print Clark "Yo\n" +client_print Bruce "bye\n" +client_print Clark "No\n" +client_print Bruce "Yep\n" +client_print Clark "Wrong\n" +client_print Bruce "Hah\n" +client_close Clark +client_print Bruce "grrr\n" +client_print Bruce "grrr\n" +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- [Bruce] : Hello +[Bruce] : Hello [Clark] : Yo +[Clark] : Yo [Bruce] : bye +[Bruce] : bye [Clark] : No +[Clark] : No [Bruce] : Yep +[Bruce] : Yep [Clark] : Wrong +[Clark] : Wrong [Bruce] : Hah +[Bruce] : Hah Clark>> +-- Clark DEPARTED -- +[Bruce] : grrr +[Bruce] : grrr +Bruce>> +EOF + +# Server and two clients, multiple messages, one client remains +((T++)) +tnames[T]="2client-6" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hello\n" +client_print Clark "Yo\n" +client_print Bruce "bye\n" +client_print Clark "No\n" +client_print Bruce "Yep\n" +client_print Clark "Wrong\n" +client_print Bruce "Hah\n" +client_print Bruce "grrr\n" +client_print Bruce "grrr\n" +client_close Bruce +client_print Clark "Ugh\n" +client_print Clark "Ugh\n" +client_print Clark "sigh..\n" +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- +-- Clark JOINED -- [Bruce] : Hello +[Bruce] : Hello [Clark] : Yo +[Clark] : Yo [Bruce] : bye +[Bruce] : bye [Clark] : No +[Clark] : No [Bruce] : Yep +[Bruce] : Yep [Clark] : Wrong +[Clark] : Wrong [Bruce] : Hah +[Bruce] : Hah [Bruce] : grrr +[Bruce] : grrr [Bruce] : grrr +[Bruce] : grrr -- Bruce DEPARTED -- +Bruce>> [Clark] : Ugh + [Clark] : Ugh + [Clark] : sigh.. + Clark>> +EOF + +# Server and two clients, multiple messages, one client rejoins +((T++)) +tnames[T]="2client-rejoin1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Bruce "Hello\n" +client_print Clark "Yo\n" +client_print Bruce "bye\n" +client_close Bruce +client_print Clark "Ugh\n" +client_spawn Bruce +client_print Bruce "back\n" +client_print Clark "great\n" +client_print Clark "gone\n" +client_print Bruce "ack\n" +client_close Clark +client_print Bruce "alone\n" +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- -- Bruce JOINED -- +[Bruce] : back [Bruce] : Hello [Bruce] : back +[Clark] : great [Clark] : Yo [Clark] : great +[Clark] : gone [Bruce] : bye [Clark] : gone +[Bruce] : ack -- Bruce DEPARTED -- [Bruce] : ack +-- Clark DEPARTED -- [Clark] : Ugh -- Clark DEPARTED -- +[Bruce] : alone -- Bruce JOINED -- [Bruce] : alone +Bruce>> [Bruce] : back Bruce>> + [Clark] : great + [Clark] : gone + [Bruce] : ack + Clark>> +EOF + +# # Server and two clients, multiple messages, two clients rejoins +# ((T++)) +# tnames[T]="2client-rejoin2" +# read -r -d '' setup[$T] <<"EOF" +# EOF +# read -r -d '' actions[$T] <<"EOF" +# server_spawn +# client_spawn Bruce +# client_print Bruce "alone\n" +# client_spawn Clark +# client_print Bruce "Hello\n" +# client_print Clark "Yo\n" +# client_print Bruce "bye\n" +# client_close Bruce +# client_print Clark "Ugh\n" +# client_spawn Bruce +# client_print Bruce "back\n" +# client_print Clark "great\n" +# client_print Clark "gone\n" +# client_print Bruce "ack\n" +# client_close Clark +# client_print Bruce "alone\n" +# client_spawn Clark +# client_print Bruce "joy\n" +# client_close Bruce +# client_close Clark +# server_close +# EOF +# read -r -d '' teardown[$T] <<"EOF" +# EOF +# read -r -d '' expect_outs[$T] <<"EOF" +# -- Bruce JOINED -- -- Clark JOINED -- -- Bruce JOINED -- -- Clark JOINED -- +# [Bruce] : back [Bruce] : joy [Bruce] : back [Bruce] : joy +# [Clark] : great -- Bruce DEPARTED -- [Clark] : great -- Bruce DEPARTED -- +# [Clark] : gone Clark>> [Clark] : gone Clark>> +# [Bruce] : ack [Bruce] : ack +# -- Clark DEPARTED -- -- Clark DEPARTED -- +# [Bruce] : alone [Bruce] : alone +# -- Clark JOINED -- -- Clark JOINED -- +# [Bruce] : joy [Bruce] : joy +# Bruce>> Bruce>> +# EOF + +# Three clients, no messages +((T++)) +tnames[T]="3clients-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_spawn Bruce +client_spawn Lois +client_close Bruce +client_close Lois +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +-- Bruce JOINED -- -- Lois JOINED -- -- Bruce DEPARTED -- +-- Lois JOINED -- Bruce>> Lois>> +-- Bruce DEPARTED -- +-- Lois DEPARTED -- +Clark>> +EOF + +# Three clients, one message +((T++)) +tnames[T]="3clients-2" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_spawn Bruce +client_spawn Lois +client_print Bruce "Batman!\n" +client_close Bruce +client_close Lois +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +-- Bruce JOINED -- -- Lois JOINED -- [Bruce] : Batman! +-- Lois JOINED -- [Bruce] : Batman! -- Bruce DEPARTED -- +[Bruce] : Batman! Bruce>> Lois>> +-- Bruce DEPARTED -- +-- Lois DEPARTED -- +Clark>> +EOF + +# Three clients, several messages +((T++)) +tnames[T]="3clients-3" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_spawn Bruce +client_spawn Lois +client_print Bruce "Batman!\n" +client_print Clark "Superman!\n" +client_print Lois "Reporter?\n" +client_print Bruce "Ha\n" +client_print Clark "He he\n" +client_print Lois "bite me\n" +client_close Lois +client_close Clark +client_close Bruce +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +-- Bruce JOINED -- -- Lois JOINED -- [Bruce] : Batman! +-- Lois JOINED -- [Bruce] : Batman! [Clark] : Superman! +[Bruce] : Batman! [Clark] : Superman! [Lois] : Reporter? +[Clark] : Superman! [Lois] : Reporter? [Bruce] : Ha +[Lois] : Reporter? [Bruce] : Ha [Clark] : He he +[Bruce] : Ha [Clark] : He he [Lois] : bite me +[Clark] : He he [Lois] : bite me Lois>> +[Lois] : bite me -- Lois DEPARTED -- +-- Lois DEPARTED -- -- Clark DEPARTED -- +Clark>> Bruce>> +EOF + +# Three clients, several messages before/after full join +((T++)) +tnames[T]="3clients-4" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_print Clark "Superman!\n" +client_spawn Bruce +client_print Bruce "Hey!\n" +client_print Clark "Superman!\n" +client_spawn Lois +client_print Bruce "Batman!\n" +client_print Clark "Superman!\n" +client_print Lois "Not again\n" +client_print Bruce "Vanish!\n" +client_close Bruce +client_print Clark "He he\n" +client_print Lois "Lame\n" +client_print Clark "Yup\n" +client_close Lois +client_print Clark "Fortress of solitude\n" +client_close Clark +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +[Clark] : Superman! [Bruce] : Hey! [Bruce] : Batman! +-- Bruce JOINED -- [Clark] : Superman! [Clark] : Superman! +[Bruce] : Hey! -- Lois JOINED -- [Lois] : Not again +[Clark] : Superman! [Bruce] : Batman! [Bruce] : Vanish! +-- Lois JOINED -- [Clark] : Superman! -- Bruce DEPARTED -- +[Bruce] : Batman! [Lois] : Not again [Clark] : He he +[Clark] : Superman! [Bruce] : Vanish! [Lois] : Lame +[Lois] : Not again Bruce>> [Clark] : Yup +[Bruce] : Vanish! Lois>> +-- Bruce DEPARTED -- +[Clark] : He he +[Lois] : Lame +[Clark] : Yup +-- Lois DEPARTED -- +[Clark] : Fortress of solitude +Clark>> +EOF + +# Three clients with rejoins and messages +((T++)) +tnames[T]="3clients-rejoin1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark1 +client_print Clark1 "Superman!\n" +client_spawn Bruce1 +client_print Bruce1 "Batman!\n" +client_print Clark1 "Superman!\n" +client_close Bruce1 +client_spawn Lois1 +client_print Clark1 "Superman!\n" +client_print Lois1 "Not again\n" +client_spawn Bruce2 +client_print Bruce2 "Vanish!\n" +client_close Bruce2 +client_print Clark1 "He he\n" +client_print Clark1 "Super speed\n" +client_close Clark1 +client_print Lois1 "Lame\n" +client_spawn Clark2 +client_print Clark2 "Yup - super hearing\n" +client_close Lois1 +client_print Clark2 "Fortress of solitude\n" +client_spawn Bruce3 +client_print Bruce3 "From the shadows!\n" +client_print Bruce3 "Kryptonite!\n" +client_close Clark2 +client_print Bruce3 "Batman!\n" +client_close Bruce3 +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark1 JOINED -- -- Bruce1 JOINED -- -- Lois1 JOINED -- -- Bruce2 JOINED -- -- Clark2 JOINED -- -- Bruce3 JOINED -- +[Clark1] : Superman! [Bruce1] : Batman! [Clark1] : Superman! [Bruce2] : Vanish! [Clark2] : Yup - super hearing [Bruce3] : From the shadows! +-- Bruce1 JOINED -- [Clark1] : Superman! [Lois1] : Not again Bruce2>> -- Lois1 DEPARTED -- [Bruce3] : Kryptonite! +[Bruce1] : Batman! Bruce1>> -- Bruce2 JOINED -- [Clark2] : Fortress of solitude -- Clark2 DEPARTED -- +[Clark1] : Superman! [Bruce2] : Vanish! -- Bruce3 JOINED -- [Bruce3] : Batman! +-- Bruce1 DEPARTED -- -- Bruce2 DEPARTED -- [Bruce3] : From the shadows! Bruce3>> +-- Lois1 JOINED -- [Clark1] : He he [Bruce3] : Kryptonite! +[Clark1] : Superman! [Clark1] : Super speed Clark2>> +[Lois1] : Not again -- Clark1 DEPARTED -- +-- Bruce2 JOINED -- [Lois1] : Lame +[Bruce2] : Vanish! -- Clark2 JOINED -- +-- Bruce2 DEPARTED -- [Clark2] : Yup - super hearing +[Clark1] : He he Lois1>> +[Clark1] : Super speed +Clark1>> +EOF + +# Four clients messages +((T++)) +tnames[T]="4clients-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Bruce +client_spawn Clark +client_print Clark "Superman!\n" +client_print Bruce "Batman!\n" +client_print Clark "Superman v Batman\n" +client_print Bruce "No: Batman v Superman\n" +client_print Clark "It would set up Super Friends" +client_spawn Lois +client_print Lois "Gentlemen" +client_print Clark "Lois, what's up\n" +client_print Bruce "I am the night!\n" +client_spawn Barbara +client_print Lois "Can anyone control him" +client_print Barbara "nope\n" +client_print Clark "not me, keeps throwing green rocks at me\n" +client_print Bruce "because..." +client_print Barbara "no no no...\n" +client_print Bruce "I'M BATMAN" +client_print Clark "nice" +client_print Lois "nope, nope, neeey-ooope" +client_close Lois +client_print Barbara "Keep antagonizing me and watch what happens\n" +client_print Clark "You end up in a wheel chair?\n" +client_print Barbara ">:-(\n" +client_print Bruce "Whoa, that's insensitive" +client_print Clark "Ummm, sorry?" +client_close Clark +client_print Barbara "And I thought you were rude" +client_print Bruce "I am rude" +client_print Bruce "I'm whatever this city needs me to be" +client_print Barbara "cripes" +client_print Bruce "Because I'm BATMAN" +client_close Bruce +client_print Barbara "I've got to find a different server" +client_close Barbara +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Bruce JOINED -- -- Clark JOINED -- -- Lois JOINED -- -- Barbara JOINED -- +-- Clark JOINED -- [Clark] : Superman! [Lois] : Gentlemen [Lois] : Can anyone control him +[Clark] : Superman! [Bruce] : Batman! [Clark] : Lois, what's up [Barbara] : nope +[Bruce] : Batman! [Clark] : Superman v Batman [Bruce] : I am the night! [Clark] : not me, keeps throwing green rocks at me +[Clark] : Superman v Batman [Bruce] : No: Batman v Superman -- Barbara JOINED -- [Bruce] : because... +[Bruce] : No: Batman v Superman [Clark] : It would set up Super Friends [Lois] : Can anyone control him [Barbara] : no no no... +[Clark] : It would set up Super Friends -- Lois JOINED -- [Barbara] : nope [Bruce] : I'M BATMAN +-- Lois JOINED -- [Lois] : Gentlemen [Clark] : not me, keeps throwing green rocks at me [Clark] : nice +[Lois] : Gentlemen [Clark] : Lois, what's up [Bruce] : because... [Lois] : nope, nope, neeey-ooope +[Clark] : Lois, what's up [Bruce] : I am the night! [Barbara] : no no no... -- Lois DEPARTED -- +[Bruce] : I am the night! -- Barbara JOINED -- [Bruce] : I'M BATMAN [Barbara] : Keep antagonizing me and watch what happens +-- Barbara JOINED -- [Lois] : Can anyone control him [Clark] : nice [Clark] : You end up in a wheel chair? +[Lois] : Can anyone control him [Barbara] : nope [Lois] : nope, nope, neeey-ooope [Barbara] : >:-( +[Barbara] : nope [Clark] : not me, keeps throwing green rocks at me Lois>> [Bruce] : Whoa, that's insensitive +[Clark] : not me, keeps throwing green rocks at me [Bruce] : because... [Clark] : Ummm, sorry? +[Bruce] : because... [Barbara] : no no no... -- Clark DEPARTED -- +[Barbara] : no no no... [Bruce] : I'M BATMAN [Barbara] : And I thought you were rude +[Bruce] : I'M BATMAN [Clark] : nice [Bruce] : I am rude +[Clark] : nice [Lois] : nope, nope, neeey-ooope [Bruce] : I'm whatever this city needs me to be +[Lois] : nope, nope, neeey-ooope -- Lois DEPARTED -- [Barbara] : cripes +-- Lois DEPARTED -- [Barbara] : Keep antagonizing me and watch what happens [Bruce] : Because I'm BATMAN +[Barbara] : Keep antagonizing me and watch what happens [Clark] : You end up in a wheel chair? -- Bruce DEPARTED -- +[Clark] : You end up in a wheel chair? [Barbara] : >:-( [Barbara] : I've got to find a different server +[Barbara] : >:-( [Bruce] : Whoa, that's insensitive Barbara>> +[Bruce] : Whoa, that's insensitive [Clark] : Ummm, sorry? +[Clark] : Ummm, sorry? Clark>> +-- Clark DEPARTED -- +[Barbara] : And I thought you were rude +[Bruce] : I am rude +[Bruce] : I'm whatever this city needs me to be +[Barbara] : cripes +[Bruce] : Because I'm BATMAN +Bruce>> +EOF + + +# Shutdown message from server +((T++)) +tnames[T]="shutdown-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +tick +server_close +client_close Clark +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- +!!! server is shutting down !!! +Clark>> +EOF + +# Shutdown message from server +((T++)) +tnames[T]="shutdown-2" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_spawn Bruce +client_spawn Lois +server_close +client_close Bruce +client_close Clark +client_close Lois +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +-- Bruce JOINED -- -- Lois JOINED -- !!! server is shutting down !!! +-- Lois JOINED -- !!! server is shutting down !!! Lois>> +!!! server is shutting down !!! Bruce>> +Clark>> +EOF + + +# Shutdown message from server +((T++)) +tnames[T]="shutdown-3" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn Clark +client_spawn Bruce +client_print Bruce "Batman!\n" +client_spawn Lois +client_print Clark "Superman!\n" +server_close +client_close Bruce +client_close Lois +client_close Clark +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- Clark JOINED -- -- Bruce JOINED -- -- Lois JOINED -- +-- Bruce JOINED -- [Bruce] : Batman! [Clark] : Superman! +[Bruce] : Batman! -- Lois JOINED -- !!! server is shutting down !!! +-- Lois JOINED -- [Clark] : Superman! Lois>> +[Clark] : Superman! !!! server is shutting down !!! +!!! server is shutting down !!! Bruce>> +Clark>> +EOF + +# Many clients messages +((T++)) +tnames[T]="stress-1" +read -r -d '' setup[$T] <<"EOF" +EOF +read -r -d '' actions[$T] <<"EOF" +server_spawn +client_spawn A +client_spawn B +client_spawn C +client_print C "1\n" +client_print B "2\n" +client_print B "3\n" +client_print A "4\n" +client_spawn D +client_spawn E +client_print A "5\n" +client_print D "6\n" +client_print E "7\n" +client_print C "8\n" +client_spawn F +client_spawn G +client_spawn H +client_print A "9\n" +client_print D "10\n" +client_print E "11\n" +client_print C "12\n" +client_print B "13\n" +client_close C +client_print F "14\n" +client_print G "15\n" +client_print D "16\n" +client_print E "17\n" +client_print B "18\n" +client_close D +client_print F "19\n" +client_print F "20\n" +client_print E "21\n" +client_print A "22\n" +client_close G +client_print B "23\n" +client_close A +client_close B +client_print F "24\n" +client_close E +client_close F +client_print H "25\n" +client_close H +server_close +EOF +read -r -d '' teardown[$T] <<"EOF" +EOF +read -r -d '' expect_outs[$T] <<"EOF" +-- A JOINED -- -- B JOINED -- -- C JOINED -- -- D JOINED -- -- E JOINED -- -- F JOINED -- -- G JOINED -- -- H JOINED -- +-- B JOINED -- -- C JOINED -- [C] : 1 -- E JOINED -- [A] : 5 -- G JOINED -- -- H JOINED -- [A] : 9 +-- C JOINED -- [C] : 1 [B] : 2 [A] : 5 [D] : 6 -- H JOINED -- [A] : 9 [D] : 10 +[C] : 1 [B] : 2 [B] : 3 [D] : 6 [E] : 7 [A] : 9 [D] : 10 [E] : 11 +[B] : 2 [B] : 3 [A] : 4 [E] : 7 [C] : 8 [D] : 10 [E] : 11 [C] : 12 +[B] : 3 [A] : 4 -- D JOINED -- [C] : 8 -- F JOINED -- [E] : 11 [C] : 12 [B] : 13 +[A] : 4 -- D JOINED -- -- E JOINED -- -- F JOINED -- -- G JOINED -- [C] : 12 [B] : 13 -- C DEPARTED -- +-- D JOINED -- -- E JOINED -- [A] : 5 -- G JOINED -- -- H JOINED -- [B] : 13 -- C DEPARTED -- [F] : 14 +-- E JOINED -- [A] : 5 [D] : 6 -- H JOINED -- [A] : 9 -- C DEPARTED -- [F] : 14 [G] : 15 +[A] : 5 [D] : 6 [E] : 7 [A] : 9 [D] : 10 [F] : 14 [G] : 15 [D] : 16 +[D] : 6 [E] : 7 [C] : 8 [D] : 10 [E] : 11 [G] : 15 [D] : 16 [E] : 17 +[E] : 7 [C] : 8 -- F JOINED -- [E] : 11 [C] : 12 [D] : 16 [E] : 17 [B] : 18 +[C] : 8 -- F JOINED -- -- G JOINED -- [C] : 12 [B] : 13 [E] : 17 [B] : 18 -- D DEPARTED -- +-- F JOINED -- -- G JOINED -- -- H JOINED -- [B] : 13 -- C DEPARTED -- [B] : 18 -- D DEPARTED -- [F] : 19 +-- G JOINED -- -- H JOINED -- [A] : 9 -- C DEPARTED -- [F] : 14 -- D DEPARTED -- [F] : 19 [F] : 20 +-- H JOINED -- [A] : 9 [D] : 10 [F] : 14 [G] : 15 [F] : 19 [F] : 20 [E] : 21 +[A] : 9 [D] : 10 [E] : 11 [G] : 15 [D] : 16 [F] : 20 [E] : 21 [A] : 22 +[D] : 10 [E] : 11 [C] : 12 [D] : 16 [E] : 17 [E] : 21 [A] : 22 -- G DEPARTED -- +[E] : 11 [C] : 12 [B] : 13 [E] : 17 [B] : 18 [A] : 22 G>> [B] : 23 +[C] : 12 [B] : 13 C>> [B] : 18 -- D DEPARTED -- -- G DEPARTED -- -- A DEPARTED -- +[B] : 13 -- C DEPARTED -- D>> [F] : 19 [B] : 23 -- B DEPARTED -- +-- C DEPARTED -- [F] : 14 [F] : 20 -- A DEPARTED -- [F] : 24 +[F] : 14 [G] : 15 [E] : 21 -- B DEPARTED -- -- E DEPARTED -- +[G] : 15 [D] : 16 [A] : 22 [F] : 24 -- F DEPARTED -- +[D] : 16 [E] : 17 -- G DEPARTED -- -- E DEPARTED -- [H] : 25 +[E] : 17 [B] : 18 [B] : 23 F>> H>> +[B] : 18 -- D DEPARTED -- -- A DEPARTED -- +-- D DEPARTED -- [F] : 19 -- B DEPARTED -- +[F] : 19 [F] : 20 [F] : 24 +[F] : 20 [E] : 21 E>> +[E] : 21 [A] : 22 +[A] : 22 -- G DEPARTED -- +-- G DEPARTED -- [B] : 23 +[B] : 23 -- A DEPARTED -- +A>> B>> +EOF diff --git a/p2-code/simpio-demo.c b/p2-code/simpio-demo.c new file mode 100644 index 0000000..1a0521f --- /dev/null +++ b/p2-code/simpio-demo.c @@ -0,0 +1,61 @@ +#include "blather.h" + +simpio_t simpio_actual; +simpio_t *simpio = &simpio_actual; + +client_t client_actual; +client_t *client = &client_actual; + +pthread_t user_thread; // thread managing user input +pthread_t background_thread; + +// Worker thread to manage user input +void *user_worker(void *arg) { + int count = 1; + while (!simpio->end_of_input) { + simpio_reset(simpio); + iprintf(simpio, ""); // print prompt + while (!simpio->line_ready && + !simpio->end_of_input) { // read until line is complete + simpio_get_char(simpio); + } + if (simpio->line_ready) { + iprintf(simpio, "%2d You entered: %s\n", count, simpio->buf); + count++; + } + } + + pthread_cancel(background_thread); // kill the background thread + return NULL; +} + +// Worker thread to listen to the info from the server. +void *background_worker(void *arg) { + char *text[3] = { + "Background text #1", "Background text #2", "Background text #3", + }; + for (int i = 0;; i++) { + sleep(3); + iprintf(simpio, "BKGND: %s\n", text[i % 3]); + } + return NULL; +} + +int main(int argc, char *argv[]) { + char prompt[MAXNAME]; + snprintf(prompt, MAXNAME, "%s>> ", "fgnd"); // create a prompt string + simpio_set_prompt(simpio, prompt); // set the prompt + simpio_reset(simpio); // initialize io + simpio_noncanonical_terminal_mode(); // set the terminal into a compatible + // mode + + pthread_create(&user_thread, NULL, user_worker, + NULL); // start user thread to read input + pthread_create(&background_thread, NULL, background_worker, NULL); + pthread_join(user_thread, NULL); + pthread_join(background_thread, NULL); + + simpio_reset_terminal_mode(); + printf("\n"); // newline just to make returning to the terminal prettier + return 0; +} diff --git a/p2-code/simpio.c b/p2-code/simpio.c new file mode 100644 index 0000000..da9b02a --- /dev/null +++ b/p2-code/simpio.c @@ -0,0 +1,114 @@ +#include "blather.h" +#include + +static struct termios oldt, newt; // structs to change the terminal input mode + +// Set non-canonical mode so that each character of input is available +// immediately +void simpio_noncanonical_terminal_mode() { + // Turn off output buffering + setvbuf(stdout, NULL, _IONBF, 0); + + // tcgetattr gets the parameters of the current terminal + // STDIN_FILENO will tell tcgetattr that it should write the + // settings of stdin to oldt + tcgetattr(STDIN_FILENO, &oldt); + + // now the settings will be copied + newt = oldt; + + // ICANON normally takes care that one line at a time will be + // processed that means it will return if it sees a "\n" or an EOF + // or an EOL + newt.c_lflag &= ~(ICANON | ECHO); + // newt.c_lflag &= ~(ICANON); + + // Those new settings will be set to STDIN TCSANOW tells tcsetattr + // to change attributes immediately. + tcsetattr(STDIN_FILENO, TCSANOW, &newt); +} + +// Reset terminal mode to what is was prior to +// simpio_set_noncanonical_mode() +void simpio_reset_terminal_mode() { tcsetattr(STDIN_FILENO, TCSANOW, &oldt); } + +// Reset the simpio_t object to have 0 for position and flags. Usually +// done after completing input and processing it. +void simpio_reset(simpio_t *simpio) { + simpio->pos = 0; + simpio->buf[0] = '\0'; + simpio->line_ready = 0; + simpio->end_of_input = 0; + simpio->infile = stdin; + simpio->outfile = stdout; +} + +// Set the prompt for the simpio handle. Maximum length for the prompt +// is MAXNAME. +void simpio_set_prompt(simpio_t *simpio, char *prompt) { + strncpy(simpio->prompt, prompt, MAXNAME); +} + +// Assumes things are in non-canonical terminal mode otherwise results +// may vary. Read a character from the input associated with +// simpio. Fields are adjusted to reflect the state of input after +// reading the character. Typically: +// +// - simpio->pos will increase +// - simpio->buf will get one more character +// - simpio->line_ready may be set to 1 if a line is completed +// - for backspaces, buf and pos decrease +// +// This funciton is used in a loop to read input until line_ready is 1. +void simpio_get_char(simpio_t *simpio) { + int c = fgetc(simpio->infile); + if (0) { + } else if (c == '\n' && simpio->pos > 0) { + simpio->buf[simpio->pos] = '\0'; + simpio->line_ready = 1; + } else if ((c == '\b' || c == DEL || c == '\n') && simpio->pos == 0) { + // ignore enter, backspace without input + } else if (c == EOT && simpio->pos > 0) { + simpio->buf[simpio->pos] = '\0'; + simpio->line_ready = 1; + } else if ((c == '\b' || c == DEL) && + simpio->pos > 0) { // backspace or delete + simpio->pos = simpio->pos - 1; + simpio->buf[simpio->pos] = '\0'; + int fd = fileno(simpio->outfile); + write(fd, "\b \b", 3); // erase last character + } else if (c != EOF && c != EOT && + simpio->pos < MAXLINE - 1) { // normal chars get added + simpio->buf[simpio->pos] = c; + simpio->pos++; + simpio->buf[simpio->pos] = '\0'; + fputc(c, simpio->outfile); + } + if (c == EOF || c == EOT) { // check for end of input + simpio->end_of_input = 1; + } +} + +// Print like printf but move the input prompt ahead and preserve the +// input that has been typed so far along with the prompt. +void iprintf(simpio_t *simpio, char *fmt, ...) { + char output[MAXLINE * 2]; // buffer for message + int max = MAXLINE * 2; + int off = 0; + off += snprintf(output + off, max - off, "\33[2K\r"); // erase line + va_list myargs; + va_start(myargs, fmt); + off += vsnprintf(output + off, MAXLINE, fmt, + myargs); // add on the new message + va_end(myargs); + off += snprintf(output + off, max - off, "%s", + simpio->prompt); // add prompt back + off += snprintf(output + off, max - off, "%s", + simpio->buf); // current typed input + + int fd = fileno(simpio->outfile); + write(fd, output, off); + + // fprintf(input->outfile, "%s", input->prompt); + // simpio_print(input); +} diff --git a/p2-code/util.c b/p2-code/util.c new file mode 100644 index 0000000..1f23c47 --- /dev/null +++ b/p2-code/util.c @@ -0,0 +1,50 @@ +#include "blather.h" + +// If condition is a truthy value, call perror() with a message +// constructed with the fmt and additional args provided then exit. +// Example: +// +// checkfail(myfd==-1, "Couldn't open file %s", filename); +void check_fail(int condition, int perr, char *fmt, ...) { + if (!condition) { + return; + } + if (perr) { + char msg[MAXLINE]; // buffer for message + va_list myargs; // declare a va_list type variable + va_start(myargs, + fmt); // initialise the va_list variable with the ... after fmt + vsnprintf(msg, MAXLINE, fmt, + myargs); // forward the '...' to vsnprintf() + va_end(myargs); // clean up the va_list + perror(msg); + } else { + va_list myargs; // declare a va_list type variable + va_start(myargs, + fmt); // initialise the va_list variable with the ... after fmt + vfprintf(stderr, fmt, myargs); // forward the '...' to vfprintf() + va_end(myargs); // clean up the va_list + } + exit(1); +} + +// Print like printf but only if DEBUG is defined as 1. Print to +// standard error. +void dbg_printf(char *fmt, ...) { + if (DEBUG) { + va_list myargs; // declare a va_list type variable + va_start(myargs, + fmt); // initialise the va_list variable with the ... after fmt + vfprintf(stderr, fmt, myargs); // forward the '...' to vfprintf() + va_end(myargs); // clean up the va_list + } +} + +// Sleep the running program for the given number of nanoseconds and +// seconds. +void pause_for(long nanos, int secs) { + struct timespec tm = { + .tv_nsec = nanos, .tv_sec = secs, + }; + nanosleep(&tm, NULL); +}