diff --git a/.gitignore b/.gitignore index c6127b3..b231303 100644 --- a/.gitignore +++ b/.gitignore @@ -1,52 +1,31 @@ -# Prerequisites -*.d - -# Object files +* +!/**/ +!*.* +# Compiled Object files +*.slo +*.lo *.o -*.ko *.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib # Executables *.exe *.out *.app -*.i*86 -*.x86_64 -*.hex +**/*.out +*/outDebug + +# +*/build/Debug/outDebug +*/output.txt +*.exe +*.out +*.app -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb +*.Identifier +gcc_errors.txt +*tests* +*old +*.txt* +*.csv -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf +!makefile diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..fad9002 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "linux-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "/usr/bin/gcc", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "linux-gcc-x64", + "compilerArgs": [ + "-lpthread" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a6f0071 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,74 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "bashdb", + "request": "launch", + "name": "pick", + "cwd": "${workspaceFolder}", + "program": "${command:SelectScriptName}", + "args": [] + }, + { + "type": "bashdb", + "request": "launch", + "name": "gccfind", + "cwd": "${workspaceFolder}", + "terminalKind": "integrated", + "showDebugOutput": true, + "trace": true, + "program": "/home/bar/projects/OpSys/OpSystems/hw1/gccfind.sh", + "args": [ + "hw1/ex-files", + "execvp", + "-r" + ] + }, + { + "type": "bashdb", + "request": "launch", + "name": "Bash-Debug (simplest configuration)", + "program": "${file}" + }, + { + "name": "prodcast", + "type": "cppdbg", + "request": "launch", + "args": [ + "config.txt" + ], + "stopAtEntry": false, + "externalConsole": false, + "cwd": "/home/bar/projects/OpSys/OpSystems/hw3", + "program": "/home/bar/projects/OpSys/OpSystems/hw3/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": false, + "cwd": "/home/bar/projects/OpSys/OpSystems/hw3", + "program": "/home/bar/projects/OpSys/OpSystems/hw3/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4a0d339 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,90 @@ +{ + "C_Cpp_Runner.cCompilerPath": "/usr/bin/gcc", + "C_Cpp_Runner.cppCompilerPath": "/usr/bin/g++", + "C_Cpp_Runner.debuggerPath": "/usr/bin/gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "", + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [ + "-lpthread" + ], + "C_Cpp_Runner.linkerArgs": [ + "-lpthread" + ], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "files.associations": { + "cmath": "c", + "*.tcc": "c", + "condition_variable": "cpp", + "mutex": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp" + }, + "cSpell.words": [ + "qutex" + ], + "C_Cpp_Runner.useMsvc": false +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..749658a --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +# OpSystems + +1.

Ex1: ⚒️ Gcc Find; 🎾 Tennis ; 💲Shell

+

+ + _____________________________________ + >

⚒️ Gcc Find:


+ > a nice little script for compiling all the c files in the folder that contains a specific word. You can turn on th -r flag for recessiveness + >

⚙️How To⚙️

+ > + > + >⚡ > ./gccfind.sh myFolder main -r +
+ _____________________________________ + + >

🎾 Tennis (paper game):


