18. Example Program hello.c int a = 5; // Stored in data section int b[20]; // Stored in bss int main() { // Stored in text int x; // Stored in stack int *p =(int*) malloc(sizeof(int)); //In heap }
19.
20.
21.
22.
23.
24. Building a Program Programmer C Preprocessor Compiler(cc) Optimizer Assembler (as) (static) Linker (ld) Editor hello.c hello.i hello.s hello.o Executable File (hello) Other .o files Static libraries (.a files) They add to the size of the executable. Shared Libraries (.so files). Only definitions. It does not add to size of executable.
32. Loading a Program Loader (runtime linker) (/usr/lib/ld.so.1) Executable File Executable in memory Shared libraries (.so, .dll)
33.
34.
35.
36. Ways to get a pointer value 2. Get memory address from another variable: int *p; int buff[ 30]; p = &buff[1]; *p =78; buff[0]:100: buff[1]:104: buff[29]:216: 220: P: 96: 104 78
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54. An Array Mapper typedef void (*FuncPtr)(int a); void intArrayMapper( int *array, int n, FuncPtr func ) { for( int = 0; i < n; i++ ) { (*func)( array[ i ] ); } } int s = 0; void sumInt( int val ){ s += val; } void printInt( int val ) { printf("val = %d ", val); }
55. Using the Array Mapper int a[ ] = {3,4,7,8}; main( ){ // Print the values in the array intArrayMapper(a, sizeof(a)/sizeof(int), printInt); // Print the sum of the elements in the array s = 0; intArrayMapper(a, sizeof(a)/sizeof(int), sumInt); printf(“total=%d, s); }
56. A More Generic Mapper typedef void (*GenFuncPtr)(void * a); void genericArrayMapper( void *array, int n, int entrySize, GenFuncPtr fun ) { for( int i = 0; i < n; i++; ){ void *entry = (void*)( (char*)array + i*entrySize ); (*fun)(entry); } }
57. Using the Generic Mapper void sumIntGen( void *pVal ){ //pVal is pointing to an int //Get the int val int *pInt = (int*)pVal; s += *pInt; } void printIntGen( void *pVal ){ int *pInt = (int*)pVal; printf("Val = %d ", *pInt); }
58. Using the Generic Mapper int a[ ] = {3,4,7,8}; main( ) { // Print integer values s = 0; genericArrayMapper( a, sizeof(a)/sizeof(int), sizeof(int), printIntGen); // Compute sum the integer values genericArrayMapper( a, sizeof(a)/sizeof(int), sizeof(int), sumIntGen); printf(“s=%d”, s); }
93. Types of Interrupts 4. Software Interrupt generated by software with a special assembly instruction. This is how a program running in user mode requests operating systems services.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103. System Calls and Interrupts Example 4. The OS tells the hard drive to write the buffer in [buff, buff+n] to disk to the file specified by fd. 5. The OS puts the current process in wait state until the disk operation is complete. Meanwhile, the OS switches to another process. 6. The Disk completes the write operation and generates an interrupt. 7. The interrupt handler puts the process calling write into ready state so this process will be scheduled by the OS in the next chance.
157. The Open File Table Open File Table 0 1 2 3 4 . . 31 Open File Object I-NODE Open Mode Offset Reference Count
158.
159.
160.
161.
162.
163.
164.
165. The fork() system call Open File Object Ref count=1 Open FileTable (parent)_ Ref count=1 Ref count=1 Before: 0 1 2 3
166. The fork() system call Open File Object Ref count=2 Open FileTable (parent) Ref count=2 Ref count=2 After: 0 1 2 3 Open FileTable (child) 0 1 2 3
167.
168.
169.
170.
171.
172. The dup2() system call Open File Object Shell Console Ref count=3 File “myout” Ref count=1 Before: 0 1 2 3 Example: redirecting stdout to file “myfile” previously created.
173.
174.
175.
176. The dup() system call Open File Object Shell Console Ref count=3 Before: 0 1 2 3
177. The dup() system call Open File Object Shell Console Ref count=4 After fd2 = dup(1) 0 1 2 3 fd2 == 3
178.
179. The pipe system call Open File Objects Shell Console Ref count=3 Before: 0 1 2 3
180. The pipe system call Open File Objects Shell Console Ref count=3 After running: int fdpipe[2]; pipe(fdpipe); 0 1 2 3 4 pipe0 Ref count=1 Pipe1 Ref count=1 fdpipe[0]==3 fdpipe[1]==4 What is written in fdpipe[0] can be read from fdpipe[1] and vice versa.
181.
182. Example of pipes and redirection // fork for "ls” int ret= fork(); if(ret==0) { // close file descriptors // as soon as are not // needed close(fdpipe[1]); char * args[3]; args[0]="ls"; args[1]=“-al"; args[2]=NULL; execvp(args[0], args); // error in execvp perror("execvp"); exit(1); } //redirection for "grep“ //redirect stdin dup2(fdpipe[1], 0); close(fdpipe[1]); //create outfile int fd=open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0600); if (fd < 0){ perror("open"); exit(1); } //redirect stdout dup2(fd,1); close(fd);
183. Example of pipes and redirection // fork for “grep” ret= fork(); if(ret==0) { char * args[2]; args[0]=“grep"; args[1]=argv[1]; args[2]=NULL; execvp(args[0], args); // error in execvp perror("execvp"); exit(1); } // Restore stdin/stdout dup2(tempin,0); dup2(tempout,1); // Parent waits for grep // process waitpid(ret,NULL); printf(“All done!!”); } // main
184.
185. Execution Strategy for Your Shell execute(){ //save in/out int tmpin=dup(0); int tmpout=dup(1); //set the initial input int fdin; if (infile) { fdin = open(infile,……); } else { // Use default input fdin=dup(tmpin); } int ret; int fdout; for(i=0;i<numsimplecommands; i++) { //redirect input dup2(fdin, 0); close(fdin); //setup output if (i == numsimplecommands-1){ // Last simple command if(outfile){ fdout=open(outfile,……); } else { // Use default output fdout=dup(tmpout); } }
186. Execution Strategy for Your Shell else { // Not last //simple command //create pipe int fdpipe[2]; pipe(fdpipe); fdout=fdpipe[0]; fdin=fdpipe[1]; }// if/else // Redirect output dup2(fdout,1); close(fdout); // Create child process ret=fork(); if(ret==0) { execvp(scmd[i].args[0], scmd[i].args); perror(“execvp”); exit(1); } } // for
187. Execution Strategy for Your Shell //restore in/out defaults dup2(tmpin,0); dup2(tmpout,1); close(tmpin); close(tmpout); if (!background) { // Wait for last command waitpid(ret, NULL); } } // execute
188.
189.
190.
191. Implementing Wildcards in Shell void expandWildcardsIfNecessary(char * arg) { // Return if arg does not contain ‘*’ or ‘?’ if (arg has neither ‘*’ nor ‘?’ (use strchr) ) { Command::_currentSimpleCommand->insertArgument(arg); return; }
192. Implementing Wildcards in Shell // 1. Convert wildcard to regular expression // Convert “*” -> “.*” // “?” -> “.” // “.” -> “” and others you need // Also add ^ at the beginning and $ at the end to match // the beginning ant the end of the word. // Allocate enough space for regular expression char * reg = (char*)malloc(2*strlen(arg)+10); char * a = arg; char * r = reg; *r = ‘^’; r++; // match beginning of line while (*a) { if (*a == ‘*’) { *r=‘.’; r++; *r=‘*’; r++; } else if (*a == ‘?’) { *r=‘.’ r++;} else if (*a == ‘.’) { *r=‘’; r++; *r=‘.’; r++;} else { *a=*r; r++;} a++; } *r=‘$’; r++; *r=0;// match end of line and add null char
193. Implementing Wildcards in Shell // 2. compile regular expression char * expbuf = compile( reg, 0, 0 ); if (expbuf==NULL) { perror(“compile”); return; } // 3. List directory and add as arguments the entries // that match the regular expression DIR * dir = opendir(“.”); if (dir == NULL) { perror(“opendir”); return; }
194. Implementing Wildcards in Shell struct dirent * ent; while ( (ent = readdir(dir))!= NULL) { // Check if name matches if (advance(ent->d_name, expbuf) ) { // Add argument Command::_currentSimpleCommand-> insertArgument(strdup(ent->d_name)); } closedir(dir); } Note: This code is not complete and contains errors. The purpose of this code is only to guide your implementation.
195.
196. Sorting Directory Entries struct dirent * ent; int maxEntries = 20; int nEntries = 0; char ** array = (char**) malloc(maxEntries*sizeof(char*)); while ( (ent = readdir(dir))!= NULL) { // Check if name matches if (advance(ent->d_name, expbuf) ) { if (nEntries == maxEntries) { maxEntries *=2; array = realloc(array, maxEntries*sizeof(char*)); assert(array!=NULL); } array[nEntries]= strdup(ent->d_name); nEntries++; } }
197. Sorting Directory Entries closedir(dir); sortArrayStrings(array, nEntries); // Add arguments for (int i = 0; i < nEntries; i++) { Command::_currentSimpleCommand-> insertArgument(array[i])); } free(array);
198.
199. Wildcards and Hidden Files if (advance (…) ) { if (ent->d_name[0] == ‘.’) { if (arg[0] == ‘.’) add filename to arguments; } } else { add ent->d_name to arguments } }
203. Subdirectory Wildcards #define MAXFILENAME 1024 void expandWildcard(char * prefix, char *suffix) { if (suffix[0]== 0) { // suffix is empty. Put prefix in argument. … ->insertArgument(strdup(prefix)); return; } // Obtain the next component in the suffix // Also advance suffix. char * s = strchr(suffix, ‘/’); char component[MAXFILENAME]; if (s!=NULL){ // Copy up to the first “/” strncpy(component,suffix, s-suffix); suffix = s + 1; } else { // Last part of path. Copy whole thing. strcpy(component, suffix); suffix = suffix + strlen(suffix); }
204. Subdirectory Wildcards // Now we need to expand the component char newPrefix[MAXFILENAME]; if ( component does not have ‘*’ or ‘?’) { // component does not have wildcards sprintf(newPrefix,”%s/%s”, prefix, component); expandWildcard(newPrefix, suffix); return; } // Component has wildcards // Convert component to regular expression char * expbuf = compile(…) char * dir; // If prefix is empty then list current directory if (prefix is empty) dir =“.”; else dir=prefix; DIR * d=opendir(dir); if (d==NULL) return;
205. Subdirectory Wildcards // Now we need to check what entries match while (( ent = readdir(d))!= NULL) { // Check if name matches if (advance(ent->d_name, expbuf) ) { // Entry matches. Add name of entry // that matches to the prefix and // call expandWildcard(..) recursively sprintf( newPrefix,”%s/%s”, prefix, ent->d_name); expandWildcard(newPrefix,suffix); } } close(d); }// expandWildcard
222. Example of Problems with Synchronization // Global counter int counter = 0; void increment_loop(int max){ for(int i=0;i<max;i++){ int tmp = counter; tmp=tmp+1; counter=tmp; } }
223. Example of Problems with Synchronization int main(){ pthread_t t1,t2; pthread_create(&t1,NULL, increment_loop,10000000); pthread_create(&t2,NULL, increment_loop,10000000); //wait until threads finish pthread_join(&t1); pthread_join(&t2); printf(“counter total=%d”,counter); }
224.
225. Example of Problems with Synchronization int counter = 0; void increment_loop(int max){ for(int i=0;i<max;i++){ a)int tmp= counter; b)tmp=tmp+1; c)counter=tmp; } } T2 int counter = 0; void increment_loop(int max){ for(int i=0;i<max;i++){ a)int tmp = counter; b)tmp=tmp+1; c)counter=tmp; } } T1
226. Example of Problems with Synchronization time T1 T2 T0 (main) for(…) a)tmp1=counter (tmp1=0) (Context switch) Join t1 (wait) Starts running a)tmp2=counter (tmp2=0) b)tmp2=tmp2+1 c)counter=tmp2 Counter=1 a)b)c)a)b)c)… Counter=23 (context switch) b)tmp1=tmp1+1 c)counter=tmp1 Counter=1
227.
228.
229.
230. Example of Mutex Locks #include <pthread.h> int counter = 0; // Global counter pthread_mutex_t mutex; void increment_loop(int max){ for(int i=0;i<max;i++){ pthread_mutex_lock(&mutex); int tmp = counter; tmp=tmp+1; counter=tmp; pthread_mutex_unlock(&mutex); } } Threads
231. Example of Mutex Locks int main(){ pthread_t t1,t2; pthread_mutex_init(&mutex,NULL); pthread_create(&t1,NULL, increment,10000000); pthread_create(&t2,NULL, increment,10000000); //wait until threads finish pthread_join(&t1); pthread_join(&t2); printf(“counter total=%d”,counter); }
241. Spin Locks int lock = 0; void spinlock(int * lock) { while (test_and_set(&lock) != 0) { // Give up CPU thr_yield(); } } void spinunlock(int*lock){ *lock = 0; }
242. Example of Spin Locks #include <pthread.h> int counter = 0; // Global counter int m = 0; void increment_loop(int max){ for(int i=0;i<max;i++){ spin_lock(&m); a) int tmp = counter; b) tmp=tmp+1; c) counter=tmp; spin_unlock(&m); } }
243. Spin Locks Example T1 T2 T0 for(…) spin_lock(&m) while (test_and_set(&m)) oldval=0 (m=1)break while a) (Context switch) Join t1 Join t2 (wait) Starts running spin_lock(&m) while (test_and_set(&m)) ->oldval=1 (m==1)continue in while thr_yield()(context switch) b)c) Counter=1 spin_unlock(&m) m=0 while (test_and_set(&m)) -> oldval=0 Break while a) b) c)