├── .gitignore ├── 2020_21 ├── 0_filesystem │ ├── countfiles.c │ ├── filesindir.c │ └── listextension.c ├── 1_processes │ ├── daemon.c │ ├── daemon2.c │ ├── exec.c │ ├── exer2.c │ ├── fork.c │ ├── fork_tree.c │ ├── forkpid.c │ ├── forksup.c │ ├── shell_simulation.c │ ├── simple.c │ ├── simple2.c │ ├── var_sharing.c │ └── zombie.c ├── 2_threads │ ├── pi.c │ ├── pthread_ids.c │ ├── pthread_nojoin.c │ ├── pthread_template.c │ ├── semaphore1.c │ ├── semaphore2.c │ ├── semaphore3.c │ └── semaphore4.c ├── 3_kernel │ ├── Makefile │ ├── Readme.md │ └── helloaxo.c └── 4_memory │ ├── first.c │ └── second.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # VAR 3 | ############### 4 | .ccls-cache 5 | ############### 6 | # C 7 | ############### 8 | # Prerequisites 9 | *.d 10 | 11 | # Object files 12 | *.o 13 | *.ko 14 | *.obj 15 | *.elf 16 | 17 | # Linker output 18 | *.ilk 19 | *.map 20 | *.exp 21 | 22 | # Precompiled Headers 23 | *.gch 24 | *.pch 25 | 26 | # Libraries 27 | *.lib 28 | *.a 29 | *.la 30 | *.lo 31 | 32 | # Shared objects (inc. Windows DLLs) 33 | *.dll 34 | *.so 35 | *.so.* 36 | *.dylib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | *.i*86 43 | *.x86_64 44 | *.hex 45 | 46 | # Debug files 47 | *.dSYM/ 48 | *.su 49 | *.idb 50 | *.pdb 51 | 52 | # Kernel Module Compile Results 53 | *.mod* 54 | *.cmd 55 | .tmp_versions/ 56 | modules.order 57 | Module.symvers 58 | Mkfile.old 59 | dkms.conf 60 | -------------------------------------------------------------------------------- /2020_21/0_filesystem/countfiles.c: -------------------------------------------------------------------------------- 1 | /* Count the Number of Files in a Directory */ 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc != 2) { 7 | printf("Usage: %s \n", argv[0]); 8 | return 1; 9 | } 10 | 11 | DIR *dir = opendir(argv[1]); 12 | if (dir == NULL) { 13 | perror("opendir"); 14 | return 1; 15 | } 16 | 17 | int fileCount = 0; 18 | struct dirent *entry; 19 | while ((entry = readdir(dir)) != NULL) { 20 | if (entry->d_type == DT_REG) { // Check if it's a regular file 21 | fileCount++; 22 | } 23 | } 24 | 25 | printf("Total files in %s: %d\n", argv[1], fileCount); 26 | 27 | closedir(dir); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /2020_21/0_filesystem/filesindir.c: -------------------------------------------------------------------------------- 1 | /* Write a C program that lists all the files and */ 2 | /* directories in a specified directory using readdir and closedir. You */ 3 | /* should provide the name of the directory as a command - */ 4 | /* line argument. */ 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) { 9 | if (argc != 2) { 10 | printf("Usage: %s \n", argv[0]); 11 | return 1; 12 | } 13 | 14 | DIR *dir = opendir(argv[1]); 15 | if (dir == NULL) { 16 | perror("opendir"); 17 | return 1; 18 | } 19 | 20 | struct dirent *entry; 21 | while ((entry = readdir(dir)) != NULL) { 22 | printf("%s\n", entry->d_name); 23 | } 24 | 25 | closedir(dir); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /2020_21/0_filesystem/listextension.c: -------------------------------------------------------------------------------- 1 | /* List Files with a Specific Extension */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) { 8 | if (argc != 3) { 9 | printf("Usage: %s \n", argv[0]); 10 | return 1; 11 | } 12 | 13 | DIR *dir = opendir(argv[1]); 14 | if (dir == NULL) { 15 | perror("opendir"); 16 | return 1; 17 | } 18 | 19 | char *fileExtension = argv[2]; 20 | int extensionLength = strlen(fileExtension); 21 | 22 | struct dirent *entry; 23 | while ((entry = readdir(dir)) != NULL) { 24 | if (entry->d_type == DT_REG) { // Check if it's a regular file 25 | int nameLength = strlen(entry->d_name); 26 | if (nameLength > extensionLength && 27 | strcmp(entry->d_name + nameLength - extensionLength, fileExtension) == 28 | 0) { 29 | printf("%s\n", entry->d_name); 30 | } 31 | } 32 | } 33 | 34 | closedir(dir); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /2020_21/1_processes/daemon.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | pid_t pid1, pid2; 9 | pid1 = fork(); 10 | if (pid1 == 0){ 11 | pid2 = fork(); 12 | if (pid2 == 0){ 13 | while (1) { 14 | printf("Hello\n"); 15 | sleep(1); 16 | } 17 | } 18 | } 19 | else{ 20 | waitpid(pid1, NULL, 0); 21 | printf("Child exited\n"); 22 | } 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /2020_21/1_processes/daemon2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | pid_t pid1, pid2; 8 | pid1 = fork(); 9 | if (pid1 == 0) { 10 | while (1) { 11 | printf("Hello\n"); 12 | sleep(1); 13 | } 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /2020_21/1_processes/exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | // Check if there are any command-line arguments 5 | for (int i = 0; i < argc; i++) { 6 | printf("Argument %d: %s\n", i, argv[i]); 7 | } 8 | 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /2020_21/1_processes/exer2.c: -------------------------------------------------------------------------------- 1 | // printf, scanf 2 | #include 3 | // exit 4 | #include 5 | // pid_t 6 | #include 7 | // posix api, including fork 8 | #include 9 | // for wait 10 | #include 11 | 12 | const int WAIT_ON = 1; 13 | 14 | int main(int argc, char *argv[]) { 15 | pid_t pid1, pid2, pid_tmp; 16 | int somma = 0; 17 | int status; 18 | int tmp; 19 | pid1 = fork(); 20 | printf("pid: %d\n", getpid()); 21 | scanf("%d", &tmp); 22 | if (pid1 == 0) { 23 | // Child 24 | somma++; 25 | printf("[child1] exiting, somma is %d\n", somma); 26 | exit(somma); 27 | } else { 28 | somma++; 29 | pid2 = fork(); 30 | printf("pid: %d\n", getpid()); 31 | scanf("%d", &tmp); 32 | if (pid2 == 0) { 33 | somma++; 34 | printf("[child2] exiting, somma is %d\n", somma); 35 | exit(somma); 36 | } else { 37 | pid_tmp = waitpid(pid1, &status, 0); 38 | printf("pid1 is %d, pid2 is %d\n", pid1, pid2); 39 | printf("[parent] waitpid, pid returned %d\n", pid_tmp); 40 | printf("[parent] pid1 exit code was %d\n", status / 256); 41 | // Try htop without wait 42 | pid_tmp = wait(&status); 43 | printf("[parent] wait, pid returned %d\n", pid_tmp); 44 | printf("[parent] pid1 exit code was %d\n", status / 256); 45 | printf("[parent] exiting, somma is %d\n", somma); 46 | exit(somma); 47 | } 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /2020_21/1_processes/fork.c: -------------------------------------------------------------------------------- 1 | /** 2 | * To show usage of execl and execlp and to show that the process PID does not 3 | * change with exec. 4 | */ 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) { 10 | pid_t pidget = getpid(); 11 | printf("Original process has pid: %d\n", pidget); 12 | // check htop/top after this 13 | // Funziona solo sotto WSL/WSL2 14 | /* execlp("notepad.exe", NULL); */ 15 | /* execlp("ls", "ls", "-l", "--color=always", NULL); */ 16 | execl("./forksup.out", "forksup.out", "do", "i", "wanna", "know", NULL); 17 | printf("Exec error"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /2020_21/1_processes/fork_tree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | printf("%d of %d>A\n", getpid(), getppid()); 6 | fork(); 7 | printf("%d of %d>B\n", getpid(), getppid()); 8 | fork(); 9 | printf("%d of %d>C\n", getpid(), getppid()); 10 | fork(); 11 | printf("%d of %d>D\n", getpid(), getppid()); 12 | sleep(100); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /2020_21/1_processes/forkpid.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple code to show the usage of htop with child processes and the output of 3 | * the getpid, getppid functions. 4 | * You can skip this if you already did simple2 5 | */ 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | pid_t pidfork, pidget; 13 | 14 | pidfork = fork(); 15 | 16 | if (pidfork == 0) { // figlio 17 | sleep(15); 18 | pidget = getpid(); 19 | printf("Child with pid: %d\n", pidget); 20 | } 21 | else { 22 | sleep(15); 23 | pidget = getpid(); 24 | printf("Parent with pid: %d, my child has pid %d\n", pidget, pidfork); 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /2020_21/1_processes/forksup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | pid_t pidget = getpid(); 7 | printf("New binary running with pid %d\n", pidget); 8 | printf("n arguments is %d\n", argc); 9 | for (int i = 0; i < argc; i++) { 10 | printf("Argument %d is %s\n", i, argv[i]); 11 | } 12 | int x; 13 | scanf("%d", &x); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /2020_21/1_processes/shell_simulation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | int main() { 7 | int i; 8 | pid_t pid1; 9 | int status; 10 | char command[128], *argv[128], *pch; 11 | while (1) { 12 | printf("myshell# "); // command prompt 13 | // splits the arguments and saves the pointers in argv[] 14 | fgets(command, 128, stdin); // read user input 15 | pch = strtok(command, " \n"); // parse first argument 16 | for (i = 0; pch != NULL && i < 127; i++) { 17 | argv[i] = pch; 18 | pch = strtok(NULL, " \n"); // arguments parsing 19 | } 20 | argv[i] = NULL; // termina l'array argv con NULL 21 | pid1 = fork(); 22 | if (pid1 == -1) { 23 | perror("Fork failed"); 24 | exit(1); 25 | } 26 | if (pid1 == 0) { 27 | execvp(argv[0], &argv[0]); 28 | perror("Command execution failed"); 29 | exit(EXIT_FAILURE); 30 | } 31 | // This code is executed by the parent process 32 | // else non necessary bcz of exec or exit 33 | pid1 = wait(&status); 34 | /* printf("figlio terminato con codice %d\n", status/256); */ 35 | printf("child terminated with code %d\n", WEXITSTATUS(status)); 36 | } // il processo genitore (shell) torna a leggere un altro command 37 | } 38 | -------------------------------------------------------------------------------- /2020_21/1_processes/simple.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple code to show the usage of htop 3 | */ 4 | #include 5 | 6 | // 7 | int main(int argc, char *argv[]) { 8 | int x; 9 | printf("Hello world\n"); 10 | scanf("%d", &x); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /2020_21/1_processes/simple2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple code to show the usage of htop with child processes and the output of 3 | * the getpid, getppid functions 4 | 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char *argv[]) { 13 | pid_t pid1, pid2; 14 | int ws1, ws2; 15 | 16 | printf("P> Before fork, my PID is %d\n", getpid()); 17 | printf("P> Before fork, my PPID is %d\n", getppid()); 18 | pid1 = fork(); 19 | if (pid1 == 0) { // child 1 20 | printf("C1> PID: %d, PPID: %d\n", getpid(), getppid()); 21 | sleep(50); 22 | exit(1); 23 | } else { // parent 24 | printf("P> after fork1, 1st child PID: %d\n", pid1); 25 | pid2 = fork(); 26 | if (pid2 == 0) { // child 2 27 | printf("C2> PID: %d, PPID: %d\n", getpid(), getppid()); 28 | sleep(45); 29 | exit(2); 30 | } else { // parent 31 | printf("P> after fork2, 2nd child PID: %d\n", pid2); 32 | int rs1 = wait(&ws1); 33 | printf("P> Child %d terminated with status %d\n", rs1, ws1 / 256); 34 | int rs2 = wait(&ws2); 35 | printf("P> Child %d terminated with status %d\n", rs2, ws2 / 256); 36 | } 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /2020_21/1_processes/var_sharing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int globalV; /* A global variable*/ 8 | int main(void) { 9 | int stackV = 0; 10 | int *heapV = (int *)malloc(2 * sizeof(int)); 11 | pid_t childPID = fork(); 12 | *heapV = 0; 13 | if (childPID == 0) { // child process 14 | printf("\n[Child] :: stackV = %d, globalV = %d", stackV, globalV); 15 | stackV++; 16 | globalV++; 17 | printf("\n[Child] :: stackV = %d, globalV = %d", stackV, globalV); 18 | printf("\n[Child] :: heapV :: address = %p, value = %d", heapV, *heapV); 19 | *heapV = 50; 20 | printf("\n[Child] :: heapV :: address = %p, value = %d", heapV, *heapV); 21 | *heapV = 200; 22 | printf("\n[Child] :: heapV :: address = %p, value = %d", heapV, *heapV); 23 | int *heapV2 = (int *)malloc(2 * sizeof(int)); 24 | printf("\n[Child] :: heapV2 :: address = %p", heapV2); 25 | } else { // Parent process 26 | printf("\n[Parent] :: stackV = %d, globalV = %d", stackV, globalV); 27 | stackV = 10; 28 | globalV = 20; 29 | printf("\n[Parent] :: stackV = %d, globalV = %d", stackV, globalV); 30 | printf("\n[Parent] :: heapV :: address = %p, value = %d", heapV, *heapV); 31 | *heapV = 100; 32 | printf("\n[Parent] :: heapV :: address = %p, value = %d", heapV, *heapV); 33 | *heapV = 400; 34 | printf("\n[Parent] :: heapV :: address = %p, value = %d", heapV, *heapV); 35 | int *heapV2 = (int *)malloc(3 * sizeof(int)); 36 | *heapV2 = 3; 37 | printf("\n[Parent] :: heapV2 :: address = %p", heapV2); 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /2020_21/1_processes/zombie.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | while (1) { 6 | printf("Press Enter to execute ls"); 7 | while (getchar() != '\n') 8 | ; 9 | if (!fork()) { 10 | sleep(10); 11 | /* printf("child\n"); */ 12 | execlp("ls", "ls", NULL); 13 | } /* else { */ 14 | /* printf("father\n"); */ 15 | /* } */ 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /2020_21/2_threads/pi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /*Number of points*/ 10 | unsigned int num_points = 0; 11 | 12 | /*Number of threads*/ 13 | unsigned int num_threads = 0; 14 | 15 | /*Points inside the circle*/ 16 | unsigned int inside_points = 0; 17 | 18 | /*Mutex */ 19 | // Only 1 thread at a time can update the global result 20 | pthread_mutex_t mutex; 21 | 22 | /** 23 | * Check if some random points are inside or outside a loop with radius 1 24 | * @param data is the index identifying the thread 25 | */ 26 | void *check_points(void *data) { 27 | /* The index of the current thread */ 28 | unsigned int index = *((unsigned int *)data); 29 | unsigned int seed = index; 30 | 31 | /* The number of points to be examined by this thread */ 32 | unsigned int num_points_per_thread = 33 | num_points / num_threads + (index < num_points % num_threads ? 1 : 0); 34 | unsigned int i; 35 | unsigned int local_count = 0; 36 | /* The core of the application */ 37 | for (i = 0; i < num_points_per_thread; i++) { 38 | double x = (double)rand_r(&seed) / (double)RAND_MAX; 39 | double y = (double)rand_r(&seed) / (double)RAND_MAX; 40 | fprintf(stdout, "Thread %d - Point %f %f\n", index, x, y); 41 | if (x * x + y * y <= 1) 42 | local_count++; 43 | } 44 | fprintf(stdout, "Thread %d - Inside points %d/%d\n", index, local_count, 45 | num_points_per_thread); 46 | fflush(stdout); 47 | 48 | /* Lock and update global result */ 49 | pthread_mutex_lock(&mutex); 50 | inside_points += local_count; 51 | pthread_mutex_unlock(&mutex); 52 | return 0; 53 | } 54 | 55 | /* To suppress stdout */ 56 | int supress_stdout() { 57 | fflush(stdout); 58 | 59 | int ret = dup(1); 60 | int nullfd = open("/dev/null", O_WRONLY); 61 | // check nullfd for error omitted 62 | dup2(nullfd, 1); 63 | close(nullfd); 64 | 65 | return ret; 66 | } 67 | 68 | /* To resume stdout */ 69 | void resume_stdout(int fd) { 70 | fflush(stdout); 71 | dup2(fd, 1); 72 | close(fd); 73 | } 74 | 75 | int main(int argc, char **argv) { 76 | if (argc != 3) { 77 | fprintf(stdout, "Wrong number of parameters\n"); 78 | return 0; 79 | } 80 | /* The number of points */ 81 | num_points = (unsigned int)atoi(argv[1]); 82 | fprintf(stdout, "Number of points is %d\n", num_points); 83 | 84 | /* The number of threads */ 85 | num_threads = (unsigned int)atoi(argv[2]); 86 | 87 | /* Thread data structure */ 88 | pthread_t threads[num_threads]; 89 | unsigned int indexes[num_threads]; 90 | 91 | /*Initialize the mutex*/ 92 | pthread_mutex_init(&mutex, NULL); 93 | 94 | /* Create the threads */ 95 | unsigned int index; 96 | /* To suppress stdout when # of threads is high and printf causes a lot of 97 | overhead. Comment this line (and the resume one) if you want to see the 98 | stdout generated by the other threads. */ 99 | int saved_stdout = supress_stdout(); 100 | 101 | for (index = 0; index < num_threads; index++) { 102 | indexes[index] = index; 103 | pthread_create(&threads[index], NULL, check_points, 104 | (void *)&indexes[index]); 105 | } 106 | for (index = 0; index < num_threads; index++) { 107 | pthread_join(threads[index], NULL); 108 | } 109 | /* Restore stdout */ 110 | resume_stdout(saved_stdout); 111 | 112 | /* Compute the final result */ 113 | double pi = (4.0 * inside_points) / num_points; 114 | fprintf(stdout, "Computed pi is %f\n", pi); 115 | 116 | /* Deallocate structures */ 117 | pthread_mutex_destroy(&mutex); 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /2020_21/2_threads/pthread_ids.c: -------------------------------------------------------------------------------- 1 | /** 2 | * To show the values of the different IDs 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void *tf(void *args) { 12 | // To comply to POSIX standard, getpid returns PPID, gettid returns PID 13 | printf("pid is %u, tid is %lu\n", getpid(), syscall(SYS_gettid)); 14 | // From htop, observe the PID and PPID values while the threads are sleeping. 15 | // Suggestion: use ctrl-S to freeze the output of the shell (and hence of 16 | // htop), ctrl-Q to resume it. 17 | sleep(5); 18 | return NULL; 19 | } 20 | 21 | int main(int argc, char *argv[]) { 22 | pthread_t pts[3]; 23 | for (int i = 0; i < 3; i++) { 24 | pthread_create(&pts[i], NULL, &tf, NULL); 25 | } 26 | for (int i = 2; i >= 0; i--) { 27 | pthread_join(pts[i], NULL); 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /2020_21/2_threads/pthread_nojoin.c: -------------------------------------------------------------------------------- 1 | /** 2 | * To show how all the threads die if main thread dies 3 | */ 4 | #include 5 | #include 6 | /* for sleep */ 7 | #include 8 | 9 | void * fun(void * arg) { 10 | sleep(1); 11 | printf("exiting fun\n"); 12 | return NULL; 13 | } 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | pthread_t td1, td2; 18 | pthread_create(&td1, NULL, fun, NULL); 19 | pthread_create(&td2, NULL, fun, NULL); 20 | //no join, main exit, child dies 21 | printf("exiting main\n"); 22 | return 0; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /2020_21/2_threads/pthread_template.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Template for threads usage 3 | */ 4 | #include 5 | #include 6 | #include 7 | 8 | int glob_counter = 0; 9 | 10 | void *tf(void *tid); 11 | 12 | int main(int argc, char *argv[]) { 13 | pthread_t t1, t2; 14 | /* 2nd: thread attributes (NULL for default). A thread can be joinable (return 15 | * an exit status) or detached. 16 | 17 | * 4th: argument of funcs. If more than one you have to create a struct. It 18 | * must be passed by reference as a pointer cast of type void. 19 | */ 20 | int arg_fun1 = 1; 21 | pthread_create(&t1, NULL, tf, &arg_fun1); 22 | int arg_fun2 = 2; 23 | pthread_create(&t2, NULL, tf, &arg_fun2); 24 | 25 | void *ret_val; 26 | /* 27 | * 2nd: contains the copy of the argument of pthread_exit invoked by the child 28 | * thread 29 | */ 30 | pthread_join(t1, &ret_val); 31 | printf("t1 ret_ret_val is %d\n", *(int *)ret_val); 32 | pthread_join(t2, &ret_val); 33 | printf("t2 ret_ret_val is %d\n", *(int *)ret_val); 34 | return 0; 35 | } 36 | 37 | void *tf(void *tid) { 38 | // local variables, change visibles only by 3ds 39 | printf("tf from %d\n", *(int *)tid); 40 | int counter = 0; 41 | counter++; 42 | // global var changes are visible by all threads. However, if no further 43 | // measure is taken, consistency is not ensured. Here the access is not 44 | // protected by anything (like a mutex or semaphore) 45 | glob_counter++; 46 | // static var, acts as a global var, but it has local visibility. Changes are 47 | // shared among threads. 48 | static int static_counter = 0; 49 | static_counter++; 50 | printf("Here's thread number %d, local counter is %d, global counter is %d, " 51 | "static counter is %d\n", 52 | *(int *)tid, counter, glob_counter, static_counter); 53 | 54 | int *ret_val = (int *)malloc(1 * sizeof(int)); 55 | printf("Here\n"); 56 | if (*(int *)tid == 1) { 57 | *ret_val = 1; 58 | } else { 59 | *ret_val = -1; 60 | } 61 | return (void *)ret_val; 62 | } 63 | -------------------------------------------------------------------------------- /2020_21/2_threads/semaphore1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | sem_t sem1; 7 | 8 | void *tf1(void *arg) { 9 | int val; 10 | // wait until the value of sem1 > 0; after wait, sem1.value-- 11 | sem_wait(&sem1); 12 | // when we are here, we may not be the only one; sems are not necessarily binary 13 | sem_getvalue(&sem1, &val); 14 | printf("from tf1, pid %lu, sem is %d\n", pthread_self(), val); 15 | // sem1.value++; notify all 16 | sem_post(&sem1); 17 | return 0; 18 | } 19 | 20 | int main(int argc, char *argv[]) { 21 | pthread_t td1, td2, td3, td4; 22 | // semaphore; 0 for sharing b/w threads, non-zero b/w processes; init value 23 | sem_init(&sem1, 0, 2); 24 | pthread_create(&td1, NULL, &tf1, NULL); 25 | pthread_create(&td2, NULL, &tf1, NULL); 26 | pthread_create(&td3, NULL, &tf1, NULL); 27 | pthread_create(&td4, NULL, &tf1, NULL); 28 | pthread_join(td1, NULL); 29 | pthread_join(td2, NULL); 30 | pthread_join(td3, NULL); 31 | pthread_join(td4, NULL); 32 | sem_destroy(&sem1); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /2020_21/2_threads/semaphore2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | sem_t sem1, sem2; 7 | 8 | void *print1(void *args) { 9 | printf("a"); 10 | sem_post(&sem1); 11 | sem_wait(&sem2); 12 | printf("b"); 13 | sem_post(&sem1); 14 | sem_wait(&sem2); 15 | printf("c"); 16 | sem_post(&sem1); 17 | 18 | return (void *)1; 19 | } 20 | 21 | void *print2(void *args) { 22 | sem_wait(&sem1); 23 | printf("1"); 24 | sem_post(&sem2); 25 | sem_wait(&sem1); 26 | printf("2"); 27 | sem_post(&sem2); 28 | sem_wait(&sem1); 29 | printf("3"); 30 | 31 | return (void *)2; 32 | } 33 | 34 | int main(int argc, char *argv[]) { 35 | pthread_t td1, td2; 36 | sem_init(&sem1, 0, 0); 37 | sem_init(&sem2, 0, 0); 38 | pthread_create(&td1, NULL, &print1, NULL); 39 | pthread_create(&td2, NULL, &print2, NULL); 40 | int rval1, rval2; 41 | pthread_join(td1, (void *)&rval1); 42 | pthread_join(td2, (void *)&rval2); 43 | printf("\nrval1 %d rval2 %d\n", rval1, rval2); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /2020_21/2_threads/semaphore3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | char buffer; 8 | sem_t empty, full; 9 | 10 | void * readd(void * args) { 11 | int * reps = (int *) args; 12 | for(int i = 0; i < *reps; i++) { 13 | printf("R: i %d\n", i); 14 | sem_wait(&full); 15 | printf("buffer %c\n", buffer); 16 | sem_post(&empty); 17 | } 18 | return NULL; 19 | } 20 | 21 | void * writee(void * args) { 22 | int * reps = (int *) args; 23 | for(int i = 0; i < *reps; i++) { 24 | printf("W: i %d\n", i); 25 | sem_wait(&empty); 26 | buffer = 'a' + (i % 26); 27 | sem_post(&full); 28 | } 29 | return NULL; 30 | } 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | sem_init(&empty, 0, 1); 35 | sem_init(&full, 0, 0); 36 | pthread_t td1, td2; 37 | int tot = 10; 38 | pthread_create(&td1, NULL, &readd, &tot); 39 | pthread_create(&td2, NULL, &writee, &tot); 40 | pthread_join(td1, NULL); 41 | pthread_join(td2, NULL); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /2020_21/2_threads/semaphore4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | sem_t sem1, sem2; 7 | /* 8 | * In response to: "What happens when a semaphore is not initialized?" 9 | */ 10 | int main(int argc, char *argv[]) 11 | { 12 | int val1, val2; 13 | sem_init(&sem2, 0, 2); 14 | sem_getvalue(&sem1, &val1); 15 | sem_getvalue(&sem2, &val2); 16 | // sem1: val1 is 0, but sem1 is null 17 | // sem2: val2 is 2, but sem2 is initialized (though not printable) 18 | printf("%d %d\n", val1, val2); 19 | printf("%s %s\n", sem1, sem2); 20 | // val1 increased, sem1 still null 21 | sem_post(&sem1); 22 | sem_getvalue(&sem1, &val1); 23 | printf("%d\n", val1); 24 | printf("%s\n", sem1); 25 | sem_wait(&sem1); 26 | printf("%d\n", val1); 27 | printf("%s\n", sem1); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /2020_21/3_kernel/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := helloaxo.o 2 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 3 | # KERNELDIR ?= /lib/modules/5.9.9-arch1-1/build 4 | PWD := $(shell pwd) 5 | # EXTRAVERSION=-arch1-1 6 | 7 | all: 8 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 9 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 10 | 11 | build: 12 | # $(MAKE) EXTRAVERSION=$(EXTRAVERSION) --debug=v -C $(KERNELDIR) M=$(PWD) modules 13 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 14 | 15 | clean: 16 | $(MAKE) -C $(KERNELDIR) M=$(PWD) clean 17 | -------------------------------------------------------------------------------- /2020_21/3_kernel/Readme.md: -------------------------------------------------------------------------------- 1 | # Build instructions 2 | * Bisogna avere installato nel proprio sistema il pacchetto `linux-headers` 3 | * Non funziona su ambienti emulati (come WSL) 4 | 5 | Per generare il modulo: 6 | * `sudo make modules_install` 7 | Per installare il modulo 8 | * `sudo modprobe helloaxo.ko` 9 | 10 | Per generale il modulo localmente, senza inserirlo in nessun percorso conosciuto da `modprobe`: 11 | * `make modules` 12 | 13 | Per osservare il modulo una volta aggiunto dinamicamente con `modprobe` invocare `dmesg`. 14 | -------------------------------------------------------------------------------- /2020_21/3_kernel/helloaxo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | MODULE_LICENSE("GPL"); 7 | MODULE_AUTHOR("Simone Perriello"); 8 | MODULE_DESCRIPTION("A simple example Linux module."); 9 | MODULE_VERSION("0.01"); 10 | 11 | static void 12 | task_explore(void) { 13 | struct task_struct *ts; 14 | int pid, tgid; 15 | void *vstack; 16 | 17 | struct thread_struct tds; 18 | unsigned long vsp, vsp0, usp; 19 | 20 | ts = get_current(); 21 | pid = ts->pid; 22 | tgid = ts->tgid; 23 | printk(KERN_INFO "PID %d\n", pid, tgid); 24 | vstack = ts->stack; 25 | printk(KERN_INFO "vstack is %p\n", vstack); 26 | 27 | tds = ts->thread; 28 | vsp = tds.sp; 29 | printk(KERN_INFO "sp = %lu\n", vsp); 30 | 31 | // Not working on recent Linux kernels 32 | /* vsp0 = tds.sp0; */ 33 | /* printk(KERN_INFO "sp0 = %lu\n", vsp0); */ 34 | /* usp = tds.usersp; */ 35 | /* printk(KERN_INFO "up = %lu\n", usp); */ 36 | } 37 | 38 | static int __init axo_init(void) { 39 | // KERN_INFO is a flag to declare logging priority (note comma absence) 40 | printk(KERN_INFO "Inserted module axo\n"); 41 | task_explore(); 42 | return 0; 43 | } 44 | 45 | static void __exit axo_exit(void) { 46 | printk("Removed module axo\n"); 47 | printk("Bye\n"); 48 | } 49 | 50 | module_init(axo_init); 51 | module_exit(axo_exit); 52 | -------------------------------------------------------------------------------- /2020_21/4_memory/first.c: -------------------------------------------------------------------------------- 1 | #include 2 | /* #include "long_code.c" //questa funzione occupa circa 3 pagine di codice */ 3 | #define PAGE_SIZE 4096 4 | long unsigned pointer; 5 | int main() { 6 | pointer = &main; 7 | printf("NPV of main %12.12lx \n", pointer/ PAGE_SIZE); 8 | pointer = &printf; 9 | printf("NPV of printf %12.12lx \n", pointer/ PAGE_SIZE); 10 | //long_code(); commentato nella prima prova 11 | /* VIRTUAL_AREAS; */ 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /2020_21/4_memory/second.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Print some addresses that falls into the different VMA segments shown during 3 | * the lectures. 4 | * Compile the program using gcc -o programName sourceCode.c -lpthread 5 | * Run the program as setarch `uname -m` -R ./programName 6 | * to temporarily disable ASLR. 7 | * 8 | * While the program is running, call cat /proc/NN/maps from another shell to 9 | * see the mappings inside the OS 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // global variables, one initialized, the other not 18 | int our_init_data = 30; 19 | int our_noinit_data; 20 | 21 | void *donothing(void* arg) { 22 | int thread_local = 1; 23 | printf("\n ?) Thread segment (T) = %p\n", &thread_local); 24 | while (1) 25 | ; 26 | } 27 | 28 | void our_prints(void) { 29 | int our_local_data = 1; 30 | int* ptr = (int*) malloc(sizeof(int)); 31 | pthread_t t1; 32 | pthread_create(&t1, NULL, donothing, NULL); 33 | printf("\nPid of the process is = %d", getpid()); 34 | printf("\nAddresses which fall into:"); 35 | printf("\n 1) Code segment (C) = %p", &our_prints); 36 | printf("\n 2) Data segment (S) = %p", &our_init_data); 37 | printf("\n 3) BSS segment (inside D) = %p", &our_noinit_data); 38 | printf("\n 5) Heap segment (D) = %p", ptr); 39 | printf("\n 6) Memory mapping segment (M) = %p", &printf); 40 | printf("\n 7) Stack segment (P) = %p\n", &our_local_data); 41 | 42 | printf("At this point, you can execute, on another shell\n"); 43 | printf("cat /proc/%d/maps\n", getpid()); 44 | pthread_join(t1, NULL); 45 | 46 | while (1) ; 47 | } 48 | 49 | int main() { 50 | our_prints(); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACSO 2 | Codice relativo alle esercitazioni di ACSO 3 | --------------------------------------------------------------------------------