+ > a funny little [tennis paper game](https://en.wikipedia.org/wiki/Tennis_(paper_game)), terminal styled. + > #### ⚙️How To⚙️ + > There are two options for the game: in place game, and logged history game + > You can choose what to use by simply run the game with flags: + > * __for in place game:__ --in-place | -p + > * __for logged game :__ --l | -log + > * The default version is logged
+ > + > ⚡ > ./tennis.sh -p + _____________________________________ + >

💲 Shell:


+ > a shell program that can be loaded with your custom commands + >

⚙️How To⚙️

+ >
  • compile myshell.c gcc -o shell myshell.c
    + >
  • There are two options:
    + > you can run the runnable script without any other params.
    + > The program will act as you expect from a normal shell
    + > Or you can send path to a folder, which contains custom scrits. The folder be then added temporarily to your env variables,
    + > so you can can any script that is defined there by simply typing it's name.

+ > for example: + > if inside a folder named 'myCommands' you have a script named 'do-somthing.sh'
+ > you can run the shell with the path to 'myCommads', then you can just type + > do-something.sh ,
no matter what pwd you are in.
+ >
+ > ⚡ > ./myshell ~/myCommands
+ _____________________________________ + +

+ +
+_______________________________________________________ + +2.

Ex2: 📂 File Comperator & Grader

+

+ + _____________________________________ + >

2.1: Files Comperator


+ > a program that get two arguments of file pathes and determines the similarity:
+ > 🔖 1: The files are identical
+ > 🔖 2: The files are different
+ > 🔖 3: The files are similar
+ >
+ > ⚡ > ./comp.out /home/os20 12 /code/1.txt /home/os20 12 /code/2.txt + > + >
+ + _____________________________________ + >

2.2: Grader


+ > A program that gets config path and grades the folders by that
+ > The config file contains 3 rows:
+ > ✏️ 1: Path to parent folder which contains sub-folders for grade. Each folder is a user folder.
+ > ✏️ 2: Path to an input file for will-be executed program
+ > ✏️ 3: Path to correct output file
+ > The program iterates through the users' folders, compiles(if exists) the c file in that folder. + > Then runs the compiled program with the input file and comperes the results to the correct output from the config file. + > If anything in the way is getting wrong, the grade will be affected as listing here:
+ > > > > > > ✨ NO_C_FILE : 0
+ > > > > > > ✨ COMPILATION_ERROR: 10
+ > > > > > > ✨ TIMEOUT: 20
+ > > > > > > ✨ WRONG: 50
+ > > > > > > ✨ SIMILAR: 75
+ > The grade will be written into an excel file, named results.csv, which will be created inside the running folder.
+ >
+ > ⚡ > ./a.out /home/os20 12 /conf.txt + > + >
+ _____________________________________ +

+ +
+_______________________________________________________ + +3.

Ex3: 🗞️ Publisher: content producer-distributer-coeditor Threads Synchronization

+

+ + _____________________________________ + > A program that gets a config file for products per procuder, and coediting abilities. + > The program syncronizing the work of everyone by threads + >
To create executable you can use the makefile + > ⚡ > ./ex3.out config.txt + _____________________________________ +

+ +
+_______________________________________________________ diff --git a/eg.code/Code-1/T6_1.c b/eg.code/Code-1/T6_1.c new file mode 100644 index 0000000..003c8ef --- /dev/null +++ b/eg.code/Code-1/T6_1.c @@ -0,0 +1,34 @@ +//To compile: gcc -l pthread T6_1.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void printids(const char *s) +{ + pid_t pid; + pthread_t tid; + + pid = getpid(); + tid = pthread_self(); + printf("%s pid %u tid %u\n", s, (unsigned int)pid,(unsigned int)tid); +} + +void* thr_fn(void *arg) +{ + printids("new thread: "); + return((void *)0); +} + +int main(void) +{ + int err; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + printids("main thread:"); + sleep(1); + exit(0); +} diff --git a/eg.code/Code-1/T6_2.c b/eg.code/Code-1/T6_2.c new file mode 100644 index 0000000..fdf9221 --- /dev/null +++ b/eg.code/Code-1/T6_2.c @@ -0,0 +1,47 @@ +//To compile: gcc -l pthread T6_2.c +#include +#include + +int int_Val[5] = {0,0,0,0,0}; +pthread_t th[5]; + +void *add_to_value(void *arg) { // arg = 0, 1, 2, 3 ,4 + int inData = *((int*)arg); + int i; + for(i = 0; i < 10000; i++){ + int_Val[i % 5] += inData; /* ? */ + } + + /* Expectation (under the incorrect assumption that threads will run one after another for sure): + thread 0: [0,0,0,0,0] (+0 to each cell) + thread 1: [2000,2000,2000,2000,2000] (+1*2000=2000 to each cell) + thread 2: [6000,6000,6000,6000,6000] (+2*2000=4000 to each cell) + thread 3: [12000,12000,12000,12000,12000] (+3*2000=6000 to each cell) + thread 4: [20000,20000,20000,20000,20000] (+4*2000=8000 to each cell) + */ + + return (NULL); +} + +int main(void) { + int i, retcode; + + /* Create the threads */ + for(i = 0; i < 5; i++) { + retcode = pthread_create(&th[i], NULL, add_to_value, (void *)&i); + if (retcode != 0) + printf("Create thread failed with error %d\n", retcode); + } + + /* Wait until all threads have finished */ + void* retVal[5]; + for(i = 0; i < 5; i++){ + pthread_join(th[i], &retVal[i]); + } + + /* Print the results */ + printf("Final values:\n"); + for(i = 0; i < 5; i++) + printf("Integer value[%d] = \t%d\n", i, int_Val[i]); + return 0; +} diff --git a/eg.code/Code-1/T6_3.c b/eg.code/Code-1/T6_3.c new file mode 100644 index 0000000..7860268 --- /dev/null +++ b/eg.code/Code-1/T6_3.c @@ -0,0 +1,35 @@ +//To compile: gcc -l pthread T6_3.c +#include +#include +#include +#include +#include + +pthread_t ntid[2]; + +void* thr_fn(void *arg) +{ + int i; + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + int i; + for(i=0;i<2;i++) + { + err = pthread_create(&ntid[i], NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + } + + sleep(1); + pthread_exit((void*)0); +} diff --git a/eg.code/Code-1/T6_4.c b/eg.code/Code-1/T6_4.c new file mode 100644 index 0000000..3c6668a --- /dev/null +++ b/eg.code/Code-1/T6_4.c @@ -0,0 +1,38 @@ +//To compile: gcc -l pthread T6_4.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void* thr_fn(void *arg) +{ + int i,x; + x=fork(); + if(x==0){ // run this code twice: with > and with == + return((void *)0); + } + + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + void *retVal; + int i; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + pthread_join(ntid, &retVal); + printf("returned\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/Code-1/T6_4_New.c b/eg.code/Code-1/T6_4_New.c new file mode 100644 index 0000000..aa28e5e --- /dev/null +++ b/eg.code/Code-1/T6_4_New.c @@ -0,0 +1,38 @@ +//To compile: gcc -l pthread t6_4_New.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void* thr_fn(void *arg) +{ + int i,x; + x=fork(); + if(x>0){ // run this code twice: with > and with == + return((void *)0); + } + + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + void *retVal; + int i; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + pthread_join(ntid, &retVal); + printf("returned\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/Code-1/T6_5.c b/eg.code/Code-1/T6_5.c new file mode 100644 index 0000000..ac45aaa --- /dev/null +++ b/eg.code/Code-1/T6_5.c @@ -0,0 +1,39 @@ +//To compile: gcc -l pthread T6_5.c +#include +#include +#include +#include +#include +pthread_t ntid[2]; +pthread_t ltid; +void* thr_fn(void *arg) +{ + int i; + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(2); + } + + return((void *)0); +} +void* thr_fn2(void *arg) +{ + execl("/bin/ls", "ls", (char*)NULL); + return((void *)0); +} + +int main(void) +{ + int err; + int i; + for(i=0;i<2;i++) + err = pthread_create(&ntid[i], NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + sleep(1); + pthread_create(<id, NULL, thr_fn2, NULL); + printf("I'm done\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/Code-1/T6_6.c b/eg.code/Code-1/T6_6.c new file mode 100644 index 0000000..c4d6982 --- /dev/null +++ b/eg.code/Code-1/T6_6.c @@ -0,0 +1,43 @@ +// To compile: gcc -l pthread T6_6.c +// thread synchronization problem + +#include +#include +#include +#include +#include + +pthread_t tid[10]; +int counter=0; + +void* doSomeThing(void *arg) +{ + unsigned long i = 0; + + for(i=0; i<1000000;i++) + counter++; + + return NULL; +} + +int main(void) +{ + int i = 0; + int err; + + while(i < 10) + { + err = pthread_create(&tid[i], NULL, doSomeThing, NULL); + if (err != 0) + printf("\ncan't create thread :[%s]", strerror(err)); + i++; + } + + for (i=0;i<10;i++) + pthread_join(tid[i], NULL); + + + printf("counter value is: %d\n",counter); + + return 0; +} diff --git a/eg.code/Code-1/T6_7.c b/eg.code/Code-1/T6_7.c new file mode 100644 index 0000000..a06e039 --- /dev/null +++ b/eg.code/Code-1/T6_7.c @@ -0,0 +1,51 @@ +//To compile: gcc -l pthread T6_7.c +//thread synchronization problem - mutex solution +#include +#include +#include +#include +#include + +pthread_t tid[10]; +int counter=0; + +pthread_mutex_t lock; + +void* doSomeThing(void *arg) +{ + unsigned long i = 0; + pthread_mutex_lock(&lock); + for(i=0; i<1000000;i++) + counter++; + pthread_mutex_unlock(&lock); + + return NULL; +} + +int main(void) +{ + int i = 0; + int err; + + if (pthread_mutex_init(&lock, NULL) != 0) + { + printf("\n mutex init failed\n"); + return 1; + } + + while(i < 10) + { + err = pthread_create(&tid[i], NULL, doSomeThing, NULL); + //printf("created\n"); + if (err != 0) + printf("\ncan't create thread :[%s]", strerror(err)); + i++; + } + for (i=0;i<10;i++) + pthread_join(tid[i], NULL); + printf("counter value is: %d\n",counter); + + pthread_mutex_destroy(&lock); + + return 0; +} diff --git a/eg.code/Code/T4_1.c b/eg.code/Code/T4_1.c new file mode 100644 index 0000000..47d8fb9 --- /dev/null +++ b/eg.code/Code/T4_1.c @@ -0,0 +1,29 @@ +#include +#include +#include + +int main (int argc, char* argv[]) +{ + char* filename = argv[1]; + char msg[64]; + + struct stat stat_p; + + if(stat(filename, &stat_p) == -1) + { + sprintf(msg," Error occurred attempting to stat %s\n", filename); // printf + perror(msg); + return 1; + } + + printf("Stats for %s \n", filename); + printf("File size is %ld bytes\n", stat_p.st_size); + + if(S_ISREG(stat_p.st_mode)) + printf("This is a regular file\n"); + + if(S_ISDIR(stat_p.st_mode)) + printf("This is a directory\n"); + + return 0; +} diff --git a/eg.code/Code/T4_2.c b/eg.code/Code/T4_2.c new file mode 100644 index 0000000..6d78975 --- /dev/null +++ b/eg.code/Code/T4_2.c @@ -0,0 +1,58 @@ +#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) { + perror("stat"); + exit(EXIT_FAILURE); + } + + printf("File type: "); + + 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"); + + + printf("I-node number: %ld\n", (long) sb.st_ino); + + printf("Mode: %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); + + printf("Last status change: %s", ctime(&sb.st_ctime)); + printf("Last file access: %s", ctime(&sb.st_atime)); + printf("Last file modification: %s", ctime(&sb.st_mtime)); + + exit(EXIT_SUCCESS); +} diff --git a/eg.code/T5code/Code/T5_2.c b/eg.code/T5code/Code/T5_2.c new file mode 100644 index 0000000..d07ee62 --- /dev/null +++ b/eg.code/T5code/Code/T5_2.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#define SIZE 10 + +main(int argc , char argv) +{ + int fdin; /* input file descriptor */ + int fdout; /* out file descriptor */ + char buf[SIZE+1]; /* input (output) buffer */ + int charsr; /* how many chars were actually red */ + int charsw; /* how many chars were actually written */ + + + fdin = open("dugma1.txt",O_RDONLY); + if (fdin < 0) /* means file open did not take place */ + { + perror("after open "); /* text explaining why */ + exit(-1); + } + /* create the file with read-write premissions */ + fdout = open("dugma2.txt", O_CREAT | O_RDWR, 0666); + if (fdout < 0) /* means file open did not take place */ + { + perror("after create "); /* text explaining why */ + exit(-1); + } + + do + { + charsr = read(fdin,buf,SIZE); + /* why writing SIZE can be wrong...*/ + charsw = write(fdout,buf,charsr); + if (charsw < charsr) + { + printf("error reading\n"); + } + }while ( (charsr == SIZE) && (charsw == SIZE)); + close(fdin); /* free allocated structures */ + close(fdout); /* free allocated structures */ +} + diff --git a/eg.code/T5code/Code/T5_3.c b/eg.code/T5code/Code/T5_3.c new file mode 100644 index 0000000..efca4e1 --- /dev/null +++ b/eg.code/T5code/Code/T5_3.c @@ -0,0 +1,27 @@ +#include +#include +#include +int main(int argc, char **argv) +{ + int pid, status; + int newfd; /* new file descriptor */ + if (argc != 2) + { + fprintf(stderr, "usage: %s output_file\n", argv[0]); + exit(1); + } + if ((newfd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0644)) < 0) + { + perror(argv[1]); /* open failed */ + exit(1); + } + printf("This goes to the standard output.\n"); + printf("Now the standard output will go to \"%s\".\n", argv[1]); + /* this new file will become the standard output */ + /*standard output is file descriptor 1, so we use dup2 */ + /* to copy the new file descriptor onto file descriptor 1 */ + /* dup2 will close the current standard output */ + dup2(newfd, 1); + printf("This goes to the file.\n"); + exit(0); +} diff --git a/eg.code/T5code/Code/T5_4.c b/eg.code/T5code/Code/T5_4.c new file mode 100644 index 0000000..bed0778 --- /dev/null +++ b/eg.code/T5code/Code/T5_4.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +#define NEWFILE (O_WRONLY | O_CREAT | O_TRUNC ) +#define MODE600 (S_IRUSR | S_IWUSR) +#define SIZE 10 + +void fileCopy(char* inPath, char* outPath) +{ + char buf[SIZE]; + int in,out,count; + + if((in=open(inPath,O_RDONLY))==-1) + { + printf("error\n"); + exit(0); + } + if((out=open(outPath,NEWFILE,MODE600))==-1) + { + printf("error\n"); + exit(0); + } + while((count=read(in,buf,sizeof(buf)))>0) + { + if(write(out,buf,count)!=count) + { + printf("error\n"); + exit(0); + } + } + if(count==-1) + { + printf("error\n"); + exit(0); + } + close(in); + close(out); +} + + +int main() +{ + fileCopy("in.txt","out.txt"); +} diff --git a/eg.code/T5code/Code/T5_5.c b/eg.code/T5code/Code/T5_5.c new file mode 100644 index 0000000..d7f0c0d --- /dev/null +++ b/eg.code/T5code/Code/T5_5.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#define NEWFILE (O_WRONLY | O_CREAT | O_TRUNC ) +#define MODE600 (S_IRUSR | S_IWUSR) +#define SIZE 10 +#define BUF_SIZE 1024 + +int my_read(int fd,char *buf,size_t count) +{ + static char read_buf[BUF_SIZE]; + static int read_offset =BUF_SIZE; + static int read_max=BUF_SIZE; + int i; + for(i=0;i0) + write(fd,write_buf,write_offset); + + write_offset=0; + return close(fd); +} + +void fileCopy(char* inPath, char* outPath) +{ + char buf[SIZE]; + int in,out,count; + + if((in=open(inPath,O_RDONLY))==-1) + { + printf("error\n"); + exit(0); + } + if((out=open(outPath,NEWFILE,MODE600))==-1) + { + printf("error\n"); + exit(0); + } + while((count=my_read(in,buf,sizeof(buf)))>0) + { + if(my_write(out,buf,count)!=count) + { + printf("error\n"); + exit(0); + } + } + if(count==-1) + { + printf("error\n"); + exit(0); + } + close(in); + write_close(out); +} + + +int main() +{ + fileCopy("in.txt","out.txt"); +} diff --git a/eg.code/T5code/Code/dup_exec_example.c b/eg.code/T5code/Code/dup_exec_example.c new file mode 100644 index 0000000..ba665a3 --- /dev/null +++ b/eg.code/T5code/Code/dup_exec_example.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + int in, out; + char* grep_args[] = {"grep", "Villanova", NULL}; + + // open input and output files + in = open("scores", O_RDONLY); + out = open("out", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWGRP | S_IWUSR); + + // replace standard input with input file + dup2(in, 0); + + // replace standard output with output file + dup2(out, 1); + + // close unused file descriptors + close(in); + close(out); + + // execute grep + execvp("grep", grep_args); +} diff --git a/eg.code/T5code/Code/ls_implementation.c b/eg.code/T5code/Code/ls_implementation.c new file mode 100644 index 0000000..d077e55 --- /dev/null +++ b/eg.code/T5code/Code/ls_implementation.c @@ -0,0 +1,41 @@ +#include +#include + +int listdir(const char* path) +{ + struct dirent* entry; + DIR* dp; + + dp = opendir(path); + if(dp == NULL) + { + perror("opendir"); + return -1; + } + + while((entry = readdir(dp)) != NULL) + { + puts(entry->d_name); + } + + closedir(dp); + return 0; +} + +int main(int argc, char **argv) +{ + int counter = 1; + + if(argc == 1) + { + listdir("."); + } + + while(++counter <= argc) + { + printf("\nListing %s...\n", argv[counter - 1]); + listdir(argv[counter - 1]); + } + + return 0; +} diff --git a/eg.code/T5code/Code/scan_dir_example.c b/eg.code/T5code/Code/scan_dir_example.c new file mode 100644 index 0000000..7dcf4d5 --- /dev/null +++ b/eg.code/T5code/Code/scan_dir_example.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + DIR* dip; + struct dirent* dit; + int i = 0; + + if(argc < 2) + { + printf("Usage: %s \n", argv[0]); + return 0; + } + + if((dip = opendir(argv[1])) == NULL) + { + perror("opendir"); + return 0; + } + + printf("Directory stream is now open\n"); + + while((dit = readdir(dip)) != NULL) + { + i++; + printf("\n%s", dit->d_name); + } + + if(closedir(dip) == -1) + { + perror("closedir"); + return 0; + } + + printf("\nDirectory stream is now closed\n"); + return 1; +} diff --git a/eg.code/T6Code/T6_1.c b/eg.code/T6Code/T6_1.c new file mode 100644 index 0000000..003c8ef --- /dev/null +++ b/eg.code/T6Code/T6_1.c @@ -0,0 +1,34 @@ +//To compile: gcc -l pthread T6_1.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void printids(const char *s) +{ + pid_t pid; + pthread_t tid; + + pid = getpid(); + tid = pthread_self(); + printf("%s pid %u tid %u\n", s, (unsigned int)pid,(unsigned int)tid); +} + +void* thr_fn(void *arg) +{ + printids("new thread: "); + return((void *)0); +} + +int main(void) +{ + int err; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + printids("main thread:"); + sleep(1); + exit(0); +} diff --git a/eg.code/T6Code/T6_2.c b/eg.code/T6Code/T6_2.c new file mode 100644 index 0000000..fdf9221 --- /dev/null +++ b/eg.code/T6Code/T6_2.c @@ -0,0 +1,47 @@ +//To compile: gcc -l pthread T6_2.c +#include +#include + +int int_Val[5] = {0,0,0,0,0}; +pthread_t th[5]; + +void *add_to_value(void *arg) { // arg = 0, 1, 2, 3 ,4 + int inData = *((int*)arg); + int i; + for(i = 0; i < 10000; i++){ + int_Val[i % 5] += inData; /* ? */ + } + + /* Expectation (under the incorrect assumption that threads will run one after another for sure): + thread 0: [0,0,0,0,0] (+0 to each cell) + thread 1: [2000,2000,2000,2000,2000] (+1*2000=2000 to each cell) + thread 2: [6000,6000,6000,6000,6000] (+2*2000=4000 to each cell) + thread 3: [12000,12000,12000,12000,12000] (+3*2000=6000 to each cell) + thread 4: [20000,20000,20000,20000,20000] (+4*2000=8000 to each cell) + */ + + return (NULL); +} + +int main(void) { + int i, retcode; + + /* Create the threads */ + for(i = 0; i < 5; i++) { + retcode = pthread_create(&th[i], NULL, add_to_value, (void *)&i); + if (retcode != 0) + printf("Create thread failed with error %d\n", retcode); + } + + /* Wait until all threads have finished */ + void* retVal[5]; + for(i = 0; i < 5; i++){ + pthread_join(th[i], &retVal[i]); + } + + /* Print the results */ + printf("Final values:\n"); + for(i = 0; i < 5; i++) + printf("Integer value[%d] = \t%d\n", i, int_Val[i]); + return 0; +} diff --git a/eg.code/T6Code/T6_3.c b/eg.code/T6Code/T6_3.c new file mode 100644 index 0000000..7860268 --- /dev/null +++ b/eg.code/T6Code/T6_3.c @@ -0,0 +1,35 @@ +//To compile: gcc -l pthread T6_3.c +#include +#include +#include +#include +#include + +pthread_t ntid[2]; + +void* thr_fn(void *arg) +{ + int i; + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + int i; + for(i=0;i<2;i++) + { + err = pthread_create(&ntid[i], NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + } + + sleep(1); + pthread_exit((void*)0); +} diff --git a/eg.code/T6Code/T6_4.c b/eg.code/T6Code/T6_4.c new file mode 100644 index 0000000..3c6668a --- /dev/null +++ b/eg.code/T6Code/T6_4.c @@ -0,0 +1,38 @@ +//To compile: gcc -l pthread T6_4.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void* thr_fn(void *arg) +{ + int i,x; + x=fork(); + if(x==0){ // run this code twice: with > and with == + return((void *)0); + } + + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + void *retVal; + int i; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + pthread_join(ntid, &retVal); + printf("returned\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/T6Code/T6_4_New.c b/eg.code/T6Code/T6_4_New.c new file mode 100644 index 0000000..aa28e5e --- /dev/null +++ b/eg.code/T6Code/T6_4_New.c @@ -0,0 +1,38 @@ +//To compile: gcc -l pthread t6_4_New.c +#include +#include +#include +#include +#include +pthread_t ntid; + +void* thr_fn(void *arg) +{ + int i,x; + x=fork(); + if(x>0){ // run this code twice: with > and with == + return((void *)0); + } + + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(1); + } + + return((void *)0); +} + +int main(void) +{ + int err; + void *retVal; + int i; + err = pthread_create(&ntid, NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + pthread_join(ntid, &retVal); + printf("returned\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/T6Code/T6_5.c b/eg.code/T6Code/T6_5.c new file mode 100644 index 0000000..ac45aaa --- /dev/null +++ b/eg.code/T6Code/T6_5.c @@ -0,0 +1,39 @@ +//To compile: gcc -l pthread T6_5.c +#include +#include +#include +#include +#include +pthread_t ntid[2]; +pthread_t ltid; +void* thr_fn(void *arg) +{ + int i; + for(i=0;i<3;i++) + { + printf("my tid is %lu, my pid is: %d, the loop value is: %d\n",pthread_self(),getpid(),i); + sleep(2); + } + + return((void *)0); +} +void* thr_fn2(void *arg) +{ + execl("/bin/ls", "ls", (char*)NULL); + return((void *)0); +} + +int main(void) +{ + int err; + int i; + for(i=0;i<2;i++) + err = pthread_create(&ntid[i], NULL, thr_fn, NULL); + if (err != 0) + perror("can't create thread\n"); + + sleep(1); + pthread_create(<id, NULL, thr_fn2, NULL); + printf("I'm done\n"); + pthread_exit((void*)0); +} diff --git a/eg.code/T6Code/T6_6.c b/eg.code/T6Code/T6_6.c new file mode 100644 index 0000000..c4d6982 --- /dev/null +++ b/eg.code/T6Code/T6_6.c @@ -0,0 +1,43 @@ +// To compile: gcc -l pthread T6_6.c +// thread synchronization problem + +#include +#include +#include +#include +#include + +pthread_t tid[10]; +int counter=0; + +void* doSomeThing(void *arg) +{ + unsigned long i = 0; + + for(i=0; i<1000000;i++) + counter++; + + return NULL; +} + +int main(void) +{ + int i = 0; + int err; + + while(i < 10) + { + err = pthread_create(&tid[i], NULL, doSomeThing, NULL); + if (err != 0) + printf("\ncan't create thread :[%s]", strerror(err)); + i++; + } + + for (i=0;i<10;i++) + pthread_join(tid[i], NULL); + + + printf("counter value is: %d\n",counter); + + return 0; +} diff --git a/eg.code/T6Code/T6_7.c b/eg.code/T6Code/T6_7.c new file mode 100644 index 0000000..a06e039 --- /dev/null +++ b/eg.code/T6Code/T6_7.c @@ -0,0 +1,51 @@ +//To compile: gcc -l pthread T6_7.c +//thread synchronization problem - mutex solution +#include +#include +#include +#include +#include + +pthread_t tid[10]; +int counter=0; + +pthread_mutex_t lock; + +void* doSomeThing(void *arg) +{ + unsigned long i = 0; + pthread_mutex_lock(&lock); + for(i=0; i<1000000;i++) + counter++; + pthread_mutex_unlock(&lock); + + return NULL; +} + +int main(void) +{ + int i = 0; + int err; + + if (pthread_mutex_init(&lock, NULL) != 0) + { + printf("\n mutex init failed\n"); + return 1; + } + + while(i < 10) + { + err = pthread_create(&tid[i], NULL, doSomeThing, NULL); + //printf("created\n"); + if (err != 0) + printf("\ncan't create thread :[%s]", strerror(err)); + i++; + } + for (i=0;i<10;i++) + pthread_join(tid[i], NULL); + printf("counter value is: %d\n",counter); + + pthread_mutex_destroy(&lock); + + return 0; +} diff --git "a/eg.code/\360\237\220\207/statChild.c" "b/eg.code/\360\237\220\207/statChild.c" new file mode 100644 index 0000000..a6f1be0 --- /dev/null +++ "b/eg.code/\360\237\220\207/statChild.c" @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +int main() { + int number, statval; + printf("%d: I'm the parent !\n", getpid()); + if (fork() == 0) { + number = 5; + printf("PID %d: exiting with number %d\n", getpid(), number); + exit(number); + } else { + printf("PID %d: waiting for child\n", getpid()); + wait(&statval); + if (WIFEXITED(statval)) + printf("Child's exit code %d\n", WEXITSTATUS(statval)); + else + printf("Child did not terminate with exit\n"); + } + return 0; +} \ No newline at end of file diff --git "a/eg.code/\360\237\220\207/withExc.c" "b/eg.code/\360\237\220\207/withExc.c" new file mode 100644 index 0000000..89d9239 --- /dev/null +++ "b/eg.code/\360\237\220\207/withExc.c" @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +int main(void) { + int pid = fork(); + + if (pid == -1) { + perror("fork() failed"); + exit(EXIT_FAILURE); + } else if (pid == 0) { + execlp("./child", "child", "1", "5", (char *)NULL); + perror("execlp() failed"); + exit(EXIT_FAILURE); + } else { + printf("Coordinator: forked and waiting for process %d\n", pid); + + int status; + if (waitpid(pid, &status, 0) != -1) { + if (WIFEXITED(status)) { + int returned = WEXITSTATUS(status); + printf("Exited normally with status %d\n", returned); + } else if (WIFSIGNALED(status)) { + int signum = WTERMSIG(status); + printf("Exited due to receiving signal %d\n", signum); + } else if (WIFSTOPPED(status)) { + int signum = WSTOPSIG(status); + printf("Stopped due to receiving signal %d\n", signum); + } else { + printf("Something strange just happened.\n"); + } + } else { + perror("waitpid() failed"); + exit(EXIT_FAILURE); + } + } + + return 0; +} \ No newline at end of file diff --git a/hw1/ex-files/0/1/3/atexit_example_1.c b/hw1/ex-files/0/1/3/atexit_example_1.c new file mode 100644 index 0000000..90d0efd --- /dev/null +++ b/hw1/ex-files/0/1/3/atexit_example_1.c @@ -0,0 +1,19 @@ +#include +#include +#include + void fnExit1 (void) { + puts ("Exit function 1."); +} + +void fnExit2 (void) { + puts ("Exit function 2."); +} + +int main () { + atexit (fnExit1); + atexit (fnExit2); + atexit (fnExit2); + puts ("Main function."); + return 0; +} + diff --git a/hw1/ex-files/0/1/3/atexit_example_2.c b/hw1/ex-files/0/1/3/atexit_example_2.c new file mode 100644 index 0000000..a925d36 --- /dev/null +++ b/hw1/ex-files/0/1/3/atexit_example_2.c @@ -0,0 +1,23 @@ +#include +#include +#include + +void bye(void) { + printf("Let’s go home, we learned enough today\n"); +} + +int main(void) +{ + long a; + int i; + a = sysconf(_SC_ATEXIT_MAX); + printf("ATEXIT_MAX = %ld\n", a); + i = atexit(bye); + if (i != 0) + { + fprintf(stderr, "cannot set exit function\n"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} + diff --git a/hw1/ex-files/0/1/4/execvp_wait_example.c b/hw1/ex-files/0/1/4/execvp_wait_example.c new file mode 100644 index 0000000..46f09d5 --- /dev/null +++ b/hw1/ex-files/0/1/4/execvp_wait_example.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + int stat,waited,ret_code; + pid_t pid; + pid = fork(); + if (pid == 0) + { /* Child */ + ret_code = execvp(argv[1],&argv[1]); + if (ret_code == -1) + { + perror("exec failed "); + exit(-1); + } + else + printf("Banana"); + } + else + { /* Parent */ + printf("Father: after fork, son proc id is %d \n",pid); + waited = wait(&stat); /* stat can tell what happened */ + printf("Father: Son proc completed, id is %d \n", waited); + } +} diff --git a/hw1/ex-files/0/1/4/fork_example_1.c b/hw1/ex-files/0/1/4/fork_example_1.c new file mode 100644 index 0000000..dbf3585 --- /dev/null +++ b/hw1/ex-files/0/1/4/fork_example_1.c @@ -0,0 +1,14 @@ +#include +#include +#include + +void main() +{ + pid_t pid; + if ((pid = fork()) == 0) + printf("1"); + else + printf("2"); + printf("3"); +} + diff --git a/hw1/ex-files/0/1/4/fork_example_2.c b/hw1/ex-files/0/1/4/fork_example_2.c new file mode 100644 index 0000000..2fd4489 --- /dev/null +++ b/hw1/ex-files/0/1/4/fork_example_2.c @@ -0,0 +1,7 @@ +int main(){ + int i; + for (i = 0; i < 3; i++) + if (fork() == 0) + while(1); +} + diff --git a/hw1/ex-files/0/1/execl_example.c b/hw1/ex-files/0/1/execl_example.c new file mode 100644 index 0000000..84cee5f --- /dev/null +++ b/hw1/ex-files/0/1/execl_example.c @@ -0,0 +1,8 @@ +#include +#include +int main() +{ + execl("/bin/ls","/bin/ls","-l", NULL); + printf("can only get here on error\n"); +} + diff --git a/hw1/ex-files/0/1/execv_example.c b/hw1/ex-files/0/1/execv_example.c new file mode 100644 index 0000000..bacdc06 --- /dev/null +++ b/hw1/ex-files/0/1/execv_example.c @@ -0,0 +1,10 @@ +#include +#include + +int main() { + char *argv[] = {"date", NULL}; + execv("/bin/date", argv); + printf("hello"); + return 0; +} + diff --git a/hw1/ex-files/0/2/5/6/t2_2.c b/hw1/ex-files/0/2/5/6/t2_2.c new file mode 100644 index 0000000..c5924a3 --- /dev/null +++ b/hw1/ex-files/0/2/5/6/t2_2.c @@ -0,0 +1,20 @@ +#include +#include + +int main(void) +{ + int status; + char *argv[] = { "/bin/env", 0 }; + char *envp[] = + { + "HOME=/", + "PATH=/bin:/usr/bin", + "TZ=UTC0", + "USER=beelzebub", + "LOGNAME=tarzan", + 0 + }; + status=execve(argv[0], &argv[0], envp); + printf("exec failed\n"); + return -1; +} diff --git a/hw1/ex-files/0/2/5/6/t2_3.c b/hw1/ex-files/0/2/5/6/t2_3.c new file mode 100644 index 0000000..d04403e --- /dev/null +++ b/hw1/ex-files/0/2/5/6/t2_3.c @@ -0,0 +1,21 @@ +#include +#include +#include + +void done(){ + printf("see ya!\n"); +} +int main(){ + int status; + atexit(done); + if(fork()) + { + wait(&status); + printf("parent PID = %d\n",getpid()); + printf("exit status= %d\n",WEXITSTATUS(status)); _Exit(73); + }else{ + sleep(2); + printf("child PID = %d\n",getpid()); + exit(55); + } +} diff --git a/hw1/ex-files/0/2/5/t2_1.c b/hw1/ex-files/0/2/5/t2_1.c new file mode 100644 index 0000000..d00c4fb --- /dev/null +++ b/hw1/ex-files/0/2/5/t2_1.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +int glob = 6; /* global variable */ +char buf[] = "a write to stdout"; + +int main(void) +{ + int var; /* automatic variable on the stack */ + pid_t pid; + + var = 88; + if(puts(buf)==EOF) + printf("error in writing to stdout"); + printf("before fork\n"); + + if ( (pid = fork()) < 0) + printf("fork error"); + else{ + if (pid == 0) + { /* child */ + glob++; /* modify variables */ + var++; + }else + { /* parent */ + sleep(2); + } + printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var); + exit(0); + } +} + diff --git a/hw1/ex-files/0/2/fork_example_3.c b/hw1/ex-files/0/2/fork_example_3.c new file mode 100644 index 0000000..a9d2099 --- /dev/null +++ b/hw1/ex-files/0/2/fork_example_3.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() +{ + pid_t val; + printf("PID before fork: %d\n",(int)getpid()); + val = fork(); + if(val>0) + printf("parent PID: %d\n",(int)getpid()); + else if(val ==0) + printf("child PID: %d\n",(int)getpid()); + else { + //if val==-1 print error to screen + } +} + diff --git a/hw1/ex-files/0/4.c b/hw1/ex-files/0/4.c new file mode 100644 index 0000000..8569322 --- /dev/null +++ b/hw1/ex-files/0/4.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main() { + pid_t bll; + int stat; + if ((bll = fork()) == 0) + printf("1\n"); + else { + wait(&stat); + printf("2\n"); + } +} diff --git a/hw1/ex-files/0/wait_example_1.c b/hw1/ex-files/0/wait_example_1.c new file mode 100644 index 0000000..7119a2d --- /dev/null +++ b/hw1/ex-files/0/wait_example_1.c @@ -0,0 +1,14 @@ +#include +#include +#include +int main() +{ + pid_t pid; + int stat; + if ((pid = fork()) == 0) + printf("1\n"); else { + wait(&stat); + printf("2\n"); + } +} + diff --git a/hw1/ex-files/0/wait_example_2.c b/hw1/ex-files/0/wait_example_2.c new file mode 100644 index 0000000..540e5a4 --- /dev/null +++ b/hw1/ex-files/0/wait_example_2.c @@ -0,0 +1,27 @@ +#include +#include + +int main() +{ + int status; + pid_t pid, pid1, pid2; + if ((pid1 = fork()) == 0) + printf("in child 1\n"); + else + if ((pid2 = fork()) == 0) + printf("in child 2\n"); + else + { + pid = wait(&status); + if (pid == pid1) + printf("child 1 finished\n"); + if (pid == pid2) + printf("child 2 finished\n"); + pid = wait(&status); + if (pid == pid1) + printf("child 1 finished\n"); + if (pid == pid2) + printf("child 2 finished\n"); + } +} + diff --git a/hw1/ex-files/0/waitpid_example.c b/hw1/ex-files/0/waitpid_example.c new file mode 100644 index 0000000..5a85e67 --- /dev/null +++ b/hw1/ex-files/0/waitpid_example.c @@ -0,0 +1,34 @@ +#include +#include +#include + +int main(void){ + pid_t pid; + if ((pid = fork()) < 0) + printf("fork error"); + else { + if (pid == 0) { /* first child */ + printf("first child\n"); + if ((pid = fork()) < 0) + printf ("fork error"); + else { + if (pid > 0){ + /* parent from second fork == first child */ + if (waitpid(pid, NULL, 0) != pid) + printf("waitpid error"); + exit(0); + } + /* We're the second child; */ + sleep(2); + printf("second child, parent pid = %d\n", getppid()); + exit(0); + } + } + if (waitpid(pid, NULL, 0) != pid) /* wait for first child */ + printf("waitpid error"); + /** We're the parent (the original process); we continue executing, knowing that we're not the parent of the second child.*/ + printf("original parent done\n"); + exit(0); + } +} + diff --git a/hw1/ex-files/3.c b/hw1/ex-files/3.c new file mode 100644 index 0000000..4c3098e --- /dev/null +++ b/hw1/ex-files/3.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main() { + pid_t bll; + int stat; + if ((bll = fork()) == 0) + printf("bin\n"); + else { + wait(&stat); + printf("2\n"); + } +} diff --git "a/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf" "b/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf" new file mode 100644 index 0000000..b82163a Binary files /dev/null and "b/hw1/ex-files/\327\252\327\250\327\222\327\231\327\234 1.pdf" differ diff --git a/hw1/gccfind.sh b/hw1/gccfind.sh new file mode 100755 index 0000000..90dad28 --- /dev/null +++ b/hw1/gccfind.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +dirPath=$1 +wordToFind=$2 +isRecursive=$3 +COMPILED_EX="*.out" +C_FILE="*.c" + +if [ "$isRecursive" == "-r" ] +then + isRecursive=true +else + isRecursive=false +fi + +# check if there is enough params +if [[ -z "$wordToFind" || "$wordToFind" == "-r" ]] +then + echo "Not enough parameters" +else + + files=$(find $dirPath -maxdepth 1) + + for file in $files + do + if [[ -d $file ]] && [ "$isRecursive" = true ] && [ $file != $dirPath ] + then + $($0 $file $wordToFind "-r") + else + if [[ $file == $COMPILED_EX ]] + then + rm $file + fi + fi + + done + + cd $dirPath + + for FILE in $(grep -liw "${wordToFind}" *.c ) + do + gcc -w -o ${FILE%.*}.out $FILE + done + +fi diff --git a/hw1/myshell.c b/hw1/myshell.c new file mode 100644 index 0000000..710ed2b --- /dev/null +++ b/hw1/myshell.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PROMPT "💲 " +#define TERMINATE_STR '\0' +#define EXIT "exit" +#define HISTORY "history" +#define CD "cd" + +typedef enum { false, true } bool; +char* logCmd[100]; +int excRun = 0; + +char** splitStringToArray(char* str) { + char** res = NULL; + char* p = strtok(str, " "); + int n_spaces = 0; + + /* split string and append tokens to 'res' */ + + while (p) { + res = realloc(res, sizeof(char*) * ++n_spaces); + + if (res == NULL) exit(-1); /* memory allocation failed */ + + res[n_spaces - 1] = p; + + p = strtok(NULL, " "); + } + + /* realloc one extra element for the last NULL */ + + res = realloc(res, sizeof(char*) * (n_spaces + 1)); + res[n_spaces] = 0; + return res; +} + +/** + * Remove trailing white space characters from string + */ +void trimTrailing(char* str) { + int index, i; + + /* Set default index */ + index = -1; + + /* Find last index of non-white space character */ + i = 0; + while (str[i] != '\0') { + if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') { + index = i; + } + + i++; + } + + /* Mark next character to last non-white space character as NULL */ + str[index + 1] = '\0'; +} + +void printHIstory() { + int i; + for (i = 0; i <= excRun; ++i) { + printf(" %s\n", logCmd[i]); + } +} + +void logHistory(int pid, char* a) { + char entry[100] = ""; + sprintf(entry, "%d ", pid); + strcat(entry, a); + logCmd[excRun] = malloc(100); + strcpy(logCmd[excRun], entry); +} + +int main(int argc, char const* argv[]) { + pid_t pid = getpid(); + char envs[100] = ""; + int i; + for (i = 1; i < argc; ++i) { + strcat(strcat(envs, ":"), argv[i]); + } + char* allenv = getenv("PATH"); + strcat(allenv, envs); + setenv("PATH", allenv, 0); + char a[100]; + char* token; + + while (1) { + char* str = malloc(100); + printf(PROMPT); + fflush(stdout); + fgets(a, sizeof(a), stdin); + trimTrailing(a); + strcpy(str, a); + + if (!strcmp(a, EXIT)) { + int i; + for (i = 0; i < excRun; i++) { + char* currentPtr = logCmd[i]; + free(currentPtr); + } + exit(1); + } + + token = strtok(a, " "); + if (token == NULL) { + logHistory(pid, a); + } else if (!strcmp(token, HISTORY)) { + logHistory(pid, a); + printHIstory(); + } else if (!strcmp(token, CD)) { + logHistory(pid, str); + + token = a + strlen(token) + 1; + int res = chdir(token); + if (res != 0) { + perror(strcat(token, " failed")); + } + + } else { + pid_t child = fork(); + int stat; + logHistory(child, str); + if (child == 0) { + // split params + char** argv = splitStringToArray(str); + int res = execvp(token, argv); + if (res != 0) { + perror(strcat(token, " failed")); + } + break; + } else { + // wait for child to finish execute + wait(&stat); + } + } + if (str != NULL) { + free(str); + } + + excRun++; + } + return 0; +} diff --git a/hw1/tennis.sh b/hw1/tennis.sh new file mode 100755 index 0000000..0ace990 --- /dev/null +++ b/hw1/tennis.sh @@ -0,0 +1,177 @@ +#!/bin/bash + +winner=0 +players=( 50 50) +guesses=( 0 0 ) + +ballState=0 +ballField=0 +turnState=1 +isGameOn=true + +isInPlace=false + +for arg in "$@" +do + case $arg in + --in-place|-p) + isInPlace=true + shift + ;; + -l|--log|--print-all) + isInPlace=false + shift + ;; + esac +done + + +printBoard () { + if [[ $isInPlace == true ]]; then clear; fi + echo " Player 1: ${players[0]} 🎾 Player 2: ${players[1]}" + echo " --------------------------------- " + echo " | | # | | " + echo " | | # | | " + case $ballState in + -3) + echo "O| | # | | " + ;; + -2) + echo " | O | # | | " + ;; + -1) + echo " | | O # | | " + ;; + 0) + echo " | | O | | " + ;; + 1) + echo " | | # O | | " + ;; + 2) + echo " | | # | O | " + ;; + 3) + echo " | | # | |O" + ;; + *) + echo " | | # | | " + ;; + esac + echo " | | # | | " + echo " | | # | | " + echo " --------------------------------- " + +} + +setTurn () { + if [[ $turnState == 1 ]] + then + turnState=2 + else + turnState=1 + fi +} + +printState () { + echo -e " Player 1 played: ${guesses[0]}\n Player 2 played: ${guesses[1]}\n\n" +} + +pickANumber () { + player=$turnState-1; + echo "PLAYER $turnState PICK A NUMBER: " + read -s guess + + # validate pick + if [[ ! $guess =~ ^-?[0-9]+$ ]] || (( $guess > ${players[($player)]} )) + then + echo "NOT A VALID MOVE !" + pickANumber + else # set guess and update score + guesses[($player)]=$guess + if (( $turnState == 2 )) + then + calculateState + fi + players[($player)]=$((${players[($player)]}-$guess)) + setTurn + fi +} + +calculateState () { + handLoser=0 + # if palyer 2 guessed smaller hand + if (( ${guesses[1]} < ${guesses[0]} )) + then + handLoser=2 + else if (( ${guesses[1]} > ${guesses[0]} )) + then + handLoser=1 + fi + fi + # checkWinner + if (( $handLoser == 0 )); then return; fi + + if (( $handLoser == $ballField )) + then + ballState=$(( $ballState < 0 ? $ballState-1 : $ballState+1 )) + else + ballField=$handLoser + ballState=$(( $handLoser == 1 ? -1 : 1 )) + fi +} + +checkWinner () { + if (( $ballState == 3 || $ballState == -3 )) + then + winner=$(( 3-$ballField )) + isGameOn=false + else + if (( ${players[0]} == 0 )) + then + isGameOn=false + if (( ${players[1]} > 0 )); then + winner=2 + else + winner=$(( $ballField == 0 ? 0 : 3-$ballField )) + fi + else + if (( ${players[1]} == 0 )) + then + winner=1 + isGameOn=false + fi + fi + fi +} + +printWinner () { +if [ $isGameOn == false ] + then + case $winner in + 0) + echo "IT'S A DRAW !" + ;; + 1) + echo "PLAYER 1 WINS !" + ;; + 2) + echo "PLAYER 2 WINS !" + ;; + *) + echo "$winner" + ;; + esac + fi +} + +printBoard +while $isGameOn +do + pickANumber + pickANumber + printBoard + printState + checkWinner +done +printWinner \ No newline at end of file diff --git a/hw1/tic-tac-toe.sh b/hw1/tic-tac-toe.sh new file mode 100755 index 0000000..d309daa --- /dev/null +++ b/hw1/tic-tac-toe.sh @@ -0,0 +1,102 @@ +# tic-tac-toe.sh + +#!/usr/bin/bash + +player_1="❌" +player_2="🟢" + +turn=1 +game_on=true + +moves=( 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ ) + +welcome_message() { + clear + echo "========================" + echo "=== LETS PLAY A GAME ===" + echo "========================" + sleep 3 +} +print_board () { + clear + echo " ${moves[0]} ❕ ${moves[1]} ❕ ${moves[2]} " + echo "➖➖➖➖➖➖" + echo " ${moves[3]} ❕ ${moves[4]} ❕ ${moves[5]} " + echo ➖➖➖➖➖➖ + echo " ${moves[6]} ❕ ${moves[7]} ❕ ${moves[8]} " +} + +player_pick(){ + if [[ $(($turn % 2)) == 0 ]] + then + play=$player_2 + echo -n "PLAYER 2 PICK A SQUARE: " + else + echo -n "PLAYER 1 PICK A SQUARE: " + play=$player_1 + fi + + read square + +# space=${moves[($square -1)]} + + if [[ ! $square =~ ^-?[0-9]+$ ]] + then + echo "Not a valid square." + player_pick + else + moves[($square -1)]=$play + ((turn=turn+1)) + fi + space=${moves[($square-1)]} +} + +check_match() { + if [[ ${moves[$1]} == ${moves[$2]} ]]&& \ + [[ ${moves[$2]} == ${moves[$3]} ]]; then + game_on=false + fi + if [ $game_on == false ]; then + if [ ${moves[$1]} == '❌' ];then + echo "Player one wins!" + return + else + echo "player two wins!" + return + fi + fi +} + +check_winner(){ + if [ $game_on == false ]; then return; fi + check_match 0 1 2 + if [ $game_on == false ]; then return; fi + check_match 3 4 5 + if [ $game_on == false ]; then return; fi + check_match 6 7 8 + if [ $game_on == false ]; then return; fi + check_match 0 4 8 + if [ $game_on == false ]; then return; fi + check_match 2 4 6 + if [ $game_on == false ]; then return; fi + check_match 0 3 6 + if [ $game_on == false ]; then return; fi + check_match 1 4 7 + if [ $game_on == false ]; then return; fi + check_match 2 5 8 + if [ $game_on == false ]; then return; fi + + if [ $turn -gt 9 ]; then + $game_on=false + echo "Its a draw!" + fi +} + +welcome_message +print_board +while $game_on +do + player_pick + print_board + check_winner +done \ No newline at end of file diff --git a/hw2/compare/ex21.c b/hw2/compare/ex21.c new file mode 100644 index 0000000..d04a61b --- /dev/null +++ b/hw2/compare/ex21.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum resemblanceStatus { + identical = 1, // identical files + different = 2, // different files + similar = 3, // similar files +}; + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead); + +// This function closes the file descriptor and set iteration to false +void handleExit(int fd1, int fd2, int* keepRead, int isErr) { + if (isErr) { + perror("Error occurred"); + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + *keepRead = 0; +} + +int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int isSpace, byteRes, res = 0; + if (isspace(chr1)) { + byteRes = read(fd1, &chr1, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + *keepRead = 0; + res = different; + } + isSpace = 1; + } + + if (isspace(chr2)) { + byteRes = read(fd2, &chr2, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + exit(1); + // *keepRead = 0; + // res = different; + } + isSpace = 1; + } + if (isSpace) { + if (chr1 != chr2) { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } else { + res = similar; + } + } + return res; // return resemblance status +} + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int res; + if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) { + handleExit(fd1, fd2, keepRead, 0); + res = different; + } else { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } + return res; +} + +int checkLeft(int left, char lastChr, int* keepRead) { + int byteRes, dirty = 0; + int res; + char chr; + while (keepRead) { + byteRes = read(left, &chr, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(left, -1, keepRead, 1); + *keepRead = 0; + return different; + } + + if (byteRes == 0) { + *keepRead = 0; + break; + } + if (!isspace(chr)) { + if (chr != lastChr || dirty) { + return different; + } else { + dirty = 1; + res = similar; + } + } + } + if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) || + (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) { + res = similar; + } else + res = different; + + return res; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} + +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + // printf("%s/%s\n", fullpath, path); + strcat(fullpath, path); + strcpy(fullpath, path); + } + } +} + +// compare two files and return resemblance status +// if the files content is exactly the same, return identical (1) +// else, if the files content is different in spaces, capitals, or line break, +// return similar (3) +// otherwise, return different (2) +int main(int argc, char* argv[]) { + if (argc < 3) { + printf("Error: not enough arguments\n"); + return 1; + } + // retrive file names + getFileName(argv[1]); + char* file1 = argv[1]; + if (file1 == NULL) return 1; + getFileName(argv[2]); + char* file2 = argv[2]; + if (file2 == NULL) return 1; + + int fd1, fd2; + fd1 = open(file1, O_RDONLY); + if (fd1 == -1) { + printf("Error opening file\n"); + return 1; + } + fd2 = open(file2, O_RDONLY); + if (fd2 == -1) { + printf("Error opening file\n"); + close(fd1); + return 1; + } + + enum resemblanceStatus res = 0; + char chr1, chr2; + int byteRes1, byteRes2; + int keepRead = 1; + + // reading the files char by char + while (keepRead) { + byteRes1 = read(fd1, &chr1, 1); + // if byteRes == -1 then error + if (byteRes1 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes1 == -1); + exit(1); + break; + } + byteRes2 = read(fd2, &chr2, 1); + // if byteRes == -1 then error + if (byteRes2 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes2 == -1); + exit(1); + break; + } + // if byteRes == 0 then end of file + if (byteRes1 == 0 && byteRes2 == 0) { + res = !res ? identical : res; + handleExit(fd1, fd2, &keepRead, 0); + + break; + } + if ((byteRes1 == 0 && isspace(chr2)) || + (byteRes2 == 0 && isspace(chr1))) { + res = different; + int left = byteRes1 == 0 ? fd2 : fd1; + char lastChr = byteRes1 == 0 ? chr2 : chr1; + res = checkLeft(left, lastChr, &keepRead); + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (byteRes1 == 0 || byteRes2 == 0) { + res = different; + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (chr1 != chr2) { + if (tolower(chr1) == tolower(chr2)) { + res = similar; + // break; + } else + res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead); + } + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + return res; +} diff --git a/hw2/ex2.docx b/hw2/ex2.docx new file mode 100644 index 0000000..4138451 Binary files /dev/null and b/hw2/ex2.docx differ diff --git a/hw2/ex2.pdf b/hw2/ex2.pdf new file mode 100644 index 0000000..232bd3e Binary files /dev/null and b/hw2/ex2.pdf differ diff --git a/hw2/ex21.c b/hw2/ex21.c new file mode 100644 index 0000000..d04a61b --- /dev/null +++ b/hw2/ex21.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum resemblanceStatus { + identical = 1, // identical files + different = 2, // different files + similar = 3, // similar files +}; + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead); + +// This function closes the file descriptor and set iteration to false +void handleExit(int fd1, int fd2, int* keepRead, int isErr) { + if (isErr) { + perror("Error occurred"); + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + *keepRead = 0; +} + +int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int isSpace, byteRes, res = 0; + if (isspace(chr1)) { + byteRes = read(fd1, &chr1, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + *keepRead = 0; + res = different; + } + isSpace = 1; + } + + if (isspace(chr2)) { + byteRes = read(fd2, &chr2, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + exit(1); + // *keepRead = 0; + // res = different; + } + isSpace = 1; + } + if (isSpace) { + if (chr1 != chr2) { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } else { + res = similar; + } + } + return res; // return resemblance status +} + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int res; + if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) { + handleExit(fd1, fd2, keepRead, 0); + res = different; + } else { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } + return res; +} + +int checkLeft(int left, char lastChr, int* keepRead) { + int byteRes, dirty = 0; + int res; + char chr; + while (keepRead) { + byteRes = read(left, &chr, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(left, -1, keepRead, 1); + *keepRead = 0; + return different; + } + + if (byteRes == 0) { + *keepRead = 0; + break; + } + if (!isspace(chr)) { + if (chr != lastChr || dirty) { + return different; + } else { + dirty = 1; + res = similar; + } + } + } + if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) || + (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) { + res = similar; + } else + res = different; + + return res; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} + +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + // printf("%s/%s\n", fullpath, path); + strcat(fullpath, path); + strcpy(fullpath, path); + } + } +} + +// compare two files and return resemblance status +// if the files content is exactly the same, return identical (1) +// else, if the files content is different in spaces, capitals, or line break, +// return similar (3) +// otherwise, return different (2) +int main(int argc, char* argv[]) { + if (argc < 3) { + printf("Error: not enough arguments\n"); + return 1; + } + // retrive file names + getFileName(argv[1]); + char* file1 = argv[1]; + if (file1 == NULL) return 1; + getFileName(argv[2]); + char* file2 = argv[2]; + if (file2 == NULL) return 1; + + int fd1, fd2; + fd1 = open(file1, O_RDONLY); + if (fd1 == -1) { + printf("Error opening file\n"); + return 1; + } + fd2 = open(file2, O_RDONLY); + if (fd2 == -1) { + printf("Error opening file\n"); + close(fd1); + return 1; + } + + enum resemblanceStatus res = 0; + char chr1, chr2; + int byteRes1, byteRes2; + int keepRead = 1; + + // reading the files char by char + while (keepRead) { + byteRes1 = read(fd1, &chr1, 1); + // if byteRes == -1 then error + if (byteRes1 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes1 == -1); + exit(1); + break; + } + byteRes2 = read(fd2, &chr2, 1); + // if byteRes == -1 then error + if (byteRes2 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes2 == -1); + exit(1); + break; + } + // if byteRes == 0 then end of file + if (byteRes1 == 0 && byteRes2 == 0) { + res = !res ? identical : res; + handleExit(fd1, fd2, &keepRead, 0); + + break; + } + if ((byteRes1 == 0 && isspace(chr2)) || + (byteRes2 == 0 && isspace(chr1))) { + res = different; + int left = byteRes1 == 0 ? fd2 : fd1; + char lastChr = byteRes1 == 0 ? chr2 : chr1; + res = checkLeft(left, lastChr, &keepRead); + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (byteRes1 == 0 || byteRes2 == 0) { + res = different; + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (chr1 != chr2) { + if (tolower(chr1) == tolower(chr2)) { + res = similar; + // break; + } else + res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead); + } + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + return res; +} diff --git a/hw2/ex22.c b/hw2/ex22.c new file mode 100644 index 0000000..6b0938e --- /dev/null +++ b/hw2/ex22.c @@ -0,0 +1,380 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_FILES_MISSING "file not exist" + +#define COMPILE_C "/usr/bin/gcc" +#define COMPILED_PNAME "output" +#define RUNNABLE "./output" +#define GCC_ERROR_FILE "gcc_errors.txt" +#define OUTPUT_FILE "user_output.txt" +#define TIMEOUT 5 +#define COMPARE "./comp.out" +#define LAST_RES "/usr/bin/echo" +#define ERRORS "errors.txt" +#define RES(CHR) "RES" CHR ".txt" + +char* getFullPath(char* path, char* fileName) { + char* fullPath = malloc(strlen(path) + strlen(fileName) + 2); + strcpy(fullPath, path); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + return fullPath; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + strcat(strcat(fullpath, "/"), path); + strcpy(path, fullpath); + } + } +} + +void trimTrailing(char* str) { + int index, i; + /* Set default index */ + index = -1; + + /* Find last index of non-white space character */ + i = 0; + while (str[i] != '\0') { + if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') { + index = i; + } + i++; + } + /* Mark next character to last non-white space character as NULL */ + str[index + 1] = '\0'; +} + +void freeConfigOnExit(char* config[3]) { + int i; + for (i = 0; i < 3; i++) { + if (config[i] != NULL) { + free(config[i]); + } + } +} + +void extractConfig(char* configFile, char* config[3]) { + // char* config[3] = {NULL, NULL, NULL}; + char* line_buf = NULL; + size_t line_buf_size = 0; + int line_count = 0; + ssize_t line_size; + FILE* fp = fopen(configFile, "r"); + if (!fp) { + perror("fopen"); + exit(EXIT_FAILURE); + } + + /* Get the first line of the file. */ + line_size = getline(&line_buf, &line_buf_size, fp); + while (line_size >= 0) { + /* Increment our line count */ + line_count++; + getFileName(line_buf); + + config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1)); + strcpy(config[line_count - 1], line_buf); + trimTrailing(config[line_count - 1]); + // VALIDATE PATH EXISTS + int fd = access(config[line_count - 1], F_OK); + if (fd == -1) { + if (line_count == 2) + printf("Input %s", CONFIG_FILES_MISSING); + else + printf("Output %s", CONFIG_FILES_MISSING); + exit(EXIT_FAILURE); + } + + /* Get the next line */ + line_size = getline(&line_buf, &line_buf_size, fp); + } + /* Free the allocated line buffer */ + free(line_buf); + line_buf = NULL; + + /* Close the file now that we are done with it */ + fclose(fp); + // return config; +} + +char* gradeMap(char* name, int gradeIndex) { + char* grade = NULL; + + switch (gradeIndex) { + case 1: + grade = ",0,NO_C_FILE\n"; + break; + case 2: + grade = ",10,COMPILATION_ERROR\n"; + break; + case 3: + grade = ",20,TIMEOUT\n"; + break; + case 4: + grade = ",50,WRONG\n"; + break; + case 5: + grade = ",75,SIMILAR\n"; + break; + case 6: + grade = ",100,EXCELLENT\n"; + break; + default: + grade = "?\n"; + } + char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2); + strcpy(record, name); + strcat(record, grade); + return record; +} + +int compileFile(char* fileName) { + // Compile the file + int isCompiled = 0; + pid_t pid; + int st; + if ((pid = fork()) < 0) + perror("fork"); + else { + if (pid == 0) { + // remove(COMPILED_PNAME); + // replace standard output with output file + int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY); + if (gccerr_fd > 0) { + dup2(gccerr_fd, 2); + close(gccerr_fd); + } + + char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL}; + int res = execvp(COMPILE_C, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + wait(&st); + // int gccerr_fd = access(COMPILED_PNAME, F_OK); + struct stat stat_p; + stat(GCC_ERROR_FILE, &stat_p); + + if (stat_p.st_size == 0) + isCompiled = 1; + else + isCompiled = 0; + remove(GCC_ERROR_FILE); + // remove(COMPILED_PNAME); + return isCompiled; + } + return -1; +} + +int runCompiledProgWithFile(char* inputFile) { + pid_t pid = fork(); + time_t start = time(NULL); + int runTime; + int st; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + // replace standard input with input file + int in_fd = open(inputFile, O_RDONLY); + dup2(in_fd, 0); + // replace standard output with output file + int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR); + dup2(out_fd, 1); + close(in_fd); + close(out_fd); + char* args[] = {RUNNABLE, NULL}; + int res = execvp(RUNNABLE, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + waitpid(pid, &st, 0); + runTime = time(NULL) - start; + + if (runTime >= TIMEOUT) + st = 3; + else + st = 4; + } + + return st; +} + +int comare(char* outputFile) { + pid_t pid = fork(); + int st, res; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL}; + execvp(COMPARE, args); + exit(0); + + } else { + wait(&st); + if (WIFEXITED(st)) { + // printf("Child's exit code %d\n", WEXITSTATUS(st)); + st = WEXITSTATUS(st); + } + if (st == 1) + res = 6; + else if (st == 2) + res = 4; + else if (st == 3) + res = 5; + } + + // if output file exists remove it + int fd = access(OUTPUT_FILE, F_OK); + // if (fd != -1) remove(OUTPUT_FILE); //TODO: REMOVE OUTPUT FILE + } + + return res; +} + +int calcUserGrade(char* userDir, char* inputFile, char* outputFile) { + DIR* dip; + struct dirent* entry; + + // open users directory + dip = opendir(userDir); + if (dip == NULL) { + perror("opendir"); + exit(EXIT_FAILURE); + } + int grade = 0; + int fileToCompile = 0; + while ((entry = readdir(dip)) != NULL && !fileToCompile) { + const char* dot = strrchr(entry->d_name, '.'); + if (dot && !strcmp(dot + 1, "c")) { + // ⚒️ build the c program inside the directory + fileToCompile = 1; + + char* filePath = getFullPath(userDir, entry->d_name); + + int isCompiled = compileFile(filePath); + if (isCompiled) { + // ⚒️ run the c program with the input file + grade = runCompiledProgWithFile(inputFile); + if (grade != 3) { + // ⚒️ compare the output file with the output file + // in the directory + grade = comare(outputFile); + } + + } else + grade = 2; + + if (filePath != NULL) free(filePath); + } + } + + if (!fileToCompile) grade = 1; + + closedir(dip); + + // ⚒️ calculate the grade: 1-6 + // ⚒️ clear exe & output files + // ⚒️ return the grade + return grade; +} + +void logGrade(int fd, char* record) { + int res = write(fd, record, strlen(record)); + if (res < 0) { + perror("write"); + close(fd); + exit(EXIT_FAILURE); + } +} + +void handleError(char* config[3], int resFd) { + freeConfigOnExit(config); + close(resFd); + exit(EXIT_FAILURE); +} + +void grade(char* config[3], int resFd) { + DIR* dip; + struct dirent* dit; + // open users directory + dip = opendir(config[0]); + if (dip == NULL) { + perror("opendir"); + handleError(config, resFd); + } + // int pathlen = strlen(config[0]); + // loop through users directory + while ((dit = readdir(dip)) != NULL) { + struct stat stat_p; + char* userFolder = getFullPath(config[0], dit->d_name); + stat(userFolder, &stat_p); + if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 && + strcmp(dit->d_name, "..") != 0) { + int grade = calcUserGrade(userFolder, config[1], config[2]); + + char* record = gradeMap(dit->d_name, grade); + logGrade(resFd, record); + + free(record); + free(userFolder); + } + } + // close users directory + if (closedir(dip) == -1) { + perror("closedir"); + handleError(config, resFd); + } +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Error: not enough arguments\n"); + return 1; + } + char* configFile = argv[1]; + char* config[3] = {NULL, NULL, NULL}; + extractConfig(configFile, config); + int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (newFd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + // open user folder (config[0]) + // for each subfolder: fork and compile the only c file in there + // if compilation is successful, run the executable on child process with + // the input file (config[1]) and compare the output with the expected + // output (config[2]) on another fork + grade(config, newFd); + + close(newFd); + freeConfigOnExit(config); + exit(EXIT_SUCCESS); +} diff --git a/hw2/files/student/Similar_output_gets_75/Example.c b/hw2/files/student/Similar_output_gets_75/Example.c new file mode 100644 index 0000000..382b903 --- /dev/null +++ b/hw2/files/student/Similar_output_gets_75/Example.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int n1, n2; + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d\n", n1+n2); +} diff --git a/hw2/files/students/Compilation_Error_gets_10/error1.c b/hw2/files/students/Compilation_Error_gets_10/error1.c new file mode 100644 index 0000000..ede91b1 --- /dev/null +++ b/hw2/files/students/Compilation_Error_gets_10/error1.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("dfg"); + diff --git a/hw2/files/students/Similar_output_gets_75/Example.c b/hw2/files/students/Similar_output_gets_75/Example.c new file mode 100644 index 0000000..382b903 --- /dev/null +++ b/hw2/files/students/Similar_output_gets_75/Example.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int n1, n2; + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d\n", n1+n2); +} diff --git a/hw2/files/students/TIMEOUT_gets_20/Example.c b/hw2/files/students/TIMEOUT_gets_20/Example.c new file mode 100644 index 0000000..759ae94 --- /dev/null +++ b/hw2/files/students/TIMEOUT_gets_20/Example.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + sleep(8); +} diff --git a/hw2/files/students/Wrong_output_gets_50/Example.c b/hw2/files/students/Wrong_output_gets_50/Example.c new file mode 100644 index 0000000..660c4bd --- /dev/null +++ b/hw2/files/students/Wrong_output_gets_50/Example.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("This is not the correct output!\n"); + return 0; +} diff --git a/hw2/files/students/test.md b/hw2/files/students/test.md new file mode 100644 index 0000000..e69de29 diff --git a/hw2/grade/ex22.c b/hw2/grade/ex22.c new file mode 100644 index 0000000..0e262c2 --- /dev/null +++ b/hw2/grade/ex22.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_FILES_MISSING "file not exist" + +#define COMPILE_C "/usr/bin/gcc" +#define COMPILED_PNAME "output" +#define RUNNABLE "./output" +#define GCC_ERROR_FILE "errors.txt" +#define OUTPUT_FILE "user_output.txt" +#define TIMEOUT 5 +#define COMPARE "./comp.out" +#define LAST_RES "/usr/bin/echo" +// #define ERRORS "errors.txt" +#define RES(CHR) "RES" CHR ".txt" + +char* getFullPath(char* path, char* fileName) { + char* fullPath = malloc(strlen(path) + strlen(fileName) + 2); + strcpy(fullPath, path); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + return fullPath; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + strcat(strcat(fullpath, "/"), path); + strcpy(path, fullpath); + } + } +} + +void trimTrailing(char* str) { + int index, i; + /* Set default index */ + index = -1; + + /* Find last index of non-white space character */ + i = 0; + while (str[i] != '\0') { + if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') { + index = i; + } + i++; + } + /* Mark next character to last non-white space character as NULL */ + str[index + 1] = '\0'; +} + +void freeConfigOnExit(char* config[3]) { + int i; + for (i = 0; i < 3; i++) { + if (config[i] != NULL) { + free(config[i]); + } + } +} + +void extractConfig(char* configFile, char* config[3]) { + // char* config[3] = {NULL, NULL, NULL}; + char* line_buf = NULL; + size_t line_buf_size = 0; + int line_count = 0; + size_t line_size; + FILE* fp = fopen(configFile, "r"); + if (!fp) { + perror("fopen"); + exit(EXIT_FAILURE); + } + + /* Get the first line of the file. */ + line_size = getline(&line_buf, &line_buf_size, fp); + + while (line_size > 0 && line_count < 3) { + /* Increment our line count */ + line_count++; + if (line_buf != NULL) getFileName(line_buf); + + config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1)); + strcpy(config[line_count - 1], line_buf); + trimTrailing(config[line_count - 1]); + // VALIDATE PATH EXISTS + int fd = access(config[line_count - 1], F_OK); + if (fd == -1) { + if (line_count == 2) + printf("Input %s", CONFIG_FILES_MISSING); + else + printf("Output %s", CONFIG_FILES_MISSING); + + exit(EXIT_FAILURE); + } + /* Get the next line */ + line_size = getline(&line_buf, &line_buf_size, fp); + } + /* Free the allocated line buffer */ + if (line_buf != NULL) free(line_buf); + line_buf = NULL; + + /* Close the file now that we are done with it */ + fclose(fp); + // return config; +} + +char* gradeMap(char* name, int gradeIndex) { + char* grade = NULL; + + switch (gradeIndex) { + case 1: + grade = ",0,NO_C_FILE\n"; + break; + case 2: + grade = ",10,COMPILATION_ERROR\n"; + break; + case 3: + grade = ",20,TIMEOUT\n"; + break; + case 4: + grade = ",50,WRONG\n"; + break; + case 5: + grade = ",75,SIMILAR\n"; + break; + case 6: + grade = ",100,EXCELLENT\n"; + break; + default: + grade = "?\n"; + } + char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2); + strcpy(record, name); + strcat(record, grade); + return record; +} + +int compileFile(char* fileName) { + // Compile the file + int isCompiled = 0; + pid_t pid; + int st; + if ((pid = fork()) < 0) + perror("fork"); + else { + if (pid == 0) { + char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL}; + int res = execvp(COMPILE_C, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + wait(&st); + if (WIFEXITED(st)) { + st = WEXITSTATUS(st); + } + + if (st == 0) + isCompiled = 1; + else + isCompiled = 0; + + return isCompiled; + } + return -1; +} + +int runCompiledProgWithFile(char* inputFile) { + pid_t pid = fork(); + time_t start = time(NULL); + int runTime; + int st; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + // replace standard input with input file + int in_fd = open(inputFile, O_RDONLY); + dup2(in_fd, 0); + // replace standard output with output file + int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR); + dup2(out_fd, 1); + close(in_fd); + close(out_fd); + char* args[] = {RUNNABLE, NULL}; + int res = execvp(RUNNABLE, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + waitpid(pid, &st, 0); + runTime = time(NULL) - start; + + if (runTime >= TIMEOUT) + st = 3; + else + st = 4; + } + + return st; +} + +int comare(char* outputFile) { + pid_t pid = fork(); + int st, res; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL}; + execvp(COMPARE, args); + exit(0); + + } else { + wait(&st); + if (WIFEXITED(st)) { + st = WEXITSTATUS(st); + } + if (st == 1) + res = 6; + else if (st == 2) + res = 4; + else if (st == 3) + res = 5; + } + + // if output file exists remove it + int fd = access(OUTPUT_FILE, F_OK); + if (fd != -1) remove(OUTPUT_FILE); + } + + return res; +} + +int calcUserGrade(char* userDir, char* inputFile, char* outputFile) { + DIR* dip; + struct dirent* entry; + + // open users directory + dip = opendir(userDir); + if (dip == NULL) { + perror("opendir"); + exit(EXIT_FAILURE); + } + int grade = 0; + int fileToCompile = 0; + while ((entry = readdir(dip)) != NULL && !fileToCompile) { + const char* dot = strrchr(entry->d_name, '.'); + if (dot && !strcmp(dot + 1, "c")) { + // ⚒️ build the c program inside the directory + fileToCompile = 1; + + char* filePath = getFullPath(userDir, entry->d_name); + + int isCompiled = compileFile(filePath); + if (isCompiled) { + // ⚒️ run the c program with the input file + grade = runCompiledProgWithFile(inputFile); + if (grade != 3) { + // ⚒️ compare the output file with the output file + // in the directory + grade = comare(outputFile); + } + + } else + grade = 2; + + if (filePath != NULL) free(filePath); + } + } + + if (!fileToCompile) grade = 1; + + closedir(dip); + remove(COMPILED_PNAME); + // a function to delete the output file + + // ⚒️ calculate the grade: 1-6 + // ⚒️ clear exe & output files + // ⚒️ return the grade + return grade; +} + +void logGrade(int fd, char* record) { + int res = write(fd, record, strlen(record)); + if (res < 0) { + perror("write"); + close(fd); + exit(EXIT_FAILURE); + } +} + +void handleError(char* config[3], int resFd) { + freeConfigOnExit(config); + close(resFd); + exit(EXIT_FAILURE); +} + +void grade(char* config[3], int resFd) { + DIR* dip; + struct dirent* dit; + // open users directory + dip = opendir(config[0]); + if (dip == NULL) { + perror("opendir"); + handleError(config, resFd); + } + + // int pathlen = strlen(config[0]); + // loop through users directory + while ((dit = readdir(dip)) != NULL) { + struct stat stat_p; + char* userFolder = getFullPath(config[0], dit->d_name); + stat(userFolder, &stat_p); + if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 && + strcmp(dit->d_name, "..") != 0) { + int grade = calcUserGrade(userFolder, config[1], config[2]); + + char* record = gradeMap(dit->d_name, grade); + logGrade(resFd, record); + + free(record); + free(userFolder); + } + } + // close users directory + if (closedir(dip) == -1) { + perror("closedir"); + handleError(config, resFd); + } +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Error: not enough arguments\n"); + return 1; + } + char* configFile = argv[1]; + char* config[3] = {NULL, NULL, NULL}; + + extractConfig(configFile, config); + + int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (newFd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + // open user folder (config[0]) + // for each subfolder: fork and compile the only c file in there + // if compilation is successful, run the executable on child process with + // the input file (config[1]) and compare the output with the expected + // output (config[2]) on another fork + int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644); + + dup2(gccerr_fd, 2); + close(gccerr_fd); + + grade(config, newFd); + + close(newFd); + freeConfigOnExit(config); + exit(EXIT_SUCCESS); +} diff --git a/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c b/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c new file mode 100644 index 0000000..ede91b1 --- /dev/null +++ b/hw2/grade/messing/up/students/Compilation_Error_gets_10/error1.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("dfg"); + diff --git a/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c b/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c new file mode 100644 index 0000000..ede91b1 --- /dev/null +++ b/hw2/grade/moodle/students/Compilation_Error_gets_10/error1.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("dfg"); + diff --git a/hw2/grade/moodle/students/Similar_output_gets_75/Example.c b/hw2/grade/moodle/students/Similar_output_gets_75/Example.c new file mode 100644 index 0000000..382b903 --- /dev/null +++ b/hw2/grade/moodle/students/Similar_output_gets_75/Example.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int n1, n2; + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d\n", n1+n2); +} diff --git a/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c b/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c new file mode 100644 index 0000000..660c4bd --- /dev/null +++ b/hw2/grade/moodle/students/Wrong_output_gets_50/Example.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("This is not the correct output!\n"); + return 0; +} diff --git a/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c b/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c new file mode 100644 index 0000000..3f96c1b --- /dev/null +++ b/hw2/grade/students/biu_student_different/you_hate_recursion_i_love_it.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I love recursion. Can you guess what my algorithm is?\n"); + printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c b/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c new file mode 100644 index 0000000..d90cdd8 --- /dev/null +++ b/hw2/grade/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + You shouldn't compile me!!!! +} \ No newline at end of file diff --git a/hw2/grade/students/biu_student_great/zzz_im_tired.c b/hw2/grade/students/biu_student_great/zzz_im_tired.c new file mode 100644 index 0000000..a3c79f4 --- /dev/null +++ b/hw2/grade/students/biu_student_great/zzz_im_tired.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/grade/students/biu_student_insensitive/close_but_no.c b/hw2/grade/students/biu_student_insensitive/close_but_no.c new file mode 100644 index 0000000..195b160 --- /dev/null +++ b/hw2/grade/students/biu_student_insensitive/close_but_no.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c b/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c new file mode 100644 index 0000000..a3c79f4 --- /dev/null +++ b/hw2/grade/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/grade/students/biu_student_terrible/cccgcc.c b/hw2/grade/students/biu_student_terrible/cccgcc.c new file mode 100644 index 0000000..381cb20 --- /dev/null +++ b/hw2/grade/students/biu_student_terrible/cccgcc.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("I'm a terrible student. See? I don't know basic syntax..."); +}} \ No newline at end of file diff --git a/hw2/to-prod/ex21.c b/hw2/to-prod/ex21.c new file mode 100644 index 0000000..844a77a --- /dev/null +++ b/hw2/to-prod/ex21.c @@ -0,0 +1,218 @@ +// 315394874 Bareket Damari + +#include +#include +#include +#include +#include +#include +#include +#include + +enum resemblanceStatus { + identical = 1, // identical files + different = 2, // different files + similar = 3, // similar files +}; + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead); + +// This function closes the file descriptor and set iteration to false +void handleExit(int fd1, int fd2, int* keepRead, int isErr) { + if (isErr) { + perror("Error occurred"); + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + *keepRead = 0; +} + +int handleSpaces(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int isSpace, byteRes, res = 0; + if (isspace(chr1)) { + byteRes = read(fd1, &chr1, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + *keepRead = 0; + res = different; + } + isSpace = 1; + } + + if (isspace(chr2)) { + byteRes = read(fd2, &chr2, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(fd1, fd2, keepRead, 1); + exit(1); + // *keepRead = 0; + // res = different; + } + isSpace = 1; + } + if (isSpace) { + if (chr1 != chr2) { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } else { + res = similar; + } + } + return res; // return resemblance status +} + +int checkSimilarity(int fd1, int fd2, char chr1, char chr2, int* keepRead) { + int res; + if (tolower(chr1) != tolower(chr2) && !isspace(chr1) && !isspace(chr2)) { + handleExit(fd1, fd2, keepRead, 0); + res = different; + } else { + res = handleSpaces(fd1, fd2, chr1, chr2, keepRead); + } + return res; +} + +int checkLeft(int left, char lastChr, int* keepRead) { + int byteRes, dirty = 0; + int res; + char chr; + while (keepRead) { + byteRes = read(left, &chr, 1); + if (byteRes == -1) { + // close files and exit with error + handleExit(left, -1, keepRead, 1); + *keepRead = 0; + return different; + } + + if (byteRes == 0) { + *keepRead = 0; + break; + } + if (!isspace(chr)) { + if (chr != lastChr || dirty) { + return different; + } else { + dirty = 1; + res = similar; + } + } + } + if ((!isspace(chr) && tolower(lastChr) == tolower(chr)) || + (isspace(chr) && isspace(lastChr)) || (isspace(lastChr) && !dirty)) { + res = similar; + } else + res = different; + + return res; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} + +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + // printf("%s/%s\n", fullpath, path); + strcat(fullpath, path); + strcpy(fullpath, path); + } + } +} + +// compare two files and return resemblance status +// if the files content is exactly the same, return identical (1) +// else, if the files content is different in spaces, capitals, or line break, +// return similar (3) +// otherwise, return different (2) +int main(int argc, char* argv[]) { + if (argc < 3) { + printf("Error: not enough arguments\n"); + return 1; + } + // retrive file names + getFileName(argv[1]); + char* file1 = argv[1]; + if (file1 == NULL) return 1; + getFileName(argv[2]); + char* file2 = argv[2]; + if (file2 == NULL) return 1; + + int fd1, fd2; + fd1 = open(file1, O_RDONLY); + if (fd1 == -1) { + printf("Error opening file\n"); + return 1; + } + fd2 = open(file2, O_RDONLY); + if (fd2 == -1) { + printf("Error opening file\n"); + close(fd1); + return 1; + } + + enum resemblanceStatus res = 0; + char chr1, chr2; + int byteRes1, byteRes2; + int keepRead = 1; + + // reading the files char by char + while (keepRead) { + byteRes1 = read(fd1, &chr1, 1); + // if byteRes == -1 then error + if (byteRes1 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes1 == -1); + exit(1); + break; + } + byteRes2 = read(fd2, &chr2, 1); + // if byteRes == -1 then error + if (byteRes2 == -1) { + handleExit(fd1, fd2, &keepRead, byteRes2 == -1); + exit(1); + break; + } + // if byteRes == 0 then end of file + if (byteRes1 == 0 && byteRes2 == 0) { + res = !res ? identical : res; + handleExit(fd1, fd2, &keepRead, 0); + + break; + } + if ((byteRes1 == 0 && isspace(chr2)) || + (byteRes2 == 0 && isspace(chr1))) { + res = different; + int left = byteRes1 == 0 ? fd2 : fd1; + char lastChr = byteRes1 == 0 ? chr2 : chr1; + res = checkLeft(left, lastChr, &keepRead); + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (byteRes1 == 0 || byteRes2 == 0) { + res = different; + handleExit(fd1, fd2, &keepRead, 0); + break; + } + if (chr1 != chr2) { + if (tolower(chr1) == tolower(chr2)) { + res = similar; + // break; + } else + res = checkSimilarity(fd1, fd2, chr1, chr2, &keepRead); + } + } + if (fd1 != -1) { + close(fd1); + } + if (fd2 != -1) { + close(fd2); + } + return res; +} diff --git a/hw2/to-prod/ex22.c b/hw2/to-prod/ex22.c new file mode 100644 index 0000000..4668c62 --- /dev/null +++ b/hw2/to-prod/ex22.c @@ -0,0 +1,382 @@ +// 315394874 Bareket Damari +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONFIG_FILES_MISSING "file not exist" + +#define COMPILE_C "/usr/bin/gcc" +#define COMPILED_PNAME "output" +#define RUNNABLE "./output" +#define GCC_ERROR_FILE "errors.txt" +#define OUTPUT_FILE "user_output.txt" +#define TIMEOUT 5 +#define COMPARE "./comp.out" +#define LAST_RES "/usr/bin/echo" +// #define ERRORS "errors.txt" +#define RES(CHR) "RES" CHR ".txt" + +char* getFullPath(char* path, char* fileName) { + char* fullPath = malloc(strlen(path) + strlen(fileName) + 2); + strcpy(fullPath, path); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + return fullPath; +} + +int startsWith(const char* a, const char* b) { + if (strncmp(a, b, strlen(b)) == 0) return 1; + return 0; +} +void getFileName(char* path) { + if (!startsWith(path, "/")) { + char fullpath[1024] = ""; + if (getcwd(fullpath, sizeof(fullpath)) != NULL) { + strcat(strcat(fullpath, "/"), path); + strcpy(path, fullpath); + } + } +} + +void trimTrailing(char* str) { + int index, i; + /* Set default index */ + index = -1; + + /* Find last index of non-white space character */ + i = 0; + while (str[i] != '\0') { + if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n') { + index = i; + } + i++; + } + /* Mark next character to last non-white space character as NULL */ + str[index + 1] = '\0'; +} + +void freeConfigOnExit(char* config[3]) { + int i; + for (i = 0; i < 3; i++) { + if (config[i] != NULL) { + free(config[i]); + } + } +} + +void extractConfig(char* configFile, char* config[3]) { + // char* config[3] = {NULL, NULL, NULL}; + char* line_buf = NULL; + size_t line_buf_size = 0; + int line_count = 0; + size_t line_size; + FILE* fp = fopen(configFile, "r"); + if (!fp) { + perror("fopen"); + exit(EXIT_FAILURE); + } + + /* Get the first line of the file. */ + line_size = getline(&line_buf, &line_buf_size, fp); + + while (line_size > 0 && line_count < 3) { + /* Increment our line count */ + line_count++; + if (line_buf != NULL) getFileName(line_buf); + + config[line_count - 1] = malloc(sizeof(char) * (strlen(line_buf) + 1)); + strcpy(config[line_count - 1], line_buf); + trimTrailing(config[line_count - 1]); + // VALIDATE PATH EXISTS + int fd = access(config[line_count - 1], F_OK); + if (fd == -1) { + if (line_count == 2) + printf("Input %s", CONFIG_FILES_MISSING); + else + printf("Output %s", CONFIG_FILES_MISSING); + + exit(EXIT_FAILURE); + } + /* Get the next line */ + line_size = getline(&line_buf, &line_buf_size, fp); + } + /* Free the allocated line buffer */ + if (line_buf != NULL) free(line_buf); + line_buf = NULL; + + /* Close the file now that we are done with it */ + fclose(fp); + // return config; +} + +char* gradeMap(char* name, int gradeIndex) { + char* grade = NULL; + + switch (gradeIndex) { + case 1: + grade = ",0,NO_C_FILE\n"; + break; + case 2: + grade = ",10,COMPILATION_ERROR\n"; + break; + case 3: + grade = ",20,TIMEOUT\n"; + break; + case 4: + grade = ",50,WRONG\n"; + break; + case 5: + grade = ",75,SIMILAR\n"; + break; + case 6: + grade = ",100,EXCELLENT\n"; + break; + default: + grade = "?\n"; + } + char* record = malloc(sizeof(char) * strlen(name) + strlen(grade) + 2); + strcpy(record, name); + strcat(record, grade); + return record; +} + +int compileFile(char* fileName) { + // Compile the file + int isCompiled = 0; + pid_t pid; + int st; + if ((pid = fork()) < 0) + perror("fork"); + else { + if (pid == 0) { + char* args[] = {COMPILE_C, "-o", COMPILED_PNAME, fileName, NULL}; + int res = execvp(COMPILE_C, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + wait(&st); + if (WIFEXITED(st)) { + st = WEXITSTATUS(st); + } + + if (st == 0) + isCompiled = 1; + else + isCompiled = 0; + + return isCompiled; + } + return -1; +} + +int runCompiledProgWithFile(char* inputFile) { + pid_t pid = fork(); + time_t start = time(NULL); + int runTime; + int st; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + // replace standard input with input file + int in_fd = open(inputFile, O_RDONLY); + dup2(in_fd, 0); + // replace standard output with output file + int out_fd = open(OUTPUT_FILE, O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR); + dup2(out_fd, 1); + close(in_fd); + close(out_fd); + char* args[] = {RUNNABLE, NULL}; + int res = execvp(RUNNABLE, args); + if (res != 0) { + perror("execvp"); + } + exit(0); + } + waitpid(pid, &st, 0); + runTime = time(NULL) - start; + + if (runTime >= TIMEOUT) + st = 3; + else + st = 4; + } + + return st; +} + +int comare(char* outputFile) { + pid_t pid = fork(); + int st, res; + if (pid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } else { + if (pid == 0) { + char* args[] = {COMPARE, outputFile, OUTPUT_FILE, NULL}; + execvp(COMPARE, args); + exit(0); + + } else { + wait(&st); + if (WIFEXITED(st)) { + st = WEXITSTATUS(st); + } + if (st == 1) + res = 6; + else if (st == 2) + res = 4; + else if (st == 3) + res = 5; + } + + // if output file exists remove it + int fd = access(OUTPUT_FILE, F_OK); + if (fd != -1) remove(OUTPUT_FILE); + } + + return res; +} + +int calcUserGrade(char* userDir, char* inputFile, char* outputFile) { + DIR* dip; + struct dirent* entry; + + // open users directory + dip = opendir(userDir); + if (dip == NULL) { + perror("opendir"); + exit(EXIT_FAILURE); + } + int grade = 0; + int fileToCompile = 0; + while ((entry = readdir(dip)) != NULL && !fileToCompile) { + const char* dot = strrchr(entry->d_name, '.'); + if (dot && !strcmp(dot + 1, "c")) { + // ⚒️ build the c program inside the directory + fileToCompile = 1; + + char* filePath = getFullPath(userDir, entry->d_name); + + int isCompiled = compileFile(filePath); + if (isCompiled) { + // ⚒️ run the c program with the input file + grade = runCompiledProgWithFile(inputFile); + if (grade != 3) { + // ⚒️ compare the output file with the output file + // in the directory + grade = comare(outputFile); + } + + } else + grade = 2; + + if (filePath != NULL) free(filePath); + } + } + + if (!fileToCompile) grade = 1; + + closedir(dip); + remove(COMPILED_PNAME); + // a function to delete the output file + + // ⚒️ calculate the grade: 1-6 + // ⚒️ clear exe & output files + // ⚒️ return the grade + return grade; +} + +void logGrade(int fd, char* record) { + int res = write(fd, record, strlen(record)); + if (res < 0) { + perror("write"); + close(fd); + exit(EXIT_FAILURE); + } +} + +void handleError(char* config[3], int resFd) { + freeConfigOnExit(config); + close(resFd); + exit(EXIT_FAILURE); +} + +void grade(char* config[3], int resFd) { + DIR* dip; + struct dirent* dit; + // open users directory + dip = opendir(config[0]); + if (dip == NULL) { + perror("opendir"); + handleError(config, resFd); + } + + // int pathlen = strlen(config[0]); + // loop through users directory + while ((dit = readdir(dip)) != NULL) { + struct stat stat_p; + char* userFolder = getFullPath(config[0], dit->d_name); + stat(userFolder, &stat_p); + if (S_ISDIR(stat_p.st_mode) && strcmp(dit->d_name, ".") != 0 && + strcmp(dit->d_name, "..") != 0) { + int grade = calcUserGrade(userFolder, config[1], config[2]); + + char* record = gradeMap(dit->d_name, grade); + logGrade(resFd, record); + + free(record); + free(userFolder); + } + } + // close users directory + if (closedir(dip) == -1) { + perror("closedir"); + handleError(config, resFd); + } +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + printf("Error: not enough arguments\n"); + return 1; + } + int gccerr_fd = open(GCC_ERROR_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644); + dup2(gccerr_fd, 2); + close(gccerr_fd); + + char* configFile = argv[1]; + char* config[3] = {NULL, NULL, NULL}; + + extractConfig(configFile, config); + + int newFd = open("results.csv", O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (newFd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + // open user folder (config[0]) + // for each subfolder: fork and compile the only c file in there + // if compilation is successful, run the executable on child process with + // the input file (config[1]) and compare the output with the expected + // output (config[2]) on another fork + + grade(config, newFd); + + close(newFd); + freeConfigOnExit(config); + exit(EXIT_SUCCESS); +} diff --git a/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c b/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c new file mode 100644 index 0000000..ede91b1 --- /dev/null +++ b/hw2/to-prod/mess/messing/up/students/Compilation_Error_gets_10/error1.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("dfg"); + diff --git a/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c b/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c new file mode 100644 index 0000000..ede91b1 --- /dev/null +++ b/hw2/to-prod/moodle/students/Compilation_Error_gets_10/error1.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("dfg"); + diff --git a/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c b/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c new file mode 100644 index 0000000..382b903 --- /dev/null +++ b/hw2/to-prod/moodle/students/Similar_output_gets_75/Example.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int n1, n2; + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d\n", n1+n2); +} diff --git a/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c b/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c new file mode 100644 index 0000000..660c4bd --- /dev/null +++ b/hw2/to-prod/moodle/students/Wrong_output_gets_50/Example.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("This is not the correct output!\n"); + return 0; +} diff --git a/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c b/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c new file mode 100644 index 0000000..3f96c1b --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_different/you_hate_recursion_i_love_it.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I love recursion. Can you guess what my algorithm is?\n"); + printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c b/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c new file mode 100644 index 0000000..d90cdd8 --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_great/ah_u_think_ur_great.c/ah_you_shouldnt_compile_me.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + You shouldn't compile me!!!! +} \ No newline at end of file diff --git a/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c b/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c new file mode 100644 index 0000000..a3c79f4 --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_great/zzz_im_tired.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c b/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c new file mode 100644 index 0000000..195b160 --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_insensitive/close_but_no.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("P l e a s e \n e n t e r \n t w o \n n u m b er s \n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/to-prod/tough/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c b/hw2/to-prod/tough/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c new file mode 100644 index 0000000..a3c79f4 --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_stupid2/really_no_file/yes_its_c_but_in_subdir.c @@ -0,0 +1,10 @@ +#include + +int main() +{ + int n1, n2; + printf("I hate recursion. Can you guess what my algorithm is?\n"); + printf("Please enter two numbers\n"); + scanf ("%d %d",&n1, &n2); + printf("%d", n1+n2); +} diff --git a/hw2/to-prod/tough/students/biu_student_terrible/cccgcc.c b/hw2/to-prod/tough/students/biu_student_terrible/cccgcc.c new file mode 100644 index 0000000..381cb20 --- /dev/null +++ b/hw2/to-prod/tough/students/biu_student_terrible/cccgcc.c @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("I'm a terrible student. See? I don't know basic syntax..."); +}} \ No newline at end of file diff --git a/hw3/assignment 3.pdf b/hw3/assignment 3.pdf new file mode 100644 index 0000000..db7ad4a Binary files /dev/null and b/hw3/assignment 3.pdf differ diff --git a/hw3/boundedQueue.h b/hw3/boundedQueue.h new file mode 100644 index 0000000..99325af --- /dev/null +++ b/hw3/boundedQueue.h @@ -0,0 +1,105 @@ +#include +#include + +#include +#include +#include + +using namespace std; + +class BoundedQueue { + private: + std::queue queue; + size_t capacity; + mutex qutex; + sem_t full; + sem_t empty; + + BoundedQueue(const BoundedQueue &) = delete; + BoundedQueue(BoundedQueue &&) = delete; + BoundedQueue &operator=(const BoundedQueue &) = delete; + BoundedQueue &operator=(BoundedQueue &&) = delete; + + void logSem(string value) { + int x, y; + sem_getvalue(&full, &x); + sem_getvalue(&empty, &y); + cout << "LOG: >>>>>>>>>>>>>>>> enqueue: " << value + << " ; full in: " << x << " ; empty in: " << y << endl; + } + + public: + BoundedQueue(size_t size) : capacity(size) { + sem_init(&full, 0, 0); + sem_init(&empty, 0, size); + }; + ~BoundedQueue(){}; + void enqueue(string value) { + sem_wait(&empty); + std::lock_guard guard(qutex); + queue.push(value); + sem_post(&full); + } + + string dequeue() { + sem_wait(&full); + qutex.lock(); + string value = queue.front(); + queue.pop(); + qutex.unlock(); + sem_post(&empty); + + return value; + }; + + int getSize() { + std::unique_lock lock(qutex); + int size = queue.size(); + lock.unlock(); + return size; + } + + string getFront() { + std::unique_lock lock(qutex); + string value = queue.front(); + lock.unlock(); + + return value; + }; + + string getRear() { + std::unique_lock lock(qutex); + string value = queue.back(); + lock.unlock(); + return value; + }; + + bool isEmpty() { + std::unique_lock lock(qutex); + bool empty = queue.empty(); + lock.unlock(); + + return empty; + }; + + bool isFull() { + std::unique_lock lock(qutex); + bool full = queue.size() == capacity; + lock.unlock(); + return full; + }; + + void print() { + std::unique_lock lock(qutex); + std::queue copy(queue); + lock.unlock(); + + cout << "◀◀ "; + + while (!copy.empty()) { + cout << copy.front() << " • "; + copy.pop(); + } + cout << "◀◀‖ " << endl; + }; +}; diff --git a/hw3/ex3.cpp b/hw3/ex3.cpp new file mode 100644 index 0000000..aa546a2 --- /dev/null +++ b/hw3/ex3.cpp @@ -0,0 +1,329 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "boundedQueue.h" +#include "omp.h" +#include "unboundedQueue.h" + +#define PRODUCER "PRODUCER" +#define COEDITOR "Co-Editor" +#define COEDITOR_COUNT 3 +#define DONE "done" +#define FINANCE_SEC 0 +#define NEWS_SEC 1 +#define TECH_SEC 2 +#define DIVIDER " // " + +using namespace std; + +struct Producer { + int id; + int numOfProducts; + int queueBound; +}; + +vector producers; +int coEditorBound = 0; +vector proQueues; +vector dispatcherQueues; +UnboundedQueue newsSec; +UnboundedQueue financeSec; +UnboundedQueue techSec; +// UnboundedQueue dispatcherQueues[3] +BoundedQueue *sharedQueue; +// *********************** +void testBq(); +void testUbq(); +void testConfig(); +void testProQueues(); +void testSharedQueue(); +// *********************** + +string getSectorNameById(int i) { + switch (i) { + case 0: + return "Finance"; + case 1: + return "News"; + case 2: + return "Tech"; + default: + return ""; + } +} + +int getIdBySectorName(string s) { + if (s == "Finance") { + return 0; + } else if (s == "News") { + return 1; + } else if (s == "Tech") { + return 2; + } else { + return -1; + } +} + +void logConfErr(exception e) { + cout << "‼️Error: " << e.what() << endl; + cout << "❣️Config file is not as excepted" << endl; +} + +void getConfig(string filename) { + ifstream in(filename); + string line; + int numOfEditors = 0; + Producer pro; + bool done = false; + while (!done) { + getline(in, line); + if (line.find(PRODUCER) != string::npos) { + pro.id = ++numOfEditors; + getline(in, line); + try { + pro.numOfProducts = stoi(line); + } catch (exception &e) { + logConfErr(e); + pro.numOfProducts = 0; + } + getline(in, line); + try { + pro.queueBound = stoi(line.substr(line.find("=") + 1).c_str()); + } catch (exception &e) { + logConfErr(e); + pro.queueBound = 0; + } + producers.push_back(pro); + } + if (line.find(COEDITOR) != string::npos) { + try { + coEditorBound = stoi(line.substr(line.find("=") + 1).c_str()); + } catch (exception &e) { + logConfErr(e); + coEditorBound = 0; + } + done = true; + } + if (line == "" && in.eof()) { + done = true; + } + } +} + +void initBoundedQueues() { + // producers queues + for (size_t i = 0; i < producers.size(); i++) { + proQueues.push_back(new BoundedQueue(producers[i].queueBound)); + }; + for (size_t i = 0; i < COEDITOR_COUNT; i++) { + dispatcherQueues.push_back(new UnboundedQueue()); + } + // co-editors queue + sharedQueue = new BoundedQueue(coEditorBound); +} + +// *********************** +void producer(size_t i) { + BoundedQueue *bq = proQueues.at(i); + + size_t prod = producers[i].numOfProducts; + // cout << " num of prod: " << prod << endl; + for (size_t j = 1; j <= prod; j++) { + // really produce something + string value = "producer " + to_string(producers[i].id) + DIVIDER + + getSectorNameById(j % 3) + DIVIDER + to_string(j); + bq->enqueue(value); + + usleep(5000); + } + bq->enqueue(DONE); + + // cout << "📎producer DONE!📎left for edit:"; + // bq->print(); +} + +void dispatcher() { + size_t countDone = 0; + bool done = false; + + while (!done) { + // circular loop for pro queues + for (size_t i = 0; i < proQueues.size(); i++) { + BoundedQueue *bq = proQueues.at(i); + if (!bq->isEmpty()) { + string value = bq->dequeue(); + // if value equal done, then countDone++ + if (value == DONE) { + countDone++; + proQueues.erase(proQueues.begin() + i); + + } else { + // dispatch value to the right co-editors queue by the + // value + int sp = value.find(DIVIDER) + 4; + string sector = + value.substr(sp, value.find(DIVIDER, sp) - sp); + cout << "📦 dispatching to sector " << sector; + int sectorId = getIdBySectorName(sector); + cout << "; sector id " << sectorId << endl; + dispatcherQueues[sectorId]->enqueue(value); + usleep(5000); + } + + } else { + } + + // circulate vector + if (proQueues.size() && i == proQueues.size() - 1) { + i = 0; + } + + // if countDone == producers.size() then done + if (countDone == producers.size()) { + done = true; + cout << "📦📦📦📦📦 Dispatcher is DONE 📦📦📦📦📦\n" << endl; + for_each(dispatcherQueues.begin(), dispatcherQueues.end(), + [](UnboundedQueue *q) { q->enqueue(DONE); }); + } + // if all pro queues are empty, then done + if (proQueues.size() == 0) { + done = true; + } + } + } +} + +void coEditor(size_t i) { + // cout << "I am co-editor " << i << endl; + UnboundedQueue *ubq = dispatcherQueues[i]; + bool done = false; + while (!done) { + string value = ubq->dequeue(); + if (value == DONE) { + done = true; + } else { + sharedQueue->enqueue(value + " ✒️edited "); + } + usleep(5000); + } +} + +int main(int argc, char **argv) { + if (argc == 1) { + cout << "❌Error: No config file provided" << endl; + return 0; + } + + string config = argv[1]; + getConfig(config); + // testConfig(); + initBoundedQueues(); + cout << ">>>>> 🗞️Start produce!🗞️" << endl; + mutex m; + std::vector threads; + for (size_t i = 0; i < producers.size(); i++) { + threads.emplace_back([&] { producer(i); }); + usleep(10000); + } + + std::thread dt(dispatcher); + std::thread fiCt(coEditor, FINANCE_SEC); + std::thread nsCt(coEditor, NEWS_SEC); + std::thread tcCt(coEditor, TECH_SEC); + + std::for_each(threads.begin(), threads.end(), + [](std::thread &x) { x.join(); }); + dt.join(); + fiCt.join(); + nsCt.join(); + tcCt.join(); + + sharedQueue->print(); + cout << "DONE!" << endl; + // testProQueues(); + // testSharedQueue(); + return 0; +} + +//========================================================== + +void testSharedQueue() { + // cout << "shared size: " << sharedQueue->getSize() << endl; + sharedQueue->print(); +} + +void testProQueues() { + // cout << "pro size: " << proQueues.size() << endl; + for (size_t i = 0; i < proQueues.size(); i++) { + proQueues[i]->print(); + } +} + +void testConfig() { + cout << "📜 CONFIG: 📜" << endl; + for (size_t i = 0; i < producers.size(); i++) { + cout << " Producer " << producers[i].id << ": " + << producers[i].numOfProducts << " products, " + << producers[i].queueBound << " queue bound" << endl; + } + cout << " co-editor: " << coEditorBound << endl; + cout << "===================================================" << endl; +} + +void testUbq() { + UnboundedQueue bq; + bq.enqueue("Hello"); + bq.enqueue("World"); + bq.enqueue("!"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + bq.enqueue("1"); + bq.enqueue("2"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + cout << " now out: " << bq.dequeue(); + cout << " now in front " << bq.getFront() << endl; + cout << " now in rear " << bq.getRear() << endl; + + bq.enqueue("3"); + cout << " now in rear " << bq.getRear() << endl; + bq.enqueue("3"); + bq.enqueue("3"); + + bq.print(); +} + +void testBq() { + BoundedQueue bq(5); + bq.enqueue("Hello"); + bq.enqueue("World"); + bq.enqueue("!"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << bq.isFull() + << endl; + bq.enqueue("1"); + bq.enqueue("2"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " but should be full " << bq.isFull() << endl; + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " but should be full " << bq.isFull() << endl; + cout << " now out: " << bq.dequeue(); + cout << " now in front " << bq.getFront() << endl; + cout << " now in rear " << bq.getRear() << endl; + + bq.enqueue("3"); + cout << " now in rear " << bq.getRear() << endl; + + bq.print(); +} \ No newline at end of file diff --git a/hw3/makefile b/hw3/makefile new file mode 100644 index 0000000..3a68314 --- /dev/null +++ b/hw3/makefile @@ -0,0 +1,5 @@ +make: ex3.cpp unboundedQueue.h boundedQueue.h + g++ -o ex3.out ex3.cpp -std=c++11 -lpthread + +clean: + rm -f *.o *.out \ No newline at end of file diff --git a/hw3/to-prod/boundedQueue.h b/hw3/to-prod/boundedQueue.h new file mode 100644 index 0000000..402f2d6 --- /dev/null +++ b/hw3/to-prod/boundedQueue.h @@ -0,0 +1,118 @@ +#include +#include + +// #include +// #include +#include +#include +#include +// #include + +using namespace std; + +class BoundedQueue { + private: + std::queue queue; + size_t capacity; + mutex qutex; + sem_t full; + sem_t empty; + + // TODO: consider this + // std::conditional_variable not_empty; + // std::conditional_variable not_full; + BoundedQueue(const BoundedQueue &) = delete; + BoundedQueue(BoundedQueue &&) = delete; + BoundedQueue &operator=(const BoundedQueue &) = delete; + BoundedQueue &operator=(BoundedQueue &&) = delete; + + void logSem(string value) { + // TODO: DELETE AFTER DEBUGGING + int x, y; + sem_getvalue(&full, &x); + sem_getvalue(&empty, &y); + cout << "LOG: >>>>>>>>>>>>>>>> enqueue: " << value + << " ; full in: " << x << " ; empty in: " << y << endl; + } + + public: + BoundedQueue(size_t size) : capacity(size) { + sem_init(&full, 0, 0); + sem_init(&empty, 0, size); + // cout << "LOG: BoundedQueue created with capacity: " << size << endl; + }; + ~BoundedQueue(){}; + void enqueue(string value) { + sem_wait(&empty); + // std::unique_lock lock(mutex); + std::lock_guard guard(qutex); + queue.push(value); + sem_post(&full); + + // logSem(value); // TODO: delete + } + + string dequeue() { + sem_wait(&full); + qutex.lock(); + string value = queue.front(); + queue.pop(); + qutex.unlock(); + sem_post(&empty); + + // logSem(value); // TODO: delete + + return value; + }; + + int getSize() { + std::unique_lock lock(qutex); + int size = queue.size(); + lock.unlock(); + return size; + } + + string getFront() { + std::unique_lock lock(qutex); + string value = queue.front(); + lock.unlock(); + + return value; + }; + + string getRear() { + std::unique_lock lock(qutex); + string value = queue.back(); + lock.unlock(); + return value; + }; + + bool isEmpty() { + std::unique_lock lock(qutex); + bool empty = queue.empty(); + lock.unlock(); + + return empty; + }; + + bool isFull() { + std::unique_lock lock(qutex); + bool full = queue.size() == capacity; + lock.unlock(); + return full; + }; + + void print() { + std::unique_lock lock(qutex); + std::queue copy(queue); + lock.unlock(); + + cout << "◀◀ "; + + while (!copy.empty()) { + cout << copy.front() << " • "; + copy.pop(); + } + cout << "◀◀‖ " << endl; + }; +}; diff --git a/hw3/to-prod/ex3.cpp b/hw3/to-prod/ex3.cpp new file mode 100644 index 0000000..aa546a2 --- /dev/null +++ b/hw3/to-prod/ex3.cpp @@ -0,0 +1,329 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "boundedQueue.h" +#include "omp.h" +#include "unboundedQueue.h" + +#define PRODUCER "PRODUCER" +#define COEDITOR "Co-Editor" +#define COEDITOR_COUNT 3 +#define DONE "done" +#define FINANCE_SEC 0 +#define NEWS_SEC 1 +#define TECH_SEC 2 +#define DIVIDER " // " + +using namespace std; + +struct Producer { + int id; + int numOfProducts; + int queueBound; +}; + +vector producers; +int coEditorBound = 0; +vector proQueues; +vector dispatcherQueues; +UnboundedQueue newsSec; +UnboundedQueue financeSec; +UnboundedQueue techSec; +// UnboundedQueue dispatcherQueues[3] +BoundedQueue *sharedQueue; +// *********************** +void testBq(); +void testUbq(); +void testConfig(); +void testProQueues(); +void testSharedQueue(); +// *********************** + +string getSectorNameById(int i) { + switch (i) { + case 0: + return "Finance"; + case 1: + return "News"; + case 2: + return "Tech"; + default: + return ""; + } +} + +int getIdBySectorName(string s) { + if (s == "Finance") { + return 0; + } else if (s == "News") { + return 1; + } else if (s == "Tech") { + return 2; + } else { + return -1; + } +} + +void logConfErr(exception e) { + cout << "‼️Error: " << e.what() << endl; + cout << "❣️Config file is not as excepted" << endl; +} + +void getConfig(string filename) { + ifstream in(filename); + string line; + int numOfEditors = 0; + Producer pro; + bool done = false; + while (!done) { + getline(in, line); + if (line.find(PRODUCER) != string::npos) { + pro.id = ++numOfEditors; + getline(in, line); + try { + pro.numOfProducts = stoi(line); + } catch (exception &e) { + logConfErr(e); + pro.numOfProducts = 0; + } + getline(in, line); + try { + pro.queueBound = stoi(line.substr(line.find("=") + 1).c_str()); + } catch (exception &e) { + logConfErr(e); + pro.queueBound = 0; + } + producers.push_back(pro); + } + if (line.find(COEDITOR) != string::npos) { + try { + coEditorBound = stoi(line.substr(line.find("=") + 1).c_str()); + } catch (exception &e) { + logConfErr(e); + coEditorBound = 0; + } + done = true; + } + if (line == "" && in.eof()) { + done = true; + } + } +} + +void initBoundedQueues() { + // producers queues + for (size_t i = 0; i < producers.size(); i++) { + proQueues.push_back(new BoundedQueue(producers[i].queueBound)); + }; + for (size_t i = 0; i < COEDITOR_COUNT; i++) { + dispatcherQueues.push_back(new UnboundedQueue()); + } + // co-editors queue + sharedQueue = new BoundedQueue(coEditorBound); +} + +// *********************** +void producer(size_t i) { + BoundedQueue *bq = proQueues.at(i); + + size_t prod = producers[i].numOfProducts; + // cout << " num of prod: " << prod << endl; + for (size_t j = 1; j <= prod; j++) { + // really produce something + string value = "producer " + to_string(producers[i].id) + DIVIDER + + getSectorNameById(j % 3) + DIVIDER + to_string(j); + bq->enqueue(value); + + usleep(5000); + } + bq->enqueue(DONE); + + // cout << "📎producer DONE!📎left for edit:"; + // bq->print(); +} + +void dispatcher() { + size_t countDone = 0; + bool done = false; + + while (!done) { + // circular loop for pro queues + for (size_t i = 0; i < proQueues.size(); i++) { + BoundedQueue *bq = proQueues.at(i); + if (!bq->isEmpty()) { + string value = bq->dequeue(); + // if value equal done, then countDone++ + if (value == DONE) { + countDone++; + proQueues.erase(proQueues.begin() + i); + + } else { + // dispatch value to the right co-editors queue by the + // value + int sp = value.find(DIVIDER) + 4; + string sector = + value.substr(sp, value.find(DIVIDER, sp) - sp); + cout << "📦 dispatching to sector " << sector; + int sectorId = getIdBySectorName(sector); + cout << "; sector id " << sectorId << endl; + dispatcherQueues[sectorId]->enqueue(value); + usleep(5000); + } + + } else { + } + + // circulate vector + if (proQueues.size() && i == proQueues.size() - 1) { + i = 0; + } + + // if countDone == producers.size() then done + if (countDone == producers.size()) { + done = true; + cout << "📦📦📦📦📦 Dispatcher is DONE 📦📦📦📦📦\n" << endl; + for_each(dispatcherQueues.begin(), dispatcherQueues.end(), + [](UnboundedQueue *q) { q->enqueue(DONE); }); + } + // if all pro queues are empty, then done + if (proQueues.size() == 0) { + done = true; + } + } + } +} + +void coEditor(size_t i) { + // cout << "I am co-editor " << i << endl; + UnboundedQueue *ubq = dispatcherQueues[i]; + bool done = false; + while (!done) { + string value = ubq->dequeue(); + if (value == DONE) { + done = true; + } else { + sharedQueue->enqueue(value + " ✒️edited "); + } + usleep(5000); + } +} + +int main(int argc, char **argv) { + if (argc == 1) { + cout << "❌Error: No config file provided" << endl; + return 0; + } + + string config = argv[1]; + getConfig(config); + // testConfig(); + initBoundedQueues(); + cout << ">>>>> 🗞️Start produce!🗞️" << endl; + mutex m; + std::vector threads; + for (size_t i = 0; i < producers.size(); i++) { + threads.emplace_back([&] { producer(i); }); + usleep(10000); + } + + std::thread dt(dispatcher); + std::thread fiCt(coEditor, FINANCE_SEC); + std::thread nsCt(coEditor, NEWS_SEC); + std::thread tcCt(coEditor, TECH_SEC); + + std::for_each(threads.begin(), threads.end(), + [](std::thread &x) { x.join(); }); + dt.join(); + fiCt.join(); + nsCt.join(); + tcCt.join(); + + sharedQueue->print(); + cout << "DONE!" << endl; + // testProQueues(); + // testSharedQueue(); + return 0; +} + +//========================================================== + +void testSharedQueue() { + // cout << "shared size: " << sharedQueue->getSize() << endl; + sharedQueue->print(); +} + +void testProQueues() { + // cout << "pro size: " << proQueues.size() << endl; + for (size_t i = 0; i < proQueues.size(); i++) { + proQueues[i]->print(); + } +} + +void testConfig() { + cout << "📜 CONFIG: 📜" << endl; + for (size_t i = 0; i < producers.size(); i++) { + cout << " Producer " << producers[i].id << ": " + << producers[i].numOfProducts << " products, " + << producers[i].queueBound << " queue bound" << endl; + } + cout << " co-editor: " << coEditorBound << endl; + cout << "===================================================" << endl; +} + +void testUbq() { + UnboundedQueue bq; + bq.enqueue("Hello"); + bq.enqueue("World"); + bq.enqueue("!"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + bq.enqueue("1"); + bq.enqueue("2"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << endl; + cout << " now out: " << bq.dequeue(); + cout << " now in front " << bq.getFront() << endl; + cout << " now in rear " << bq.getRear() << endl; + + bq.enqueue("3"); + cout << " now in rear " << bq.getRear() << endl; + bq.enqueue("3"); + bq.enqueue("3"); + + bq.print(); +} + +void testBq() { + BoundedQueue bq(5); + bq.enqueue("Hello"); + bq.enqueue("World"); + bq.enqueue("!"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " and neither should be full " << bq.isFull() + << endl; + bq.enqueue("1"); + bq.enqueue("2"); + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " but should be full " << bq.isFull() << endl; + cout << "LOG>>>> size is: " << bq.getSize() << " queue should not be empty " + << bq.isEmpty() << " but should be full " << bq.isFull() << endl; + cout << " now out: " << bq.dequeue(); + cout << " now in front " << bq.getFront() << endl; + cout << " now in rear " << bq.getRear() << endl; + + bq.enqueue("3"); + cout << " now in rear " << bq.getRear() << endl; + + bq.print(); +} \ No newline at end of file diff --git a/hw3/to-prod/makefile b/hw3/to-prod/makefile new file mode 100644 index 0000000..3a68314 --- /dev/null +++ b/hw3/to-prod/makefile @@ -0,0 +1,5 @@ +make: ex3.cpp unboundedQueue.h boundedQueue.h + g++ -o ex3.out ex3.cpp -std=c++11 -lpthread + +clean: + rm -f *.o *.out \ No newline at end of file diff --git a/hw3/to-prod/unboundedQueue.h b/hw3/to-prod/unboundedQueue.h new file mode 100644 index 0000000..561ba0b --- /dev/null +++ b/hw3/to-prod/unboundedQueue.h @@ -0,0 +1,100 @@ +#include +#include + +#include +#include +#include + +class UnboundedQueue { + private: + std::queue queue; + mutex qutex; + sem_t full; + + UnboundedQueue(const UnboundedQueue &) = delete; + UnboundedQueue(UnboundedQueue &&) = delete; + UnboundedQueue &operator=(const UnboundedQueue &) = delete; + UnboundedQueue &operator=(UnboundedQueue &&) = delete; + + void logSem(string value) { + // TODO: DELETE AFTER DEBUGGING + int x; + sem_getvalue(&full, &x); + cout << "LOG: >>>>>>>>>>>>>>>> enqueue: " << value + << " ; full in: " << x << endl; + } + + public: + UnboundedQueue() { sem_init(&full, 0, 0); }; + ~UnboundedQueue(){}; + void enqueue(string value) { + // std::lock_guard guard(qutex); + qutex.lock(); + queue.push(value); + qutex.unlock(); + sem_post(&full); + + // logSem(value); // TODO: delete + } + + string dequeue() { + sem_wait(&full); + qutex.lock(); + string value = queue.front(); + queue.pop(); + qutex.unlock(); + + // logSem(value); // TODO: delete + + return value; + }; + + int getSize() { + std::unique_lock lock(qutex); + int size = queue.size(); + lock.unlock(); + // std::unique_lock unlock(mutex); + return size; + } + + string getFront() { + std::unique_lock lock(qutex); + string value = queue.front(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return value; + }; + + string getRear() { + std::unique_lock lock(qutex); + string value = queue.back(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return value; + }; + + bool isEmpty() { + std::unique_lock lock(qutex); + bool empty = queue.empty(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return empty; + }; + + void print() { + std::unique_lock lock(qutex); + std::queue copy(queue); + lock.unlock(); + + cout << "◀◀ "; + + while (!copy.empty()) { + cout << copy.front() << " • "; + copy.pop(); + } + cout << "◀≡‖ " << endl; + }; +}; diff --git a/hw3/unboundedQueue.h b/hw3/unboundedQueue.h new file mode 100644 index 0000000..561ba0b --- /dev/null +++ b/hw3/unboundedQueue.h @@ -0,0 +1,100 @@ +#include +#include + +#include +#include +#include + +class UnboundedQueue { + private: + std::queue queue; + mutex qutex; + sem_t full; + + UnboundedQueue(const UnboundedQueue &) = delete; + UnboundedQueue(UnboundedQueue &&) = delete; + UnboundedQueue &operator=(const UnboundedQueue &) = delete; + UnboundedQueue &operator=(UnboundedQueue &&) = delete; + + void logSem(string value) { + // TODO: DELETE AFTER DEBUGGING + int x; + sem_getvalue(&full, &x); + cout << "LOG: >>>>>>>>>>>>>>>> enqueue: " << value + << " ; full in: " << x << endl; + } + + public: + UnboundedQueue() { sem_init(&full, 0, 0); }; + ~UnboundedQueue(){}; + void enqueue(string value) { + // std::lock_guard guard(qutex); + qutex.lock(); + queue.push(value); + qutex.unlock(); + sem_post(&full); + + // logSem(value); // TODO: delete + } + + string dequeue() { + sem_wait(&full); + qutex.lock(); + string value = queue.front(); + queue.pop(); + qutex.unlock(); + + // logSem(value); // TODO: delete + + return value; + }; + + int getSize() { + std::unique_lock lock(qutex); + int size = queue.size(); + lock.unlock(); + // std::unique_lock unlock(mutex); + return size; + } + + string getFront() { + std::unique_lock lock(qutex); + string value = queue.front(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return value; + }; + + string getRear() { + std::unique_lock lock(qutex); + string value = queue.back(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return value; + }; + + bool isEmpty() { + std::unique_lock lock(qutex); + bool empty = queue.empty(); + lock.unlock(); + + // std::unique_lock unlock(mutex); + return empty; + }; + + void print() { + std::unique_lock lock(qutex); + std::queue copy(queue); + lock.unlock(); + + cout << "◀◀ "; + + while (!copy.empty()) { + cout << copy.front() << " • "; + copy.pop(); + } + cout << "◀≡‖ " << endl; + }; +};