├── Makefile ├── README.md ├── docs ├── README-submission-guidelines ├── build │ ├── Makefile1 │ ├── Makefile2 │ ├── Makefile3 │ ├── README │ ├── hello_world.c │ ├── hello_world.h │ └── printpid.c ├── gdb-sheet ├── macro-expressions.c └── simple-pipe-linux-commandline ├── files ├── Makefile ├── README ├── check-fileinfo.c ├── file_as_a_lock.c ├── flocking.c ├── flush.c ├── myincludes.h ├── pipecmd.c ├── readfile.c ├── redirect.c ├── repeated_printf.c ├── test2_link.c ├── test_link.c ├── testfile ├── usingdup.c └── xyz ├── ipc ├── mq-posix │ ├── Makefile │ ├── README │ └── mq_ctl.c ├── msgque │ ├── Makefile │ ├── README │ ├── common.h │ ├── msg_ctl.c │ ├── msg_reader.c │ └── msg_writer.c ├── named-pipes │ ├── Makefile │ ├── README │ ├── common.h │ ├── fifo-re-wr.c │ ├── fifo-reader.c │ └── fifo-writer.c ├── sem-posix │ ├── Makefile │ ├── README │ ├── pc.c │ └── sem_ctl.c ├── sem │ ├── Makefile │ ├── README │ ├── configs.h │ ├── mysemops.c │ ├── mysemops.h │ ├── safe_ops.c │ ├── safe_ops.h │ ├── sem_ctl.c │ ├── setup.sh │ ├── shm_consumer.c │ ├── shm_ctl.c │ ├── shm_producer.c │ └── teardown.sh ├── shm-posix │ ├── Makefile │ ├── README │ ├── common.h │ ├── filler.c │ ├── reader.c │ └── shm_ctl.c ├── shm │ ├── Makefile │ ├── README │ ├── common.h │ ├── filler.c │ ├── reader.c │ └── shm_ctl.c ├── simple-pipe │ └── pipe.c └── sockets │ ├── Makefile │ ├── README │ ├── commons.h │ ├── conc_server.c │ ├── simple_tcp_client.sh │ ├── simple_tcp_server.sh │ ├── tcp_client.c │ ├── tcp_long_client.c │ ├── tcp_server.c │ ├── udp_client.c │ ├── udp_echo_server.c │ ├── udp_server.c │ ├── unx_client.c │ └── unx_server.c ├── memory ├── Makefile ├── README └── frameit.c ├── misc ├── Makefile ├── Mmap-test-file ├── README ├── address.c ├── check-endian.c ├── divbyzero.c ├── eratosthenes.c ├── fact.c ├── gtotd.c ├── mallocing.c ├── mmap-simple.c ├── mmap1.c ├── printpid.c ├── reading.c ├── showlim.c ├── sig.c ├── sig2.c ├── timer_intr.c ├── touch_bad_memory.c ├── x.c └── y.c ├── procs ├── Makefile ├── README ├── duper.c ├── exceptions.c ├── fork_and_termC.c ├── fork_and_termP.c ├── fork_experiment.c ├── forkloop.c ├── loopy.c ├── myincludes.h ├── permfile ├── priority_ops.c ├── reparent.c ├── savefile ├── sched_info.c ├── sched_policychange.c ├── sched_priochange.c ├── shell.c ├── simple_exec.c ├── simple_fork.c ├── simple_getpid.c ├── syscall.s ├── syscallC.c ├── tempfile └── zomB.c ├── pthreads ├── Makefile ├── README ├── find_some_primes.c ├── find_some_primes_2r.c ├── find_some_primes_cv.c ├── find_some_primes_cv_many.c ├── find_some_primes_mutex.c ├── prod_con.c ├── safe_ops.c ├── safe_ops.h ├── simple.c ├── update_balance.c └── update_balance_mutex.c └── utils └── mymake /Makefile: -------------------------------------------------------------------------------- 1 | EXECS= simple pc 2 | 3 | help: 4 | echo USAGE: make all or make clean 5 | 6 | all: 7 | utils/mymake * 8 | 9 | 10 | 11 | clean: 12 | utils/mymake clean * 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Teach-OS 2 | 3 | The content here was created for an introductory course on operating systems 4 | I taught for the undergraduate students at IIIT Bangalore in the 5 | semester January to May 2022. 6 | 7 | There is an attempt to use makefiles, some times in different formats to 8 | encourage students to think about how makefiles work. 9 | 10 | 11 | Not all the code is perfect, but most of it works quite well. Also the intention 12 | is that students will pick up the code, modify and experiment with it. 13 | 14 | A lot can be improved and it is perhaps best left to students to figure out 15 | issues and fix them :-) 16 | -------------------------------------------------------------------------------- /docs/README-submission-guidelines: -------------------------------------------------------------------------------- 1 | PURPOSE: 2 | Provide suidelines to enable students to submit assignments in a uniform way to simplify build and execution: 3 | 4 | 0. Write a first version of your program and a first version of the Makefile 5 | Create the Makefile from the template located in: 6 | docs/build/Makefile? 7 | 8 | 1. Use your makefile while doing your development. (Not as an afterthought!) 9 | Often it is good to simply do "make" just to be sure you are 10 | not breaking anything. See the compilation steps in the output to be sure. 11 | 12 | 2. Once you have done development, testing etc. Then tar things together. 13 | tar cvf 14 | tar cvf IMT2019789-Assn1.tar Makefile hello_world.c hello_world.h 15 | This combines into the new file IMT2019789-Add1.tar 16 | all the files listed after, i.e. Makefile hello_world.c and hello_world.h 17 | 18 | 3. Test your tar file in a new empty directory: As an example: 19 | mkdir /tmp/testdir 20 | cp IMT2019789-Assn1.tar /tmp/testdir 21 | cd /tmp/testdir 22 | tar xvf IMT2019789-Assn1.tar # Note the "x" in "xvf" it is for extraction 23 | make 24 | 25 | It should build properly, and execute properly after that. 26 | 27 | 4. Submit the tar file AFTER you are happy your build and execution worked 28 | FROM THE TEST DIRECTORY. 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/build/Makefile1: -------------------------------------------------------------------------------- 1 | # A SIMPLE FIRST VERSION OF THE Makefile for one executable 2 | 3 | 4 | # ------------- the target and how to make ------------ 5 | 6 | # Lines come in groups of this form: 7 | # : 8 | # 9 | # 10 | # Wierd: Did you notice the mentioned above???? 11 | 12 | # In our case: 13 | # "hello_world" executable depends on 14 | # both "hello_world.c" and "hello_world.h" files 15 | # "hello_world" is built using gcc 16 | # Target 1 17 | hello_world: hello_world.c hello_world.h 18 | gcc -o hello_world hello_world.c 19 | 20 | # Did you find the in the above example? 21 | 22 | # -------------- Here is a useful target ------------- 23 | # cleanup utility - quite useful shorthand 24 | # Target 2 25 | clean: 26 | rm -f hello_world 27 | 28 | # note in the case of target "clean" it has no dependencies which means that it will check nothing and do the command :-) 29 | # 30 | # Target 3 31 | run: 32 | ./hello_world 33 | -------------------------------------------------------------------------------- /docs/build/Makefile2: -------------------------------------------------------------------------------- 1 | # A slightly enhanced.. 2 | # SIMPLE FIRST VERSION OF THE Makefile with some useful 3 | # additions 4 | # 5 | # The next few lines are just shorthand definitions, 6 | # 7 | # We want to make two executables 8 | EXEC=hello_world printpid 9 | CC=gcc 10 | 11 | # ------------- the target and how to make ------------ 12 | 13 | # The first is always the default target to build 14 | # lets use this to list all the executables to build 15 | 16 | #Target 1 17 | all: $(EXEC) 18 | 19 | # executables : one by one say how to make each executable 20 | # note that hello_world executable depends on both the 21 | # hello_world.c and the hello_world.h so we list both files 22 | # as dependencies. 23 | # Target 2 24 | hello_world: hello_world.c hello_world.h 25 | $(CC) -o hello_world hello_world.c 26 | 27 | # Target 3 28 | printpid: printpid.c 29 | $(CC) -o printpid printpid.c 30 | 31 | 32 | # Target 4 33 | # cleanup utility - quite useful shorthand 34 | clean: 35 | rm -f $(EXEC) 36 | -------------------------------------------------------------------------------- /docs/build/Makefile3: -------------------------------------------------------------------------------- 1 | # A more DETAILED Makefile 2 | # We probably need very little beyond what is here 3 | # We can always to do with a simpler Makefile 4 | # ---------------- definitions -------------- 5 | EXEC=hello_world printpid 6 | CC=gcc 7 | CFLAGS= 8 | DEPS = hello_world.h 9 | # These are the .o files from which 10 | # hello_world executable is built 11 | HWOBJS= hello_world.o 12 | 13 | # These are the .o files from which 14 | # printpid xecutable is built 15 | POBJS= printpid.o 16 | 17 | # ---------------- first target to catch all executables ----- 18 | # default target is this first one 19 | all: $(EXEC) 20 | 21 | # ---------------- object files -------------- 22 | # This time we first build .o from .c and then create the 23 | # executables from the .o 24 | # objects(.o) : Here is a tricky shorthand to build all objs 25 | # "%.o depends on the corresponding %.c and 26 | # the files listed in DEPS 27 | # In the build command 28 | # $@ is the left side of the ":" 29 | # $< is the first thing on the right of the ":" 30 | %.o: %.c $(DEPS) 31 | $(CC) -c -o $@ $< $(CFLAGS) 32 | 33 | # ---------------- executables -------------- 34 | # In the build command note a little trick 35 | # The $^ refers to all the stuff on the 36 | # right of the ":" 37 | hello_world: $(HWOBJS) 38 | $(CC) -o $@ $^ 39 | 40 | printpid: $(POBJS) 41 | $(CC) -o $@ $^ 42 | 43 | # ---------------- utilities -------------- 44 | # cleanup utility 45 | 46 | clean: 47 | rm -f $(EXEC) $(HWOBJS) $(POBJS) 48 | 49 | # for fun just try make help 50 | 51 | help: 52 | echo " make clean to remove executables, objs \n" "make all to build executables" 53 | -------------------------------------------------------------------------------- /docs/build/README: -------------------------------------------------------------------------------- 1 | PURPOSE: 2 | This directory is intended to illustrate usage of Makefile 3 | The aim is to do just enough to enable the student to start 4 | using 'make' to build executables on a regular basis 5 | 6 | MORE INFORMATION: 7 | See 'man make' for info on the make command 8 | See 9 | https://www.gnu.org/software/make/manual/html_node/Introduction.html#Introduction 10 | for more information on the Makefile format 11 | 12 | FILES: 13 | 14 | Makefile1 15 | contains a simple makefile for 16 | building the hello_world program 17 | 18 | Makefile2 extends Makefile2 and also builds printpid 19 | 20 | Makefile3 21 | Shows some additional tricks typically used to make 22 | Makefiles more generic .. often not needed at this level. 23 | 24 | -------------------------------------------------------------------------------- /docs/build/hello_world.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hello_world.h" 3 | 4 | int main(){ 5 | #ifndef NAME 6 | #define NAME "Ram" 7 | #endif 8 | 9 | printf("Hello dear %s\n",NAME); 10 | } 11 | -------------------------------------------------------------------------------- /docs/build/hello_world.h: -------------------------------------------------------------------------------- 1 | #define NAME "Sreevatsa" 2 | -------------------------------------------------------------------------------- /docs/build/printpid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | /* Simple program that executes (overlays) anoher program */ 13 | void main(){ 14 | printf("My PID = %d\n",(int)getpid()); 15 | } 16 | -------------------------------------------------------------------------------- /docs/gdb-sheet: -------------------------------------------------------------------------------- 1 | Some useful gdb commands one can use to investigate what the code 2 | that is running looks like, in addition to of course debugging real code. 3 | 4 | NOTE: Before using gdb, make sure to compile code with a '-g' flag and 5 | you may want to experiment by turning off optimizations. 6 | 7 | A SUPER QUICK INTRO with a sample run 8 | 9 | Here is a sample run, you should be able to do this with a very simple program, 10 | perhaps it a main() and one more function with local variables. 11 | 12 | $ gcc -g myprog.c # will compile the program so that you can use gdb on it meaningfully 13 | $ gdb a.out 14 | (gdb) l # will list program source 15 | (gdb) l # will list program source from given lineno 16 | (gdb) l # will list program source from given function 17 | (gdb) b # set a breakpoint at the given lineno 18 | (gdb) b # set a breakpoint at the given function 19 | (gdb) run # Run the program from beginning and stop at the next breakpoint 20 | (gdb) n # will execute the current line and stop after that 21 | (gdb) s # like n, but if its a call it steps into the function and stop 22 | (gdb) p # will print the value of the given variable 23 | (gdb) finish # will run to the end of the current function and print the return value 24 | (gdb) info locals # will print all local and their values 25 | (gdb) i lo # same as info locals 26 | (gdb) info frame # will print information about the current stack frame 27 | (gdb) i f # same as info frame 28 | (gdb) set variable = # will assign a value to a variable 29 | (gdb) cont # will continue execution from the current line till the next breakpoint 30 | (gdb) bt # will print backtrace ie sequence of frames upto current 31 | # with set to 'full' it will print locals too. 32 | 33 | 34 | NB: 35 | It is also possible to view the program lines as it is running: 36 | At the gdb prompt say: 37 | (gdb) tui enable # At this point you can see a split window showing your program in execution as you type the gdb commands. 38 | Another way to do this is to use emacs and the M-x gdb command 39 | 40 | 41 | 42 | OTHER USEFUL COMMANDS: 43 | 44 | * Listng lines of code: 45 | (gdb) list [n] 46 | * Listing lines starting at the current ip 47 | (gdb) list * $rip 48 | * looking at assembler code 49 | (gdb) disassemble ; lists assembly of the current function 50 | (gdb) disassemble * $rip 51 | (gdb) disassemble 52 | * Stack frames listing 53 | (gdb) bt 54 | (gdb) bt full 55 | * more informatio with info 56 | (gdb) info frame [n] ; information abouta stack frame (0 is topmost) 57 | (gdb) info locals ; information about locals and args 58 | (gdb) info args 59 | * Dumping the contents of memory 60 | (gdb) x/nfu 61 | eg x/20xw $rip ; examine 20 hexformatted words starting at $rip 62 | x/20db $rbp-12 ; useful to examine something moved into $rbp-0xc 63 | x/20db 0x55000000 ; dump content of memory byte wise starting at 0x5500 64 | 65 | More details list of commands 66 | https://ccrma.stanford.edu/~jos/stkintro/Useful_commands_gdb.html 67 | Also see a quick overview 68 | https://www.geeksforgeeks.org/gdb-step-by-step-introduction/ 69 | -------------------------------------------------------------------------------- /docs/macro-expressions.c: -------------------------------------------------------------------------------- 1 | // Just use 'gcc -E ' to see the output. 2 | // 3 | // Beware, this file will not compile as a C program. 4 | // It is just to see how macros expand 5 | // 6 | // 7 | // For a documentation see 8 | // https://gcc.gnu.org/onlinedocs/cpp/Macros.html#Macros 9 | // 10 | // 11 | // ALWAYS 12 | // 0. Macro definition is setting up a Name <-> Expansion associaiton 13 | // 1. Macro usage causes substituting Name by Expansion 14 | // 2. MACRO is expanded only on usage; during definition it is just kept as is 15 | // 3. After expansion again check if other macros expansions apply 16 | // 4. Dont expand inside quotes (strings) 17 | // In the comments below the arrows '->' are used to indicate 18 | // immediate macro expansion 19 | // There are two types of macros 20 | // TYPE 1 object-like macros 21 | // Expansion = simple replacement 22 | // 23 | #define X 100 24 | o1. X // X -> 100 25 | #define BIG 1 26 | o2. BIG // BIG -> 1 27 | #define MYBIG BIG 28 | o3. MYBIG // MYBIG -> BIG -> 1 (Note two step process) 29 | #define A B // Note that B is undefined 30 | #define B 1 31 | ooo. A // A -> B -> 1 32 | #define L_BIG 2 // L_BIG -> 2 33 | 34 | 35 | // TYPE 2 function-like macros 36 | // Now expansion is in two ordered steps 37 | // step 1. Expand all args 38 | // step 2. Expanded macro with args substituted. 39 | // Exceptions to this order are when # and ## are used in the expansion 40 | #define NAMEIT(X) X 41 | f1. NAMEIT(BIG) // NAMEIT(BIG) -> NAMEIT(1) -> 1 Arg expands first 42 | #define DAY(X) "Today is " X 43 | f2. DAY(X) //-> DAY(100) -> "Today is " 100 Arg expands first 44 | 45 | // Exception 1: In case of # on RHS of function-like 46 | // #X => "X" without further expansion of X 47 | // Note as an exception Arg NOT expanded first if stringized! 48 | #define DDAY(N) "Today is " #N 49 | e1. DDAY(X) // DDAY(X) 50 | // -> "Today is " #X Not the arg not expanded 51 | // -> "Today is " "X" 52 | 53 | // Therefore to expand and quote, take two steps: 54 | #define EDDAY(N) DDAY(N) 55 | e2. EDDAY(X) // EDDAY(X) 56 | // -> EDDAY(100) ->DDAY(100) -> "Today is " #100 57 | // ->"Today is " "100" 58 | 59 | // What happens to string around a string ?? 60 | #define STRINGIT(X) #X 61 | e3. STRINGIT(BIG) // -> #BIG ->"BIG" expand before arg expansion 62 | #define EXPSTRINGIT(X) STRINGIT(X) 63 | e4. EXPSTRINGIT(BIG) // -> EXPSTRINGIT ( 1 ) 64 | // -> STRINGIT(1) -> #1 -> "1" 65 | #define QEXPSTRINGIT(X) EXPSTRINGIT(STRINGIT(X)) 66 | e5. QEXPSTRINGIT(BIG) 67 | // QEXPSTRINGIT(BIG) 68 | // -> QEXPSTRINGIT(1) 69 | // -> EXPSTRINGIT(STRINGIT(1)) 70 | // -> EXPSTRINGIT( "1" ) 71 | // -> STRINGIT("1") 72 | // -> #"1" 73 | // -> "\"1\"" : Notice nice escaping 74 | // of inner quote marks 75 | 76 | // Eception 2: ## is used for concatenation, again DONT expand argument first. 77 | #define CON(X) L_##X 78 | e6. CON(BIG) // CON(BIG) 79 | // ->L_BIG 80 | // ->2 81 | 82 | 83 | // What if argument X occurs with and without #? 84 | // first treat it as an exception and expand macro first 85 | #define MYDAY(N) #N N 86 | e7. MYDAY(X) // -> #X X expand body first 87 | // -> "X" 100 88 | 89 | -------------------------------------------------------------------------------- /docs/simple-pipe-linux-commandline: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # simple code to show how piping works and a feel for the way people use it 3 | 4 | # This uses sed to change the first occurrence of void to int 5 | cat x.c | sed s/void/int/ 6 | # More examples on sed, see https://linuxhint.com/50_sed_command_examples/ 7 | # And also https://edoras.sdsu.edu/doc/sed-oneliners.html 8 | 9 | 10 | # This uses awk to do somehing like cat -n x.c 11 | cat x.c | awk ' { print NR " : " $0 }' 12 | # Handy awk one-liners https://linoxide.com/useful-awk-one-liners-to-keep-handy/ 13 | 14 | # This uses perl to add a line before and after the contents of x.c 15 | cat x.c | perl -pE 'BEGIN{say "// Sample header"} END{say "// Sample tail"}' 16 | # Handy perl stuff https://learnbyexample.github.io/learn_perl_oneliners/one-liner-introduction.html 17 | 18 | # The next one is NOT a command line pipe, but I find it very useful 19 | # This copies x.txt to x.txt.back (-i can be used without .bak as well) 20 | # Then is replaces all occurrences of SMALL by BIG in x.txt 21 | # The useful thing is it changes x.txt itself, not sending stuff to stdout. 22 | perl -pi.bak -e s/SMALL/BIG/g x.txt 23 | 24 | -------------------------------------------------------------------------------- /files/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | EXEC = check-fileinfo flush usingdup test_link test2_link \ 3 | file_as_a_lock readfile pipecmd redirect repeated_printf flocking 4 | 5 | all: $(EXEC) 6 | 7 | clean: 8 | rm -f a.out *.o $(EXEC) 9 | 10 | clean-objs: 11 | rm -f *.o 12 | 13 | help: 14 | echo all-execs/ all-objs /all /clean-all 15 | -------------------------------------------------------------------------------- /files/README: -------------------------------------------------------------------------------- 1 | ABOUT 2 | Some miscellaneous files to try things out 3 | 4 | FILES 5 | check-fileinfo.c calls stat to get info about a file 6 | ./check-fileinfo 7 | flush.c using fflush, the notion of buffer and flushing 8 | repeated_printf.c understanding how C library is using buffering 9 | file_as_a_lock.c Using file locking 10 | readfile.c Use open() read() and write() syscalls 11 | also tells us a bit more about file descriptors 12 | test_link.c A Simple program to test hard and soft links 13 | : do test_link --help for more info 14 | test2_link.c A Simple program to test hard and soft links : 15 | : introduced unlink.... must cleanup 16 | flocking.c A simple program to show how locking works 17 | To see it work, run two instances of the program on different windows and see ps -alx 18 | redirect.c Example using open and dup for redirection 19 | pipecmd.c Use pipe between parent and child using 20 | usingdup.c A program to show the effect of using dup 21 | instead of open the file twice 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /files/check-fileinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | struct stat sb; 16 | 17 | if (argc != 2) { 18 | fprintf(stderr, "Usage: %s \n", argv[0]); 19 | exit(EXIT_FAILURE); 20 | } 21 | 22 | if (lstat(argv[1], &sb) == -1) { 23 | perror("lstat"); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | printf("ID of containing device: [%lx,%lx]\n", 28 | (long) major(sb.st_dev), (long) minor(sb.st_dev)); 29 | 30 | printf("File type: "); 31 | 32 | switch (sb.st_mode & S_IFMT) { 33 | case S_IFBLK: printf("block device\n"); break; 34 | case S_IFCHR: printf("character device\n"); break; 35 | case S_IFDIR: printf("directory\n"); break; 36 | case S_IFIFO: printf("FIFO/pipe\n"); break; 37 | case S_IFLNK: printf("symlink\n"); break; 38 | case S_IFREG: printf("regular file\n"); break; 39 | case S_IFSOCK: printf("socket\n"); break; 40 | default: printf("unknown?\n"); break; 41 | } 42 | 43 | printf("I-node number: %ld\n", (long) sb.st_ino); 44 | 45 | printf("Mode: %lo (octal)\n", 46 | (unsigned long) sb.st_mode); 47 | 48 | printf("Link count: %ld\n", (long) sb.st_nlink); 49 | printf("Ownership: UID=%ld GID=%ld\n", 50 | (long) sb.st_uid, (long) sb.st_gid); 51 | 52 | printf("Preferred I/O block size: %ld bytes\n", 53 | (long) sb.st_blksize); 54 | printf("File size: %lld bytes\n", 55 | (long long) sb.st_size); 56 | printf("Blocks allocated: %lld\n", 57 | (long long) sb.st_blocks); 58 | 59 | 60 | printf("Last status change: %s", ctime(&sb.st_ctime)); 61 | printf("Last file access: %s", ctime(&sb.st_atime)); 62 | printf("Last file modification: %s", ctime(&sb.st_mtime)); 63 | 64 | exit(EXIT_SUCCESS); 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /files/file_as_a_lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | // Global 9 | static char * lockfile="lockfile"; 10 | int create_and_acquire_lock(int *fd){ 11 | // return value 12 | // 0 succesfully created, fd is the file descriptor 13 | // 1 unsuccessful 14 | *fd=open(lockfile,O_CREAT|O_EXCL|O_RDWR,S_IRWXU); 15 | if ((*fd) < 0 ) { 16 | if ( errno == EEXIST ) { 17 | printf(" create_and_aquire(): file already exists\n"); 18 | return 1 ; // File already exists 19 | } 20 | perror("open failed unexpectedly "); 21 | exit (1); 22 | 23 | } 24 | return 0 ; // Created a new File 25 | } 26 | void remove_lockfile(){ 27 | int r = unlink(lockfile); 28 | if ( r < 0 ) { 29 | perror("RemoveLockfile() failed "); 30 | exit(1); 31 | } 32 | } 33 | void delete_and_release_lock(int fd){ 34 | close(fd); 35 | remove_lockfile(); // cheating 36 | } 37 | int main(){ 38 | int r; 39 | int fd; 40 | int successes=0; 41 | int i; 42 | for (i = 0 ; i < 10 ; i++) { 43 | printf("Attempting:...\n"); 44 | r = create_and_acquire_lock(&fd); 45 | if (r==0) { //successfully created and acquired 46 | printf(" %d %d: Success, Got it! busy now... \n", i, (int) getpid()); 47 | sleep(5); 48 | delete_and_release_lock(fd); 49 | printf(" ..Done\n"); 50 | successes++; 51 | sleep(3); // simulating some fixed time work 52 | 53 | } else { // unsuccessful in creating 54 | printf(" %d %d: **FAILED**\n", i, (int) getpid()); 55 | // retry 56 | int x=random()%3; 57 | sleep(x); // wait for a random time before retrying 58 | } 59 | 60 | } 61 | printf("Succeeded %d out of %d times\n",successes,i); 62 | 63 | } 64 | -------------------------------------------------------------------------------- /files/flocking.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // syntax: int flock(int fd, int operation); 6 | // Valid values for operation are: LOCK_EX , LOCK_SH , LOCK_UN 7 | // return value is -1 if there is an error, 0 otherwise. See man flock(2) 8 | void main(){ 9 | int fd = open("xyz",O_RDONLY); 10 | flock(fd,LOCK_EX); 11 | int pid = getpid(); 12 | for(int i=0;i<9;i++) { 13 | printf("%d is using the lock\n",pid); 14 | for(int j=0;j 2 | #include 3 | 4 | // which test read or write ? 5 | #define DOREADTEST 0 6 | 7 | // for write test use write vs printf ? 8 | #define USEWRITE 0 9 | 10 | // when using printf, do you want to flush after printf before fork? 11 | #define USEFLUSH 1 12 | #define FLUSHCMD fflush(stdout) 13 | 14 | 15 | int forked_read(),forked_write(); 16 | 17 | int main(int argc, char * argv[]){ 18 | if ( DOREADTEST ) 19 | forked_read(); 20 | else 21 | forked_write(); 22 | } 23 | 24 | int forked_read(){ 25 | // check read buffering 26 | int i1; 27 | 28 | printf("Test read buffering\n"); 29 | // read and print first number in the file 30 | FILE * f = fopen("/tmp/myfile","r"); 31 | fscanf(f,"%d ",&i1); 32 | printf("1st integer before fork: %d.. waiting for an enter... \n",i1); 33 | 34 | // wait and then fork 35 | getchar(); 36 | int r = fork(); 37 | 38 | // read the second number from the file and print 39 | fscanf(f,"%d ",&i1); 40 | printf("Next From %d: , %d\n",getpid(),i1); 41 | 42 | fclose(f); 43 | } 44 | 45 | int forked_write(){ 46 | int i1; 47 | // Try with printf vs try with write 48 | if (USEWRITE == 1 ) 49 | write(1,"Test write buffers: before fork().. ",35); 50 | else { 51 | printf("Test printf buffers: flush=%d before fork().. ",USEFLUSH); 52 | if (USEFLUSH) 53 | FLUSHCMD; 54 | } 55 | 56 | // Use without flush and try both printf and write above 57 | 58 | int r = fork(); 59 | if (r == 0 ) { // This is child 60 | printf("From C %d ",getpid()); 61 | sleep(2); // Just to see from Parent first 62 | }else{ 63 | printf("From P %d ",getpid()); 64 | } 65 | printf("\n"); 66 | } 67 | -------------------------------------------------------------------------------- /files/myincludes.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/pipecmd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void main(){ 7 | int p[2]; 8 | if ( pipe(p) < 0 ) { 9 | perror("pipe creation: "); 10 | exit(1); 11 | } 12 | int c=fork(); 13 | // alternately 14 | if ( c == 0 ) { 15 | dup2(p[1],1); // from now on in child 1 is same as p[1] 16 | close(p[0]); // dont need p[0] in child 17 | char string[]="This is the house that jack built"; 18 | printf("%s\n",string); 19 | } else if ( c > 0 ){ 20 | dup2(p[0],0); // from now on in parent 0 is same as p[0] 21 | close(p[1]); // dont need p[1] in parent 22 | char word[100]; 23 | while( scanf("%s",word) != EOF ) 24 | printf("GOT:%s\n",word); 25 | } else 26 | perror("Failed fork:"); 27 | } 28 | -------------------------------------------------------------------------------- /files/readfile.c: -------------------------------------------------------------------------------- 1 | // open the file twice 2 | #include "myincludes.h" 3 | #include 4 | #define CMP_ARGV(I,X) (strcmp(argv[I],X)==0) 5 | void main(int argc, char * argv[]){ 6 | char buf[100]; 7 | char fname[50]="xyz"; 8 | 9 | if (argc > 1) 10 | strcpy(fname,argv[1]); 11 | 12 | int fd1 = open(fname,O_RDONLY); 13 | printf("fd1 is %d\n",fd1); // expect to see 3 14 | 15 | int n = read(fd1,buf,10); 16 | write(1,buf,10); // use write(2) to print to the screen 17 | 18 | close(fd1); 19 | 20 | // The below part shows how file descriptors get allocated: 21 | // Uncomment to see it work 22 | /* 23 | 24 | // close the STDIN 25 | close(0); 26 | // open the same file 27 | fd1 = open(fname,O_RDONLY); 28 | printf("\nfd1 is %d\n",fd1); 29 | 30 | // now try to read from this file 31 | n = read(fd1,buf,10); 32 | write(1,buf,10); 33 | 34 | // Lets try scanf 35 | scanf("%s",buf); 36 | printf("\n%s\n",buf); 37 | 38 | // What is your conclusion ? 39 | */ 40 | 41 | } 42 | -------------------------------------------------------------------------------- /files/redirect.c: -------------------------------------------------------------------------------- 1 | #include "myincludes.h" 2 | #include 3 | #define CMP_ARGV(I,X) (strcmp(argv[I],X)==0) 4 | 5 | void print_help_exit(char * cmd){ 6 | printf("%s [-h|--help] redirect-outfile " 7 | "command-to-execute arg1 arg2 ...\n", 8 | cmd); 9 | exit(0); 10 | } 11 | int check_args(char * argv[]){ 12 | int i=0; 13 | for(i=1;argv[i]!=NULL;i++) { 14 | if (CMP_ARGV(i,"-h") || CMP_ARGV(i,"--help")) { 15 | print_help_exit(argv[0]); 16 | } 17 | } 18 | return i; 19 | } 20 | 21 | void main(int argc, char * argv[]){ 22 | int n = check_args(argv); 23 | if (n < 3 ) 24 | print_help_exit(argv[0]); 25 | char * of=argv[1]; 26 | char * cmd=argv[2]; 27 | char ** newlist=&argv[2]; 28 | // This is to setup redirection 29 | int ofd = open(of,O_WRONLY|O_CREAT,S_IWUSR|S_IRUSR); 30 | if (ofd < 0 ) { 31 | printf("** Open %s failed",of); 32 | exit(1); 33 | } else { 34 | dup2(ofd,1); 35 | } 36 | 37 | execvp(cmd,newlist); 38 | } 39 | -------------------------------------------------------------------------------- /files/repeated_printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define NOFLUSH "noflush" 7 | #define FFLUSH "fflush" 8 | #define SCANF "scanf" 9 | #define GETCHAR "getchar" 10 | 11 | // set FLUSH to be one of the four above 12 | #define FLUSH NOFLUSH 13 | 14 | #define CMP(X,Y) strcmp(X,Y)==0 15 | 16 | // C Langauge buffering.. more experimentation 17 | // It appears the buffered read(scanf getchar etc) sometimes 18 | // causes stdout to be flushed. 19 | 20 | void main(){ 21 | int j; 22 | for(int i=0;i<10;i++) { 23 | // do strace and see what system calls are executed 24 | // does write happen repeatedly? 25 | printf(" %d ,",i); 26 | // Without any of the below flushing ways 0, 1, 2, 3,... 27 | // get printed at the end (see the sleep below) 28 | // different ways to flush: 29 | if ( CMP(FLUSH,FFLUSH) ) { 30 | // This one is the standard way 31 | // Call fflush for event time i%4==0 32 | if (i%4==0) 33 | fflush(stdout); 34 | } else if (CMP(FLUSH,SCANF) ) { 35 | // It so happens that doing a scanf when the 36 | // input buffer is empty also casuses an flushing 37 | // .. give multiple integers here for fun 38 | // .. also for fun give a non integer as input 39 | if (scanf("%d",&j)==EOF) 40 | exit(0); 41 | } else if ( CMP(FLUSH,GETCHAR) ) { 42 | // A getchar too: try multiple characters here for fun 43 | getchar(); 44 | } 45 | sleep(1); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /files/test2_link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #define COMMAND(X) (strcmp(argv[1],X)==0) 10 | int main(int argc, char ** argv){ 11 | 12 | printf("%d\n", argc); 13 | for( int i = 0; i 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | // #define DEBUG 1 10 | 11 | // Small macro to test if argv[1] is X 12 | #define COMMAND(X) (strcmp(argv[1],X)==0) 13 | // future:: COMMAND(i,X) (strcmp(argv[i],X)==0) 14 | 15 | int main(int argc, char ** argv){ 16 | 17 | 18 | // Process arguments - here just printing for fun 19 | #ifdef DEBUG 20 | printf("%d\n", argc); 21 | for( int i = 0; i 4 | #define CMP_ARGV(I,X) (strcmp(argv[I],X)==0) 5 | void withoutdup(){ 6 | char buf[100]; 7 | 8 | // open same file twice 9 | int fd1 = open("xyz",O_RDONLY); 10 | int fd2 = open("xyz",O_RDONLY); 11 | 12 | // read from first fd and print on screen 13 | int n = read(fd1,buf,10); 14 | write(1,buf,10); 15 | 16 | // read from second fd and print on screen 17 | n = read(fd2,buf,10); 18 | write(1,buf,10); 19 | 20 | // they have two different internal structures/information 21 | } 22 | void withdup(){ 23 | char buf[100]; 24 | 25 | // open the file only once 26 | int fd1 = open("xyz",O_RDONLY); 27 | // duplicate the fd ... (NOT open again) 28 | int fd2 = dup(fd1); 29 | 30 | // read using fd1 and print on the screen 31 | int n = read(fd1,buf,10); 32 | write(1,buf,10); 33 | 34 | // read using fd2 and print on the screen 35 | n = read(fd2,buf,10); 36 | write(1,buf,10); 37 | 38 | // the two fds share the same internal structures 39 | } 40 | void main(int argc, char *argv[]){ 41 | if (argc > 1 ) { 42 | if (CMP_ARGV(1,"--nodup") || CMP_ARGV(1,"-n")) 43 | withoutdup(); 44 | } else 45 | withdup(); 46 | } 47 | -------------------------------------------------------------------------------- /files/xyz: -------------------------------------------------------------------------------- 1 | ABCDEFGHIJ1234567890 2 | -------------------------------------------------------------------------------- /ipc/mq-posix/Makefile: -------------------------------------------------------------------------------- 1 | EXECS= mq_ctl 2 | 3 | all: $(EXECS) 4 | 5 | mq_ctl: mq_ctl.c 6 | gcc -o mq_ctl mq_ctl.c -lrt 7 | 8 | clean: 9 | rm -f $(EXECS) a.out 10 | -------------------------------------------------------------------------------- /ipc/mq-posix/README: -------------------------------------------------------------------------------- 1 | ABOUT: 2 | A very simple example to show message queues can be used to trandfer messages 3 | between processes.... unlike pipes which is a stream of data. 4 | 5 | mq_ctl.c : The simple iterative controller program 6 | 7 | 8 | ./mq_ctl : Note that you need to read attrutes ( option 'a' ) 9 | before you can successfully receive ( option 'r' ) 10 | -------------------------------------------------------------------------------- /ipc/mq-posix/mq_ctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define MQ_NAME "/mq-1" 13 | #define MQ_MSGSIZE 1024 14 | #define MQ_MSGCOUNT 10 15 | 16 | char g_msg[50]="hello world A"; 17 | char rcv_buf[MQ_MSGSIZE*2]; 18 | 19 | void print_help(char * argv[]){ 20 | printf("%s [-n] : The optoinal u argument means do not initialize\n",argv[0]); 21 | printf("option: choose from:\n"); 22 | printf(" n open new mq\n"); 23 | printf(" r receive from the mq\n"); 24 | printf(" s send to the mq\n"); 25 | printf(" c close the mq\n"); 26 | printf(" u unlink the mq\n"); 27 | printf(" a howmany messages in the mq\n"); 28 | printf(" h print this help message\n"); 29 | printf(" q quit this program\n"); 30 | } 31 | void main(int argc, char *argv[]){ 32 | mqd_t mq; 33 | mqd_t rmq; 34 | struct mq_attr attr; 35 | attr.mq_msgsize=MQ_MSGSIZE; 36 | attr.mq_maxmsg=MQ_MSGCOUNT; 37 | 38 | int mode=1; // by default initialize 39 | 40 | if (argc > 1 && strcmp(argv[1],"-n")==0){ 41 | printf("Setting uninitialized mode for opening\n"); 42 | mode=0; 43 | } 44 | 45 | printf("My pid is %d\n",getpid()); 46 | printf("Using MQ_NAME for operations is = %s\n",MQ_NAME); 47 | 48 | while(1) { 49 | char options[10]; 50 | scanf("%s",options); 51 | 52 | if (strcmp(options,"q")==0) 53 | exit(0); 54 | 55 | if (strcmp(options,"h")==0){ 56 | print_help(argv); 57 | continue; 58 | } 59 | 60 | if (strcmp(options,"o")==0){ 61 | // create the new shm assuming it doesnt exist 62 | // if it exists, just get an fd to it. Like open() 63 | // use attribs here 64 | 65 | mq= mq_open(MQ_NAME, O_CREAT|O_RDWR,0644,NULL);// struct mq_attr *attr); 66 | if ( (int) mq < 0 ) { 67 | perror("Trying to open mq:"); 68 | exit(1); 69 | } else 70 | printf("Opened mq\n"); 71 | continue; 72 | } 73 | 74 | if (strcmp(options,"r")==0){ 75 | rmq= mq_open(MQ_NAME, O_RDONLY); 76 | if (rmq < 0 ) 77 | perror("open for Receive failed"); 78 | ssize_t n= mq_receive(rmq, rcv_buf, attr.mq_msgsize, NULL); //unsigned int *msg_prio); 79 | close(rmq); 80 | if ( n < 0 ) 81 | perror("Failed in Receive"); 82 | else 83 | printf("Current Message is %d bytes long = %s\n",(int)n,rcv_buf); 84 | continue; 85 | } 86 | 87 | if (strcmp(options,"s")==0){ 88 | rmq= mq_open(MQ_NAME, O_WRONLY); 89 | int r= mq_send(rmq, g_msg,strlen(g_msg)+1, 0 );//unsigned int msg_prio); 90 | close(rmq); 91 | if ( r != 0 ) 92 | perror("Send problem"); 93 | else { 94 | printf("Sent a Message of %d bytes \"%s\"\n",(int)strlen(g_msg)+1,g_msg); 95 | // update the message for next time 96 | g_msg[strlen(g_msg)-1]+=1; 97 | } 98 | continue; 99 | } 100 | if (strcmp(options,"a")==0){ 101 | // Read the number of messages in the queue 102 | if ( mq_getattr(mq, &attr) != 0 ) 103 | perror("Getting attribures"); 104 | else { 105 | printf("Number of messages in the queue: %d\n", (int)attr.mq_curmsgs); 106 | printf("msgsize: %d\n", (int)attr.mq_msgsize); 107 | printf("n_msgs: %d\n", (int)attr.mq_maxmsg); 108 | } 109 | } 110 | // to remove the mq ... 111 | if (strcmp(options,"u")==0) 112 | if ( mq_unlink(MQ_NAME) != 0 ) 113 | perror("unlink failed"); 114 | else 115 | printf("unlinked\n"); 116 | 117 | // to close the mq ... 118 | if (strcmp(options,"c")==0) 119 | if ( mq_close(mq) != 0 ) 120 | perror("close failed"); 121 | else 122 | printf("closed\n"); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ipc/msgque/Makefile: -------------------------------------------------------------------------------- 1 | 2 | EXECS= rd wr ctl 3 | 4 | all: $(EXECS) 5 | 6 | ctl: msg_ctl.c common.h 7 | gcc -o ctl msg_ctl.c 8 | 9 | rd: msg_reader.c common.h 10 | gcc -o rd msg_reader.c 11 | 12 | wr: msg_writer.c common.h 13 | gcc -o wr msg_writer.c 14 | 15 | clean: 16 | rm -f $(EXECS) 17 | -------------------------------------------------------------------------------- /ipc/msgque/README: -------------------------------------------------------------------------------- 1 | ABOUT 2 | Simple message queue illustration 3 | 4 | FILES 5 | common.h : some common definitions 6 | msg_reader.c : to read from a message queue 7 | msg_writer.c : to write to a message queue 8 | msg_ctl.c : simple interface to create remove and print msgq info 9 | RUNNING 10 | ./rd 11 | ./wr 12 | ./msq_ctl -h 13 | -------------------------------------------------------------------------------- /ipc/msgque/common.h: -------------------------------------------------------------------------------- 1 | // Needed for acquiring token via ftok: 2 | #define MYPROJECTPATH "/tmp/blah" 3 | #define MYPROJECTID 6764 4 | 5 | // Message structure definition: 6 | #define MSGSIZE 100 7 | #define TYPEA 1 8 | struct msgbuf { 9 | long mtype; 10 | char mtext[MSGSIZE]; 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /ipc/msgque/msg_ctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "string.h" 8 | #include "common.h" 9 | 10 | 11 | int print_help(char * argv[]){ 12 | printf("%s