├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── avx512.c ├── ch02 ├── clock_gettime.c ├── clock_gettime_loop.c ├── makefile ├── memory_layout.c ├── pointer.c ├── pointer1.c ├── rdtsc.c └── table.c ├── ch03 ├── clock_gettime.c ├── hello.c ├── makefile ├── malloc.c ├── malloc2.c ├── malloc3.c ├── mmfile.c ├── pointer.c ├── rdtscp.c └── table.c ├── ch04 ├── flock.c ├── hole.c ├── lockf.c ├── makefile ├── mmap_cp.c ├── mycp1.c ├── mycp2.c ├── perror.c ├── sync.c ├── syncDataOnly.c ├── syncNone.c ├── system-programming.txt ├── testMandatory.sh └── vio.c ├── ch05 ├── append+fseek.c ├── feof.c ├── fileper_TC.c ├── fileperf.c ├── fopen.c ├── fprintf.c ├── hello_cht.c ├── makefile ├── mktemp.c ├── setvbuf.c ├── strlen.c ├── system-programming.txt ├── wcslen.c └── write+read.c ├── ch06 ├── README ├── change.c ├── chmod.c ├── chowngrp2root.c ├── dir.c ├── dir2.c ├── dir3.c ├── getresuid.c ├── gettime.c ├── hw5.c ├── inotify.c ├── link.c ├── listDirRec.c ├── list_acl.c ├── list_acl_simple.c ├── listattr.c ├── makefile ├── name2id.c ├── rename.c └── watchFile.c ├── ch08 ├── atexit.c ├── cpu_set.c ├── echo.c ├── getEnv.c ├── listEnv.c ├── makefile ├── myNice.c ├── on_exit.c └── vfork8.c ├── ch09 ├── NoZombie.c ├── _myShell.c ├── debugFork1.c ├── debugFork2.c ├── fork1.c ├── fork2.c ├── makefile ├── manyFork.c ├── manyVFork.c ├── myShell.c ├── testDebug.c ├── testStack.c ├── wait.c └── zombie.c ├── ch10 ├── list_sig.c ├── makefile ├── myShell.c ├── myshell2.c ├── rec_sig.c ├── seg_fault.c ├── seg_fault2.c ├── seg_fault_recover.c ├── send_sig.c ├── setjmp_longjmp.c ├── shell_sigfd.c ├── sigprocmask.c ├── sigwait.c ├── testStack2.c └── test_sig.c ├── ch11 ├── fifo1.c ├── fifo2-r.c ├── fifo2-w.c ├── makefile ├── pipe-perf.c ├── pipe-perf2.c ├── pipe1.c ├── pipe2.c ├── pipe3.c ├── pipe4-2.c ├── pipe4-3.c └── pipe4.c ├── ch12 ├── 06-03.c ├── 2threads │ ├── 2threads_atomic.c │ ├── 2threads_base.c │ ├── 2threads_mutex.c │ ├── 2threads_nosync.c │ ├── 2threads_notvolatile.c │ ├── 2threads_semaphore.c │ ├── 2threads_spinlock.c │ ├── 2threads_using_local_var.c │ ├── makefile │ ├── pi_grid.c │ └── test.c ├── alignedas.c ├── conCurrentQ │ ├── buffer_lockfree.c │ ├── buffer_sem.c │ ├── buffer_sem_mutex.c │ └── makefile ├── cppThread.cpp ├── cpuShowAffinity.c ├── instructionReordering.c ├── isItSupportC11thread.c ├── lockfreeQueue.c ├── makefile ├── memoryModel_assembly.c ├── memoryModel_reorder.c ├── memoryTest │ ├── makefile │ ├── mem_aligned.c │ ├── mem_atomic.c │ ├── mem_mutex.c │ ├── mem_pingpong.c │ ├── mem_sem.c │ ├── mem_share.c │ └── mem_spinlock.c ├── mutex_adaptive.c ├── perfrecord.c ├── perfstat.c ├── pi │ ├── makefile │ ├── pi.c │ ├── pi_drand48_r.c │ └── pi_rand.c ├── readWriteShareVar.c ├── rwspinlock.c ├── seqlock.c ├── seqlock_acquire_release.c ├── signal-wait_adptive_mutex.c ├── signal-wait_mutex.c ├── signal-wait_semaphore.c ├── signal-wait_spinlock.c ├── spinlock.c ├── table.c ├── testPerf.c ├── thread_local_storage.c ├── thread_print_id.c ├── ticketlock.c ├── timedetail.c └── volitailPtr.c ├── ch13 ├── count_svr.c ├── makefile ├── shmget_cli.c └── shmget_svr.c ├── color.h ├── git-ignore-elf.sh ├── makefile ├── mem ├── createFile.c ├── makefile ├── mmap.c ├── myShell.c ├── shell_sigfd.c └── testStack2.c ├── showexeName.c ├── std.txt └── tool.h /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ch02/clock_gettime_loop 3 | ch02/pointer 4 | ch02/table 5 | ch02/clock_gettime 6 | ch02/pointer1 7 | ch02/rdtsc 8 | ch02/hello 9 | ch02/memory_layout 10 | ch06/dir3 11 | ch06/gettime 12 | ch06/dir2 13 | ch06/getresuid 14 | ch06/listattr 15 | ch06/list_acl_simple 16 | ch06/dir 17 | ch06/chmod 18 | ch06/list_acl 19 | ch06/inotify 20 | ch06/link 21 | ch06/hw5 22 | ch06/rename 23 | ch06/chowngrp2root 24 | ch06/listDirRec 25 | ch06/name2id 26 | ch06/change 27 | ch05/mktemp 28 | ch05/write+read 29 | ch05/fileperf 30 | ch05/strlen 31 | ch05/append+fseek 32 | ch05/fprintf 33 | ch05/wcslen 34 | ch05/setvbuf 35 | ch05/hello_cht 36 | ch05/feof 37 | ch05/fopen 38 | fileperf 39 | a.out 40 | ch04/mmap_cp 41 | ch04/mycp1 42 | ch04/mycp2 43 | ch04/syncNone 44 | ch04/syncDataOnly 45 | ch04/perror 46 | ch04/hole 47 | ch04/sync 48 | ch04/flock 49 | ch04/vio 50 | ch04/lockf 51 | avx512 52 | printf 53 | showexeName 54 | ch06/watchFile 55 | ch08/atexit 56 | ch08/cpu_set 57 | ch08/echo 58 | ch08/getEnv 59 | ch08/listEnv 60 | ch08/myNice 61 | ch08/on_exit 62 | ch08/vfork8 63 | ch09/debugFork1 64 | ch09/debugFork2 65 | ch09/fork1 66 | ch09/manyFork 67 | ch09/manyVFork 68 | ch09/_myShell 69 | ch09/myShell 70 | ch09/NoZombie 71 | ch09/testDebug 72 | ch09/testStack 73 | ch09/wait 74 | ch09/zombie 75 | ch09/fork2 76 | ch11/fifo1 77 | ch11/fifo2-r 78 | ch11/fifo2-w 79 | ch11/pipe1 80 | ch11/pipe2 81 | ch11/pipe3 82 | ch11/pipe4-2 83 | ch11/pipe4-3 84 | ch11/pipe4 85 | ch11/pipe-perf2 86 | ch11/pipe-perf 87 | ch12/06-03 88 | ch12/alignedas 89 | ch12/cpuShowAffinity 90 | ch12/instructionReordering 91 | ch12/isItSupportC11thread 92 | ch12/lockfreeQueue 93 | ch12/memoryModel_assembly 94 | ch12/memoryModel_reorder 95 | ch12/mutex_adaptive 96 | ch12/perfrecord 97 | ch12/perfstat 98 | ch12/readWriteShareVar 99 | ch12/rwspinlock 100 | ch12/seqlock_acquire_release 101 | ch12/seqlock 102 | ch12/signal-wait_adptive_mutex 103 | ch12/signal-wait_mutex 104 | ch12/signal-wait_semaphore 105 | ch12/signal-wait_spinlock 106 | ch12/spinlock 107 | ch12/table 108 | ch12/testPerf 109 | ch12/thread_local_storage 110 | ch12/thread_print_id 111 | ch12/ticketlock 112 | ch12/timedetail 113 | ch12/volitailPtr 114 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(gdb) Launch", 9 | "preLaunchTask": "C/C++: gcc build active file", 10 | "type": "cppdbg", 11 | "request": "launch", 12 | "program": "${fileDirname}/${fileBasenameNoExtension}", 13 | "args": ["/"], 14 | "stopAtEntry": false, 15 | "cwd": "${fileDirname}", 16 | "environment": [], 17 | "externalConsole": false, 18 | "MIMode": "gdb", 19 | "setupCommands": [ 20 | { 21 | "description": "Enable pretty-printing for gdb", 22 | "text": "-enable-pretty-printing", 23 | "ignoreFailures": true 24 | }, 25 | { 26 | "description": "Set Disassembly Flavor to Intel", 27 | "text": "-gdb-set disassembly-flavor intel", 28 | "ignoreFailures": true 29 | } 30 | ] 31 | } 32 | 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "makefile.extensionOutputFolder": "./.vscode" 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: gcc build active file", 6 | "command": "/usr/bin/gcc", 7 | "args": [ 8 | "-fdiagnostics-color=always", 9 | "-g", 10 | "${file}", 11 | "-o", 12 | "${fileDirname}/${fileBasenameNoExtension}" 13 | ], 14 | "options": { 15 | "cwd": "${fileDirname}" 16 | }, 17 | "problemMatcher": [ 18 | "$gcc" 19 | ], 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | }, 24 | "detail": "Task generated by Debugger." 25 | } 26 | ], 27 | "version": "2.0.0" 28 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # system-programming 2 | 中正大學,資工系,羅習五,系統程式設計課程 3 | 4 | ## 關於課程相關資訊 5 | 使用的編譯器是:gcc-8,Ubuntu Linux 18.04.1 6 | 7 | 使用的編輯軟體是:CLion,這軟體可從底下這個網址下載 8 | https://www.jetbrains.com/clion/download/#section=mac 9 | 免費試用一個月 10 | 老師或者學生可以從底下這個網站註冊免費版本 11 | https://www.jetbrains.com/buy/classroom/?fromMenu 12 | 13 | 上課的投影片在這個網址 14 | https://goo.gl/X7mUPx 15 | 16 | 數位教材在 17 | https://goo.gl/JgRcxa 18 | 19 | 課程論壇在 20 | https://groups.google.com/d/forum/ccu_system_programming 21 | 22 | ## 課程章節 23 | ### ch01,Linux安裝與操作 24 | https://www.cs.ccu.edu.tw/~shiwulo/course/2019-sp/ecourse/01.Linux_install_and_setup/ 25 | 26 | ### ch02,編譯環境介紹 27 | ### ch03,追蹤執行擋與作業系統的互動 28 | ### ch04,檔案輸入與輸出 29 | ### ch05,C標準輸出入函數庫 30 | ### ch06,檔案及目錄 31 | ### ch08,行程 32 | ### ch09,程序控制 33 | ### ch10,信號 34 | ### ch11,pipe_fifo 35 | ### ch12,pthread 36 | ### ch13,System V IPC 37 | -------------------------------------------------------------------------------- /avx512.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | long ts2ns(struct timespec ts) 8 | { 9 | return ts.tv_sec * 1000000000 + ts.tv_nsec; 10 | } 11 | 12 | long long cache[2048*2048+1]; 13 | 14 | int main() 15 | { 16 | __m512i temp1[32]; //64*8=2K 17 | __m512i temp2[3200]; 18 | __m512i zero={0}; 19 | atomic_llong *ary1 = (atomic_llong *)temp1; 20 | atomic_llong *ary2 = (atomic_llong *)&temp2[1024]; 21 | 22 | //printf("sizeof atomic_llong is %ld\n", sizeof(atomic_llong)); 23 | for (int i=0; i< 256; i++) { 24 | //ary1[i]=i; //驗證用 25 | } 26 | 27 | //清空cache 28 | for (int i=0; i< 2048*2048; i++) { 29 | cache[i] = cache[i+1]; 30 | } 31 | //避免編譯器優化 32 | printf("避免編譯器優化的輸出 %lld\n", cache[2048 * 2048]); 33 | 34 | for (int i = 0; i < 256; i++) 35 | { 36 | //printf("%lld, ",ary1[i]); //驗證用 37 | } 38 | 39 | //printf("\n\n\n"); 40 | __asm__( 41 | "vpxorq %%zmm0, %%zmm0, %%zmm0;\n" 42 | : //output, b的代號是"%0" 43 | : //input, a代號是"%1", da代號是"%2" 44 | : //搞髒掉的暫存器,gcc會幫我們還原 45 | ); 46 | 47 | struct timespec time1, time2; 48 | clock_gettime(CLOCK_MONOTONIC, &time1); 49 | //2048 byte 50 | __asm__( 51 | //"VMOVDQA64 (%1), %%zmm0\n" 52 | "vmovdqa64 %%zmm0, 0x00(%0)\n" 53 | "vmovdqa64 %%zmm0, 0x40(%0)\n" 54 | "vmovdqa64 %%zmm0, 0x80(%0)\n" 55 | "vmovdqa64 %%zmm0, 0x0c0(%0)\n" 56 | "vmovdqa64 %%zmm0, 0x100(%0)\n" 57 | "vmovdqa64 %%zmm0, 0x140(%0)\n" 58 | "vmovdqa64 %%zmm0, 0x180(%0)\n" 59 | "vmovdqa64 %%zmm0, 0x1C0(%0)\n" 60 | "vmovdqa64 %%zmm0, 0x200(%0)\n" 61 | "vmovdqa64 %%zmm0, 0x240(%0)\n" 62 | "vmovdqa64 %%zmm0, 0x280(%0)\n" 63 | "vmovdqa64 %%zmm0, 0x2C0(%0)\n" 64 | "vmovdqa64 %%zmm0, 0x300(%0)\n" 65 | "vmovdqa64 %%zmm0, 0x340(%0)\n" 66 | "vmovdqa64 %%zmm0, 0x380(%0)\n" 67 | "vmovdqa64 %%zmm0, 0x3C0(%0)\n" 68 | "vmovdqa64 %%zmm0, 0x400(%0)\n" 69 | "vmovdqa64 %%zmm0, 0x440(%0)\n" 70 | "vmovdqa64 %%zmm0, 0x480(%0)\n" 71 | "vmovdqa64 %%zmm0, 0x4C0(%0)\n" 72 | "vmovdqa64 %%zmm0, 0x500(%0)\n" 73 | "vmovdqa64 %%zmm0, 0x540(%0)\n" 74 | "vmovdqa64 %%zmm0, 0x580(%0)\n" 75 | "vmovdqa64 %%zmm0, 0x5C0(%0)\n" 76 | "vmovdqa64 %%zmm0, 0x600(%0)\n" 77 | "vmovdqa64 %%zmm0, 0x640(%0)\n" 78 | "vmovdqa64 %%zmm0, 0x680(%0)\n" 79 | "vmovdqa64 %%zmm0, 0x6C0(%0)\n" 80 | "vmovdqa64 %%zmm0, 0x700(%0)\n" 81 | "vmovdqa64 %%zmm0, 0x740(%0)\n" 82 | "vmovdqa64 %%zmm0, 0x780(%0)\n" 83 | "vmovdqa64 %%zmm0, 0x7C0(%0)\n" 84 | : //output 85 | : "g"(temp1), "g"(zero) //input 86 | : //搞髒掉的暫存器,gcc會幫我們還原 87 | ); 88 | clock_gettime(CLOCK_MONOTONIC, &time2); 89 | printf("AVX花在prefetch的時間 = %ld ns\n", ts2ns(time2) - ts2ns(time1)); 90 | /* 91 | for (int i = 0; i < 32 * 8; i++) 92 | { 93 | printf("%lld, ", ary1[i]); //驗證用 94 | } 95 | printf("\n\n\n"); 96 | */ 97 | for (int i=0; i<32; i++) { 98 | __asm__( 99 | "vmovdqa64 %%zmm0, 0x0(%0)\n" 100 | : //output, b的代號是"%0" 101 | : "g"(temp1+i) //input, a代號是"%1", da代號是"%2" 102 | : //搞髒掉的暫存器,gcc會幫我們還原 103 | ); 104 | } 105 | /* 106 | for (int i=0; i<32*8; i++) { 107 | printf("%lld, ", ary1[i]); //驗證用 108 | } 109 | */ 110 | printf("AVX花在prefetch的時間(沒展開) = %ld ns\n", ts2ns(time2) - ts2ns(time1)); 111 | 112 | clock_gettime(CLOCK_MONOTONIC, &time1); 113 | for (int i = 0; i < 32; i++) 114 | { 115 | atomic_load_explicit(ary1 + i * 8, memory_order_relaxed); 116 | } 117 | clock_gettime(CLOCK_MONOTONIC, &time2); 118 | printf("存取被AVX prefetch過的陣列 = %ld ns\n", ts2ns(time2) - ts2ns(time1)); 119 | 120 | 121 | clock_gettime(CLOCK_MONOTONIC, &time1); 122 | for (int i = 0; i < 32; i++) 123 | { 124 | atomic_load_explicit(ary2 + i*8, memory_order_relaxed); 125 | } 126 | clock_gettime(CLOCK_MONOTONIC, &time2); 127 | printf("使用普通load以prefetch ary2 %ld ns\n", ts2ns(time2) - ts2ns(time1)); 128 | 129 | clock_gettime(CLOCK_MONOTONIC, &time1); 130 | for (int i = 0; i < 32; i++) 131 | { 132 | atomic_load_explicit(ary2 + i*8, memory_order_relaxed); 133 | } 134 | clock_gettime(CLOCK_MONOTONIC, &time2); 135 | printf("存取prefetch過的ary2的時間= %ld ns\n", ts2ns(time2) - ts2ns(time1)); 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /ch02/clock_gettime.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern inline int myRand() 11 | { 12 | int i, result; 13 | return result; 14 | for (i=0; i<100000000; i++) 15 | result = rand()*rand(); 16 | } 17 | 18 | //將timespec轉成nanoseconds 19 | long ts_to_long(struct timespec t) { 20 | return t.tv_sec * 1000000000 + t.tv_nsec; 21 | } 22 | 23 | int main(int argc, char **argv) 24 | { 25 | int result, i; 26 | //clock_gettime的精准度 27 | struct timespec t_res; 28 | //開始及結束時間 29 | struct timespec tt1, tt2; 30 | 31 | printf("不同參數下,clock_gettime的精準度\n"); 32 | clock_getres(CLOCK_REALTIME, &t_res); 33 | printf("CLOCK_REALTIME resolution:\t\t %ld nanoseconds\n", t_res.tv_nsec); 34 | clock_getres(CLOCK_MONOTONIC, &t_res); 35 | printf("CLOCK_MONOTONIC resolution:\t\t %ld nanoseconds\n", t_res.tv_nsec); 36 | clock_getres(CLOCK_BOOTTIME, &t_res); 37 | printf("CLOCK_BOOTTIME resolution:\t\t %ld nanoseconds\n", t_res.tv_nsec); 38 | clock_getres(CLOCK_PROCESS_CPUTIME_ID, &t_res); 39 | printf("CLOCK_PROCESS_CPUTIME_ID resolution:\t %ld nanoseconds\n", t_res.tv_nsec); 40 | 41 | printf("印出執行『i++』花多少時間\n"); 42 | clock_gettime(CLOCK_MONOTONIC, &tt1); 43 | i++; 44 | clock_gettime(CLOCK_MONOTONIC, &tt2); 45 | printf("i++ consumes %ld nanoseconds!\n", ts_to_long(tt2) - ts_to_long(tt1)); 46 | } 47 | -------------------------------------------------------------------------------- /ch02/clock_gettime_loop.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //將timespec轉成nanoseconds 11 | long ts_to_long(struct timespec t) { 12 | return t.tv_sec * 1000000000 + t.tv_nsec; 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | clockid_t clk_id; 18 | struct timespec tt; 19 | //開始及結束時間 20 | struct timespec tt1, tt2; 21 | const int loopSize =1000; 22 | 23 | //clk_id = CLOCK_REALTIME; 24 | //clk_id = CLOCK_BOOTTIME; 25 | //clk_id = CLOCK_PROCESS_CPUTIME_ID; 26 | clk_id = CLOCK_MONOTONIC; 27 | 28 | clock_gettime(clk_id, &tt1); 29 | for (int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int global_a; 8 | int global_b=10; 9 | int main() 10 | { 11 | int local_c=10; 12 | int local_d; 13 | int *malloc_e = malloc(100); 14 | printf("印出指標的位址,因為ASLR的關係,每次印出來的結果會不一樣\n"); 15 | printf(" global_a\t%p\n global_b\t%p\n local_c\t%p\n local_d\t%p\n malloc_e\t%p\n", 16 | &global_a, &global_b, &local_c, &local_d, malloc_e); 17 | char command[1024]; 18 | printf("按任意按鍵,印出這個task的memory layout\n"); 19 | getchar(); 20 | sprintf(command, "pmap %d", getpid()); 21 | assert(system(command)==0); 22 | } 23 | -------------------------------------------------------------------------------- /ch02/pointer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int *p; /*指標未給初始值 */ 7 | int ret; 8 | printf("輸入數字\n"); 9 | ret = scanf("%d", p); //這一行會出錯 10 | printf("ret = %d, %d", ret, *p); //這一行會出錯 11 | } 12 | -------------------------------------------------------------------------------- /ch02/pointer1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int p; 7 | int ret; 8 | ret = scanf("%d", &p); 9 | printf("ret = %d, %d", ret, p); 10 | } 11 | -------------------------------------------------------------------------------- /ch02/rdtsc.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | The RDTSCP instruction reads the same TSC as the RDTSC instruction, so if RDTSC is invariant, then RDTSCP will be as well. 13 | RDTSCP is slightly more ordered than RDTSC. RDTSC is not ordered at all, which means that it will execute some time in the out-of-order window of the processor, which may be before or after the instruction(s) that you are interested in timing. RDTSCP will not execute until all prior instructions (in program order) have executed. So it can't execute "early", but there is no guarantee that the execution won't be delayed until after some subsequent (in program order) instructions have executed. 14 | */ 15 | extern __inline__ uint64_t rdtscp(void) 16 | { 17 | uint32_t lo, hi; 18 | // take time stamp counter, rdtscp does serialize by itself, and is much cheaper than using CPUID 19 | __asm__ __volatile__("rdtscp":"=a"(lo), "=d"(hi)); 20 | return ((uint64_t) lo) | (((uint64_t) hi) << 32); 21 | } 22 | 23 | long ts_to_long(struct timespec t) { 24 | return t.tv_sec * 1000000000 + t.tv_nsec; 25 | } 26 | 27 | int main(int argc, char **argv) 28 | { 29 | int tmp=0; 30 | uint64_t cycles1, cycles2; 31 | struct timespec ts1, ts2; 32 | 33 | printf("這個程式是量測一個指令執行的時間,但CPU可同時執行數十個指令\n"); 34 | printf("因此這些量測方法比較適合量測大範圍的程式碼\n\n"); 35 | 36 | cycles1 = rdtscp(); 37 | tmp++; 38 | cycles2 = rdtscp(); 39 | 40 | clock_gettime(CLOCK_MONOTONIC, &ts1); 41 | tmp++; 42 | clock_gettime(CLOCK_MONOTONIC, &ts2); 43 | 44 | printf("開始 %lu, 結束 %lu\n",cycles1, cycles2); 45 | printf("rdtscp: tmp++ consumes %lu cycles!\n", cycles2-cycles1); 46 | printf("開始 %lu, 結束 %lu\n",ts_to_long(ts1), ts_to_long(ts2)); 47 | printf("clock_gettime: tmp++ consumes %lu nanoseconds!\n", ts_to_long(ts2)-ts_to_long(ts1)); 48 | assert(system("cat /proc/cpuinfo | grep 'cpu MHz' | head -1")>=0); 49 | } 50 | -------------------------------------------------------------------------------- /ch02/table.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define size 1200 12 | long long table[size][size]; 13 | long long col_m; 14 | long long row_m; 15 | long long pseudo_rand=0; 16 | 17 | //將timespec轉成nanoseconds 18 | double ts_to_double(struct timespec t) { 19 | return (double)(t.tv_sec * 1000000000 + t.tv_nsec)/1000000000; 20 | } 21 | 22 | void initTable() 23 | { 24 | int i, j; 25 | for (i = 0; i < size; i++) 26 | for (j = 0; j < size; j++) { 27 | pseudo_rand += 17749; 28 | table[i][j] = pseudo_rand; 29 | } 30 | } 31 | 32 | void sumCol() 33 | { 34 | int i, j; 35 | for (j = 0; j < size; j++) 36 | for (i = 0; i < size; i++) 37 | col_m += table[i][j]; 38 | } 39 | 40 | void sumRow() 41 | { 42 | int i, j; 43 | for (i = 0; i < size; i++) 44 | for (j = 0; j < size; j++) 45 | row_m += table[i][j]; 46 | } 47 | 48 | int main() 49 | { 50 | struct timespec row1, row2; 51 | struct timespec col1, col2; 52 | struct timespec init1, init2; 53 | struct timespec init3, init4; 54 | 55 | printf("size of table %f MB\n", (double)sizeof(table)/1024/1024); 56 | 57 | clock_gettime(CLOCK_MONOTONIC, &init1); 58 | initTable(); 59 | clock_gettime(CLOCK_MONOTONIC, &init2); 60 | 61 | clock_gettime(CLOCK_MONOTONIC, &init3); 62 | initTable(); 63 | clock_gettime(CLOCK_MONOTONIC, &init4); 64 | 65 | clock_gettime(CLOCK_MONOTONIC, &row1); 66 | sumRow(); 67 | clock_gettime(CLOCK_MONOTONIC, &row2); 68 | 69 | clock_gettime(CLOCK_MONOTONIC, &col1); 70 | sumCol(); 71 | clock_gettime(CLOCK_MONOTONIC, &col2); 72 | 73 | //printResult(); 74 | 75 | printf(" col_m %lld\n row_m %lld\n", col_m, row_m); 76 | printf("比較第一次初始化,和第二次初始化的時間差異\n"); 77 | printf("first init:\t%f\n", ts_to_double(init2)-ts_to_double(init1)); 78 | printf("second init:\t%f\n", ts_to_double(init4)-ts_to_double(init3)); 79 | printf("比較row major和column major的速度的差異\n"); 80 | printf("row major:\t%f\n", ts_to_double(row2)-ts_to_double(row1)); 81 | printf("column major:\t%f\n", ts_to_double(col2)-ts_to_double(col1)); 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /ch03/clock_gettime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | long long nspersec = 1000000000; 7 | long long timespec2nsec(struct timespec ts) { 8 | long long ns = ts.tv_nsec; 9 | ns += ts.tv_sec * nspersec; 10 | return ns; 11 | //return (double)ns/1000000000.0; 12 | } 13 | 14 | int main(int argc, char** argv) { 15 | struct timespec ts_begin; 16 | struct timespec ts_end; 17 | long long begin_ns; 18 | long long end_ns; 19 | long long ns=0; 20 | int i; 21 | const int loopCount = 10000000; 22 | for (int i=0; i 2 | #include 3 | #include 4 | 5 | int main() { 6 | printf("pid = %d\n", getpid()); 7 | printf("hello\n"); 8 | while(1); 9 | } 10 | -------------------------------------------------------------------------------- /ch03/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g -pthread 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch03/malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | char* p1; 9 | char* p2; 10 | char command[1024]; 11 | /*印出行程的pid,方便我們到/proc目錄裡面找到相對映的檔案*/ 12 | //printf("pid = %d\n", getpid()); 13 | printf("malloc(64)\n"); 14 | /*配置64byte記憶體*/ 15 | p1 = (char*)malloc(64); 16 | printf("p1=%p\n", p1); 17 | printf("malloc 64*4K\n"); 18 | /*配置256K記憶體*/ 19 | p2 = (char*)malloc(64*4096); 20 | printf("p2=%p\n", p2); 21 | sprintf(command, "pmap %d", getpid()); 22 | assert(system(command) >=0); 23 | } 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ch03/malloc2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | int i; 9 | char* p; 10 | char command[1024]; 11 | printf("執行malloc『前』的memory的layout\n"); 12 | sprintf(command, "pmap %d", getpid()); 13 | assert(system(command) >=0); 14 | printf("malloc 64*4K\n"); 15 | for (i=0; i<64*4096; i++) 16 | p=(char*)malloc(1); 17 | printf("執行malloc『後』的memory的layout\n"); 18 | sprintf(command, "pmap %d", getpid()); 19 | assert(system(command) >=0); 20 | } 21 | -------------------------------------------------------------------------------- /ch03/malloc3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | int i; 8 | char* p1; 9 | char* p2; 10 | char* p3; 11 | printf("pid = %d\n", getpid()); 12 | printf("malloc 256K\n"); 13 | p1=(char*)malloc(64*4096); 14 | printf("malloc(1)\n"); 15 | p2=(char*)malloc(1); 16 | printf("malloc(1)\n"); 17 | p3=(char*)malloc(1); 18 | char command[1024]; 19 | printf("執行malloc『後』的memory的layout\n"); 20 | sprintf(command, "pmap %d", getpid()); 21 | } 22 | -------------------------------------------------------------------------------- /ch03/mmfile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | const size_t k=1024; 11 | const size_t m=k*k; 12 | const size_t g=k*m; 13 | const size_t t=k*g; 14 | 15 | int main (int argc, char** argv) { 16 | const int fileSize = 500000; 17 | char* mmfile=NULL; 18 | char* stringBuf="end"; 19 | int fd = open("./mmfile.data", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 20 | lseek(fd, fileSize-sizeof(stringBuf), SEEK_SET); 21 | assert(write(fd, stringBuf, sizeof(stringBuf))==sizeof(stringBuf)); 22 | //sync(); 23 | //exit(0); 24 | mmfile = mmap(NULL, fileSize, PROT_WRITE, MAP_SHARED, fd, 0); 25 | assert(mmfile != NULL); 26 | for (int i=0; i< fileSize; i++) { 27 | mmfile[i] = 'B'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch03/pointer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main () { 5 | int *p; 6 | scanf("%d", p); 7 | printf("%d", *p); 8 | } 9 | -------------------------------------------------------------------------------- /ch03/rdtscp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static unsigned long long rdtsc(void) 11 | { 12 | unsigned int low, high; 13 | 14 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); 15 | 16 | return low | ((unsigned long long)high) << 32; 17 | } 18 | 19 | const long long nspersec = 1000000000; 20 | inline long long timespec2nsec(struct timespec ts) { 21 | long long ns = ts.tv_nsec; 22 | ns += ts.tv_sec * nspersec; 23 | return ns; 24 | //return (double)ns/1000000000.0; 25 | } 26 | 27 | int main(int argc, char** argv) { 28 | //struct timespec ts_begin; 29 | //struct timespec ts_end; 30 | const int loopCount=10000000; 31 | unsigned long long begin_ns=0; 32 | unsigned long long end_ns=0; 33 | unsigned long long delta=0; 34 | for (volatile int i=0; i 2 | #include 3 | 4 | #define size 10000 5 | long table[size][size]; 6 | long col[size]; 7 | long row[size]; 8 | 9 | void initTable() { 10 | int i, j; 11 | for (i=0; i< size; i++) 12 | for (j=0; j 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | int file_descriptor; // 檔案描述符 8 | int flock_return_value; // flock函數回傳值 9 | char lock_option; // 鎖定選項 10 | file_descriptor = open(argv[1], O_WRONLY); // 以寫入模式開啟檔案 11 | printf("已開啟檔案,描述符為:%d\n", file_descriptor); 12 | sscanf(argv[2], "%c", &lock_option); // 從輸入中取得鎖定選項 13 | switch (lock_option) { 14 | case 's': 15 | flock_return_value = flock(file_descriptor, LOCK_SH); // 共享鎖定 16 | break; 17 | case 'e': 18 | flock_return_value = flock(file_descriptor, LOCK_EX); // 獨佔鎖定 19 | break; 20 | case 'u': 21 | flock_return_value = flock(file_descriptor, LOCK_UN); // 釋放鎖定 22 | break; 23 | default: 24 | printf("輸入錯誤\n"); 25 | } 26 | if (flock_return_value != 0) // 若鎖定失敗 27 | perror("flock"); 28 | printf("已執行完畢\n"); 29 | getchar(); 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /ch04/hole.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | int fd; 11 | const int G=1000000000; 12 | const int M=1000000; 13 | 14 | printf("這個程式會在當前的目錄下,製造檔案myHole\n"); 15 | fd = open("./myHole", O_RDWR| O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR); 16 | if (fd <0) 17 | perror("無法製造myHole"); 18 | //lseek將『檔案指標』由開始位置向後移動100G,lseek比較可能出錯,用assert檢查一下 19 | assert(lseek(fd, 10*M, SEEK_SET) != -1); 20 | //寫入“1”,很少出錯,懶得檢查 21 | write(fd, "1", sizeof("1")); 22 | //lseek將『檔案指標』由『目前』位置向後移動100G,lseek比較可能出錯,用assert檢查一下 23 | assert(lseek(fd, 10, SEEK_CUR) != -1); 24 | write(fd, "2", sizeof("2")); 25 | assert(lseek(fd, 10, SEEK_CUR) != -1); 26 | write(fd, "3\n", sizeof("3\n")); 27 | close(fd); 28 | system("ls myHole -alhs"); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /ch04/lockf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int main(int argc, char* argv[]) { 9 | int fd; 10 | int ret; 11 | char opt; 12 | off_t begin, end; 13 | 14 | if (argc == 1) printf("lockf [file] [type(l/u)] [begin] [end]\n"); 15 | 16 | fd = open (argv [1], O_WRONLY); 17 | printf("fd = %d is opened\n", fd); 18 | 19 | sscanf(argv[2], "%c", &opt); 20 | sscanf(argv[3], "%ld", &begin); 21 | sscanf(argv[4], "%ld", &end); 22 | 23 | switch (opt) { 24 | case 'l': 25 | lseek(fd, begin, SEEK_SET); 26 | ret = lockf(fd, F_LOCK, end - begin + 1); 27 | break; 28 | case 'u': 29 | lseek(fd, begin, SEEK_SET); 30 | ret = lockf(fd, F_UNLCK, end - begin + 1); 31 | break; 32 | default: 33 | printf("input error\n"); 34 | } 35 | if (ret != 0) 36 | perror("flock"); 37 | printf("end\n"); 38 | getchar(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /ch04/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g -pthread 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} -------------------------------------------------------------------------------- /ch04/mmap_cp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char* argv[]) { 14 | 15 | int inputFd, outputFd; 16 | char *inputPtr, *outputPtr; 17 | ssize_t numIn, numOut; 18 | ssize_t fileSize=0; 19 | //char buffer[BUF_SIZE]; 20 | 21 | //只可讀取模式打開 22 | inputFd = open (argv [1], O_RDONLY); 23 | if (inputFd == -1) { 24 | perror ("cannot open the file for read"); exit(1); } 25 | 26 | //open後可對該檔案**『可讀可寫』**(因為mmap的需求),如果沒有該檔案,就建立該檔案。如果要建立,設定該檔案的屬性為owner可讀可寫 27 | outputFd = open(argv[2], O_RDWR | O_CREAT, S_IRUSR| S_IWUSR); 28 | if(outputFd == -1){ 29 | perror("canot open the file for write"); exit(1); } 30 | 31 | //lseek的回傳是該檔案的絕對位址,因此lseek(0, seek_end)相當於檔案大小 32 | //linux有專門讀取檔案大小的函數,但我習慣用這一個 33 | fileSize = lseek(inputFd, 0, SEEK_END); 34 | printf("file size = %ld\n", fileSize); 35 | 36 | //NULL,不指定映射到記憶體的哪個位置。通常不指定 37 | //filesize,將檔案中多少內容映射到記憶體 38 | //prot_read,只會對該段記憶體做讀取 39 | //MAP_SHARED,對mmap出的記憶體的所有修改讓整個系統裡的人都看到。因此底藏的檔案會跟著變更 40 | //inputFd從哪個檔案映射進來 41 | //0, 映射的起點為 0 42 | inputPtr = mmap(NULL, fileSize, PROT_READ, MAP_SHARED , inputFd , 0);//🐶 🐱 🐭 🐹 🐰 🦊 43 | perror("mmap"); 44 | printf("inputPtr = %p\n", inputPtr); 45 | //assert(madvise(inputPtr, fileSize, MADV_SEQUENTIAL|MADV_WILLNEED|MADV_HUGEPAGE)==0); 46 | 47 | //ftruncate的名字是:縮小 48 | //實際上是設定檔案大小 49 | ftruncate(outputFd, fileSize); //🐶 🐱 🐭 🐹 🐰 🦊 50 | outputPtr = mmap(NULL, fileSize, PROT_WRITE, MAP_SHARED , outputFd , 0); //🐶 🐱 🐭 🐹 🐰 🦊 51 | perror("mmap, output"); 52 | printf("outputPtr = %p\n", outputPtr); 53 | //madvise(inputPtr, fileSize, MADV_SEQUENTIAL|MADV_WILLNEED|MADV_HUGEPAGE); 54 | 55 | printf("memory copy\n"); 56 | time_t timer1, timer2; 57 | timer1 = time(NULL); 58 | //這一行實現檔案複製 59 | memcpy(outputPtr, inputPtr, fileSize);//🐶 🐱 🐭 🐹 🐰 🦊 60 | timer2 = time(NULL); 61 | 62 | printf("time(memcpy) = %ld sec \n", timer2 - timer1); 63 | 64 | assert(munmap(inputPtr, fileSize) == 0); 65 | assert(munmap(outputPtr, fileSize) == 0); 66 | 67 | assert(close (inputFd) == 0); 68 | assert(close (outputFd) == 0); 69 | 70 | return (EXIT_SUCCESS); 71 | } -------------------------------------------------------------------------------- /ch04/mycp1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BUF_SIZE 4096 10 | 11 | int main(int argc, char* argv[]) { 12 | 13 | //從inputFd將檔案寫到outputFd 14 | int inputFd, outputFd; 15 | //讀進多少,寫出多少 16 | ssize_t numIn, numOut; 17 | //把檔案內容讀到buffer,再寫出去 18 | char buffer[BUF_SIZE]; 19 | 20 | //確定使用者輸入二個參數 21 | if (argc != 3) { 22 | char* filename=basename(argv[0]); 23 | printf("『%s』的功能是檔案複製,要有二個參數,來源檔案和目標檔案\n", filename); 24 | exit(0); 25 | } 26 | 27 | //打開來源檔案 28 | inputFd = open (argv [1], O_RDONLY); 29 | if (inputFd == -1) { 30 | char* filename=basename(argv[1]); 31 | char errmsg[1024]; 32 | sprintf(errmsg, "無法開啟來源檔案 (%s)", filename); 33 | perror (errmsg); 34 | exit(1); 35 | } 36 | 37 | //打開目的檔案 38 | //注意 open 的參數,可讀、創造、歸零(O_WRONLY | O_CREAT | O_TRUNC) 39 | //比較常忘記的是歸零,是否歸零是情況而定 40 | //如果沒有歸零就會有新舊混淆的問題 41 | //資料庫系統(DBMS)打開打檔案通常不會歸零,因為他們會在既有的上面做更新 42 | //word打開檔案通常要歸零,因為使用者的新文章可能更短,這會造成新舊混淆問題 43 | outputFd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR); 44 | if(outputFd == -1){ 45 | char* filename=basename(argv[3]); 46 | char errmsg[1024]; 47 | sprintf(errmsg, "無法打開目的檔案 (%s)", filename); 48 | perror (errmsg); 49 | exit(1); 50 | } 51 | 52 | //在while敘述中,將檔案的資料讀入,共毒入numIn個字元 53 | while((numIn = read (inputFd, buffer, BUF_SIZE)) > 0) { 54 | //將資料寫出到目的檔案 55 | numOut = write (outputFd, buffer, (ssize_t) numIn); 56 | //如果寫出的和讀取的數量不同,那就是有問題 57 | if(numIn != numOut) { 58 | perror("numIn != numOut"); exit(1); 59 | } 60 | } 61 | close (inputFd); 62 | close (outputFd); 63 | return (EXIT_SUCCESS); 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /ch04/mycp2.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define BUF_SIZE 4096 15 | 16 | 17 | int main(int argc, char* argv[]) { 18 | //從inputFd將檔案寫到outputFd 19 | int inputFd, outputFd; 20 | //讀進多少,寫出多少 21 | ssize_t numIn, numOut; 22 | //把檔案內容讀到buffer,再寫出去 23 | char buffer[BUF_SIZE]; 24 | 25 | //確定使用者輸入二個參數 26 | if (argc != 3) { 27 | char* filename=basename(argv[0]); 28 | printf("『%s』的功能是檔案複製,要有二個參數,來源檔案和目標檔案\n", filename); 29 | exit(0); 30 | } 31 | 32 | //打開來源檔案 33 | inputFd = open (argv [1], O_RDONLY); 34 | if (inputFd == -1) { 35 | char* filename=basename(argv[1]); 36 | char errmsg[1024]; 37 | sprintf(errmsg, "無法開啟來源檔案 (%s)", filename); 38 | perror (errmsg); 39 | exit(1); 40 | } 41 | 42 | //打開目的檔案 43 | //注意 open 的參數,可讀、創造、歸零(O_WRONLY | O_CREAT | O_TRUNC) 44 | //比較常忘記的是歸零,是否歸零是情況而定 45 | //如果沒有歸零就會有新舊混淆的問題 46 | //資料庫系統(DBMS)打開打檔案通常不會歸零,因為他們會在既有的上面做更新 47 | //word打開檔案通常要歸零,因為使用者的新文章可能更短,這會造成新舊混淆問題 48 | outputFd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR| S_IWUSR); 49 | if(outputFd == -1){ 50 | char* filename=basename(argv[3]); 51 | char errmsg[1024]; 52 | sprintf(errmsg, "無法打開目的檔案 (%s)", filename); 53 | perror (errmsg); 54 | exit(1); 55 | } 56 | 57 | //🍏 🍎 與 mycp 不同的地方 58 | off_t data_off=0, hole_off=0, cur_off=0; 59 | long long fileSize, blockSize, pos=0; 60 | //🍏 🍎 拿到檔案大小的方法,用lseek移到檔案尾巴,看回傳值 61 | fileSize = lseek(inputFd, 0, SEEK_END); 62 | //🍏 🍎 讀到大小後記得用lseek回到原位(0) 63 | lseek(inputFd, 0, SEEK_SET); 64 | 65 | while (1) { 66 | cur_off = lseek(inputFd, cur_off, SEEK_DATA); 67 | data_off = cur_off; 68 | cur_off = lseek(inputFd, cur_off, SEEK_HOLE); 69 | hole_off = cur_off; 70 | //第一種情況,資料在前面,洞在後面,不用特別處理 71 | //第二種情況,洞在前面,資料在後面,處理一下 72 | if (data_off > hole_off) { 73 | //現在是這樣: 74 | // ...............data data data data data.... 75 | // ^hole_off ^data_off=cur_off 76 | //因為cur_off已經移到後面了,所以下一輪執行會變成 77 | // ...............data data data data data.... 78 | // ^data_off ^hole_off=curoff 79 | continue; 80 | } 81 | //🐶 🐱 🐭 🐹 🐰 🦊 底下這一段可以用 mmap + memcpy 取代 82 | //至此,data_off一定在前面,hole_off一定在後面 83 | blockSize=hole_off-data_off; 84 | lseek(inputFd, data_off, SEEK_SET); 85 | lseek(outputFd, data_off, SEEK_SET); 86 | //這個while loop與 mycp 相同 87 | while((numIn = read (inputFd, buffer, BUF_SIZE)) > 0) { 88 | numOut = write (outputFd, buffer, (ssize_t) numIn); 89 | if (numIn != numOut) perror("numIn != numOut"); 90 | blockSize-=numIn; 91 | if (blockSize == 0) break; 92 | } 93 | //檢查一下是否已經到最後了 94 | if (lseek(outputFd, 0, SEEK_CUR) == fileSize) break; 95 | } 96 | close (inputFd); 97 | close (outputFd); 98 | 99 | return (EXIT_SUCCESS); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /ch04/perror.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | errno=1; 6 | perror("the error is"); 7 | } 8 | -------------------------------------------------------------------------------- /ch04/sync.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char** argv) { 9 | int fd; 10 | int num; 11 | int printFileInfo=0; 12 | printf("『%s print』即時列印檔案訊息,不加參數則會列印\n", argv[0]); 13 | if (argc == 1) { 14 | printf("不列印檔案訊息\n"); 15 | printFileInfo = 0; 16 | } else { 17 | printf("列印檔案訊息\n"); 18 | printFileInfo = 1; 19 | } 20 | printf("按下enter後繼續\n"); 21 | getchar(); 22 | 23 | fd = open("./syncFile.data",O_WRONLY | O_CREAT | O_TRUNC, 0644); 24 | for(num=0; num <=100000; num++) { 25 | write(fd, "1234", sizeof("1234")); 26 | //將資料立即同步到檔案系統中 27 | fsync(fd); 28 | if (num%10000==1) { 29 | write(1, "*", sizeof("*")); 30 | fsync(1); 31 | } 32 | if (num%100==0 && printFileInfo==1) 33 | system("ls syncFile.data -alhs"); 34 | } 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /ch04/syncDataOnly.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char** argv) { 9 | int fd; //要寫出的檔案 10 | int num; //計算列印到檔案多少字元了 11 | int printFileInfo=0; 12 | printf("『%s print』即時列印檔案訊息,不加參數則會列印\n", argv[0]); 13 | if (argc == 1) { 14 | printf("不列印檔案訊息\n"); 15 | printFileInfo = 0; 16 | } else { 17 | printf("列印檔案訊息\n"); 18 | printFileInfo = 1; 19 | } 20 | printf("按下enter後繼續\n"); 21 | getchar(); 22 | 23 | 24 | fd = open("./syncDataOnly.data",O_WRONLY | O_CREAT | O_TRUNC, 0644); 25 | for(num=0; num <=100000; num++) { 26 | write(fd, "1234", sizeof("1234")); 27 | //只同步data沒有同步metadata 28 | fdatasync(fd); 29 | if (num%10000==1) { 30 | write(1, "*", sizeof("*")); 31 | fsync(1); 32 | } 33 | if (num%100==0 && printFileInfo==1) 34 | system("ls syncDataOnly.data -alhs"); 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /ch04/syncNone.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char** argv) { 9 | int fd; 10 | int num; 11 | int printFileInfo=0; 12 | printf("『%s print』即時列印檔案訊息,不加參數則會列印\n", argv[0]); 13 | if (argc == 1) { 14 | printf("不列印檔案訊息\n"); 15 | printFileInfo = 0; 16 | } else { 17 | printf("列印檔案訊息\n"); 18 | printFileInfo = 1; 19 | } 20 | printf("按下enter後繼續\n"); 21 | getchar(); 22 | 23 | fd = open("./synFile.data",O_WRONLY | O_CREAT | O_TRUNC, 0644); 24 | for(num=0; num <=100000; num++) { 25 | write(fd, "1234", sizeof("1234")); 26 | //完全不做同步 27 | if (num%10000==1) { 28 | write(1, "*", sizeof("*")); 29 | fsync(1); 30 | } 31 | if (num%100==0 && printFileInfo==1) 32 | system("ls synFile.data -alhs"); 33 | } 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /ch04/system-programming.txt: -------------------------------------------------------------------------------- 1 | 0123456789abcdefghijklmnopqrstuvwxyz 2 | system programming 3 | 4 | _ _ 5 | | | (_) 6 | ___ _ _ ___| |_ ___ _ __ ___ _ __ _ __ ___ __ _ _ __ __ _ _ __ ___ _ __ ___ _ _ __ __ _ 7 | / __| | | / __| __/ _ \ '_ ` _ \ | '_ \| '__/ _ \ / _` | '__/ _` | '_ ` _ \| '_ ` _ \| | '_ \ / _` | 8 | \__ \ |_| \__ \ || __/ | | | | | | |_) | | | (_) | (_| | | | (_| | | | | | | | | | | | | | | | (_| | 9 | |___/\__, |___/\__\___|_| |_| |_| | .__/|_| \___/ \__, |_| \__,_|_| |_| |_|_| |_| |_|_|_| |_|\__, | 10 | __/ | | | __/ | __/ | 11 | |___/ |_| |___/ |___/ 12 | -------------------------------------------------------------------------------- /ch04/testMandatory.sh: -------------------------------------------------------------------------------- 1 | sudo mount -oremount,mand / 2 | chmod g+s system-programming.txt 3 | chmod g-x system-programming.txt 4 | -------------------------------------------------------------------------------- /ch04/vio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define NUMBUFS 3 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | const char *buf1 = "Hello "; 15 | const char *buf2 = "Wikipedia "; 16 | const char *buf3 = "Community!\n"; 17 | 18 | struct iovec bufs[NUMBUFS]; 19 | 20 | bufs[0].iov_base = (void*) buf1; 21 | bufs[0].iov_len = strlen(buf1); 22 | 23 | bufs[1].iov_base = (void*) buf2; 24 | bufs[1].iov_len = strlen(buf2); 25 | 26 | bufs[2].iov_base = (void*) buf3; 27 | bufs[2].iov_len = strlen(buf3); 28 | 29 | printf("vio\n"); 30 | if (-1 == writev(STDOUT_FILENO, bufs, NUMBUFS)) 31 | { 32 | perror("writev()"); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /ch05/append+fseek.c: -------------------------------------------------------------------------------- 1 | // 這個程式示範了如何在 C 語言中使用標準 I/O 库對文件進行讀寫操作 2 | #include 3 | #include 4 | 5 | int main() { 6 | FILE *stream; // 宣告一個文件指針 7 | char buf[10000]; // 宣告一個字符數組作為緩衝區 8 | int ret; // 定義一個整數變數 ret 9 | 10 | // 以讀寫方式打開一個文件,並獲取其文件指針 11 | stream = fopen("./system-programming.txt", "a+"); 12 | 13 | // 使用 fseek 函數設置文件指針的位置,並輸出其返回值 14 | ret = fseek(stream, 10, SEEK_SET); 15 | printf("\nreturn value of fseek(stream, 10)= %d\n", ret); 16 | 17 | // 使用 ftell 函數獲取文件指針的位置,並輸出其返回值 18 | printf("file position after fseek(10) = %ld\n", ftell(stream)); 19 | 20 | // 使用 memset 函數初始化緩衝區,並使用 fread 函數讀取文件內容到緩衝區 21 | memset(buf, 0, 10000); 22 | int nItem = fread(buf, 26, 1, stream); 23 | 24 | // 輸出從文件中讀取的內容 25 | printf("%s\n", buf); 26 | 27 | // 再次使用 ftell 函數獲取文件指針的位置,並輸出其返回值 28 | printf("file position after fread() = %ld\n", ftell(stream)); 29 | 30 | // 使用 getchar 函數等待用戶輸入一個字符 31 | getchar(); 32 | 33 | // 使用 fprintf 函數將一個字符串寫入文件 34 | fprintf(stream, "append?\n"); 35 | 36 | // 再次使用 ftell 函數獲取文件指針的位置,並輸出其返回值 37 | printf("\nfile position = %ld\n", ftell(stream)); 38 | 39 | // 關閉文件,並結束程式 40 | fclose(stream); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /ch05/feof.c: -------------------------------------------------------------------------------- 1 | // 這個程式示範了如何在 C 語言中使用標準 I/O 库對文件進行讀取操作 2 | #include 3 | 4 | int main() { 5 | FILE *stream; // 宣告一個文件指針 6 | char buf[5000]; // 宣告一個字符數組作為緩衝區 7 | int ret; // 定義一個整數變數 ret 8 | 9 | // 以讀寫方式打開一個文件,並獲取其文件指針 10 | stream = fopen("./tmp", "a+"); 11 | 12 | // 使用 fread 函數從文件中讀取 500 個字節到緩衝區 buf 中,並輸出其返回值 13 | ret = fread(buf, 10, 500, stream); 14 | printf("ret = %d\n", ret); 15 | 16 | // 再次使用 fread 函數從文件中讀取 500 個字節到緩衝區 buf 中,並輸出其返回值 17 | ret = fread(buf, 10, 500, stream); 18 | printf("ret = %d\n", ret); 19 | 20 | // 如果返回值不為 1,則判斷讀取是否出現錯誤或到達了文件結尾,並輸出對應信息 21 | if(ret!=1) { 22 | if (ferror(stream)) 23 | printf("error\n"); 24 | if (feof(stream)) 25 | printf("EOF\n"); 26 | } 27 | 28 | // 關閉文件,並結束程式 29 | fclose(stream); 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /ch05/fileperf.c: -------------------------------------------------------------------------------- 1 | // 這個程式是一個文本處理程式,用於將輸入文件中的單詞以指定的方式格式化輸出到輸出文件中 2 | // 可以使用命令行參數指定輸入文件名、輸出文件名以及緩衝模式 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | FILE *input = fopen(argv[1], "r"); // 以只讀方式打開輸入文件,並獲取其文件指針 11 | FILE *output = fopen(argv[2], "w"); // 以寫入方式打開輸出文件,並獲取其文件指針 12 | 13 | int num = atoi(argv[3]); // 將第三個命令行參數轉換為整數,並賦值給變數 num 14 | 15 | if (num == 0) 16 | { //unbuffered 17 | printf("unbuffered\n"); 18 | assert(setvbuf(input, NULL, _IONBF, 0)==0); // 使用 setvbuf 函數將輸入文件設置為無緩衝模式 19 | assert(setvbuf(output, NULL, _IONBF, 0)==0); // 使用 setvbuf 函數將輸出文件設置為無緩衝模式 20 | } 21 | else if (num == -1) 22 | { //linebuffered 23 | printf("linebuffered\n"); 24 | assert(setvbuf(input, NULL, _IOLBF, 0)==0); // 使用 setvbuf 函數將輸入文件設置為行緩衝模式 25 | assert(setvbuf(output, NULL, _IOLBF, 0)==0); // 使用 setvbuf 函數將輸出文件設置為行緩衝模式 26 | } 27 | else 28 | { //fullybuffered 29 | printf("fullybuffered\n"); 30 | int buff_size = num; 31 | assert(setvbuf(input, NULL, _IOFBF, buff_size) == 0); // 使用 setvbuf 函數將輸入文件設置為全緩衝模式 32 | assert(setvbuf(output, NULL, _IOFBF, buff_size) == 0); // 使用 setvbuf 函數將輸出文件設置為全緩衝模式 33 | } 34 | 35 | char word_buf[82]; // 宣告一個字符數組作為單詞的緩衝區,長度為最大單詞長度加上空格 36 | int buflen = 0; // 定義一個整數變數 buflen,表示單詞緩衝區中已經寫入的字符數 37 | int linePos = 0; // 定義一個整數變量 linePos,表示在輸出文件中當前行中已經寫入的字符數 38 | int total = 0; // 定義一個整數變數 total,表示在輸出文件中已經寫入的總字符數 39 | while (1) 40 | { 41 | int inputInt = getc(input); // 從輸入文件中讀取一個字符的 ASCII 編碼 42 | if (inputInt == EOF) // 如果已經到達了輸入文件的結尾,則退出循環 43 | break; 44 | unsigned char inputChar = (unsigned char)inputInt; // 將讀取到的整數轉換為 unsigned char 型別 45 | if (inputChar == '\n') { // 如果讀取到的字符為換行符,則在輸出文件中插入一個換行符 46 | fprintf(output, "\n"); 47 | linePos=0; 48 | } 49 | if (inputChar == ' ') 50 | { // 如果讀取到的字符為空格,則將單詞緩衝區中的內容格式化輸出到輸出文件中 51 | if (linePos + buflen > 80) // 如果單詞緩衝區中的內容加上當前行已經寫入的內容超過了 80 個字符,則在輸出文件中插入一個換行符 52 | { 53 | fprintf(output, "\n"); 54 | total += linePos; 55 | linePos = 0; 56 | } 57 | word_buf[buflen] = ' '; // 將空格寫入單詞緩衝區中 58 | word_buf[buflen+1] = '\0'; // 在單詞緩衝區中加入字符串結束符 59 | fprintf(output, "%s", word_buf); // 將單詞緩衝區中的內容寫入輸出文件中 60 | linePos += buflen+1; // 更新當前行中已經寫入的字符數 61 | buflen = 0; // 清空單詞緩衝區 62 | continue; 63 | } 64 | word_buf[buflen++] = inputChar; // 如果讀取到的字符不是空格或換行符,則將其寫入單詞緩衝區中 65 | } 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /ch05/fopen.c: -------------------------------------------------------------------------------- 1 | // 這個程式創建了一個名為 tmp 的文件,並在其中寫入一行文字 2 | #include 3 | 4 | int main(int argc, char **argv) 5 | { 6 | FILE* file; 7 | file = fopen("./tmp", "w"); // 創建一個文件,文件名為 tmp,以寫入方式打開,並獲取其文件指針 8 | fprintf(file, "this is a tmp file\n"); // 在文件中寫入一行文字 9 | return 0; 10 | } 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch05/fprintf.c: -------------------------------------------------------------------------------- 1 | // 這個程式創建了一個名為 tmp 的文件,並在其中寫入一行文字,打開方式由命令行參數指定 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | FILE* file; 6 | file = fopen("./tmp", argv[1]); // 創建一個文件,文件名為 tmp,打開方式由命令行參數指定,並獲取其文件指針 7 | fprintf(file, "this_is_a_tmp_file\n"); // 在文件中寫入一行文字 8 | fclose(file); // 關閉文件 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch05/hello_cht.c: -------------------------------------------------------------------------------- 1 | // 這個程式主要示範了一些關於 Unicode 字串在 C 語言中的操作 2 | // 包括使用 wchar_t 定義 Unicode 字串、使用 fwide 函數判斷標準輸出流的編碼方案、以及使用 wcslen 函數獲取 Unicode 字串的長度 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | // 使用 wchar_t 定義一個 Unicode 字串 wstr 9 | wchar_t *wstr = L"中文"; 10 | 11 | // 使用 fwide 函數判斷標準輸出流的編碼方案,並輸出其返回值 12 | printf("%d\n",fwide(stdout, 0)); 13 | 14 | // 使用 wprintf 函數輸出 Unicode 字串 wstr 15 | wprintf(L"%lc\n",wstr); 16 | 17 | // 再次使用 fwide 函數判斷標準輸出流的編碼方案,並輸出其返回值 18 | printf("%d",fwide(stdout, 1)); 19 | 20 | // 使用 wcslen 函數獲取 Unicode 字串 L"好" 的長度,並輸出其返回值 21 | printf("strlen(好) = %d\n",(int)wcslen(L"好")); 22 | 23 | // 再次使用 fwide 函數判斷標準輸出流的編碼方案,並輸出其返回值 24 | printf("%d",fwide(stdout, 0)); 25 | 26 | // 輸出 "end",並結束程式 27 | printf("end\n"); 28 | return 0; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /ch05/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g -z lazy -pg -finstrument-functions 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch05/mktemp.c: -------------------------------------------------------------------------------- 1 | // 這個程式創建了一個以隨機文件名命名的文件,並在其中寫入一行文字 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | FILE* stream; 8 | char tmpStr[] = "./shiwulo_XXXXXX"; // 宣告一個字符數組,用於存放隨機文件名 9 | mktemp(tmpStr); // 使用 mktemp 函數生成一個隨機文件名,並將其保存在字符數組 tmpStr 中 10 | printf("%s\n", tmpStr); // 在控制台輸出隨機文件名 11 | stream = fopen(tmpStr, "w+"); // 創建一個以隨機文件名命名的文件,以讀寫方式打開,並獲取其文件指針 12 | if (stream == NULL) 13 | perror("error: "); // 如果打開文件失敗,則在控制台輸出錯誤信息 14 | fputs("hello\0", stdout); // 在標準輸出中輸出一行文字 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /ch05/setvbuf.c: -------------------------------------------------------------------------------- 1 | // 這個程式創建了一個名為 tmp 的文件,並在其中寫入 10000000 個字母 d,使用 setvbuf 函數將文件的緩衝區設置為指定大小,並使用 malloc 函數動態分配內存空間 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | FILE* stream; 8 | int bufSize; 9 | int dataSize = 10000000; 10 | char *buf; 11 | int i; 12 | 13 | stream = fopen("./tmp", "w+"); // 創建一個文件,文件名為 tmp,以讀寫方式打開,並獲取其文件指針 14 | sscanf(argv[1], "%d", &bufSize); // 從命令行參數中讀取緩衝區大小,並將其轉換為整數 15 | buf = (char*)malloc(bufSize); // 使用 malloc 函數動態分配內存空間,大小為緩衝區大小 16 | setvbuf(stream, buf, _IOFBF, bufSize); // 使用 setvbuf 函數將文件的緩衝區設置為指定大小,並指定分配的內存空間 17 | // 在文件中寫入 10000000 個字母 d 18 | for (i=0; i 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | char *str = "中文"; // 宣告一個字符指針 str,並賦值為 "中文" 9 | printf("%d\n", (int)strlen(str)); // 使用 strlen 函數獲取 str 的長度,並輸出其返回值 10 | return 0; 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch05/system-programming.txt: -------------------------------------------------------------------------------- 1 | 0123456789abcdefghijklmnopqrstuvwxyz 2 | system programming 3 | 4 | _ _ 5 | | | (_) 6 | ___ _ _ ___| |_ ___ _ __ ___ _ __ _ __ ___ __ _ _ __ __ _ _ __ ___ _ __ ___ _ _ __ __ _ 7 | / __| | | / __| __/ _ \ '_ ` _ \ | '_ \| '__/ _ \ / _` | '__/ _` | '_ ` _ \| '_ ` _ \| | '_ \ / _` | 8 | \__ \ |_| \__ \ || __/ | | | | | | |_) | | | (_) | (_| | | | (_| | | | | | | | | | | | | | | | (_| | 9 | |___/\__, |___/\__\___|_| |_| |_| | .__/|_| \___/ \__, |_| \__,_|_| |_| |_|_| |_| |_|_|_| |_|\__, | 10 | __/ | | | __/ | __/ | 11 | |___/ |_| |___/ |___/ 12 | append? 13 | -------------------------------------------------------------------------------- /ch05/wcslen.c: -------------------------------------------------------------------------------- 1 | // 這個程式使用寬字符集(wchar_t)輸出一個中文字符串的長度 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | wchar_t* wstr = L"中文"; // 宣告一個寬字符集字符串 wstr,並將其初始化為中文字符串 9 | printf("%d\n", (int)wcslen(wstr)); // 輸出寬字符集字符串的長度,即中文字符串的長度 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /ch05/write+read.c: -------------------------------------------------------------------------------- 1 | // 這個程式創建了一個名為 tmp 的文件,並在其中寫入一行文字,打開方式由命令行參數指定 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | FILE* file; 6 | file = fopen("./tmp", argv[1]); // 創建一個文件,文件名為 tmp,打開方式由命令行參數指定,並獲取其文件指針 7 | fprintf(file, "this_is_a_tmp_file\n"); // 在文件中寫入一行文字 8 | fclose(file); // 關閉文件 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /ch06/README: -------------------------------------------------------------------------------- 1 | sudo apt install -y acl-dev 2 | -------------------------------------------------------------------------------- /ch06/change.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * 功能:用指定的 uid 來執行 /bin/bash 指令 7 | * 用法:./program 8 | * 其中 為要切換的使用者 ID 9 | * 備註:本程式必須以 root 權限執行 10 | */ 11 | int main(int argc, char** argv) { 12 | int uid; 13 | 14 | // 從命令行參數中讀取要切換的使用者 ID 15 | sscanf(argv[1], "%d", &uid); 16 | 17 | // 先以 root 權限執行 setuid(0),再以指定 uid 切換使用者權限 18 | setuid(0); 19 | setuid(uid); 20 | 21 | // 執行 /bin/bash 指令 22 | system("/bin/bash"); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch06/chmod.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * 功能:設定檔案權限 6 | * 用法:./program <檔案名稱> <三位數權限碼> 7 | * 其中 <三位數權限碼> 為三位數數字,表示檔案的所有者、群組、其他人權限 8 | * 備註:本程式必須以 root 權限執行 9 | */ 10 | int main(int argc, char **argv) 11 | { 12 | int perm; 13 | int owner, grp, others; 14 | 15 | // 從命令行參數中讀取要設定權限的檔案名稱和三位數權限碼 16 | sscanf(argv[2], "%1d%1d%1d", &owner, &grp, &others); 17 | 18 | // 將三位數權限碼合併為一個八進制數字 19 | perm = owner << 6 | grp << 3 | others; 20 | 21 | // 使用 chmod 函數設定檔案權限 22 | chmod(argv[1], (mode_t)perm); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /ch06/chowngrp2root.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * 功能:將指定檔案的所有者和群組設為 root 6 | * 用法:sudo ./program <檔案名稱> 7 | * 備註:本程式必須以 root 權限執行 8 | */ 9 | int main(int argc, char** argv) 10 | { 11 | // 使用 chown 函數將檔案的所有者和群組都設為 root 12 | chown(argv[1], 0, 0); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /ch06/dir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * 功能:列出指定目錄中的所有檔案和子目錄名稱 6 | * 用法:./program <目錄名稱> 7 | */ 8 | int main(int argc, char **argv) 9 | { 10 | DIR* dir; 11 | struct dirent* ent; 12 | 13 | // 打開目錄 14 | dir = opendir(argv[1]); 15 | 16 | // 讀取目錄中的所有檔案和子目錄 17 | ent = readdir(dir); 18 | while(ent!=NULL) { 19 | printf("%s\n", ent->d_name); 20 | ent = readdir(dir); 21 | } 22 | 23 | // 關閉目錄 24 | closedir(dir); 25 | 26 | return 0; 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /ch06/dir2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | * 功能:列出指定目錄中的所有檔案和子目錄名稱,以及它們的詳細資訊 11 | * 用法:./program <目錄名稱> 12 | */ 13 | int main(int argc, char **argv) { 14 | DIR* dir; 15 | struct dirent* ent; 16 | char* curDir = "./"; 17 | char pathname[512]; 18 | struct stat buf; 19 | int perm; 20 | char *time; 21 | 22 | // 打開目錄 23 | dir = opendir(argv[1]); 24 | 25 | // 讀取目錄中的所有檔案和子目錄 26 | ent = readdir(dir); 27 | while(ent!=NULL) { 28 | // 構造檔案的完整路徑名稱 29 | strcpy(pathname, curDir); 30 | strcat(pathname, ent->d_name); 31 | 32 | // 使用 stat 函數讀取檔案的詳細資訊 33 | stat(pathname, &buf); 34 | perm = (buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); 35 | time = ctime(&buf.st_atime); 36 | time[strlen(time)-1] = 0; 37 | 38 | // 輸出檔案的詳細資訊 39 | printf("%o %d %d %8d %s %s\n", perm, buf.st_uid, buf.st_gid, (int)buf.st_size, time, ent->d_name); 40 | 41 | ent = readdir(dir); 42 | } 43 | 44 | // 關閉目錄 45 | closedir(dir); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /ch06/dir3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * 功能:列出指定目錄中的所有檔案和子目錄名稱,以及它們的詳細資訊(包括檔案的權限、所有者、群組、大小和修改時間等資訊) 13 | * 用法:./program <目錄名稱> 14 | */ 15 | int main(int argc, char **argv) 16 | { 17 | DIR *dir; 18 | struct dirent *ent; 19 | char *curDir = "./"; 20 | char pathname[512]; 21 | struct stat buf; 22 | int perm; 23 | char *time; 24 | 25 | // 打開目錄 26 | dir = opendir(argv[1]); 27 | 28 | // 讀取目錄中的所有檔案和子目錄 29 | ent = readdir(dir); 30 | while (ent != NULL) 31 | { 32 | // 構造檔案的完整路徑名稱 33 | strcpy(pathname, curDir); 34 | strcat(pathname, ent->d_name); 35 | 36 | // 使用 stat 函數讀取檔案的詳細資訊 37 | stat(pathname, &buf); 38 | perm = (buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); 39 | time = ctime(&buf.st_atime); 40 | time[strlen(time) - 1] = 0; 41 | 42 | // 使用 getpwuid 和 getgrgid 函數獲取檔案的所有者和群組 43 | printf("%o %8s %8s %8d %s %s\n", perm, getpwuid(buf.st_uid)->pw_name, getgrgid(buf.st_gid)->gr_name, (int)buf.st_size, time, ent->d_name); 44 | 45 | ent = readdir(dir); 46 | } 47 | 48 | // 關閉目錄 49 | closedir(dir); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /ch06/getresuid.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * 功能:列出當前進程的實際用戶 ID、有效用戶 ID 和保存的設定 ID 9 | * 用法:./program 10 | */ 11 | int main(int argc, char** argv) { 12 | uid_t ruid, euid, suid; 13 | 14 | // 使用 getresuid 函數獲取當前進程的實際用戶 ID、有效用戶 ID 和保存的設定 ID 15 | getresuid(&ruid, &euid, &suid); 16 | 17 | // 輸出當前進程的用戶 ID 以及對應的用戶名稱 18 | printf("ruid = %d, euid = %d, suid = %d\n", ruid, euid, suid); 19 | printf("ruid = %s, ", getpwuid(ruid)->pw_name); 20 | printf("euid = %s, ", getpwuid(euid)->pw_name); 21 | printf("suid = %s\n", getpwuid(suid)->pw_name); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /ch06/gettime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gettime.c 3 | * 功能:顯示當前系統時間 4 | * 用法:./program 5 | */ 6 | #include 7 | #include 8 | 9 | int main(void) 10 | { 11 | // 獲取當前時間 12 | time_t t = time(NULL); 13 | 14 | // 使用 localtime 函數將時間轉換為 struct tm 格式 15 | struct tm *pTM = localtime(&t); 16 | 17 | // 獲取年、月、日、時、分、秒等時間元素 18 | int yyyy = pTM->tm_year + 1900; 19 | int mm = pTM->tm_mon + 1; 20 | int dd = pTM->tm_mday; 21 | int hh = pTM->tm_hour; 22 | int min = pTM->tm_min; 23 | int ss = pTM->tm_sec; 24 | 25 | // 輸出格式化後的時間 26 | printf("%d-%02d-%02d-%02d:%02d:%02d\n", yyyy, mm, dd, hh, min, ss); 27 | } 28 | -------------------------------------------------------------------------------- /ch06/hw5.c: -------------------------------------------------------------------------------- 1 | /** 2 | DT_BLK This is a block device. 「b」 3 | DT_CHR This is a character device. 「c」 4 | DT_DIR This is a directory. 「d」 5 | DT_FIFO This is a named pipe (FIFO). 「f」 6 | DT_LNK This is a symbolic link. 「l」 7 | DT_REG This is a regular file. 「-」 8 | DT_SOCK This is a UNIX domain socket. 「s」 9 | DT_UNKNOWN The file type could not be determined. 「U」 10 | */ 11 | 12 | 13 | #define _DEFAULT_SOURCE 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | //底下這個.h定義了最長的path name長度 25 | #include 26 | 27 | //檔案型別應該不會超過100個 28 | int filetype[100]; 29 | char fileSymbol[100]; 30 | 31 | //準備統計目錄中到底有多少種檔案型別,如果有該型別在filetype[X]上設定為1,該型別的代表字放在fileSymbol 32 | void initFileTypoe() { 33 | for (int i=0; i< 99; i++) { 34 | filetype[i] = -1; 35 | } 36 | /*同學自己補下去*/ 37 | fileSymbol[DT_BLK]='b'; 38 | fileSymbol[DT_CHR]='c'; 39 | fileSymbol[DT_DIR]='c'; 40 | } 41 | 42 | //回傳某個檔案的大小 43 | int readSize(char* pathname) { 44 | struct stat buf; 45 | //On success, zero is returned. On error, -1 is returned, and errno is set appropriately. 46 | //https://blog.xuite.net/chowler/mainblog/5194764-assert%28%29+%E7%94%A8%E6%B3%95 47 | //assert()裡面填寫『我認為應該如此』,如果不是這樣的話,C函數庫會吐出錯誤訊息給programmer 48 | //在這裡用lstat和stat都可以,因為pathname傳進來的只會是normal file,不會是「捷徑」(softlink) 49 | printf("readSize:%s\n", pathname); 50 | assert(stat(pathname, &buf)==0); 51 | return buf.st_size; 52 | 53 | } 54 | 55 | //使用遞迴計算某個目錄中的所有正規檔案的大小,並統計到底有多少種檔案型別 56 | //如果沒有權限打開該打檔案怎麼辦? 57 | // man access 58 | /* access() checks whether the calling process can access the file path‐ 59 | name. If pathname is a symbolic link, it is dereferenced. 60 | 61 | The mode specifies the accessibility check(s) to be performed, and is 62 | either the value F_OK, or a mask consisting of the bitwise OR of one 63 | or more of R_OK, W_OK, and X_OK. F_OK tests for the existence of the 64 | file. R_OK, W_OK, and X_OK test whether the file exists and grants 65 | read, write, and execute permissions, respectively. 66 | */ 67 | long myCountDir(char* path) { 68 | long size = 0; 69 | //打開該目錄 70 | DIR* dirp = opendir(path); 71 | //讀取該目錄的第一個「物件」 72 | struct dirent* ent = readdir(dirp); 73 | while (ent != NULL) { 74 | //『這個目錄』及『上一層目錄』跳過不處理 75 | if (strcmp(ent->d_name, "." )==0 || strcmp(ent->d_name, ".." )==0) { 76 | ent = readdir(dirp); 77 | continue; 78 | } 79 | //設定有這種檔案型別 80 | filetype[ent->d_type] = 1; 81 | //製造『路徑/名』 82 | //如果使用者的輸入是「/」怎麼辦?,例如:「//home」會發生錯誤嗎? 83 | char pathname[PATH_MAX]=""; 84 | strcat(pathname, path); 85 | strcat(pathname, "/"); 86 | strcat(pathname, ent->d_name); 87 | printf("%s", pathname); 88 | //如果是目錄 89 | if (ent->d_type == DT_REG) { 90 | //遞迴呼叫 91 | size += readSize(pathname); 92 | } else if (ent->d_type == DT_DIR) { 93 | printf("myCountDir:%s\n", pathname); 94 | size += myCountDir(pathname); 95 | } 96 | ent = readdir(dirp); 97 | } 98 | closedir(dirp); 99 | return size; 100 | } 101 | 102 | int main(int argc, char** argv) { 103 | initFileTypoe(); 104 | myCountDir(argv[1]); 105 | } 106 | -------------------------------------------------------------------------------- /ch06/inotify.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //設定每次read最多讀取1000個物件,這裡如果設定太小,可能會有「漏失」某些事件 10 | #define BUF_LEN (1000 * (sizeof(struct inotify_event) + NAME_MAX + 1)) 11 | 12 | void printInotifyEvent(struct inotify_event *event); 13 | 14 | //key-value的映射,陣列的形式,key就是第一個index 15 | //最多可以映射1000個,value最多是10000個字母 16 | char wd[1000][4000]; 17 | 18 | void printInotifyEvent(struct inotify_event *event) 19 | { 20 | int eatRet; 21 | char buf[8192] = ""; 22 | //printf("@event = %p\n", event); 23 | sprintf(buf, "來自[%s]的事件 ", wd[event->wd]); 24 | 25 | //底下是將所有的事件做檢查,照理說應該只會有一個事件 26 | strncat(buf+strlen(buf), "{", 4095); 27 | if (event->mask & IN_ACCESS) { 28 | strncat(buf + strlen(buf), "ACCESS, ", 4095); 29 | } 30 | if (event->mask & IN_ATTRIB) { 31 | strncat(buf + strlen(buf), "ATTRIB, ", 4095); 32 | } 33 | if (event->mask & IN_CLOSE_WRITE) { 34 | strncat(buf + strlen(buf), "CLOSE_WRITE, ", 4095); 35 | } 36 | if (event->mask & IN_CLOSE_NOWRITE) { 37 | strncat(buf + strlen(buf), "IN_CLOSE_NOWRITE, ", 4095); 38 | } 39 | if (event->mask & IN_CREATE) { 40 | strncat(buf + strlen(buf), "IN_CREATE, ", 4095); 41 | } 42 | if (event->mask & IN_DELETE) { 43 | strncat(buf + strlen(buf), "IN_DELETE, ", 4095); 44 | } 45 | if (event->mask & IN_DELETE_SELF) { 46 | strncat(buf + strlen(buf), "IN_DELETE_SELF, ", 4095); 47 | } 48 | if (event->mask & IN_MODIFY) { 49 | strncat(buf + strlen(buf), "IN_MODIFY, ", 4095); 50 | } 51 | if (event->mask & IN_MOVE_SELF) { 52 | strncat(buf + strlen(buf), "IN_MOVE_SELF, ", 4095); 53 | } 54 | if (event->mask & IN_MOVED_FROM) { 55 | strncat(buf + strlen(buf), "IN_MOVED_FROM, ", 4095); 56 | } 57 | if (event->mask & IN_MOVED_TO) { 58 | strncat(buf + strlen(buf), "IN_MOVED_TO, ", 4095); 59 | } 60 | if (event->mask & IN_OPEN) { 61 | strncat(buf + strlen(buf), "IN_OPEN", 4095); 62 | } 63 | if (event->mask & IN_IGNORED) { 64 | strncat(buf + strlen(buf), "IN_IGNORED, ", 4095); 65 | } 66 | if (event->mask & IN_ISDIR) { 67 | strncat(buf + strlen(buf), "IN_ISDIR, ", 4095); 68 | } 69 | if (event->mask & IN_Q_OVERFLOW) { 70 | strncat(buf + strlen(buf), "IN_Q_OVERFLOW, ", 4095); 71 | } 72 | strncat(buf, "}, ", 4095); 73 | eatRet = snprintf(buf + strlen(buf), 4095, "cookie=%d, ", event->cookie); 74 | if (event->len > 0) 75 | eatRet = snprintf(buf + strlen(buf), 4095, "name = %s\n", event->name); 76 | else 77 | eatRet = snprintf(buf + strlen(buf), 4095, "name = null\n"); 78 | printf("%s\n", buf); 79 | } 80 | 81 | int main(int argc, char **argv) 82 | { 83 | //監聽的頻道 84 | int fd; 85 | int nRead, ret, i; 86 | char *eventPtr; 87 | char *inotify_entity = (char *)malloc(BUF_LEN); 88 | //跟作業系統要一個監聽專用的『頻道』,作業系統會幫我們建立一個檔案, 89 | //用這個檔案「送」資料給我們,並且自動開啟該「檔案/頻道」,並給它的fd 90 | fd = inotify_init(); 91 | //設定在哪些檔案監聽哪些事件 92 | for (i = 1; i < argc; i++) 93 | { 94 | //inotify_add_watch,對檔案其路徑是『argv[i]』,監聽所有事件 95 | ret = inotify_add_watch(fd, argv[i], IN_ALL_EVENTS); 96 | if (ret == -1) { 97 | printf("argv[%d]=%s\n", i, argv[i]); 98 | perror("inotify_add_watch"); 99 | } else { 100 | printf("監聽檔案 %s \n", argv[i]); 101 | } 102 | //這裡構成一個簡單的 key-value 的結構 103 | //key是 「watch descriptor」, value是檔案名稱 104 | strcpy(wd[ret], argv[i]); 105 | } 106 | //使用一個while loop不斷地讀取 inotify_init() 所開啟的檔案 fd 107 | //fd 裏面就是我們要監聽的訊息 108 | while (1) 109 | { 110 | //一直讀取,作業系統開給我們的頻道,nRead是這次頻道中的資料量大小 111 | nRead = read(fd, inotify_entity, BUF_LEN); 112 | printf("🎄 🌲 🌳 🌴 🪵 🌱 🌿 ☘️ 🍀 🎍 🪴 🎋\n"); 113 | printf("從與作業系統的秘密檔案通道讀到『%d』個字元\n", nRead); 114 | //底下的 for loop 不斷地將收進來的資料切割成『不定長度的』的 inotify_event 115 | printf("這些字元的解析如下\n"); 116 | for (eventPtr = inotify_entity; eventPtr < inotify_entity + nRead;) 117 | { 118 | printInotifyEvent((struct inotify_event *)eventPtr); 119 | /* 120 | struct inotify_event { 121 | int wd; // Watch descriptor 122 | uint32_t mask; // Mask describing event 123 | uint32_t cookie; // Unique cookie associating related 124 | // events (for rename(2)) 125 | uint32_t len; // Size of name field 🦐 🦞 🦀 在這裏OS會告訴我們name的長度 126 | char name[]; // Optional null-terminated name 127 | }; 128 | */ 129 | //目前這個物件的長度是 基本的inotiry_event的長度 + name字串的長度 130 | //將eventPtr加上物件長度,就是下一個物件的開始位置 131 | eventPtr += sizeof(struct inotify_event) + ((struct inotify_event *)eventPtr)->len; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /ch06/link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) 6 | { 7 | int ret; 8 | 9 | // 確認參數是否符合預期 10 | printf("%d \n", argc); 11 | if (argc == 4) { /* 3個參數,建立符號連結 */ 12 | ret = symlink(argv[2], argv[3]); 13 | printf("%s, %s\n", argv[2], argv[3]); 14 | 15 | // 確認是否建立成功,如果不成功則輸出錯誤訊息 16 | if (ret != 0) 17 | perror("soft link:"); 18 | } else { /* 2個參數,建立硬連結 */ 19 | ret = link(argv[1], argv[2]); 20 | printf("%s, %s\n", argv[1], argv[2]); 21 | 22 | // 確認是否建立成功,如果不成功則輸出錯誤訊息 23 | if (ret != 0) 24 | perror("hard link"); 25 | } 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /ch06/listDirRec.c: -------------------------------------------------------------------------------- 1 | /** 2 | 功能:列出目錄中所有的檔案和子目錄,並以樹狀結構顯示。 3 | 用法:./a.out directory_path 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // 儲存目前的深度,用於縮排 16 | int level = 0; 17 | 18 | // 列出檔案或子目錄的函數 19 | void printName(char* type, char* name) { 20 | printf("%s", type); // 印出檔案型別 21 | for (int i = 0; i < level; i++) { 22 | printf(" "); // 縮排 23 | } 24 | if (strcmp("d", type) == 0) { 25 | printf("+"); // 表示目錄的符號 26 | } else { 27 | printf("|"); // 表示檔案的符號 28 | } 29 | printf("%s\n", name); 30 | } 31 | 32 | // 列出目錄中所有檔案和子目錄的函數 33 | void listDir(char* pathName) 34 | { 35 | level++; // 每進入一層目錄,深度加一 36 | DIR* curDir = opendir(pathName); // 開啟目錄 37 | assert(curDir != NULL); // 確認目錄存在 38 | char* newPathName = (char*)malloc(PATH_MAX); // 記憶體分配 39 | struct dirent entry; 40 | struct dirent* result; 41 | struct direct* ret; 42 | result = readdir(curDir); // 讀取目錄中的內容 43 | while (result != NULL) { 44 | if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) { // 跳過「.」和「..」 45 | result = readdir(curDir); 46 | assert(ret == 0); 47 | continue; 48 | } 49 | assert(ret == 0); 50 | if (entry.d_type == DT_LNK) // 印出軟連結 51 | printName("l", entry.d_name); 52 | if (entry.d_type == DT_REG) // 印出檔案 53 | printName("f", entry.d_name); 54 | if (entry.d_type == DT_DIR) { // 印出目錄,並遞迴呼叫 55 | printName("d", entry.d_name); 56 | sprintf(newPathName, "%s/%s", pathName, entry.d_name); 57 | printf("%s\n", newPathName); 58 | listDir(newPathName); 59 | } 60 | result = readdir(curDir); 61 | assert(ret == 0); 62 | } 63 | closedir(curDir); // 關閉目錄 64 | level--; // 回到上一層目錄,深度減一 65 | } 66 | 67 | int main(int argc, char** argv) { 68 | listDir(argv[1]); // 列出目錄中的所有檔案和子目錄 69 | } 70 | -------------------------------------------------------------------------------- /ch06/list_acl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999-2002 3 | Andreas Gruenbacher, 4 | shiwulo, 5 | usage: ./list_acl ./list_acl.c 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | acl_t acl; 21 | acl_type_t type; 22 | acl_entry_t entry; 23 | acl_tag_t tag; 24 | uid_t *uidp; 25 | gid_t *gidp; 26 | acl_permset_t permset; 27 | char *name; 28 | int entryId, permVal, opt; 29 | char buf[132]; 30 | int ret; 31 | 32 | type = ACL_TYPE_ACCESS; 33 | while ((opt = getopt(argc, argv, "d")) != -1) { 34 | switch (opt) { 35 | case 'd': type = ACL_TYPE_DEFAULT; break; 36 | } 37 | } 38 | acl = acl_get_file(argv[optind], type); 39 | /* Walk through each entry in this ACL */ 40 | for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { 41 | 42 | if (acl_get_entry(acl, entryId, &entry) != 1) 43 | break; /* Exit on error or no more entries */ 44 | 45 | /* Retrieve and display tag type */ 46 | assert(acl_get_tag_type(entry, &tag) != -1); 47 | printf("%-12s", (tag == ACL_USER_OBJ) ? "user_obj" : 48 | (tag == ACL_USER) ? "user" : 49 | (tag == ACL_GROUP_OBJ) ? "group_obj" : 50 | (tag == ACL_GROUP) ? "group" : 51 | (tag == ACL_MASK) ? "mask" : 52 | (tag == ACL_OTHER) ? "other" : "???"); 53 | 54 | /* Retrieve and display optional tag qualifier */ 55 | if (tag == ACL_USER) { 56 | uidp = (uid_t*) acl_get_qualifier(entry); 57 | assert(uidp!=NULL); 58 | name = getpwuid(*uidp)->pw_name; 59 | if (name == NULL) 60 | printf("%-8d ", *uidp); 61 | else 62 | printf("%-8s ", name); 63 | assert(acl_free(uidp) != -1); 64 | } else if (tag == ACL_GROUP) { 65 | gidp = (gid_t*) acl_get_qualifier(entry); 66 | assert(gidp != NULL); 67 | name = getgrgid(*gidp)->gr_name; 68 | if (name == NULL) 69 | printf("%-8d ", *gidp); 70 | else 71 | printf("%-8s ", name); 72 | assert(acl_free(gidp) != -1); 73 | } else { 74 | printf(" "); 75 | } 76 | 77 | /* Retrieve and display permissions */ 78 | acl_get_permset(entry, &permset); 79 | permVal = acl_get_perm(permset, ACL_READ); 80 | assert(permVal != -1); 81 | printf("%c", (permVal == 1) ? 'r' : '-'); 82 | permVal = acl_get_perm(permset, ACL_WRITE); 83 | assert(permVal != -1); 84 | printf("%c", (permVal == 1) ? 'w' : '-'); 85 | permVal = acl_get_perm(permset, ACL_EXECUTE); 86 | assert(permVal != -1); 87 | printf("%c", (permVal == 1) ? 'x' : '-'); 88 | 89 | printf("\n"); 90 | } 91 | assert(acl_free(acl) != -1); 92 | } -------------------------------------------------------------------------------- /ch06/list_acl_simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999-2002 3 | Andreas Gruenbacher, 4 | shiwulo, 5 | 6 | 這個C語言程式碼的主要作用是顯示文件的訪問控制列表(ACL)條目。 7 | 主函數遍歷ACL中的每個條目,顯示標籤類型、可選標籤限定符和權限。 8 | usage:./list_acl_simple ./list_acl.c 9 | */ 10 | 11 | // 引入必要的庫文件 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // 主函數 23 | int main(int argc, char *argv[]) 24 | { 25 | // 定義變數 26 | acl_t acl; 27 | acl_type_t aclType; 28 | acl_entry_t aclEntry; 29 | acl_tag_t aclTag; 30 | uid_t *uidPtr; 31 | gid_t *gidPtr; 32 | acl_permset_t permset; 33 | char *name; 34 | int entryId, permVal, opt, ret; 35 | 36 | // 設置ACL類型 37 | aclType = ACL_TYPE_ACCESS; 38 | if ((opt = getopt(argc, argv, "def")) != -1) { 39 | aclType = ACL_TYPE_DEFAULT; 40 | } 41 | 42 | // 從文件中獲取ACL 43 | acl = acl_get_file(argv[optind], aclType); 44 | 45 | // 遍歷ACL中的每個條目 46 | for (entryId = ACL_FIRST_ENTRY; ; entryId = ACL_NEXT_ENTRY) { 47 | // 檢查是否有更多條目 48 | if (acl_get_entry(acl, entryId, &aclEntry) != 1) 49 | break; 50 | 51 | // 獲取並顯示標籤類型 52 | acl_get_tag_type(aclEntry, &aclTag); 53 | printf("%-12s", (aclTag == ACL_USER_OBJ) ? "owner " : 54 | (aclTag == ACL_USER) ? "user " : 55 | (aclTag == ACL_GROUP_OBJ) ? "file grp " : 56 | (aclTag == ACL_GROUP) ? "group " : 57 | (aclTag == ACL_MASK) ? "mask " : 58 | (aclTag == ACL_OTHER) ? "other " : "???"); 59 | 60 | // 獲取並顯示可選標籤限定符 61 | if (aclTag == ACL_USER) { 62 | uidPtr = (uid_t*) acl_get_qualifier(aclEntry); 63 | printf("%-8s\t", getpwuid(*uidPtr)->pw_name); 64 | } else if (aclTag == ACL_GROUP) { 65 | gidPtr = (gid_t*) acl_get_qualifier(aclEntry); 66 | printf("%-8s\t", getgrgid(*gidPtr)->gr_name); 67 | } else printf("\t\t"); 68 | 69 | // 獲取並顯示權限 70 | acl_get_permset(aclEntry, &permset); 71 | permVal = acl_get_perm(permset, ACL_READ); 72 | printf("%c", (permVal == 1) ? 'r' : '-'); 73 | permVal = acl_get_perm(permset, ACL_WRITE); 74 | printf("%c", (permVal == 1) ? 'w' : '-'); 75 | permVal = acl_get_perm(permset, ACL_EXECUTE); 76 | printf("%c", (permVal == 1) ? 'x' : '-'); 77 | printf("\n"); 78 | } 79 | // 釋放ACL資源 80 | acl_free(acl); 81 | } 82 | -------------------------------------------------------------------------------- /ch06/listattr.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: 3 | listattr filename 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void print_value(char* pathname, char* attr) { 12 | char buf[4096]; 13 | int total; 14 | total=getxattr(pathname, attr, buf, 4096); 15 | for (int i=0; i 6 | #include 7 | #include 8 | #include 9 | int main(int argc, char** argv) 10 | { 11 | struct passwd *user; 12 | user= getpwnam(argv[1]); 13 | assert(user!=NULL); 14 | printf("name:%s\n", user->pw_name); 15 | printf("uid:%d\n", user->pw_uid); 16 | printf("gid:%d\n", user->pw_gid); 17 | } -------------------------------------------------------------------------------- /ch06/rename.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | rename(argv[1], argv[2]); 6 | return 0; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /ch06/watchFile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | //設定每次read最多讀取1000個物件,這裡如果設定太小,可能會有「漏失」某些事件 16 | #define BUF_LEN (1000 * (sizeof(struct inotify_event) + NAME_MAX + 1)) 17 | 18 | //key-value的映射,陣列的形式,key就是第一個index 19 | //最多可以映射1000個,value最多是10000個字母 20 | char wd[1000][4000]; 21 | 22 | int parseInotifyEvent(struct inotify_event *event) 23 | { 24 | int eatRet; 25 | char buf[8192] = ""; 26 | //printf("@event = %p\n", event); 27 | sprintf(buf, "來自[%s]的事件 ", wd[event->wd]); 28 | 29 | //底下是將所有的事件做檢查,照理說應該只會有一個事件 30 | strncat(buf+strlen(buf), "{", 4095); 31 | if (event->mask & IN_ACCESS) return 0; 32 | if (event->mask & IN_ATTRIB) return 0; 33 | //應該只有底下二個事件改變了檔案內容 34 | if (event->mask & IN_CLOSE_WRITE) return 1; 35 | if (event->mask & IN_MODIFY) return 1; 36 | return 0; 37 | } 38 | 39 | void getMTime(int fd, struct tm* tm) { 40 | struct stat statbuf; 41 | struct tm t; 42 | char buf[1000]; 43 | fstat(fd, &statbuf); 44 | tzset(); 45 | localtime_r(&(statbuf.st_mtime), tm); 46 | } 47 | 48 | int main(int argc, char **argv) 49 | { 50 | //監聽的頻道 51 | int fd, readFd; 52 | int nRead, ret, i; 53 | char *eventPtr; 54 | char *inotify_entity = (char *)malloc(BUF_LEN); 55 | struct tm last_mtime, cur_mtime; 56 | char timeStr[100]; 57 | //跟作業系統要一個監聽專用的『頻道』,作業系統會幫我們建立一個檔案, 58 | //用這個檔案「送」資料給我們,並且自動開啟該「檔案/頻道」,並給它的fd 59 | fd = inotify_init(); 60 | //設定在哪些檔案監聽哪些事件 61 | ret = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS); 62 | readFd = open(argv[1], O_RDONLY); 63 | getMTime(readFd, &cur_mtime); 64 | strftime(timeStr, 1000, "%F %T", &cur_mtime); 65 | printf("這次修改時間:%s, 上次修改時間:%s\n", timeStr, timeStr); 66 | FILE *fp = fdopen(readFd, "r"); 67 | assert(fp!=NULL); 68 | char readBuf[1000]; 69 | assert(fgets(readBuf, 1000, fp)!=NULL); 70 | printf("%s\n",readBuf); 71 | 72 | //使用一個while loop不斷地讀取 inotify_init() 所開啟的檔案 fd 73 | //fd 裏面就是我們要監聽的訊息 74 | while (1) 75 | { 76 | int isModify = 0; 77 | for (eventPtr = inotify_entity; eventPtr < inotify_entity + nRead;) 78 | { 79 | isModify=parseInotifyEvent((struct inotify_event *)eventPtr); 80 | //😜 🤪 🤨 🧐當isModify為1時應該要印出時間和資料😜 🤪 🤨 🧐 81 | /* 82 | struct inotify_event { 83 | int wd; // Watch descriptor 84 | uint32_t mask; // Mask describing event 85 | uint32_t cookie; // Unique cookie associating related 86 | // events (for rename(2)) 87 | uint32_t len; // Size of name field 🦐 🦞 🦀 在這裏OS會告訴我們name的長度 88 | char name[]; // Optional null-terminated name 89 | }; 90 | */ 91 | //目前這個物件的長度是 基本的inotiry_event的長度 + name字串的長度 92 | //將eventPtr加上物件長度,就是下一個物件的開始位置 93 | eventPtr += sizeof(struct inotify_event) + ((struct inotify_event *)eventPtr)->len; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ch08/atexit.c: -------------------------------------------------------------------------------- 1 | /* 2 | 目的:測試執行結束時,自動執行函數的功能 3 | 用法:atexit 不用接參數 4 | 練習:除了印出shiwulo以外,再註冊一個函數,列印出你的名字 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | 11 | void myName() { 12 | printf("shiwulo\n"); 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | atexit(myName); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /ch08/cpu_set.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) { 7 | cpu_set_t set; 8 | CPU_ZERO(&set); 9 | int i,j,ret; 10 | CPU_ZERO(&set); 11 | CPU_SET(3, &set); 12 | //ret=sched_setaffinity(0, sizeof(cpu_set_t), &set); 13 | //if (ret==-1) 14 | // perror("sched_setaffinity"); 15 | for(i=0; i<100000; i++) { 16 | for(j=0; j<10000000; j++) { 17 | j=j+1; 18 | } 19 | } 20 | return j; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /ch08/echo.c: -------------------------------------------------------------------------------- 1 | /* 2 | 用法:echo 參數1 參數2 ... 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /*argc,代表在呼叫這個執行檔的時候,總共有幾個參數*/ 10 | /*請注意,第一個參數一定是執行檔的檔名,這樣的設計,有助於除錯*/ 11 | /*例如在pipe中(後面張婕蕙教授),可以將檔名當成輸出資料的一部份*/ 12 | /*argv則是字串陣列,最後一個字串是NULL*/ 13 | 14 | int main(int argc, char**argv) { 15 | int i=0; 16 | 17 | while(argv[i]!=NULL) { 18 | printf("%s\n", argv[i]); 19 | i++; 20 | 21 | } 22 | 23 | /*依照程式的屬性,設定適當的return value*/ 24 | return 1; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /ch08/getEnv.c: -------------------------------------------------------------------------------- 1 | /* 2 | 目的:拿到環境變數的值 3 | 使用方法: 4 | getEnv 環境變數的名稱 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | int main(int argc, char **argv) 11 | { 12 | int i; 13 | char* value; 14 | for (i=1; argv[i]!=NULL; i++) { 15 | value = getenv(argv[i]); 16 | printf("%s=%s\n", argv[i], value); 17 | } 18 | 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /ch08/listEnv.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法: 3 | 不用給任何參數 4 | */ 5 | #define _GNU_SOURCE 6 | #include 7 | #include 8 | #include 9 | extern char **environ; 10 | 11 | int main(int argc, char**argv) { 12 | int i=0; 13 | while(environ[i] != NULL) { 14 | printf("%s\n", environ[i++]); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ch08/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g -pthread 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} -------------------------------------------------------------------------------- /ch08/myNice.c: -------------------------------------------------------------------------------- 1 | /* 2 | 目的:了解如何調整優先權 3 | 用法:myNice 接一個數字(可以是正整數,或者負整數) 4 | 測試: 5 | myNice 10 //優先權降低10 6 | myNice -10 //優先權提高10,如果不是超級使用者無法提高優先權,因此要用sudo myNice -10 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | int main(int argc, char **argv) { 14 | int niceVal; 15 | int newNiceVal; 16 | int i; 17 | int ret=0; 18 | sscanf(argv[1], "%d", &niceVal); 19 | errno =0; 20 | newNiceVal = nice(niceVal); 21 | if (newNiceVal == -1 && errno !=0) 22 | perror("Error: nice"); 23 | else { 24 | printf("new val = %d\n", newNiceVal); 25 | } 26 | 27 | for (int i=0; i<=500000000; i++) { 28 | if (i%50000000 == 0) fprintf(stderr, "*"); 29 | ret+=i; 30 | } 31 | return ret; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /ch08/on_exit.c: -------------------------------------------------------------------------------- 1 | /* 2 | 目的:atexit函數沒辦法帶參數給「離開函數」,atexit可以傳參數 3 | 使用方法: 4 | on_exit 不用接參數 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | 11 | void myName(int ret, void *arg) { 12 | printf("%s shiwulo\n", (char*)arg); 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | char* p = "professor"; 17 | on_exit(myName, p); 18 | return 0; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /ch08/vfork8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int n_fork=0; 7 | int pid; 8 | for (n_fork=0; n_fork<=7; n_fork++) { 9 | pid=fork(); 10 | if (pid==0) continue; 11 | else break; 12 | } 13 | while(1); 14 | } -------------------------------------------------------------------------------- /ch09/NoZombie.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: ./NoZombie 10000 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void manyChild(int num) { 10 | int i, pid; 11 | for (int i=0; i 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | ///color/// 12 | #define NONE "\033[m" 13 | #define RED "\033[0;32;31m" 14 | #define LIGHT_RED "\033[1;31m" 15 | #define GREEN "\033[0;32;32m" 16 | #define LIGHT_GREEN "\033[1;32m" 17 | #define BLUE "\033[0;32;34m" 18 | #define LIGHT_BLUE "\033[1;34m" 19 | #define DARY_GRAY "\033[1;30m" 20 | #define CYAN "\033[0;36m" 21 | #define LIGHT_CYAN "\033[1;36m" 22 | #define PURPLE "\033[0;35m" 23 | #define LIGHT_PURPLE "\033[1;35m" 24 | #define BROWN "\033[0;33m" 25 | #define YELLOW "\033[1;33m" 26 | #define LIGHT_GRAY "\033[0;37m" 27 | #define WHITE "\033[1;37m" 28 | #define RED_BOLD "\x1b[;31;1m" 29 | #define BLU_BOLD "\x1b[;34;1m" 30 | #define YEL_BOLD "\x1b[;33;1m" 31 | #define GRN_BOLD "\x1b[;32;1m" 32 | #define CYAN_BOLD_ITALIC "\x1b[;36;1;3m" 33 | #define RESET "\x1b[0;m" 34 | 35 | /* 36 | 全域變數,放解析過後的使用者指令(字串陣列) 37 | */ 38 | char* argVect[256]; 39 | 40 | /* 41 | parseString:將使用者傳進的命令轉換成字串陣列 42 | str:使用者傳進的命令 43 | cmd:回傳執行檔 44 | 更好的作法:使用strtok 45 | */ 46 | void parseString(char* str, char** cmd) { 47 | char* buf; 48 | int totalLen = strlen(str)-1; 49 | /*fgets拿進來的字串有換行符號,因此扣掉1*/ 50 | int cur=0, flag=0, idx=0; 51 | /*cur代表目前正要讀的字串開頭位置*/ 52 | /*將開頭的空白符號吃光光*/ 53 | while(str[cur] == ' ') 54 | cur++; 55 | while (1) { 56 | sscanf(str+cur, "%ms", &buf); 57 | /*%ms會自動配置記憶體*/ 58 | if (idx==0) *cmd=buf; 59 | /*第一個參數就是執行檔*/ 60 | argVect[idx++]=buf; 61 | cur += strlen(buf)+1; 62 | /*將空白符號吃光光*/ 63 | while(str[cur] == ' ') 64 | cur++; 65 | if (cur >= totalLen) 66 | break; 67 | } 68 | /*依照規定,字串陣列的最尾端要填入NULL*/ 69 | argVect[idx]=NULL; 70 | } 71 | 72 | /* 73 | freeArgVect:釋放掉sanf("%ms");所配置的字串 74 | */ 75 | void freeArgVect() { 76 | int idx; 77 | for(idx=0; argVect[idx]!=NULL; idx++) 78 | free(argVect[idx]); 79 | } 80 | 81 | int main (int argc, char** argv) { 82 | char cmdLine[4096]; 83 | char hostName[256]; 84 | char cwd[256]; 85 | char* exeName; 86 | int pid, pos, wstatus; 87 | while(1) { 88 | char* showPath; 89 | char* loginName = getlogin(); 90 | int homeLen = 0; 91 | gethostname(hostName, 256); 92 | /* 93 | 底下程式碼製造要顯示的路徑字串, 94 | 會參考"home"將"home"路徑取代為~ 95 | */ 96 | getcwd(cwd, 256); 97 | pos=strspn(getenv("HOME"), cwd); 98 | homeLen = strlen(getenv("HOME")); 99 | //printf("cwd=%s, home=%s, pos=%d, prompt=%s", cwd, getenv("HOME"), pos, &cwd[pos]); 100 | if(pos>=homeLen) { 101 | cwd[pos-1]='~'; 102 | showPath=&cwd[pos-1]; 103 | } 104 | else 105 | showPath=cwd; 106 | /* 107 | 底下程式碼負責印出提示符號 108 | */ 109 | printf(LIGHT_GREEN"%s@%s:", loginName, hostName); 110 | printf(BLU_BOLD"%s>> ", showPath); 111 | printf(NONE); 112 | /* 113 | 接收使用者命令,除了cd, exit以外,其他指令呼叫對應的執行檔 114 | */ 115 | fgets(cmdLine, 4096, stdin); 116 | if (strlen(cmdLine)>1) 117 | parseString(cmdLine, &exeName); 118 | else 119 | continue; 120 | if (strcmp(exeName, "exit") == 0) { 121 | freeArgVect(); 122 | break; 123 | } 124 | if (strcmp(exeName, "cd") == 0) { 125 | if (strcmp(argVect[1], "~")==0) 126 | chdir(getenv("HOME")); 127 | else 128 | chdir(argVect[1]); 129 | freeArgVect(); 130 | continue; 131 | } 132 | pid = fork(); 133 | if (pid == 0) { 134 | /* 135 | 產生一個child執行使用者的指令 136 | */ 137 | if (execvp(exeName, argVect)==-1) { 138 | perror("myShell"); 139 | exit(errno*-1); 140 | } 141 | } else { 142 | /* 143 | parent(myShell)等待child完成命令 144 | 完成命令後,parent將child的結束回傳值印出來 145 | */ 146 | wait(&wstatus); 147 | printf(RED "return value of " YELLOW "%s" RED " is " YELLOW "%d\n", 148 | exeName, WEXITSTATUS(wstatus)); 149 | printf(NONE); 150 | } 151 | freeArgVect(); 152 | } 153 | } -------------------------------------------------------------------------------- /ch09/debugFork1.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage debugFork1 3 | */ 4 | #include 5 | #include 6 | #include 7 | 8 | int main(void) 9 | { 10 | pid_t pid; 11 | if ((pid = fork()) == 0) { 12 | printf("child\n"); 13 | } else { 14 | //child執行得太快了,很難去使用 gdb attach 15 | printf("child's pid = %d\n", pid); 16 | printf("parent\n"); 17 | } 18 | printf("end\n"); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /ch09/debugFork2.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: debugFork2 3 | */ 4 | #include 5 | #include 6 | #include 7 | 8 | int main(void) 9 | { 10 | pid_t pid; 11 | int waiting = 1; 12 | if ((pid = fork()) == 0) { 13 | //在child的地方加入一個空回圈,gdb attach成功以後再從gdb中,將waiting設定為 0 14 | while (waiting) 15 | ; 16 | printf("child"); 17 | } else { 18 | printf("child's pid = %d\n", pid); 19 | printf("parent"); 20 | } 21 | printf("end\n"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch09/fork1.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: fork1 3 | */ 4 | 5 | #include 6 | #include 7 | int main () { 8 | int var = 0; 9 | pid_t pid; 10 | pid = fork (); 11 | //注意,printf是在fork後面 12 | printf ("%d", var); 13 | if (pid == 0) { 14 | /* child 執行 */ 15 | fprintf(stderr, "chlid\n"); 16 | var = 1; 17 | } else if (pid > 0) { 18 | /* parent 執行 */ 19 | fprintf(stderr, "parent\n"); 20 | var = 2; 21 | } 22 | printf ("%d", var); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch09/fork2.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: fork2 3 | */ 4 | #include 5 | #include 6 | #include 7 | int main() 8 | { 9 | int var = 0; 10 | pid_t pid; 11 | //printf是在fork前面 12 | //printf("<>");a 13 | pid = fork(); 14 | if(pid == 0) { /* child 執行 */ 15 | var = 1; 16 | printf("child以死,黃天當立\n"); 17 | sleep(1); 18 | 19 | } else if (pid > 0) { /* parent 執行 */ 20 | //signal(SIGCHLD, SIG_IGN); 21 | printf("my pid = %d\n", getpid()); 22 | sleep(100); 23 | } 24 | printf("<<%d>>", var); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /ch09/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch09/manyFork.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: time ./manyFork 100000 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv) { 10 | int i, num, pid, wstatus; 11 | sscanf(argv[1], "%d", &num); 12 | printf("這個應用程式是測試fork %d 次需要花多少時間\n", num); 13 | for (int i=0; i 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char** argv) { 10 | int i, num, pid, wstatus; 11 | sscanf(argv[1], "%d", &num); 12 | printf("這個應用程式是測試 『vfork』 %d 次需要花多少時間\n", num); 13 | //sscanf(argv[1], "%d", &num); 14 | for (int i=0; i 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | ///color/// 12 | #define NONE "\033[m" 13 | #define RED "\033[0;32;31m" 14 | #define LIGHT_RED "\033[1;31m" 15 | #define GREEN "\033[0;32;32m" 16 | #define LIGHT_GREEN "\033[1;32m" 17 | #define BLUE "\033[0;32;34m" 18 | #define LIGHT_BLUE "\033[1;34m" 19 | #define DARY_GRAY "\033[1;30m" 20 | #define CYAN "\033[0;36m" 21 | #define LIGHT_CYAN "\033[1;36m" 22 | #define PURPLE "\033[0;35m" 23 | #define LIGHT_PURPLE "\033[1;35m" 24 | #define BROWN "\033[0;33m" 25 | #define YELLOW "\033[1;33m" 26 | #define LIGHT_GRAY "\033[0;37m" 27 | #define WHITE "\033[1;37m" 28 | #define RED_BOLD "\x1b[;31;1m" 29 | #define BLU_BOLD "\x1b[;34;1m" 30 | #define YEL_BOLD "\x1b[;33;1m" 31 | #define GRN_BOLD "\x1b[;32;1m" 32 | #define CYAN_BOLD_ITALIC "\x1b[;36;1;3m" 33 | #define RESET "\x1b[0;m" 34 | 35 | /* 36 | 全域變數,放解析過後的使用者指令(字串陣列) 37 | */ 38 | char* argVect[256]; 39 | 40 | /* 41 | parseString:將使用者傳進的命令轉換成字串陣列 42 | str:使用者傳進的命令 43 | cmd:回傳執行檔 44 | */ 45 | void parseString(char* str, char** cmd) { 46 | int idx=0; 47 | char* retPtr; 48 | //printf("%s\n", str); 49 | retPtr=strtok(str, " \n"); 50 | while(retPtr != NULL) { 51 | //printf("token =%s\n", retPtr); 52 | //if(strlen(retPtr)==0) continue; 53 | argVect[idx++] = retPtr; 54 | if (idx==1) 55 | *cmd = retPtr; 56 | retPtr=strtok(NULL, " \n"); 57 | } 58 | argVect[idx]=NULL; 59 | } 60 | 61 | int main (int argc, char** argv) { 62 | //在函數中使用陣列不太好,消耗太多stack空間,但主程式應該不會被遞迴呼叫,比較沒關係 63 | char cmdLine[4096]; 64 | char hostName[256]; 65 | char cwd[256]; 66 | char* exeName; 67 | int pid, pos, wstatus; 68 | while(1) { 69 | char* showPath; 70 | char* loginName = getlogin(); 71 | int homeLen = 0; 72 | gethostname(hostName, 256); 73 | /* 74 | 底下程式碼製造要顯示的路徑字串, 75 | 會參考"home"將"home"路徑取代為~ 76 | */ 77 | getcwd(cwd, 256); 78 | pos=strspn(getenv("HOME"), cwd); 79 | homeLen = strlen(getenv("HOME")); 80 | //printf("cwd=%s, home=%s, pos=%d, prompt=%s", cwd, getenv("HOME"), pos, &cwd[pos]); 81 | if(pos>=homeLen) { 82 | cwd[pos-1]='~'; 83 | showPath=&cwd[pos-1]; 84 | } 85 | else 86 | showPath=cwd; 87 | /* 88 | 底下程式碼負責印出提示符號 89 | */ 90 | printf(LIGHT_GREEN"%s@%s:", loginName, hostName); 91 | printf(BLU_BOLD"%s>> ", showPath); 92 | printf(NONE); 93 | /* 94 | 接收使用者命令,除了cd, exit以外,其他指令呼叫對應的執行檔 95 | */ 96 | fgets(cmdLine, 4096, stdin); 97 | if (strlen(cmdLine)>1) 98 | parseString(cmdLine, &exeName); 99 | else 100 | continue; 101 | if (strcmp(exeName, "exit") == 0) 102 | break; 103 | if (strcmp(exeName, "cd") == 0) { 104 | if (strcmp(argVect[1], "~")==0) 105 | chdir(getenv("HOME")); 106 | else 107 | chdir(argVect[1]); 108 | continue; 109 | } 110 | //準備產生child,child會執行execve,parent等待child執行結束 111 | pid = fork(); 112 | if (pid == 0) { 113 | /* 114 | 產生一個child執行使用者的指令 115 | */ 116 | if (execvp(exeName, argVect)==-1) { 117 | perror("myShell"); 118 | exit(errno*-1); 119 | } 120 | } else { 121 | /* 122 | parent(myShell)等待child完成命令 123 | 完成命令後,parent將child的結束回傳值印出來 124 | */ 125 | wait(&wstatus); 126 | printf(RED "return value of " YELLOW "%s" RED " is " YELLOW "%d\n", 127 | exeName, WEXITSTATUS(wstatus)); 128 | printf(NONE); 129 | } 130 | } 131 | } -------------------------------------------------------------------------------- /ch09/testDebug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(void) 7 | { 8 | pid_t pid; 9 | if ((pid = fork()) == 0) { 10 | printf("child's pid = %d\n", getpid()); 11 | } else { 12 | printf("parent's pid = %d\n", getpid()); 13 | } 14 | //可以在下一行設定中斷點 15 | printf("breakpoint\n"); 16 | if (pid ==0) { 17 | //照理說只有child會執行下面這一行,我們之前已經設定中斷點了,gdb可以追蹤到這一行嗎? 18 | //應該無法,這是因為gdb預設追蹤parent 19 | //如果要讓他預設追蹤child的話 20 | //請用google 搜尋 『gdb child process』 21 | system("touch child"); 22 | } 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch09/testStack.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: testStack 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | long long i; 13 | int main(int argc, char** argv) { 14 | char a; 15 | struct rlimit rlim; 16 | //底下是獲得 stack 的大小,預設應該是 8MB 17 | getrlimit(RLIMIT_STACK, &rlim); 18 | printf("soft=%dK, hard=%dK\n", 19 | (int)rlim.rlim_cur/1024, (int)rlim.rlim_max/1024); 20 | printf("pid = %d", getpid()); 21 | //準備開始測試 22 | getchar(); 23 | //測試方法是: 24 | // 1. 變數 a 在堆疊中 25 | // 2. 取得 a 的 address 26 | // 3. 堆疊由上往下長,因此從 a 的 address 開始,不斷的往下存取 27 | // 4. 超過OS預設的堆疊大小時,程式就死掉了,哈哈哈 28 | for (i=0; i<(8192 * 1024); i++) { 29 | if (i%1024 ==0) 30 | printf("%8lld kb\n",i/1024); 31 | *(&a - i) =1; 32 | } 33 | printf("sucess, i = %lld\n", i); 34 | } -------------------------------------------------------------------------------- /ch09/wait.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: 3 | 1st terminal 4 | $ ./wait 5 | 6 | 2nd terminal 7 | $ kill -STOP pid 8 | $ kill -STOP pid 9 | $ kill -CONT pid 10 | $ kill -TERM pid 11 | */ 12 | #include 13 | #include 14 | #include 15 | #include 16 | int main(int argc, char *argv[]) { 17 | pid_t cpid, w; 18 | int wstatus; 19 | cpid = fork(); 20 | if (cpid == 0) { /* Code executed by child */ 21 | //把 pid 記下來,到第二個terminal發出signal給這個 pid 22 | printf("Child PID is %ld\n", (long) getpid()); 23 | //signal後面章節會教, 24 | pause(); /* Wait for signals */ 25 | } 26 | else { /* Code executed by parent */ 27 | do { 28 | //大致上是等待child執行結束 29 | //waitpid的詳細用法請參考 man wait 30 | w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED); 31 | //後續就是用一堆內建的macro,檢查child的狀態 32 | if (WIFEXITED(wstatus)) 33 | printf("Parent: child is exited, status=%d\n", WEXITSTATUS(wstatus)); 34 | if (WIFSIGNALED(wstatus)) 35 | printf("Parent: child is killed by signal %d\n", WTERMSIG(wstatus)); 36 | if (WIFSTOPPED(wstatus)) 37 | printf("Parent: child is stopped by signal %d\n", WSTOPSIG(wstatus)); 38 | if (WIFCONTINUED(wstatus)) 39 | printf("Parent: child is continued\n"); 40 | } while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); 41 | /*當子行程沒有結束並且沒有被signal終止*/ 42 | printf("Parent: bye bye\n"); 43 | exit(EXIT_SUCCESS); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ch09/zombie.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: 3 | 1st terminal 4 | $ ./zombie 10000 5 | 6 | 2nd terminal 7 | $ ps -a 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main(int argc, char** argv) { 15 | int i, num, pid, wstatus; 16 | sscanf(argv[1], "%d", &num); 17 | //底下這個loop會製造很多個child, 18 | for (int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | * @brief sys_siglist 是 libc 內建的,存放所有signal的「邏輯名稱」 10 | * 11 | * @param signumber 12 | */ 13 | 14 | void sighandler(int signumber) { 15 | printf("get a signal named '%d', '%s'\n", signumber, 16 | strsignal(signumber)); 17 | } 18 | 19 | /** 20 | * @brief 假設系統中最多有100個signal,每個號碼都拿去註冊 signalhandler 21 | * 要特別注意一下,有些跟process control的signal是無法註冊的,例如:SIGKILL 22 | * 23 | * @param argc 24 | * @param argv 25 | * @return int 26 | */ 27 | 28 | int main(int argc, char **argv) { 29 | int sig_exist[100]; 30 | int idx = 0; 31 | for (idx = 0; idx < 100; idx++) { 32 | if (signal(idx, sighandler) == SIG_ERR) { 33 | sig_exist[idx] = 0; 34 | } else { 35 | sig_exist[idx] = 1; 36 | } 37 | } 38 | for (idx = 0; idx < 100; idx++) { 39 | if (sig_exist[idx] == 1) 40 | printf("%2d %s\n", idx, strsignal(idx)); 41 | } 42 | printf("my pid is %d\n", getpid()); 43 | printf("press any key to resume\n"); 44 | getchar(); 45 | return 0; 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /ch10/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch10/rec_sig.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /** 8 | * @brief 在這個程式中假設作業系統最多有100個signal, 9 | * 然後每一個signal都去攔截看看 10 | * 這個程式要和send_sig搭配使用 11 | * 12 | */ 13 | 14 | int nSig[100]; 15 | 16 | //所有的signal都使用這一個signal handler接收 17 | void sighandler(int signumber) { 18 | //統計某一種signal收集了多少個 19 | nSig[signumber]++; 20 | } 21 | 22 | int main(int argc, char **argv) { 23 | //得知某一個signal是否可以「註冊」 24 | //特別注意,有些行程管理用的signal是不能註冊的,例如SIGKILL 25 | int sig_exist[100]; 26 | int idx = 0; 27 | for (idx = 0; idx < 100; idx++) { 28 | if (signal(idx, sighandler) == SIG_ERR) { 29 | sig_exist[idx] = 0; 30 | } else { 31 | sig_exist[idx] = 1; 32 | } 33 | } 34 | printf("my pid is %d\n", getpid()); 35 | printf("現在這一個process已經可以開始接收signal了\n"); 36 | printf("press any key to count the signal number\n"); 37 | getchar(); 38 | //列印某種signal各自接收了多少個 39 | for (idx=0; idx<100; idx++) { 40 | if (nSig[idx] != 0) 41 | printf("signal #%d, %d times\n", idx, nSig[idx]); 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /ch10/seg_fault.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int *c; 9 | void sighandler(int signumber) { 10 | printf("get a signal named '%d', '%s'\n", signumber, strsignal(signumber)); 11 | } 12 | int main(int argc, char **argv) { 13 | assert(signal(SIGSEGV, sighandler) != SIG_ERR); 14 | *c = 0xC0FE;/*c沒有初始化就使用*/ 15 | printf("press any key to resume\n"); 16 | getchar(); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /ch10/seg_fault2.c: -------------------------------------------------------------------------------- 1 | /*作者 https://www.facebook.com/scottt.tw*/ 2 | /*修改 羅習五*/ 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* Define 'c' as a global register variable 13 | https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html */ 14 | register unsigned long *c __asm__("r12"); 15 | 16 | void sighandler(int signumber, siginfo_t *sinfo, void *ucontext) { 17 | ucontext_t *context = ucontext; 18 | 19 | printf("got a signal %d(%s)\n", signumber, 20 | strsignal(signumber)); 21 | 22 | /* NOTE: assigning to 'c' instead of 'REG_R12' likely won't work on most systems 23 | due to register content restoration after a signal handler returns */ 24 | context->uc_mcontext.gregs[REG_R12] = (unsigned long) malloc(sizeof(char)); 25 | } 26 | 27 | __attribute__((optimize("Os"))) 28 | int main(int argc, char **argv) { 29 | int r; 30 | struct sigaction sa = { {0} }; 31 | sa.sa_flags = SA_SIGINFO; 32 | sa.sa_sigaction = sighandler; 33 | r = sigaction(SIGSEGV, &sa, NULL); 34 | assert(r == 0); 35 | *c = 0xC0FE; /*segmentation fault*/ 36 | //printf("my pid is %d\n", getpid()); 37 | printf("press any key to resume\n"); 38 | getchar(); 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /ch10/seg_fault_recover.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int *c; 9 | void sighandler(int signumber) { 10 | printf("get a signal named '%d', '%s'\n", signumber, strsignal(signumber)); 11 | c=(int*)malloc(sizeof(int)); 12 | } 13 | int main(int argc, char **argv) { 14 | assert(signal(SIGSEGV, sighandler) != SIG_ERR); 15 | *c = 0xC0FE;/*c沒有初始化就使用*/ 16 | printf("press Enter to continue\n"); 17 | getchar(); 18 | } 19 | -------------------------------------------------------------------------------- /ch10/send_sig.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /** 6 | * @brief 與rec_sig.c搭配使用,可以檢測送出的signal對方是否都收得到 7 | * 8 | * @return int 9 | */ 10 | 11 | int main() { 12 | int pid, signum, times; 13 | int i; 14 | printf("要將signal送給?process ID\n"); 15 | scanf("%d", &pid); 16 | printf("要送出第幾號signal?signal number\n"); 17 | scanf("%d", &signum); 18 | printf("要送出多少個signal?stimes\n"); 19 | scanf("%d", ×); 20 | for (i = 0; i < times; i++) { 21 | //kill不是「殺」,他的意思是「送出signal」 22 | assert(kill(pid, signum) == 0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch10/setjmp_longjmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /** 5 | * @brief 示範setjmp和longjmp的使用方式,請特別注意,只能longjmp到caller 6 | * 可以試試看longjmp到callee看看,如果longjmp到callee會造成錯誤 7 | * 8 | */ 9 | 10 | jmp_buf buf; 11 | 12 | int b() { 13 | puts("stat of b"); 14 | //回傳值可以是任意數字, 15 | //例如5,但請不要回傳0以免造成混淆 16 | longjmp(buf, 5); 17 | puts("end of b"); 18 | } 19 | 20 | int a() { 21 | puts("stat of a"); 22 | b(); 23 | puts("end of a"); 24 | } 25 | 26 | int main(int argc, char** argv) { 27 | int ret; 28 | register int p1=11; 29 | volatile int p2=22; 30 | int p3=33; 31 | p1=1; 32 | p2=2; 33 | p3=3; 34 | //回傳值0有特別用途,代表setjmp成功 35 | if ((ret=setjmp(buf)) == 0) { 36 | a(); 37 | } else { 38 | printf("return form longjmp." 39 | " the return value is %d\n", ret); 40 | printf("p1 = %d, p2 = %d, p3 = %d\n", p1, p2, p3); 41 | } 42 | } -------------------------------------------------------------------------------- /ch10/sigprocmask.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void sighandler(int signumber) { 8 | printf("get a signal named '%d', '%s'\n", signumber, strsignal(signumber)); 9 | } 10 | 11 | /** 12 | * @brief 設定signal的「遮罩」,被「遮住」的signal會被作業系統「暫停分發」, 13 | * 如果發生了「被遮掉的signal」,那麼該signal的狀態會變成「pending」 14 | * 解開「遮罩」的時候,這個process會收到所有的pending signal 15 | * 16 | * @param argc 17 | * @param argv 18 | * @return int 19 | */ 20 | 21 | int main(int argc, char **argv) { 22 | sigset_t sigset; 23 | assert(signal(SIGQUIT, sighandler) != SIG_ERR); 24 | /*終止所有的signal*/ 25 | sigfillset(&sigset); 26 | sigprocmask(SIG_SETMASK, &sigset, NULL); 27 | /*睡10秒鐘,這段時間不會接收signal,因此signal頂多就是pending*/ 28 | printf("sleep 10sec\n"); 29 | for(int i=0; i<10; i++) { 30 | sleep(1); write(1, "*", 1); 31 | } 32 | printf("\n"); 33 | /*重新啓動所有的signal*/ 34 | sigemptyset(&sigset); 35 | sigprocmask(SIG_SETMASK, &sigset, NULL); 36 | while (1) { 37 | pause(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ch10/sigwait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /** 8 | * @brief 主程式停下來,直到等待的signal發生 9 | * 10 | * @return int 11 | */ 12 | 13 | int main() { 14 | sigset_t sigset; 15 | int signo; 16 | //設定為『等所有的signal』 17 | sigfillset(&sigset); 18 | //sigprocmask(SIG_SETMASK, &sigset, NULL); 19 | printf("pid = %d\n", getpid()); 20 | while(1) { 21 | assert(sigwait(&sigset, &signo) == 0); 22 | printf("recv sig#%d\n", signo); 23 | } 24 | } -------------------------------------------------------------------------------- /ch10/testStack2.c: -------------------------------------------------------------------------------- 1 | //gcc decSP4K.s getSP.s -o testStack 2 | //usage testStack mem|reg 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void seg_fault(int sigNo) { 16 | while(1); 17 | } 18 | 19 | /** 20 | * @brief 這個程式碼是不斷的修改SP(stack pointer),藉此讓堆疊變大,Linux預設stack最大只有8MB 21 | * 22 | * @param argc 23 | * @param argv 24 | * @return int 25 | */ 26 | 27 | int main(int argc, char** argv) { 28 | char base; 29 | char *stackP=&base; 30 | int i; 31 | struct rlimit rlim; 32 | int usingSP; 33 | if (signal(SIGSEGV, seg_fault)==SIG_ERR) { 34 | perror("SIGSEGV"); 35 | } 36 | 37 | if (argc != 2) exit(-1); 38 | if (strcmp("reg", argv[1]) ==0) 39 | usingSP = 1; 40 | else usingSP = 0; 41 | 42 | getrlimit(RLIMIT_STACK, &rlim); 43 | printf("soft=%dK, hard=%dK\n", 44 | (int)rlim.rlim_cur/1024, 45 | (int)rlim.rlim_max/1024); 46 | printf("pid = %d", getpid()); 47 | getchar(); 48 | // 在底下這個while loop中不斷的 rsp 暫存器 減去 (4096-8) 49 | // 因為堆疊是由上往下長,因此相當於堆疊不斷的往下長 50 | // 底下有二種寫法,分別使用組合語言,另一個則是使用一個區域變數的address 51 | // 把local variable的address當作是堆疊的開始位址,然後往下移動4096 bytes 52 | while(1) { 53 | if(usingSP) { 54 | __asm__( 55 | "SUB $(4096-8), %rsp;\n" 56 | ); 57 | asm ( 58 | "MOVQ %%rsp, %0;\n" 59 | :"=r"(stackP) 60 | ); 61 | } else { 62 | stackP -= 4096; 63 | } 64 | *stackP = 1; 65 | printf("%ldK\n",(&base - stackP)/(1024)); 66 | } 67 | } -------------------------------------------------------------------------------- /ch10/test_sig.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | volatile char *c; 12 | 13 | void sighandler(int signumber) { 14 | printf("get a signal named '%d', '%s'\n", signumber, strsignal(signumber)); 15 | //c=malloc(sizeof(char)); //這一行到底有沒有用,要看編譯器怎樣編譯 16 | } 17 | 18 | /** 19 | * @brief 一個很簡單程式,故意存取錯誤的記憶體然後攔截這個錯誤。 20 | * 21 | * @param argc 22 | * @param argv 23 | * @return int 24 | */ 25 | 26 | int main(int argc, char **argv) { 27 | assert(signal(SIGINT, sighandler) != SIG_ERR); 28 | //*c = 'a'; //雖然在signal handler的地方重新給 c 值,但 *c 其實已經放在暫存器(register)中,因此signal handler無法修正這個錯誤 29 | printf("my pid is %d\n", getpid()); 30 | printf("press any key to resume\n"); 31 | getchar(); 32 | return 0; 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /ch11/fifo1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char buf[200]; 9 | 10 | int main(int argc, char **argv) { 11 | int fd; 12 | mkfifo("/tmp/shiwulo", 0666); 13 | fd = open("/tmp/shiwulo",O_RDWR); 14 | write(fd, "hello", strlen("hello")+1); 15 | read(fd, buf, 200); 16 | printf("%s\n", buf); 17 | close(fd); 18 | getchar(); 19 | unlink("/tmp/shiwulo"); 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /ch11/fifo2-r.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | char buf[200]; 8 | 9 | int main(int argc, char **argv) { 10 | int fd; int ret; 11 | ret = mkfifo("/tmp/shiwulo", 0666); 12 | printf("mkfifo() = %d\n", ret); 13 | close(0); 14 | fd = open("/tmp/shiwulo",O_RDONLY); 15 | scanf("%s", buf); 16 | printf("%s\n", buf); 17 | scanf("%s", buf); 18 | printf("%s\n", buf); 19 | scanf("%s", buf); 20 | printf("%s\n", buf); 21 | close(fd); 22 | unlink("/tmp/shiwulo"); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ch11/fifo2-w.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char buf[200]; 9 | 10 | int main(int argc, char **argv) { 11 | int fd; 12 | int ret; 13 | ret=mkfifo("/tmp/shiwulo", 0666); 14 | printf("mkfifo() = %d\n", ret); 15 | close(1); 16 | fd = open("/tmp/shiwulo",O_WRONLY); 17 | printf("hello\n"); 18 | printf("1234\n"); 19 | printf("5678\n"); 20 | close(fd); 21 | unlink("/tmp/shiwulo"); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /ch11/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch11/pipe-perf.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法: pipe-perf 讀寫pipe的長度 測試時間 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int cont = 1; 16 | void sig_alarm(int signNo) { 17 | cont = 0; //讓main跳出loop 18 | } 19 | 20 | int main(int argc, char **argv) { 21 | int pipefd[2]; 22 | int child_pid=-1, nloop=0, nsize=0, wstatus, alarmSec=10; 23 | int buf[100000]; 24 | int dest[100000]; 25 | struct timespec start, end; 26 | long elapseTime; 27 | float timeSec; 28 | 29 | if (argc != 3) exit(-1); 30 | sscanf(argv[2], "%d", &alarmSec); 31 | sscanf(argv[1], "%d", &nsize); 32 | 33 | for(int i=0; i < 100000; i++) //初始化buffer 34 | buf[i]=random(); 35 | 36 | signal(SIGALRM, sig_alarm); //註冊alarm 37 | signal(SIGPIPE, SIG_IGN); //避免有人離開造成pipe中斷,同學們可以註解掉這段程式碼看看 38 | 39 | pipe(pipefd); 40 | child_pid = fork(); 41 | if (child_pid==0) { //child; 42 | printf("child's pid is %d\n", getpid()); 43 | close(pipefd[0]); /*for read*/ 44 | alarm(alarmSec); //於"alarmSec"sec以後發出SIGALRM這個訊號 fork並不會繼承alarm,因此要對parent和child各設定一次 45 | while(cont) { 46 | write(pipefd[1], buf, nsize); 47 | nloop++; 48 | } 49 | close(pipefd[1]); 50 | printf("child write: throughput\t%.2fMB/s\n", (((float)nsize* nloop)/ alarmSec/(1024*1024))); 51 | //getchar(); 52 | } else { //parent 53 | printf("parent's pid is %d\n", getpid()); 54 | close(pipefd[1]); 55 | alarm(alarmSec); //於"alarmSec"sec以後發出SIGALRM這個訊號, fork並不會繼承alarm,因此要對parent和child各設定一次 56 | while(cont) { //一直執行,直到程式收到alarm這個signal 57 | read(pipefd[0], buf, nsize); 58 | nloop++; 59 | } 60 | close(pipefd[0]); //要關掉,不然child收不到EOF 61 | wait(&wstatus); 62 | printf("parent read: throughput\t%.2fMB/s\n", (((float)nsize* nloop)/ alarmSec/(1024*1024))); 63 | //測試單純記憶體複製的速度 64 | cont = 1; 65 | nloop = 0; 66 | alarm(alarmSec); 67 | //printf("starting test memory r/w speed...\n"); 68 | while(cont) { 69 | memcpy(dest, buf, nsize); 70 | nloop++; 71 | } 72 | printf("speed of memcpy is \t%.2fMB/s\n", (((float)nsize* nloop)/ alarmSec/(1024*1024))); 73 | //getchar(); 74 | return 0; 75 | } 76 | } -------------------------------------------------------------------------------- /ch11/pipe-perf2.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法: pipe-perf 讀寫pipe的長度 測試時間 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int cont = 1; 19 | const int MB = 1024*1024; 20 | void sig_alarm(int signNo) { 21 | cont = 0; //讓main跳出loop 22 | } 23 | 24 | double timeval2sec(struct timeval input) { 25 | long long us = input.tv_sec*1000000; 26 | us += input.tv_usec; 27 | //printf("%ldsec, %ld us\n", input.tv_sec, input.tv_usec); 28 | return (double)us/1000000.0; 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | int pipefd[2]; 33 | int child_pid=-1, nloop=0, nsize=0, wstatus, alarmSec=10; 34 | int buf[100000]; 35 | int dest[100000]; 36 | struct timespec start, end; 37 | long elapseTime; 38 | float timeSec; 39 | struct itimerval iTime={0}; 40 | struct itimerval virTime={0}; 41 | struct itimerval profTime={0}; 42 | struct rusage resUsage; 43 | 44 | if (argc != 3) exit(-1); 45 | sscanf(argv[2], "%d", &alarmSec); 46 | iTime.it_value.tv_sec = alarmSec; 47 | virTime.it_value.tv_sec = 100; //設定一個很大的值,讓系統不會發生signal SIGVTALRM 48 | profTime.it_value.tv_sec = 100; //設定一個很大的值,讓系統不會發生signal SIGPROF 49 | sscanf(argv[1], "%d", &nsize); 50 | 51 | for(int i=0; i < 100000; i++) //初始化buffer 52 | buf[i]=random(); 53 | 54 | signal(SIGALRM, sig_alarm); //註冊alarm 55 | signal(SIGPIPE, SIG_IGN); //避免有人離開造成pipe中斷,同學們可以註解掉這段程式碼看看 56 | 57 | pipe(pipefd); 58 | child_pid = fork(); 59 | if (child_pid==0) { //child; 60 | //printf("child's pid is %d\n", getpid()); 61 | close(pipefd[0]); /*for read*/ 62 | //alarm(alarmSec); //於"alarmSec"sec以後發出SIGALRM這個訊號 fork並不會繼承alarm,因此要對parent和child各設定一次 63 | assert(setitimer(ITIMER_REAL, &iTime, NULL)==0); 64 | assert(setitimer(ITIMER_VIRTUAL, &virTime, NULL)==0); 65 | assert(setitimer(ITIMER_PROF, &profTime, NULL)==0); 66 | while(cont) { 67 | write(pipefd[1], buf, nsize); 68 | nloop++; 69 | } 70 | close(pipefd[1]); 71 | printf("\nchild write: throughput\t%.2fMB/s\n", (((float)nsize* nloop)/ alarmSec/MB)); 72 | getitimer(ITIMER_VIRTUAL,&virTime); 73 | getitimer(ITIMER_PROF,&profTime); 74 | printf("在user space花費\t= %fsec\n", 100.0-timeval2sec(virTime.it_value)); 75 | printf("整個時間花費\t\t= %fsec\n", 100.0-timeval2sec(profTime.it_value)); 76 | //getchar(); 77 | } else { //parent 78 | //printf("parent's pid is %d\n", getpid()); 79 | close(pipefd[1]); 80 | //alarm(alarmSec); //於"alarmSec"sec以後發出SIGALRM這個訊號, fork並不會繼承alarm,因此要對parent和child各設定一次 81 | assert(setitimer(ITIMER_REAL, &iTime, NULL)==0); 82 | assert(setitimer(ITIMER_VIRTUAL, &virTime, NULL)==0); 83 | assert(setitimer(ITIMER_PROF, &profTime, NULL)==0); 84 | while(cont) { //一直執行,直到程式收到alarm這個signal 85 | read(pipefd[0], buf, nsize); 86 | nloop++; 87 | } 88 | close(pipefd[0]); //要關掉,不然child收不到EOF 89 | //wait(&wstatus); 90 | printf("\nparent read: throughput\t%.2fMB/s\n", (((float)nsize* nloop)/ alarmSec/MB)); 91 | getitimer(ITIMER_VIRTUAL,&virTime); 92 | getitimer(ITIMER_PROF,&profTime); 93 | printf("在user space花費\t= %fsec\n", 100.0-timeval2sec(virTime.it_value)); 94 | printf("整個時間花費\t\t= %fsec\n", 100.0-timeval2sec(profTime.it_value)); 95 | wait3(&wstatus, 0, &resUsage); 96 | //wait(&wstatus); 97 | //int ret=getrusage(RUSAGE_CHILDREN, &resUsage); 98 | //printf("ret = %d\n", ret); 99 | double sysTime = timeval2sec(resUsage.ru_stime); 100 | double usrTime = timeval2sec(resUsage.ru_utime); 101 | printf("total: \t%fs\n" 102 | "user:\t%fs\n" 103 | "sys:\t%fs\n", sysTime+usrTime , usrTime, sysTime); 104 | return 0; 105 | } 106 | } -------------------------------------------------------------------------------- /ch11/pipe1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv) { 6 | int pipefd[2]; 7 | char *str = "hello\n\0"; 8 | char buf[200]; 9 | pipe(pipefd); 10 | write(pipefd[1], str, strlen(str)+1); 11 | read(pipefd[0], buf, 200); 12 | printf("%s", buf); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /ch11/pipe2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) { 7 | int pipefd[2]; 8 | char *str = "hello\n"; 9 | char buf[200]; 10 | 11 | int ret; 12 | pipe(pipefd); 13 | ret = fork(); 14 | assert(ret>=0); 15 | if (ret==0) { 16 | close(pipefd[0]); /*for read*/ 17 | write(pipefd[1], str, strlen(str)+1); 18 | } else { 19 | close(pipefd[1]); 20 | read(pipefd[0], buf, 200); 21 | printf("child: %s", buf); 22 | } 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ch11/pipe3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | int pipefd[2]; 7 | char buf[200]; 8 | 9 | int ret; 10 | pipe(pipefd); 11 | ret = fork(); 12 | assert(ret>=0); 13 | if (ret==0) { /*child*/ 14 | close(1); /*關閉stdout*/ 15 | dup(pipefd[1]); /*將pipefd複製到stdout*/ 16 | close(pipefd[1]); 17 | close(pipefd[0]); 18 | printf("hello"); /*印出 “hello” 到stdout*/ 19 | } else { 20 | close(0); /*關閉stdin*/ 21 | dup(pipefd[0]); /*將pipefd複製到stdin*/ 22 | close(pipefd[0]); 23 | close(pipefd[1]); 24 | scanf("%s", buf); /*從stdin讀入資料*/ 25 | printf("parent: %s\n", buf); 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /ch11/pipe4-2.c: -------------------------------------------------------------------------------- 1 | //usage: pipe4-2 2 | //結果相當於執行: ls | wc 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | int main(int argc, char **argv) { 10 | int pipefd[2]; 11 | int ret, wstat, pid1, pid2; 12 | //char **param={"EXENAME", NULL}; 13 | pipe(pipefd); 14 | pid1 = fork(); //產生第一個child 15 | if (pid1==0) { 16 | close(1); //關閉stdout 17 | dup(pipefd[1]); //將pipefd[1]複製到stdout 18 | close(pipefd[1]); //將沒用到的關閉 19 | close(pipefd[0]); //將沒用到的關閉 20 | execlp("ls", "ls", NULL); //執行ls,ls會將東西藉由stdout輸出到pipefd[1] 21 | } else printf("1st child's pid = %d\n", pid1); 22 | if (pid1>0) { 23 | pid2 = fork();//產生第二個child 24 | if (pid2==0) { 25 | close(0); //關閉stdin 26 | dup(pipefd[0]); //將pipefd[0]複製到stdin 27 | close(pipefd[1]); //將沒用到的關閉 28 | close(pipefd[0]); //將沒用到的關閉 29 | execlp("wc","wc", NULL); //執行wc,wc將透過stdin從pipefd[0]讀入資料 30 | } else printf("2nd child's pid = %d\n", pid2); 31 | } 32 | //parent一定要記得關掉pipe不然wc不會結束(因為沒有接到EOF) 33 | close(pipefd[0]); close(pipefd[1]); 34 | printf("child %d\n",wait(&wstat)); 35 | printf("child %d\n",wait(&wstat)); 36 | } -------------------------------------------------------------------------------- /ch11/pipe4-3.c: -------------------------------------------------------------------------------- 1 | //usage: pipe4-3 killgrp或 pipe4-3 killproc 2 | //結果相當於執行: ls | sort 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int pid1, pid2, killgrp = 0; 13 | 14 | void signal_ctr_c(int signum) { 15 | //殺掉process group 16 | if (killgrp==1) { 17 | fprintf(stderr, "kill process group %d\n", -1*pid1); 18 | kill(-1*pid1, signum); 19 | } else { //殺process 20 | kill(pid1,signum); 21 | } 22 | //parent結束離開 23 | _exit(0); 24 | } 25 | 26 | int main(int argc, char **argv) { 27 | int pipefd[2]; 28 | int ret, wstat; 29 | 30 | if (argc != 2) { 31 | printf("usage pipe4-3 [killgrp|killproc]\n"); 32 | exit(0); 33 | } 34 | if (argc == 2) { 35 | if (strcmp(argv[1], "killgrp") == 0) killgrp=1; 36 | else killgrp=0; 37 | } else if (strcmp(argv[1], "killproc") == 0){ 38 | printf("usage: pipe4-3 [killgrp|killproc]\n"); 39 | exit(0); 40 | } 41 | 42 | //char **param={"EXENAME", NULL}; 43 | printf("parent's group id is %d\n", getpgrp()); 44 | pipe(pipefd); 45 | pid1 = fork(); //產生第一個child 46 | if (pid1==0) { 47 | printf("1st child's group id is %d\n", getpgrp()); 48 | setpgid(0, 0); //將第一個child設定為新的group 49 | printf("1st child's new group id is %d\n", getpgrp()); 50 | close(1); //關閉stdout 51 | dup(pipefd[1]); //將pipefd[1]複製到stdout 52 | close(pipefd[1]); //將沒用到的關閉 53 | close(pipefd[0]); //將沒用到的關閉 54 | execlp("ls", "ls", "-R", "/","--color=always", NULL);//執行ls,ls會將東西藉由stdout輸出到pipefd[1] 55 | //execlp("sleep", "sleep", "100s", NULL);//睡100sec 56 | } else printf("1st child's pid = %d\n", pid1); 57 | if (pid1>0) { 58 | pid2 = fork();//產生第二個child 59 | if (pid2==0) { 60 | printf("2nd child's group id is %d\n", getpgrp()); 61 | setpgid(0, pid1); //第二個child加入第一個child的group 62 | printf("2nd child's new group id is %d\n", getpgrp()); 63 | close(0); //關閉stdin 64 | dup(pipefd[0]); //將pipefd[0]複製到stdin 65 | close(pipefd[1]); //將沒用到的關閉 66 | close(pipefd[0]); //將沒用到的關閉 67 | execlp("sort","sort", NULL); //執行wc,wc將透過stdin從pipefd[0]讀入資料 68 | } else printf("2nd child's pid = %d\n", pid2); 69 | } 70 | //parent一定要記得關掉pipe不然wc不會結束(因為沒有接到EOF) 71 | close(pipefd[0]); close(pipefd[1]); 72 | /*parent註冊signal handler*/ 73 | signal(SIGINT, signal_ctr_c); 74 | printf("child %d\n",wait(&wstat)); 75 | printf("child %d\n",wait(&wstat)); 76 | } -------------------------------------------------------------------------------- /ch11/pipe4.c: -------------------------------------------------------------------------------- 1 | /* 2 | usage: pipe4 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | int main(int argc, char **argv) { 9 | int pipefd[2]; 10 | char buf[200]; 11 | FILE *in_stream; 12 | int ret; 13 | pipe(pipefd); 14 | ret = fork(); 15 | if (ret==0) { /*child 1*/ 16 | printf("I am child 1\n"); 17 | close(1); dup(pipefd[1]); 18 | close(pipefd[1]); close(pipefd[0]); 19 | printf("send by pipe"); 20 | } 21 | if (ret>0) { 22 | ret = fork(); 23 | if (ret==0) { /*child 2*/ 24 | close(0); dup(pipefd[0]); 25 | close(pipefd[1]); close(pipefd[0]); 26 | in_stream=fdopen(0, "r"); 27 | /*用fgets取代gets*/ 28 | fgets(buf, 200, in_stream); 29 | printf("child 2: %s\n", buf); 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /ch12/06-03.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int global=0; 8 | int global1=0, global2=0; 9 | pthread_mutex_t mutex; 10 | 11 | // 1. thread create join (fork, wait。) 12 | // 2. 共用變數的修改要『想辦法』『確保一次只有一個人改』 13 | // 3. 可以將一個共用變數,變成數個,然後再合併結果 14 | 15 | void thread(void* para) { 16 | int i; 17 | int* tmp=(int*)para; 18 | for (i=0; i<1000000000; i++) { 19 | //pthread_mutex_lock(&mutex); //進入critical section 20 | //global+=1; //cache coherence 21 | //atomic_fetch_add(&global, 1); 22 | (*tmp)++; 23 | //pthread_mutex_unlock(&mutex); //離開critical section 24 | } 25 | } 26 | 27 | int main(void) { 28 | pthread_t id1, id2; 29 | int global3=0, global4=0; 30 | //pthread_mutex_init(&mutex, NULL); //mutex預設是unlock 31 | //pthread_create(&id1,NULL,(void *) thread,&global1); 32 | //pthread_create(&id2,NULL,(void *) thread,&global2); 33 | pthread_create(&id1, NULL, (void *)thread, &global3); 34 | pthread_create(&id2, NULL, (void *)thread, &global4); 35 | 36 | pthread_join(id1,NULL); 37 | pthread_join(id2,NULL); 38 | global = global1 + global2; 39 | printf("1000000000+1000000000 = %d\n", global); 40 | } -------------------------------------------------------------------------------- /ch12/2threads/2threads_atomic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | atomic_int global=0; 6 | 7 | void thread(void) { 8 | int i; 9 | for (i=0; i<1000000000; i++) 10 | atomic_fetch_add(&global, 1); 11 | } 12 | 13 | int main(void) { 14 | pthread_t id1, id2; 15 | pthread_create(&id1,NULL,(void *) thread,NULL); 16 | pthread_create(&id2,NULL,(void *) thread,NULL); 17 | pthread_join(id1,NULL); 18 | pthread_join(id2,NULL); 19 | printf("1000000+1000000 = %d\n", global); 20 | return (0); 21 | } 22 | -------------------------------------------------------------------------------- /ch12/2threads/2threads_base.c: -------------------------------------------------------------------------------- 1 | #include 2 | int global=0; 3 | int main(int argc, char **argv) 4 | { 5 | int i; 6 | for (i=0; i<2000000000; i++) { 7 | global+=1; 8 | } 9 | printf("1000000000+1000000000 = %d\n", global); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /ch12/2threads/2threads_mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_mutex_t mutex; 8 | 9 | void thread(void) { 10 | int i; 11 | for (i=0; i<1000000000; i++) { 12 | pthread_mutex_lock(&mutex); //進入critical section 13 | global+=1; 14 | pthread_mutex_unlock(&mutex); //離開critical section 15 | } 16 | } 17 | 18 | int main(void) { 19 | pthread_t id1, id2; 20 | pthread_mutex_init(&mutex, NULL); //mutex預設是unlock 21 | pthread_create(&id1,NULL,(void *) thread,NULL); 22 | pthread_create(&id2,NULL,(void *) thread,NULL); 23 | pthread_join(id1,NULL); 24 | pthread_join(id2,NULL); 25 | printf("1000000000+1000000000 = %d\n", global); 26 | } -------------------------------------------------------------------------------- /ch12/2threads/2threads_nosync.c: -------------------------------------------------------------------------------- 1 | atomic_int turn=0; 2 | atomic_int flag[2] = {0, 0}; 3 | 4 | void p0(void) { 5 | printf("start p0\n"); 6 | while (1) { 7 | atomic_store(&flag[0], 1); 8 | atomic_thread_fence(memory_order_seq_cst); 9 | atomic_store(&turn, 1); 10 | while (atomic_load(&flag[1]) && atomic_load(&turn)==1) 11 | ; //waiting 12 | //底下程式碼用於模擬在critical section 13 | in_cs++; 14 | nanosleep(&ts, NULL); 15 | if (in_cs == 2) fprintf(stderr, "p0及p1都在critical section\n"); 16 | p0_in_cs++; 17 | nanosleep(&ts, NULL); 18 | in_cs--; 19 | //離開critical section 20 | atomic_store(&flag[0], 0); 21 | } 22 | } 23 | 24 | atomic_store(&flag[0], 1); 25 | atomic_thread_fence(memory_order_seq_cst); 26 | atomic_store(&turn, 1); 27 | 28 | struct semaphore { 29 | raw_spinlock_t lock; 30 | unsigned int count; 31 | struct list_head wait_list; 32 | }; 33 | 34 | //在這個driver中,需要先鎖定write_buffer,如果鎖定不成功會cotext-switch 35 | down_interruptible(&dev->write_buffer) 36 | //鎖住spinlock,將這個task放到這個device的waiting queue 37 | spin_lock_irqsave(&device->lock, flags); 38 | //設定:如果收到signal,kernel會喚醒這一個task 39 | set_current_state(TASK_INTERRUPTIBLE); 40 | add_wait_queue(&device->wq, &wait); 41 | spin_unlock_irqrestore(&device->lock, flags); 42 | //task已經進入到waiting queue,因此呼叫scheduler,準備切換到下一個task 43 | schedule_timeout(msecs_to_jiffies(max_waiting_time)); 44 | //能執行到底下這一行,表示這一個task已經被喚醒,因此這一個task已經在run-queue。將自己從wating queue移除 45 | remove_wait_queue(&device->wq, &wait); 46 | //檢查一下被喚醒的原因,是真的等到I/O或者是有人送signal給這個task 47 | if (signal_pending(current)) { 48 | /*被signal喚醒,因此就不等這個I/O了,釋放掉之前鎖定的write buffer*/ 49 | up(&dev->write_buffer); /*被signal喚醒,因此就不等這個I/O了,釋放掉之前鎖定的write buffer*/ 50 | return -ERESTARTSYS; 51 | } 52 | up(&dev->write_buffer); /*等到I/O,要釋放掉之前佔用的write_buffer,如果剛好有人在等,喚醒他*/ 53 | return success; 54 | -------------------------------------------------------------------------------- /ch12/2threads/2threads_notvolatile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int prt = 0; 7 | void sig_handler(int signum) { 8 | prt = 1; 9 | } 10 | 11 | int main(int arg, char** argv) { 12 | signal(SIGINT, sig_handler); 13 | int vol=0; 14 | while(1) { 15 | vol=vol+1; 16 | if (prt==1) { 17 | printf("%d\n", vol); 18 | prt = 0; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch12/2threads/2threads_semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int global=0; 6 | sem_t semaphores; 7 | void thread(void) { 8 | int i; 9 | for (i=0; i<1000000000; i++) { 10 | sem_wait(&semaphores); //向OS要求進入critical section修改global 11 | global+=1; 12 | sem_post(&semaphores); //告訴OS修改完成,離開critical section 13 | } 14 | } 15 | int main(void) { 16 | pthread_t id1, id2; 17 | sem_init(&semaphores, 0, 1); /*0: thread使用,1: semaphore只允許一個人修改global*/ 18 | pthread_create(&id1,NULL,(void *) thread,NULL); 19 | pthread_create(&id2,NULL,(void *) thread,NULL); 20 | pthread_join(id1,NULL); 21 | pthread_join(id2,NULL); 22 | printf("1000000000+1000000000 = %d\n", global); 23 | return (0); 24 | } -------------------------------------------------------------------------------- /ch12/2threads/2threads_spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_spinlock_t spinlock; 8 | 9 | void thread(void) { 10 | int i; 11 | for (i=0; i<1000000000; i++) { 12 | pthread_spin_lock(&spinlock); 13 | global+=1; 14 | pthread_spin_unlock(&spinlock); 15 | } 16 | } 17 | int main(void) { 18 | pthread_t id1, id2; 19 | pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); 20 | pthread_create(&id1,NULL,(void *) thread,NULL); 21 | pthread_create(&id2,NULL,(void *) thread,NULL); 22 | pthread_join(id1,NULL); 23 | pthread_join(id2,NULL); 24 | printf("1000000000+1000000000 = %d\n", global); 25 | return (0); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /ch12/2threads/2threads_using_local_var.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_mutex_t mutex; 8 | 9 | void thread(void) { 10 | int local=0; 11 | int i; 12 | for (i=0; i<1000000000; i++) 13 | local+=1; 14 | 15 | pthread_mutex_lock(&mutex); 16 | global+=local; 17 | pthread_mutex_unlock(&mutex); 18 | } 19 | 20 | int main(void) { 21 | pthread_t id1, id2; 22 | pthread_mutex_init(&mutex, NULL); 23 | pthread_create(&id1,NULL,(void *) thread,NULL); 24 | pthread_create(&id2,NULL,(void *) thread,NULL); 25 | pthread_join(id1,NULL); 26 | pthread_join(id2,NULL); 27 | printf("1000000000+1000000000 = %d\n", global); 28 | } 29 | -------------------------------------------------------------------------------- /ch12/2threads/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -O3 -pthread -D_Float32x=float -D_Float64x="long double" -D_Float32=float -D_Float64="long double" 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch12/2threads/pi_grid.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法: 3 | pi_drand48_r 點的數量 thread的數量 4 | */ 5 | #define _GNU_SOURCE 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int num_thread = 4; 16 | long long total_loopcount = 1000000000; 17 | long long loop_count = 100000; 18 | double global_hit=0.0; 19 | pthread_mutex_t mutex; 20 | 21 | atomic_int assigned_cpuid=0; 22 | 23 | void thread(void* rand_buffer) 24 | { 25 | double point_x,point_y; 26 | long hit=0; 27 | long i; 28 | int j; 29 | long local_loopcount = total_loopcount/num_thread; 30 | double rand_d; 31 | 32 | cpu_set_t cpu_mask; 33 | CPU_ZERO(&cpu_mask); 34 | CPU_SET((int)assigned_cpuid, &cpu_mask); 35 | atomic_fetch_add(&assigned_cpuid, 2); 36 | int ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpu_mask); 37 | assert(ret==0); 38 | 39 | float x=0.0,y=0.0; 40 | long long hit=0; 41 | float granularity = (flaot)1/loop_count; 42 | for (int i=0; i<100000; i++) { 43 | x+=granularity; 44 | for (int j=0; j<100000; j++) { 45 | y+=granularity; 46 | if ((x*x +y*y) <1.0) hit+=1; 47 | } 48 | } 49 | printf("finally, x=%f, y=%f\n", x, y); 50 | printf("hit = %lld\n", hit); 51 | pthread_mutex_lock(&mutex); 52 | global_hit += hit; 53 | pthread_mutex_unlock(&mutex); 54 | } 55 | 56 | 57 | void main(int argc,char*argv[]) { 58 | pthread_t id[16]; 59 | /*初始化drand48_r所要使用的資料結構*/ 60 | //struct drand48_data rand_buffer[16]; 61 | int i; 62 | double pi = 0.0; 63 | double rand_d; 64 | 65 | if (argc >= 2) 66 | total_loopcount=atol(argv[1]); 67 | if (argc >=3) 68 | num_thread=atoi(argv[2]); 69 | pthread_mutex_init(&mutex,NULL); 70 | for(i=0;i 2 | void fun() { 3 | do { 4 | do { 5 | atomic_spin_nop (); 6 | val = atomic_load_relaxed (lock); 7 | } 8 | while (val != 0); 9 | } 10 | while (!atomic_compare_exchange_weak_acquire (lock, &val, 1)); 11 | } 12 | -------------------------------------------------------------------------------- /ch12/alignedas.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | /**/ 6 | struct DS { 7 | int alignas(64) a; 8 | int alignas(64) b; 9 | }; 10 | 11 | void thread(void* local) { 12 | int* _local=(int*) local; 13 | int i; 14 | for (i=0; i<1000000000; i++) 15 | *_local+=1; 16 | } 17 | 18 | int main(void) { 19 | pthread_t id1, id2; 20 | struct DS ds; 21 | ds.a=0; ds.b=0; 22 | printf("sizeof(DS)=%d\n",(int)sizeof(ds)); 23 | pthread_create(&id1,NULL,(void *) thread,&(ds.a)); 24 | pthread_create(&id2,NULL,(void *) thread,&(ds.b)); 25 | pthread_join(id1,NULL); 26 | pthread_join(id2,NULL); 27 | return (0); 28 | } 29 | -------------------------------------------------------------------------------- /ch12/conCurrentQ/buffer_lockfree.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define bufsize 10 15 | unsigned long long buffer[bufsize]; 16 | //__Alignas(int) 17 | _Alignas(int) volatile int in=0, out=0, num=0;; //新進的資料放在buffer[in],讀取資料從buffer[out] 18 | unsigned long long putWaitingOverhead =0; 19 | unsigned long long getWaitingOverhead =0; 20 | int producerProgress = 0; 21 | int consumerProgress = 0; 22 | 23 | void printBufStatus(int signo) { //每100usec印出buffer資料 24 | printf("buf size = %d, in =%d, out =%d\n", num, in, out); 25 | printf("producerProgress = %d, consumerProgress = %d\n", producerProgress, consumerProgress); 26 | } 27 | 28 | void put() { 29 | //puts("put: enter\n"); 30 | static int item=1; //用於除錯,放入buffer的資料都是嚴格遞增的數列 31 | while ((in+1)%bufsize == out) { 32 | //puts("put: waiting\n"); 33 | //putWaitingOverhead++; 34 | ; 35 | } 36 | //atomic_fetch_add(&num, 1); 37 | //puts("put: add a new item\n"); 38 | buffer[in]=item++; //將資料放入 39 | in = (in + 1)%bufsize; 40 | //atomic_thread_fence(???) 41 | //atomic_fetch_add(&in, 1); //規劃下筆資料應該擺放的地點 42 | 43 | } 44 | 45 | void get() { 46 | static int item=0; //用於除錯,紀錄上一次讀取的數字為何 47 | int tmpItem; //讀取的數字暫時放在tmpItem 48 | while (in == out) { 49 | //getWaitingOverhead++; 50 | ; 51 | } 52 | //atomic_fetch_sub(&num, 1); 53 | tmpItem=buffer[out]; //讀出buffer的東西 54 | out = (out + 1)%bufsize; 55 | //atomic_thread_fence(???) 56 | //atomic_fetch_add(&out, 1); //規劃下次要提取資料的地方 57 | 58 | if ((tmpItem - item) != 1) { 59 | fprintf(stderr, "error: tmpItem - item = %d, in=%d, out=%d\n", tmpItem - item, in, out); //用於除錯,如果拿到的資料不是嚴格遞增,表示程式邏輯有錯 60 | getchar(); 61 | } 62 | item=tmpItem; //用於除錯,紀錄這次拿到的數字 63 | } 64 | 65 | void producer(void* name) { //生產資料的執行緒 66 | //ULLONG_MAX 67 | for (producerProgress=0; producerProgress<100000000; producerProgress++) { 68 | put(); 69 | //delay loop 70 | //for (int k=0; i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define bufsize 10 12 | long buffer[bufsize]; 13 | int in=0, out=0; //新進的資料放在buffer[in],讀取資料從buffer[out] 14 | atomic_int num; //用於統計buf內共有多少資料,因為producer和consumer都可能同時修改num,因此需要宣告為atomic_int,後面會介紹 15 | sem_t notFull, notEmpty; //使用semaphore判斷buffer的狀態 16 | 17 | void printBufStatus(int signo) { //每100usec印出buffer資料 18 | printf("buf status is %d\n", num); 19 | } 20 | 21 | void put() { 22 | static int item=1; //用於除錯,放入buffer的資料都是嚴格遞增的數列 23 | sem_wait(¬Full); //等待buffer有空間 24 | //printf("put %d\n", item); 25 | buffer[in]=item++; //將資料放入 26 | in++; in=in%bufsize; //規劃下筆資料應該擺放的地點 27 | atomic_fetch_add(&num, 1); //讀取、加一、寫入,三個動作一次完成 28 | //if (num==bufsize) printf("buffer full\n"); 29 | sem_post(¬Empty); //放入資料了,所以就不是empty 30 | } 31 | 32 | void get() { 33 | static int item=0; //用於除錯,紀錄上一次讀取的數字為何 34 | int tmpItem; //讀取的數字暫時放在tmpItem 35 | sem_wait(¬Empty); //等待buffer有東西 36 | tmpItem=buffer[out]; //讀出buffer的東西 37 | //printf("get %d\n", tmpItem); 38 | out++; out=out%bufsize; //規劃下次要提取資料的地方 39 | if ((tmpItem - item) != 1) fprintf(stderr, "error: tmpItem - item = %d\n", tmpItem - item); //用於除錯,如果拿到的資料不是嚴格遞增,表示程式邏輯有錯 40 | item=tmpItem; //用於除錯,紀錄這次拿到的數字 41 | atomic_fetch_sub(&num, 1); //讀取、減一、寫入,三個動作一次完成 42 | //if (num==0) printf("buffer empty\n"); 43 | sem_post(¬Full); //拿出資料了,因此一定不是full 44 | } 45 | 46 | void producer(void* name) { //生產資料的執行緒 47 | for (int i=0; i<100000000; i++) 48 | put(); 49 | } 50 | 51 | void consumer(void* name) { //消化資料的執行緒 52 | for (int i=0; i<100000000; i++) 53 | get(); 54 | } 55 | int main(void) { 56 | pthread_t id1, id2, id3, id4; 57 | 58 | struct itimerval itime = {0}; 59 | itime.it_interval.tv_usec=1000; 60 | itime.it_value.tv_usec=1000; 61 | signal(SIGPROF, printBufStatus); 62 | //setitimer(ITIMER_PROF, &itime, NULL); 63 | 64 | sem_init(¬Full, 0, bufsize); //剛開始全部是空,因此有bufsize的空間可以放 65 | sem_init(¬Empty, 0, 0); //剛開始沒有東西放在buffer內 66 | pthread_create(&id1,NULL,(void *) producer,NULL); 67 | //pthread_create(&id2,NULL,(void *) producer,NULL); //這個程式只支援一個producer一個consumer,拿掉這個註解會發生錯誤 68 | pthread_create(&id3,NULL,(void *) consumer,NULL); 69 | //pthread_create(&id4,NULL,(void *) consumer,NULL); //這個程式只支援一個producer一個consumer,拿掉這個註解會發生錯誤 70 | pthread_join(id1,NULL); 71 | //pthread_join(id2,NULL); 72 | pthread_join(id3,NULL); 73 | //pthread_join(id4,NULL); 74 | } 75 | -------------------------------------------------------------------------------- /ch12/conCurrentQ/buffer_sem_mutex.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define bufsize 10 12 | long buffer[bufsize]; 13 | int in=0, out=0; //新進的資料放在buffer[in],讀取資料從buffer[out] 14 | atomic_int num; //用於統計buf內共有多少資料,因為producer和consumer都可能同時修改num,因此需要宣告為atomic_int,後面會介紹 15 | sem_t notFull, notEmpty; //使用semaphore判斷buffer的狀態 16 | pthread_mutex_t getMutex, putMutex; 17 | 18 | void printBufStatus(int signo) { //每100usec印出buffer資料 19 | printf("buf status is %d\n", num); 20 | } 21 | 22 | void put() { 23 | static int item=1; //用於除錯,放入buffer的資料都是嚴格遞增的數列 24 | sem_wait(¬Full); //等待buffer有空間 25 | //printf("put %d\n", item); 26 | pthread_mutex_lock(&putMutex); //限制一次一個producer進入 27 | buffer[in]=item++; //將資料放入 28 | in++; in=in%bufsize; //規劃下筆資料應該擺放的地點 29 | pthread_mutex_unlock(&putMutex); 30 | atomic_fetch_add(&num, 1); //讀取、加一、寫入,三個動作一次完成 31 | //if (num==bufsize) printf("buffer full\n"); 32 | sem_post(¬Empty); //放入資料了,所以就不是empty 33 | } 34 | 35 | void get() { 36 | static int item=0; //用於除錯,紀錄上一次讀取的數字為何 37 | int tmpItem; //讀取的數字暫時放在tmpItem 38 | sem_wait(¬Empty); //等待buffer有東西 39 | pthread_mutex_lock(&getMutex); //限制一次一個consumer進入 40 | tmpItem=buffer[out]; //讀出buffer的東西 41 | //printf("get %d\n", tmpItem); 42 | out++; out=out%bufsize; //規劃下次要提取資料的地方 43 | if ((tmpItem - item) != 1) fprintf(stderr, "error: tmpItem - item = %d\n", tmpItem - item); //用於除錯,如果拿到的資料不是嚴格遞增,表示程式邏輯有錯 44 | item=tmpItem; //用於除錯,紀錄這次拿到的數字 45 | pthread_mutex_unlock(&getMutex); 46 | atomic_fetch_sub(&num, 1); //讀取、減一、寫入,三個動作一次完成 47 | //if (num==0) printf("buffer empty\n"); 48 | sem_post(¬Full); //拿出資料了,因此一定不是full 49 | } 50 | 51 | void producer(void* name) { //生產資料的執行緒 52 | for (int i=0; i<100000000; i++) 53 | put(); 54 | } 55 | 56 | void consumer(void* name) { //消化資料的執行緒 57 | for (int i=0; i<100000000; i++) 58 | get(); 59 | } 60 | int main(void) { 61 | pthread_t id1, id2, id3, id4; 62 | 63 | struct itimerval itime = {0}; 64 | itime.it_interval.tv_usec=1000; 65 | itime.it_value.tv_usec=1000; 66 | signal(SIGPROF, printBufStatus); 67 | //setitimer(ITIMER_PROF, &itime, NULL); 68 | 69 | 70 | sem_init(¬Full, 0, bufsize); //剛開始全部是空,因此有bufsize的空間可以放 71 | sem_init(¬Empty, 0, 0); //剛開始沒有東西放在buffer內 72 | pthread_mutex_init(&putMutex, NULL); 73 | pthread_mutex_init(&getMutex, NULL); 74 | pthread_create(&id1,NULL,(void *) producer,NULL); 75 | pthread_create(&id2,NULL,(void *) producer,NULL); //這個程式只支援一個producer一個consumer,拿掉這個註解會發生錯誤 76 | pthread_create(&id3,NULL,(void *) consumer,NULL); 77 | pthread_create(&id4,NULL,(void *) consumer,NULL); //這個程式只支援一個producer一個consumer,拿掉這個註解會發生錯誤 78 | pthread_join(id1,NULL); 79 | pthread_join(id2,NULL); 80 | pthread_join(id3,NULL); 81 | pthread_join(id4,NULL); 82 | } 83 | -------------------------------------------------------------------------------- /ch12/conCurrentQ/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = icc 3 | CFLAGS = -O3 -pthread -D_Float32x=float -D_Float64x="long double" -D_Float32=float -D_Float64="long double" 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch12/cppThread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../tool.h" 3 | #include 4 | #include 5 | 6 | int run(int par) { 7 | for (int i=0; i< 100000; i++) 8 | switch (par) { 9 | case 1: printf(RED"%5d ", i); break; 10 | case 2: printf(GREEN"%5d ", i); break; 11 | case 3: printf(CYAN"%5d ", i); break; 12 | case 4: printf(YELLOW"%5d ", i); break; 13 | } 14 | } 15 | int main(int argc, char** argv) { 16 | std::thread thrd1 (run,0); std::thread thrd2 (run,1); 17 | std::thread thrd3 (run,2); std::thread thrd4 (run,3); 18 | thrd1.join();thrd2.join(); 19 | thrd3.join();thrd4.join(); 20 | } -------------------------------------------------------------------------------- /ch12/cpuShowAffinity.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int global=0; 12 | pthread_mutex_t mutex; 13 | __thread char* threadID; //thread local storage,後面會介紹 14 | 15 | void printCPU(int sigNum) { 16 | //cpu_set_t cpu_set; 17 | //sched_getaffinity(0, sizeof(cpu_set_t), &cpu_set); 18 | if (strcmp(threadID, "1")) 19 | printf("cpu# is %d\n", sched_getcpu()); 20 | else 21 | printf("cpu# is \t%d\n", sched_getcpu()); 22 | } 23 | 24 | void thread(char* id) { 25 | threadID = id; 26 | int i; 27 | for (i=0; i<1000000000; i++) { 28 | pthread_mutex_lock(&mutex); 29 | global+=1; 30 | pthread_mutex_unlock(&mutex); 31 | } 32 | } 33 | 34 | int main(void) { 35 | pthread_t id1, id2; 36 | struct itimerval itime = {0}; 37 | itime.it_interval.tv_sec=1; 38 | itime.it_value.tv_sec=1; 39 | signal(SIGPROF, printCPU); 40 | setitimer(ITIMER_PROF, &itime, NULL); 41 | pthread_mutex_init(&mutex, NULL); //mutex預設是unlock 42 | pthread_create(&id1,NULL,(void *) thread, "1"); 43 | pthread_create(&id2,NULL,(void *) thread, "2"); 44 | pthread_join(id1,NULL); 45 | pthread_join(id2,NULL); 46 | printf("1000000000+1000000000 = %d\n", global); 47 | } -------------------------------------------------------------------------------- /ch12/instructionReordering.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | volatile atomic_int a, b, c, d, e, f; 15 | 16 | int main(int argc, char** argv) { 17 | int w, x, y, z, l , m, n; 18 | atomic_int vol_local; 19 | w = 0x11; 20 | //x = 0x22222; 21 | //y = 0x33333; 22 | //z = 0x44444; 23 | x = &w; 24 | x = &w + 0x22; 25 | atomic_fetch_add_explicit(&vol_local, 1, memory_order_relaxed); 26 | 27 | a=0xaa; 28 | //b=0xbbbb|random(); 29 | //c=0xdddd|random(); 30 | //e=0xeeee|random(); 31 | //f=0xffff|random(); 32 | //printf("%d\n", a|b|c|d|e|f|w|x|y|z); 33 | printf("%d\n", a|w|x); 34 | } -------------------------------------------------------------------------------- /ch12/isItSupportC11thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char** argv) { 3 | #ifdef __STDC_NO_THREADS__ 4 | printf("NO theading support\n"); 5 | #else 6 | printf("have threading support\n"); 7 | #endif 8 | } 9 | -------------------------------------------------------------------------------- /ch12/lockfreeQueue.c: -------------------------------------------------------------------------------- 1 | /* 2 | 執行方法:lockfreeQueue 3 | 不用任何參數 4 | ******注意****** 5 | 這個方法只可以一個producer,一個consumer 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define bufsize 10 22 | unsigned long long buffer[bufsize]; 23 | //__Alignas(int) 24 | _Alignas(int) volatile int in=0, out=0, num=0;; //新進的資料放在buffer[in],讀取資料從buffer[out] 25 | volatile atomic_int putWaitingOverhead =0; 26 | volatile atomic_int getWaitingOverhead =0; 27 | volatile int producerProgress = 0; 28 | volatile int consumerProgress = 0; 29 | 30 | void printBufStatus(int signo) { //每100usec印出buffer資料 31 | printf("buf size = %d, in =%d, out =%d\n", num, in, out); 32 | printf("producerProgress = %d, consumerProgress = %d\n", producerProgress, consumerProgress); 33 | printf("put overhead = %d/sec, get overhead = %d/sec\n", putWaitingOverhead, getWaitingOverhead); 34 | putWaitingOverhead = 0; 35 | getWaitingOverhead = 0; 36 | } 37 | 38 | void put() { 39 | //puts("put: enter\n"); 40 | static int item=1; //用於除錯,放入buffer的資料都是嚴格遞增的數列 41 | while ((in+1)%bufsize == out) { 42 | atomic_fetch_add(&putWaitingOverhead, 1); 43 | ; 44 | } 45 | //atomic_fetch_add(&num, 1); 46 | //puts("put: add a new item\n"); 47 | buffer[in]=item++; //將資料放入 48 | in = (in + 1)%bufsize; 49 | //atomic_thread_fence(???) 50 | //atomic_fetch_add(&in, 1); //規劃下筆資料應該擺放的地點 51 | 52 | } 53 | 54 | void get() { 55 | static int item=0; //用於除錯,紀錄上一次讀取的數字為何 56 | int tmpItem; //讀取的數字暫時放在tmpItem 57 | while (in == out) { 58 | atomic_fetch_add(&getWaitingOverhead, 1); 59 | ; 60 | } 61 | //atomic_fetch_sub(&num, 1); 62 | tmpItem=buffer[out]; //讀出buffer的東西 63 | out = (out + 1)%bufsize; 64 | //atomic_thread_fence(???) 65 | //atomic_fetch_add(&out, 1); //規劃下次要提取資料的地方 66 | 67 | if ((tmpItem - item) != 1) { 68 | fprintf(stderr, "error: tmpItem - item = %d, in=%d, out=%d\n", tmpItem - item, in, out); //用於除錯,如果拿到的資料不是嚴格遞增,表示程式邏輯有錯 69 | getchar(); 70 | } 71 | item=tmpItem; //用於除錯,紀錄這次拿到的數字 72 | } 73 | 74 | void producer(void* name) { //生產資料的執行緒 75 | //ULLONG_MAX 76 | for (producerProgress=0; producerProgress<100000000; producerProgress++) { 77 | put(); 78 | //delay loop 79 | //for (int k=0; i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | volatile atomic_int a, b, c, d, e, f; 15 | 16 | int main(int argc, char** argv) { 17 | volatile int w, x, y, z, l , m, n; 18 | w = 0x1111; 19 | atomic_store_explicit(&a, 0x2222, memory_order_relaxed); 20 | x = 0x3333; 21 | atomic_load_explicit(&b, memory_order_consume); 22 | y=0x5555; 23 | atomic_load_explicit(&c, memory_order_acquire); 24 | z=0x7777; 25 | atomic_store_explicit(&d, 0x8888, memory_order_release); 26 | l=0x9999; 27 | //atomic_store_explicit(&e, 0xAAAA, memory_order_acq_rel); 28 | m=0xBBBB; 29 | //atomic_store_explicit(&f, 0xCCCC, memory_order_seq_cst); 30 | n=0xDDDD; 31 | printf("%d\n", a | b | c | d | e | f | w | x | y | z | l | m | n); 32 | } -------------------------------------------------------------------------------- /ch12/memoryModel_reorder.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(int argc, char** argv) { 3 | volatile int a; 4 | int b; 5 | b = 0xdead; 6 | a = 0xc0fe; 7 | printf("a = %x, b = %x\n", a, b); 8 | } -------------------------------------------------------------------------------- /ch12/memoryTest/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = icc 3 | CFLAGS = -g -pthread -D_Float32x=float -D_Float64x="long double" -D_Float32=float -D_Float64="long double" 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch12/memoryTest/mem_aligned.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct DS { 6 | __attribute__((aligned(64))) volatile long long a; 7 | __attribute__((aligned(64))) volatile long long b; 8 | }; 9 | 10 | struct DS ds; 11 | 12 | void* thread(void* local) { 13 | int select=(int) local; 14 | long long i; 15 | for (i=0; i<10000000000L; i++) { 16 | if (select == 1) 17 | ds.a++; 18 | else 19 | ds.b++; 20 | } 21 | if (select == 1) 22 | printf("%lld\n", ds.a); 23 | else 24 | printf("%lld\n", ds.b); 25 | } 26 | 27 | int main(void) { 28 | pthread_t id1, id2; 29 | volatile struct DS ds; 30 | ds.a=0; ds.b=0; 31 | printf("sizeof(DS)=%d\n",(int)sizeof(ds)); 32 | pthread_create(&id1,NULL,thread, (void *) 0); 33 | pthread_create(&id2,NULL,thread, (void *) 1); 34 | pthread_join(id1,NULL); 35 | pthread_join(id2,NULL); 36 | return (0); 37 | } 38 | -------------------------------------------------------------------------------- /ch12/memoryTest/mem_atomic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | atomic_int atomic=0; 7 | void thread(void* local) { 8 | unsigned long long i; 9 | for (i=0; i<100000000; i++) 10 | atomic_fetch_add(&atomic, 1); 11 | printf("%d\n", atomic); 12 | } 13 | 14 | int main(void) { 15 | pthread_t id1, id2; 16 | printf("sizeof(DS)=%d\n",(int)sizeof(atomic_int)); 17 | pthread_create(&id1,NULL,(void *) thread,NULL); 18 | pthread_create(&id2,NULL,(void *) thread,NULL); 19 | pthread_join(id1,NULL); 20 | pthread_join(id2,NULL); 21 | return (0); 22 | } -------------------------------------------------------------------------------- /ch12/memoryTest/mem_mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_mutex_t mutex; 8 | 9 | void thread(void* local) { 10 | unsigned long long i; 11 | for (i=0; i<100000000; i++) { 12 | pthread_mutex_lock(&mutex); //進入critical section 13 | global+=1; 14 | pthread_mutex_unlock(&mutex); //離開critical section 15 | } 16 | printf("%d\n",global); 17 | } 18 | 19 | int main(void) { 20 | pthread_t id1, id2; 21 | pthread_mutex_init(&mutex, NULL); //mutex預設是unlock 22 | printf("sizeof(DS)=%d\n",(int)sizeof(atomic_int)); 23 | pthread_create(&id1,NULL,(void *) thread,NULL); 24 | pthread_create(&id2,NULL,(void *) thread,NULL); 25 | pthread_join(id1,NULL); 26 | pthread_join(id2,NULL); 27 | return (0); 28 | } -------------------------------------------------------------------------------- /ch12/memoryTest/mem_pingpong.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /*a和b大小只有4個byte,二者合計8個byte*/ 6 | struct DS { 7 | volatile long a; 8 | volatile long b; 9 | }; 10 | 11 | struct DS ds; 12 | 13 | void* thread(void* local) { 14 | int select=(int) local; 15 | long long i; 16 | for (i=0; i<10000000000L; i++) { 17 | if (select == 1) 18 | ds.a++; 19 | else 20 | ds.b++; 21 | } 22 | if (select == 1) 23 | printf("%ld\n", ds.a); 24 | else 25 | printf("%ld\n", ds.b); 26 | } 27 | 28 | int main(void) { 29 | pthread_t id1, id2; 30 | volatile struct DS ds; 31 | ds.a=0; ds.b=0; 32 | printf("sizeof(DS)=%d\n",(int)sizeof(ds)); 33 | pthread_create(&id1,NULL,thread, (void *) 0); 34 | pthread_create(&id2,NULL,thread, (void *) 1); 35 | pthread_join(id1,NULL); 36 | pthread_join(id2,NULL); 37 | return (0); 38 | } 39 | -------------------------------------------------------------------------------- /ch12/memoryTest/mem_sem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | sem_t semaphores; 8 | void thread(void* local) { 9 | unsigned long long i; 10 | for (i=0; i<100000000; i++) { 11 | sem_wait(&semaphores); //向OS要求進入critical section修改global 12 | global+=1; 13 | sem_post(&semaphores); //告訴OS修改完成,離開critical section 14 | } 15 | printf("%d\n", global); 16 | } 17 | 18 | int main(void) { 19 | pthread_t id1, id2; 20 | sem_init(&semaphores, 0, 1); /*0: thread使用,1: semaphore只允許一個人修改global*/ 21 | printf("sizeof(DS)=%d\n",(int)sizeof(atomic_int)); 22 | pthread_create(&id1,NULL,(void *) thread,NULL); 23 | pthread_create(&id2,NULL,(void *) thread,NULL); 24 | pthread_join(id1,NULL); 25 | pthread_join(id2,NULL); 26 | return (0); 27 | } 28 | -------------------------------------------------------------------------------- /ch12/memoryTest/mem_share.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | volatile int share=0; 6 | void thread(void* local) { 7 | unsigned long long i; 8 | for (i=0; i<10000000000; i++) 9 | share+=1; 10 | printf("%d\n", share); 11 | } 12 | 13 | int main(void) { 14 | pthread_t id1, id2; 15 | printf("sizeof(DS)=%d\n",(int)sizeof(int)); 16 | pthread_create(&id1,NULL,(void *) thread,NULL); 17 | pthread_create(&id2,NULL,(void *) thread,NULL); 18 | pthread_join(id1,NULL); 19 | pthread_join(id2,NULL); 20 | return (0); 21 | } -------------------------------------------------------------------------------- /ch12/memoryTest/mem_spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_spinlock_t spinlock; 8 | 9 | void thread(void* local) { 10 | unsigned long long i; 11 | for (i=0; i<100000000; i++) { 12 | pthread_spin_lock(&spinlock); 13 | global+=1; 14 | pthread_spin_unlock(&spinlock); 15 | } 16 | printf("%d\n", global); 17 | } 18 | 19 | int main(void) { 20 | pthread_t id1, id2; 21 | pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); 22 | printf("sizeof(DS)=%d\n",(int)sizeof(atomic_int)); 23 | pthread_create(&id1,NULL,(void *) thread,NULL); 24 | pthread_create(&id2,NULL,(void *) thread,NULL); 25 | pthread_join(id1,NULL); 26 | pthread_join(id2,NULL); 27 | return (0); 28 | } -------------------------------------------------------------------------------- /ch12/mutex_adaptive.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_mutex_t mutex; 8 | 9 | void* thread(void* para) { 10 | int i; 11 | for (i=0; i<1000000; i++) { 12 | pthread_mutex_lock(&mutex); 13 | global+=1; 14 | pthread_mutex_unlock(&mutex); 15 | } 16 | } 17 | 18 | int main(void) { 19 | pthread_t id1, id2; 20 | pthread_mutexattr_t attr; 21 | pthread_mutexattr_init(&attr); 22 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 23 | pthread_mutex_init(&mutex, &attr); 24 | pthread_create(&id1,NULL,(void *) thread,NULL); 25 | pthread_create(&id2,NULL,(void *) thread,NULL); 26 | pthread_join(id1,NULL); 27 | pthread_join(id2,NULL); 28 | printf("1000000+1000000 = %d\n", global); 29 | return (0); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /ch12/perfrecord.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法 sudo perfrecord 執行檔 參數1 參數2 ... 3 | 輸出結果:產生檔案,檔名為 執行檔.perf.data 4 | 觀看執行結果,執行 sudo perf report 執行檔.perf.data 5 | */ 6 | 7 | #define _GNU_SOURCE 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | //#define basic "Power:u,CPI:u,ILP:u,cpu-cycles:u,instructions:u,MLP:u,Load_Miss_Real_Latency:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,task-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u,cpu-migrations:u,Page_Walks_Utilization:u" 25 | //#define basic "cpu-cycles:u,instructions:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,task-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u,cpu-migrations:u" 26 | #define basic "cpu-cycles:u,instructions:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u" 27 | //L1, L2 cache 28 | //#define L1L2 "L1-dcache-loads:u,L1-dcache-load-misses:u,L1-dcache-stores:u,L1-icache-load-misses:u,l2_rqsts.demand_data_rd_hit:u,l2_rqsts.demand_data_rd_miss" 29 | //mem load L3 xsnp 30 | #define mem_load "mem_inst_retired.lock_loads:u,mem_inst_retired.split_loads:u,mem_inst_retired.split_stores:u" 31 | #define cache "mem_load_retired.l1_hit:u,mem_load_retired.l1_miss:u,mem_load_retired.l2_hit:u,mem_load_retired.l2_miss:u,mem_load_retired.l3_hit:u,mem_load_retired.l3_miss:u" 32 | //cross core snoop in one pkg (in package?) 33 | #define xsnp "mem_load_l3_hit_retired.xsnp_hit:u,mem_load_l3_hit_retired.xsnp_hitm:u,mem_load_l3_hit_retired.xsnp_miss:u,mem_load_l3_hit_retired.xsnp_none:u" 34 | //Counts the number of machine clears due to memory order conflicts 35 | #define reorder "machine_clears.memory_ordering:u" 36 | //last level cache 37 | //#define LLC "LLC-loads:u,LLC-load-misses:u,LLC-stores:u,LLC-store-misses:u" 38 | //TLB 39 | #define TLB "dTLB-loads:u,dTLB-load-misses:u,dTLB-stores:u,dTLB-store-misses:u,iTLB-loads:u,iTLB-load-misses:u" 40 | //branch target buffer? 41 | //#define branch "branch-loads:u,branch-load-misses:u" 42 | //cross core (offcore?) snoop 43 | //#define snoop "offcore_response.demand_code_rd.l3_hit.any_snoop:u,offcore_response.demand_code_rd.l3_hit.snoop_hit_no_fwd:u,offcore_response.demand_code_rd.l3_hit.snoop_hitm:u,offcore_response.demand_code_rd.l3_hit.snoop_miss:u,offcore_response.demand_code_rd.l3_hit.snoop_none:u,offcore_response.demand_code_rd.l3_hit.snoop_not_needed:u" 44 | //uncore_cbox L3 Lookup any request that access cache and found line in MESI-state 45 | //#define mesi "unc_cbo_cache_lookup.read_mesi:u,unc_cbo_cache_lookup.write_mesi:u" 46 | //A cross-core snoop initiated by this Cbox 47 | //#define unc_xsnp "unc_cbo_xsnp_response.hit_xcore:u,unc_cbo_xsnp_response.hitm_xcore:u,unc_cbo_xsnp_response.miss_eviction:u,unc_cbo_xsnp_response.miss_xcore:u" 48 | 49 | /* 50 | 全域變數,放解析過後的使用者指令(字串陣列) 51 | */ 52 | char* argVect[256]; 53 | 54 | volatile sig_atomic_t hasChild = 0; 55 | pid_t childPid; 56 | 57 | /*signal handler專門用來處理ctr-c*/ 58 | void ctrC_handler(int sigNumber) { 59 | if (hasChild) { 60 | kill(childPid, sigNumber); 61 | hasChild = 0; 62 | } else { 63 | return; 64 | } 65 | } 66 | 67 | //frequency可以設定到多少請用cat /proc/sys/kernel/perf_event_max_sample_rate查閱,我的是15250,因此設定為 "-F 15250" 68 | char tmpCmdline[4000] = "perf record -e " basic "," mem_load "," cache "," xsnp "," reorder "," TLB " -F 15250 --output=%s.perf.data"; 69 | char cmdLine[4000]; 70 | int idx=0; 71 | 72 | /* 73 | parseString:將使用者傳進的命令轉換成字串陣列 74 | str:使用者傳進的命令 75 | cmd:回傳執行檔 76 | */ 77 | void parseString(char* str, char** cmd) { 78 | 79 | char* retPtr; 80 | //printf("%s\n", str); 81 | retPtr=strtok(str, " "); 82 | while(retPtr != NULL) { 83 | //printf("token =%s\n", retPtr); 84 | //if(strlen(retPtr)==0) continue; 85 | argVect[idx++] = retPtr; 86 | if (idx==1) 87 | *cmd = retPtr; 88 | retPtr=strtok(NULL, " "); 89 | } 90 | //argVect[idx]=NULL; 91 | } 92 | 93 | int main (int argc, char** argv) { 94 | int pid, wstatus, logmode=0; 95 | struct rusage resUsage; //資源使用率 96 | struct timespec statTime, endTime; 97 | /*底下程式碼註冊signal的處理方式*/ 98 | signal(SIGINT, ctrC_handler); 99 | 100 | char** exeName = malloc(200); 101 | 102 | sprintf(cmdLine, tmpCmdline, argv[1]); 103 | //printf("%s\n", cmdLine); 104 | parseString(cmdLine, exeName); 105 | 106 | for (int i=1; ipw_uid, ptr->pw_gid, ptr->pw_name); 124 | //chown(perf_data_pathname, ruid, rgid); 125 | } 126 | } -------------------------------------------------------------------------------- /ch12/perfstat.c: -------------------------------------------------------------------------------- 1 | /* 2 | 使用方法:sudo perfstat 執行檔 參數1 參數2 3 | 如果要產生制式化的顯示,執行 touch ~/.perflog 4 | 如果要產生可讀的的顯示,執行 rm ~/.perflog 5 | */ 6 | 7 | #define _GNU_SOURCE 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | //#define basic "Power:u,CPI:u,ILP:u,cpu-cycles:u,instructions:u,MLP:u,Load_Miss_Real_Latency:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,task-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u,cpu-migrations:u,Page_Walks_Utilization:u" 25 | //#define basic "cpu-cycles:u,instructions:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,task-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u,cpu-migrations:u" 26 | #define basic "cpu-cycles:u,instructions:u,cache-references:u,cache-misses:u,branch-instructions:u,branch-misses:u,bus-cycles:u,cpu-clock:u,page-faults:u,minor-faults:u,major-faults:u,context-switches:u" 27 | //L1, L2 cache 28 | //#define L1L2 "L1-dcache-loads:u,L1-dcache-load-misses:u,L1-dcache-stores:u,L1-icache-load-misses:u,l2_rqsts.demand_data_rd_hit:u,l2_rqsts.demand_data_rd_miss" 29 | //mem load L3 xsnp 30 | #define mem_load "mem_inst_retired.lock_loads:u,mem_inst_retired.split_loads:u,mem_inst_retired.split_stores:u" 31 | #define cache "mem_load_retired.l1_hit:u,mem_load_retired.l1_miss:u,mem_load_retired.l2_hit:u,mem_load_retired.l2_miss:u,mem_load_retired.l3_hit:u,mem_load_retired.l3_miss:u" 32 | //cross core snoop in one pkg (in package?) 33 | #define xsnp "mem_load_l3_hit_retired.xsnp_hit:u,mem_load_l3_hit_retired.xsnp_hitm:u,mem_load_l3_hit_retired.xsnp_miss:u,mem_load_l3_hit_retired.xsnp_none:u" 34 | //Counts the number of machine clears due to memory order conflicts 35 | #define reorder "machine_clears.memory_ordering:u" 36 | //last level cache 37 | //#define LLC "LLC-loads:u,LLC-load-misses:u,LLC-stores:u,LLC-store-misses:u" 38 | //TLB 39 | #define TLB "dTLB-loads:u,dTLB-load-misses:u,dTLB-stores:u,dTLB-store-misses:u,iTLB-loads:u,iTLB-load-misses:u" 40 | //branch target buffer? 41 | //#define branch "branch-loads:u,branch-load-misses:u" 42 | //cross core (offcore?) snoop 43 | //#define snoop "offcore_response.demand_code_rd.l3_hit.any_snoop:u,offcore_response.demand_code_rd.l3_hit.snoop_hit_no_fwd:u,offcore_response.demand_code_rd.l3_hit.snoop_hitm:u,offcore_response.demand_code_rd.l3_hit.snoop_miss:u,offcore_response.demand_code_rd.l3_hit.snoop_none:u,offcore_response.demand_code_rd.l3_hit.snoop_not_needed:u" 44 | //uncore_cbox L3 Lookup any request that access cache and found line in MESI-state 45 | //#define mesi "unc_cbo_cache_lookup.read_mesi:u,unc_cbo_cache_lookup.write_mesi:u" 46 | //A cross-core snoop initiated by this Cbox 47 | //#define unc_xsnp "unc_cbo_xsnp_response.hit_xcore:u,unc_cbo_xsnp_response.hitm_xcore:u,unc_cbo_xsnp_response.miss_eviction:u,unc_cbo_xsnp_response.miss_xcore:u" 48 | 49 | char* argVect[256]; 50 | volatile sig_atomic_t hasChild = 0; 51 | pid_t childPid; 52 | 53 | /*signal handler專門用來處理ctr-c*/ 54 | void ctrC_handler(int sigNumber) { 55 | if (hasChild) { 56 | kill(childPid, sigNumber); 57 | hasChild = 0; 58 | } else { 59 | return; 60 | } 61 | } 62 | 63 | int main (int argc, char** argv) { 64 | int pid, wstatus, logmode=0; 65 | struct rusage resUsage; //資源使用率 66 | struct timespec statTime, endTime; 67 | /*底下程式碼註冊signal的處理方式*/ 68 | signal(SIGINT, ctrC_handler); 69 | 70 | logmode = 1; 71 | 72 | if (logmode == 0) { 73 | argVect[0]="perf"; 74 | argVect[1]="stat"; 75 | argVect[2]="-a"; 76 | argVect[3]="-r"; 77 | argVect[4]="10"; 78 | argVect[5]="--log-fd"; 79 | argVect[6]="2"; 80 | argVect[7]="-e"; 81 | argVect[8]=basic "," mem_load "," cache "," xsnp "," reorder "," TLB ; 82 | for (int i=1; i< argc; i++) 83 | argVect[8+i] = argv[i]; 84 | } else { 85 | argVect[0]="perf"; 86 | argVect[1]="stat"; 87 | argVect[2]="-a"; 88 | argVect[3]="-r"; 89 | argVect[4]="10"; 90 | argVect[5]="-x"; 91 | argVect[6]=";"; 92 | argVect[7]="--log-fd"; 93 | argVect[8]="2"; 94 | argVect[9]="-e"; 95 | argVect[10]=basic "," mem_load "," cache "," xsnp "," reorder "," TLB ; 96 | for (int i=1; i< argc; i++) 97 | argVect[10+i] = argv[i]; 98 | } 99 | 100 | pid = fork(); //除了exit, cd,其餘為外部指令 101 | if (pid == 0) { 102 | /* 103 | cpu_set_t set; 104 | CPU_ZERO(&set); 105 | CPU_SET(5, &set); 106 | int ret = sched_setaffinity(1, sizeof(set), &set); 107 | if (ret==-1) { 108 | perror("sudo"); 109 | exit(errno); 110 | } 111 | */ 112 | if (execvp(argVect[0], argVect)==-1) { 113 | perror("perfstat"); 114 | exit(errno); 115 | } 116 | } else { 117 | childPid = pid;/*通知singal handler,如果使用者按下ctr-c時,要處理這個child*/ 118 | hasChild = 1;/*通知singal handler,正在處理child*/ 119 | wait(&wstatus); 120 | } 121 | } -------------------------------------------------------------------------------- /ch12/pi/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -O3 -lm -pthread -D_Float32x=float -D_Float64x="long double" -D_Float32=float -D_Float64="long double" 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch12/pi/pi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int num_thread; 10 | long total_loopcount; 11 | double global_hit=0.0; 12 | pthread_mutex_t mutex; 13 | long hit[16]; 14 | int idx = 0; 15 | 16 | void sighandler(int signum){ 17 | for (int i=0; i 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int num_thread = 4; 16 | long long total_loopcount = 1000000000; 17 | double global_hit=0.0; 18 | pthread_mutex_t mutex; 19 | 20 | atomic_int assigned_cpuid=0; 21 | 22 | void thread(void* rand_buffer) 23 | { 24 | double point_x,point_y; 25 | long hit=0; 26 | long i; 27 | int j; 28 | long local_loopcount = total_loopcount/num_thread; 29 | double rand_d; 30 | 31 | cpu_set_t cpu_mask; 32 | CPU_ZERO(&cpu_mask); 33 | CPU_SET((int)assigned_cpuid, &cpu_mask); 34 | atomic_fetch_add(&assigned_cpuid, 2); 35 | int ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpu_mask); 36 | assert(ret==0); 37 | 38 | printf("local_loopcount =%ld\n", local_loopcount); 39 | for(i=0;i= 2) 67 | total_loopcount=atol(argv[1]); 68 | if (argc >=3) 69 | num_thread=atoi(argv[2]); 70 | pthread_mutex_init(&mutex,NULL); 71 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | int threadcount; 6 | long loopcount; 7 | double globalPi=0.0; 8 | pthread_mutex_t mutex; 9 | 10 | void thread(void) 11 | { 12 | double localPi = 0.0; 13 | double point_x,point_y; 14 | long incount=0; 15 | long i; 16 | long localtotal = loopcount/threadcount; 17 | 18 | srand((unsigned)time(NULL)); 19 | 20 | for(i=0;i 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | volatile atomic_int complete=0; //complete是二個thread共用的變數 21 | const long long nspersec = 1000000000; 22 | 23 | long long timespec2ns(struct timespec ts) { 24 | long long ns = ts.tv_nsec; 25 | ns += ts.tv_sec * nspersec; 26 | return ns; 27 | } 28 | 29 | void workingThread(void) { 30 | volatile double result; 31 | struct timespec start, end; 32 | clock_gettime(CLOCK_MONOTONIC, &start); 33 | for (volatile long long j=0; j<100000; j++) 34 | for (volatile long long i=0; i<100000; i++) 35 | result += (double)i*j; 36 | clock_gettime(CLOCK_MONOTONIC, &end); 37 | long long delta = timespec2ns(end) - timespec2ns(start); 38 | atomic_store_explicit(&complete, 1, memory_order_relaxed); 39 | printf("res=%f, time = %lld.%lld\n", result, delta/nspersec, delta%nspersec); 40 | } 41 | 42 | volatile int doSleep=0; 43 | void waitingThread(void) { 44 | int local=0; 45 | while (local != 1) { //密集迴圈不斷的讀取complete 46 | //local=atomic_load_explicit(&complete, memory_order_relaxed); 47 | local=atomic_load_explicit(&complete, memory_order_seq_cst); 48 | if (doSleep==1) sleep(1); //如果doSleep設定為1,則不會執行密集的讀取,每秒讀取一次 49 | } 50 | } 51 | 52 | int main(int argc, char** argv) { 53 | printf("argc=%d\n", argc); 54 | if (argc == 2) doSleep =1; 55 | pthread_t id1, id2; 56 | pthread_create(&id1,NULL,(void *) workingThread,NULL); 57 | pthread_create(&id2,NULL,(void *) waitingThread,NULL); 58 | pthread_join(id1,NULL); 59 | pthread_join(id2,NULL); 60 | } -------------------------------------------------------------------------------- /ch12/rwspinlock.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | __thread int thread_local_id; 14 | //atomic_int count; 15 | 16 | const int maxTicket = 1000; 17 | volatile atomic_int nTicket; //一定要加上volatile,否則-O3會出錯 18 | 19 | volatile atomic_int wrt_in_cs_success; 20 | volatile atomic_int rd_in_cs_success; 21 | //volatile atomic_int rd_in_parallel; 22 | volatile atomic_int n_rd_parallel; 23 | volatile int total_parallel; 24 | volatile atomic_int rd_count; 25 | 26 | void alarmHandler(int sigNo) { //for debugging 27 | printf("nTicket = %d\n", nTicket); 28 | printf("total number of reader entering CS = %d/sec\n", rd_in_cs_success); 29 | printf("total number of writer entering CS = %d/sec\n", wrt_in_cs_success); 30 | printf("parallel level of read = %f\n", ((float)total_parallel)/rd_count); 31 | atomic_store(&rd_in_cs_success,0); 32 | atomic_store(&wrt_in_cs_success,0); 33 | alarm(1); 34 | } 35 | 36 | void init_rwspinlock() { 37 | atomic_store(&nTicket, maxTicket); 38 | } 39 | 40 | void wrt_lock() { 41 | while(1) { 42 | atomic_fetch_sub(&nTicket, maxTicket); 43 | int ret=atomic_load(&nTicket); 44 | if (ret == 0) { //success 45 | atomic_fetch_add(&wrt_in_cs_success, 1); //for debugging 46 | return; 47 | } 48 | else { 49 | atomic_fetch_add(&nTicket, maxTicket); 50 | } 51 | } 52 | } 53 | 54 | void wrt_unlock() { 55 | atomic_fetch_add(&nTicket, maxTicket); 56 | //printf("wrt_unlock, nTicket = %d\n", nTicket); 57 | } 58 | 59 | 60 | 61 | void rd_lock() { 62 | while(1) { 63 | atomic_fetch_sub(&nTicket, 1); 64 | int ret = atomic_load(&nTicket); 65 | if (ret > 0) { //success 66 | atomic_fetch_add(&n_rd_parallel, 1); //for debugging 67 | total_parallel += atomic_load(&n_rd_parallel); //for debugging 68 | atomic_fetch_add(&rd_count, 1); //for debugging 69 | return; 70 | } 71 | else 72 | atomic_fetch_add(&nTicket, 1); //redo 73 | } 74 | } 75 | 76 | void rd_unlock() { 77 | atomic_fetch_sub(&n_rd_parallel, 1); 78 | //atomic_fetch_sub(&rd_in_parallel, 1); //for debugging 79 | atomic_fetch_add(&nTicket, 1); 80 | } 81 | 82 | void rd_thread(void* para) { 83 | for (;;) { 84 | rd_lock(); 85 | atomic_fetch_add_explicit(&rd_in_cs_success, 1, memory_order_relaxed); //for debugging 86 | for (int i=0; i< random()%100; i++) //computing 87 | ; 88 | rd_unlock(); 89 | 90 | for (int i=0; i< random()%100; i++) //remainder section 91 | ; 92 | } 93 | } 94 | 95 | void wrt_thread(void* para) { //注意,可以有多個writer 96 | while(1) { 97 | wrt_lock(); 98 | //printf("enter writer's CS\n"); 99 | for (int i=0; i< random()%100; i++) //computing, read-write 100 | ; 101 | wrt_unlock(); 102 | //printf("writer exit CS\n"); 103 | for (int i=0; i< random()%100; i++) //remainder section 104 | ; 105 | } 106 | } 107 | 108 | int main(int argc, char** argv) { 109 | pthread_t* r_id; 110 | pthread_t* w_id; 111 | int nThread = 4; 112 | if (argc == 2) 113 | sscanf(argv[1], "%d", &nThread); 114 | printf("建立%d個reader\n", nThread); 115 | printf("建立%d個writer\n", nThread); 116 | printf("按下Enter鍵繼續"); 117 | getchar(); 118 | r_id = (pthread_t*)malloc(sizeof(pthread_t) * nThread); 119 | w_id = (pthread_t*)malloc(sizeof(pthread_t) * nThread); 120 | 121 | init_rwspinlock(); 122 | for (int i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | pthread_mutex_t mutex; 9 | sem_t semaphore1, semaphore2; 10 | int gotoSleep; 11 | 12 | int nsecpersec = 1000000000; 13 | char* showTime() { 14 | static char timeStr[200]; 15 | struct timespec ts; 16 | clock_gettime(CLOCK_REALTIME, &ts); 17 | long nsec = ts.tv_sec * nsecpersec + ts.tv_nsec; 18 | sprintf(timeStr, "%ld.%ld", nsec/nsecpersec, nsec%nsecpersec); 19 | return timeStr; 20 | } 21 | 22 | void p(void* para) { 23 | for (int i=0; i< 100; i++) { 24 | pthread_mutex_lock(&mutex); 25 | //printf("%s, thread1 enter CS\n", showTime()); 26 | sem_post(&semaphore1); 27 | if(gotoSleep) usleep(1); 28 | pthread_mutex_unlock(&mutex); 29 | sem_wait(&semaphore2); 30 | } 31 | } 32 | 33 | void q(void* para) { 34 | for(int i=0; i< 100; i++) { 35 | //printf("%s, thread2 try lock\n", showTime()); 36 | sem_wait(&semaphore1); 37 | //printf("%s, thread2 enter CS\n", showTime()); 38 | pthread_mutex_lock(&mutex); 39 | 40 | pthread_mutex_unlock(&mutex); 41 | sem_post(&semaphore2); 42 | } 43 | } 44 | 45 | int main(int argc, char** argv) { 46 | pthread_t id1, id2; 47 | pthread_mutexattr_t attr; 48 | 49 | if (argc >= 2) 50 | gotoSleep = 1; 51 | else gotoSleep = 0; 52 | 53 | sem_init(&semaphore1, 0, 0); 54 | sem_init(&semaphore2, 0, 0); 55 | pthread_mutexattr_init(&attr); 56 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 57 | pthread_mutex_init(&mutex, &attr); 58 | pthread_create(&id1,NULL,(void *) p,NULL); 59 | pthread_create(&id2,NULL,(void *) q,NULL); 60 | pthread_join(id1,NULL); 61 | pthread_join(id2,NULL); 62 | return (0); 63 | } -------------------------------------------------------------------------------- /ch12/signal-wait_mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | pthread_mutex_t mutex; 8 | 9 | void thread1(void) { 10 | int ret = pthread_mutex_unlock(&mutex);//喚醒thead2//post 11 | if (ret != 0) { 12 | errno=ret; //蠻特別的,要自己設定errno 13 | perror("ulock"); 14 | } 15 | } 16 | 17 | void thread2(void) { 18 | int ret = pthread_mutex_lock(&mutex); 19 | ret = pthread_mutex_lock(&mutex); 20 | if (ret != 0) { //thread1等待thread2//wait 21 | errno=ret; //蠻特別的,要自己設定errno 22 | perror("lock"); 23 | } 24 | } 25 | 26 | int main(void) { 27 | pthread_t id1, id2; 28 | pthread_mutexattr_t attr; 29 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 30 | pthread_mutex_init(&mutex, &attr); //如果傳的第二個參數是NULL,程式會卡死 31 | pthread_create(&id1,NULL,(void *) thread1,NULL); 32 | pthread_create(&id2,NULL,(void *) thread2,NULL); 33 | pthread_join(id1,NULL); 34 | pthread_join(id2,NULL); 35 | } -------------------------------------------------------------------------------- /ch12/signal-wait_semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | sem_t semaphores; 10 | 11 | void thread1(void) { 12 | printf("thread1: sleep 10 sec.\n"); 13 | for (int i=0; i<10; i++){ 14 | fprintf(stderr, "%d ", i); 15 | sleep(1); 16 | } 17 | printf("10\n"); 18 | printf("thread1: post a signal.\n"); 19 | int ret = sem_post(&semaphores);//喚醒thead2//post 20 | } 21 | 22 | void thread2(void) { 23 | printf("thread2: wait for thread1...\n"); 24 | int ret = sem_wait(&semaphores); 25 | printf("thread2: continue\n"); 26 | } 27 | 28 | int main(void) { 29 | pthread_t id1, id2; 30 | sem_init(&semaphores, 0, 0); 31 | pthread_create(&id1,NULL,(void *) thread1,NULL); 32 | pthread_create(&id2,NULL,(void *) thread2,NULL); 33 | pthread_join(id1,NULL); 34 | pthread_join(id2,NULL); 35 | } -------------------------------------------------------------------------------- /ch12/signal-wait_spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | pthread_spinlock_t spinlock; 10 | 11 | void thread1(void) { 12 | pthread_spin_lock(&spinlock); 13 | printf("thread1: sleep 10 sec.\n"); 14 | for (int i=0; i<10; i++){ 15 | fprintf(stderr, "%d ", i); 16 | sleep(1); 17 | } 18 | printf("10\n"); 19 | printf("thread1: post a signal.\n"); 20 | pthread_spin_unlock(&spinlock);//喚醒thead2//post 21 | } 22 | 23 | void thread2(void) { 24 | printf("thread2: wait for thread1...\n"); 25 | pthread_spin_lock(&spinlock); 26 | printf("thread2: continue\n"); 27 | pthread_spin_unlock(&spinlock); 28 | } 29 | 30 | int main(void) { 31 | pthread_t id1, id2; 32 | pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); 33 | pthread_create(&id1,NULL,(void *) thread1,NULL); 34 | pthread_create(&id2,NULL,(void *) thread2,NULL); 35 | pthread_join(id1,NULL); 36 | pthread_join(id2,NULL); 37 | } -------------------------------------------------------------------------------- /ch12/spinlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int global=0; 7 | pthread_spinlock_t spinlock; 8 | 9 | void thread(void) { 10 | int i; 11 | for (i=0; i<1000000000; i++) { 12 | pthread_spin_lock(&spinlock); 13 | global+=1; 14 | pthread_spin_unlock(&spinlock); 15 | } 16 | } 17 | int main(void) { 18 | pthread_t id1, id2; 19 | pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); 20 | pthread_create(&id1,NULL,(void *) thread,NULL); 21 | pthread_create(&id2,NULL,(void *) thread,NULL); 22 | pthread_join(id1,NULL); 23 | pthread_join(id2,NULL); 24 | printf("1000000000+1000000000 = %d\n", global); 25 | return (0); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /ch12/table.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define size 10000 6 | float table[size][size]; 7 | float col[size]; 8 | float row[size]; 9 | 10 | void initTable() 11 | { 12 | int i, j; 13 | for (i = 0; i < size; i++) 14 | for (j = 0; j < size; j++) 15 | table[i][j] *= 10.0; 16 | } 17 | 18 | void sumCol() 19 | { 20 | int i, j; 21 | for (j = 0; j < size; j++) 22 | for (i = 0; i < size; i++) 23 | col[j] *= table[i][j]; 24 | } 25 | 26 | void sumRow() 27 | { 28 | int i, j; 29 | for (i = 0; i < size; i++) 30 | for (j = 0; j < size; j++) 31 | row[i] *= table[i][j]; 32 | } 33 | 34 | 35 | int main() 36 | { 37 | initTable(); 38 | table[random()%size][random()%size] = (float)random(); 39 | sumRow(); 40 | sumCol(); 41 | printf("%f\n", col[random()%size]+row[random()%size]); 42 | } 43 | -------------------------------------------------------------------------------- /ch12/testPerf.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define bufsize 10 15 | unsigned long long buffer[bufsize]; 16 | //__Alignas(int) 17 | _Alignas(int) volatile int in=0, out=0, num=0;; //新進的資料放在buffer[in],讀取資料從buffer[out] 18 | unsigned long long putWaitingOverhead =0; 19 | unsigned long long getWaitingOverhead =0; 20 | int producerProgress = 0; 21 | int consumerProgress = 0; 22 | 23 | void printBufStatus(int signo) { //每100usec印出buffer資料 24 | printf("buf size = %d, in =%d, out =%d\n", num, in, out); 25 | printf("producerProgress = %d, consumerProgress = %d\n", producerProgress, consumerProgress); 26 | } 27 | 28 | void put() { 29 | //puts("put: enter\n"); 30 | static int item=1; //用於除錯,放入buffer的資料都是嚴格遞增的數列 31 | while ((in+1)%bufsize == out) { 32 | //puts("put: waiting\n"); 33 | //putWaitingOverhead++; 34 | ; 35 | } 36 | atomic_fetch_add(&num, 1); 37 | //puts("put: add a new item\n"); 38 | buffer[in]=item++; //將資料放入 39 | in = (in + 1)%bufsize; 40 | //atomic_thread_fence(???) 41 | //atomic_fetch_add(&in, 1); //規劃下筆資料應該擺放的地點 42 | 43 | } 44 | 45 | void get() { 46 | static int item=0; //用於除錯,紀錄上一次讀取的數字為何 47 | int tmpItem; //讀取的數字暫時放在tmpItem 48 | while (in == out) { 49 | //getWaitingOverhead++; 50 | ; 51 | } 52 | atomic_fetch_sub(&num, 1); 53 | tmpItem=buffer[out]; //讀出buffer的東西 54 | out = (out + 1)%bufsize; 55 | //atomic_thread_fence(???) 56 | //atomic_fetch_add(&out, 1); //規劃下次要提取資料的地方 57 | 58 | if ((tmpItem - item) != 1) { 59 | fprintf(stderr, "error: tmpItem - item = %d, in=%d, out=%d\n", tmpItem - item, in, out); //用於除錯,如果拿到的資料不是嚴格遞增,表示程式邏輯有錯 60 | getchar(); 61 | } 62 | item=tmpItem; //用於除錯,紀錄這次拿到的數字 63 | } 64 | 65 | void producer(void* name) { //生產資料的執行緒 66 | //ULLONG_MAX 67 | for (producerProgress=0; producerProgress<100000000; producerProgress++) { 68 | put(); 69 | //delay loop 70 | //for (int k=0; i 2 | #include 3 | #include 4 | 5 | volatile int global=0; 6 | pthread_mutex_t mutex; 7 | __thread int thread_local = 0; 8 | 9 | void thread(void) { 10 | int i; 11 | for (i=0; i<1000000000; i++) 12 | thread_local+=1; 13 | printf("@thread_local = %p\n", &thread_local); 14 | 15 | pthread_mutex_lock(&mutex); 16 | global+=thread_local; 17 | pthread_mutex_unlock(&mutex); 18 | } 19 | 20 | int main(void) { 21 | pthread_t id1, id2; 22 | pthread_mutex_init(&mutex, NULL); 23 | pthread_create(&id1,NULL,(void *) thread,NULL); 24 | pthread_create(&id2,NULL,(void *) thread,NULL); 25 | pthread_join(id1,NULL); 26 | pthread_join(id2,NULL); 27 | printf("1000000000+1000000000 = %d\n", global); 28 | return (0); 29 | } 30 | -------------------------------------------------------------------------------- /ch12/thread_print_id.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int gettid() { 10 | return syscall(SYS_gettid); 11 | } 12 | 13 | void thread(void) { 14 | printf("pthread_t tid = %p\n", (void*)pthread_self()); 15 | printf("tid = %d\n", gettid()); 16 | while(1); 17 | } 18 | 19 | int main(void) { 20 | pthread_t id1, id2; 21 | printf("my pid = %d\n", getpid()); 22 | pthread_create(&id1,NULL,(void *) thread,NULL); 23 | pthread_create(&id2,NULL,(void *) thread,NULL); 24 | //pthread_join(id1,NULL); 25 | //pthread_join(id2,NULL); 26 | getchar(); 27 | return (0); 28 | } 29 | -------------------------------------------------------------------------------- /ch12/ticketlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | FIFO版的spinlock 3 | 使用方法:ticketlock [numThread] 4 | 如果不指定numThread,預設數量為4個 5 | */ 6 | 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | __thread int thread_local_id; 20 | atomic_int count; 21 | atomic_int num_thread_in_cs; //for debugging 22 | 23 | struct ticketlock_t { 24 | volatile atomic_int next_ticket; //一定要加上volatile,否則-O3會出錯 25 | //一定要加上volatile,否則-O3會出錯,這一個不用是atomic_int,因為執行時它已經在CS 26 | volatile int now_serving; 27 | }; 28 | 29 | void ticketLock_acquire(volatile atomic_int* next_ticket,volatile int* now_serving){ 30 | int my_ticket; 31 | my_ticket = atomic_fetch_add(next_ticket, 1); 32 | //printf("thread_%d get tick %d\n", thread_local_id, my_ticket); //for debugging 33 | while(*now_serving != my_ticket) 34 | ; 35 | } 36 | 37 | 38 | void ticketLock_release(volatile int *now_serving) { 39 | ++*now_serving; 40 | //printf("now_serving = %d\n", *now_serving); //for debugging 41 | } 42 | 43 | void thread(void* para) { 44 | thread_local_id = atomic_fetch_add(&count, 1); 45 | pid_t x = syscall(__NR_gettid); //一定要用syscall(__NR_gettid),這一個函數印出來的thread id是Linux kernel內部使用的id,可以用來gdb 46 | printf("pid = %d\n", getpid()); 47 | printf("thread_%d's thread id is %d\n", thread_local_id, x); 48 | 49 | struct ticketlock_t* myTicketlock = (struct ticketlock_t*) para; 50 | //printf("thread ") 51 | for (int i=0; i< 1000000000; i++) { 52 | printf("thread_%d wait for entering CS\n", thread_local_id); //for debugging 53 | 54 | ticketLock_acquire(&myTicketlock->next_ticket, &myTicketlock->now_serving); 55 | printf("thread_%d in CS\n", thread_local_id); 56 | atomic_fetch_add(&num_thread_in_cs, 1); //for debugging; 57 | //printf("thread_%d in CS. loop_i = %d\n", thread_local_id, i); //for debugging 58 | if (num_thread_in_cs > 1) //for debugging 59 | fprintf(stderr, "ERROR: thread_%d is in CS, and num_thread is %d\n",thread_local_id, num_thread_in_cs); //for debugging 60 | 61 | for (int i=0; inow_serving); 67 | 68 | //remainder section 69 | for (int i=0; i 2 | #include 3 | 4 | volatile int global; 5 | 6 | int main(int argv, char** argc) { 7 | volatile int* volPtr; 8 | int* ptr; 9 | volPtr = &global; 10 | ptr = &global; 11 | *volPtr = 0xc0fe; 12 | *ptr = 0xdead; 13 | for (int i=0; i< 100; i++) { 14 | (*volPtr)++; 15 | (*ptr)++; 16 | } 17 | return *volPtr|*ptr; 18 | } 19 | -------------------------------------------------------------------------------- /ch13/count_svr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | key_t mem_key; 9 | int shmid; 10 | char* addr; 11 | /*key_t ftok(const char *pathname, int proj_id);*/ 12 | mem_key = ftok("/tmp", 0); 13 | printf("%d\n", mem_key); 14 | /*int shmget(key_t key, size_t size, int shmflg);*/ 15 | shmid = shmget(mem_key, 4096, IPC_CREAT | 0666); 16 | perror("shmget"); 17 | printf("shmid = %d", shmid); 18 | /*void *shmat(int shmid, const void *shmaddr, int shmflg);*/ 19 | addr=shmat(shmid, 0, 0); 20 | printf("%p", addr); 21 | getchar(); 22 | sprintf(addr, "shm ready"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /ch13/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /ch13/shmget_cli.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | char *shm_ary; 9 | key_t mem_key; 10 | int shmid; 11 | mem_key = ftok("/tmp", 0); 12 | shmid=shmget(mem_key, 4096, 0666); 13 | shm_ary=shmat(shmid, 0, 0); 14 | printf("%s\n", shm_ary); 15 | return 0; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /ch13/shmget_svr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) 7 | { 8 | key_t mem_key; 9 | int shmid; 10 | char* addr; 11 | /*key_t ftok(const char *pathname, int proj_id);*/ 12 | mem_key = ftok("/tmp", 0); 13 | printf("%d\n", mem_key); 14 | /*int shmget(key_t key, size_t size, int shmflg);*/ 15 | shmid = shmget(mem_key, 4096, IPC_CREAT | 0666); 16 | perror("shmget"); 17 | printf("shmid = %d", shmid); 18 | /*void *shmat(int shmid, const void *shmaddr, int shmflg);*/ 19 | addr=shmat(shmid, 0, 0); 20 | printf("%p", addr); 21 | getchar(); 22 | sprintf(addr, "shm ready"); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /color.h: -------------------------------------------------------------------------------- 1 | #define NONE "\033[m" 2 | #define RED "\033[0;32;31m" 3 | #define LIGHT_RED "\033[1;31m" 4 | #define GREEN "\033[0;32;32m" 5 | #define LIGHT_GREEN "\033[1;32m" 6 | #define BLUE "\033[0;32;34m" 7 | #define LIGHT_BLUE "\033[1;34m" 8 | #define DARY_GRAY "\033[1;30m" 9 | #define CYAN "\033[0;36m" 10 | #define LIGHT_CYAN "\033[1;36m" 11 | #define PURPLE "\033[0;35m" 12 | #define LIGHT_PURPLE "\033[1;35m" 13 | #define BROWN "\033[0;33m" 14 | #define YELLOW "\033[1;33m" 15 | #define LIGHT_GRAY "\033[0;37m" 16 | #define WHITE "\033[1;37m" 17 | #define RED_BOLD "\x1b[;31;1m" 18 | #define BLU_BOLD "\x1b[;34;1m" 19 | #define YEL_BOLD "\x1b[;33;1m" 20 | #define GRN_BOLD "\x1b[;32;1m" 21 | #define CYAN_BOLD_ITALIC "\x1b[;36;1;3m" 22 | #define RESET "\x1b[0;m" -------------------------------------------------------------------------------- /git-ignore-elf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | cd "$(git rev-parse --show-toplevel)" 4 | file=.gitignore 5 | new=$file.new.$$ 6 | ( 7 | if [ -e "$file" ]; then 8 | cat "$file" 9 | fi 10 | find . -name .git -prune -o -type f ! -name '*.o' ! -name '*.so' -print0 | xargs -0 file | grep ': *ELF ' | sed 's/:.*//' | 11 | sed 's,^./,,' 12 | ) | perl -ne 'print if !$already{$_}++' >"$new" 13 | mv "$new" "$file" 14 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -O3 -pg -g -march=skylake -mavx512f -finstrument-functions -z lazy -lrt 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /mem/createFile.c: -------------------------------------------------------------------------------- 1 | #define _LARGEFILE64_SOURCE 2 | #define _FILE_OFFSET_BITS 64 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | const int K=1024; 13 | const int M=1024*1024; 14 | const int G=1024*1024*1024; 15 | 16 | int main (int argc, char** argv) { 17 | int fd=open("./mmapFile", O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR); 18 | off_t off = lseek(fd, 400*M-6, SEEK_SET); 19 | perror("lseek"); 20 | printf("off =%ld\n", off); 21 | write(fd, "hello", 6); 22 | } -------------------------------------------------------------------------------- /mem/makefile: -------------------------------------------------------------------------------- 1 | SHELL = /bin/bash 2 | CC = gcc 3 | CFLAGS = -g -D_Float32x=float -D_Float64x="long double" -D_Float32=float -D_Float64="long double" 4 | SRC = $(wildcard *.c) 5 | EXE = $(patsubst %.c, %, $(SRC)) 6 | 7 | all: ${EXE} 8 | 9 | %: %.c 10 | ${CC} ${CFLAGS} $@.c -o $@ 11 | 12 | clean: 13 | rm ${EXE} 14 | -------------------------------------------------------------------------------- /mem/mmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const int K=1024; 10 | const int M=1024*1024; 11 | const int G=1024*1024*1024; 12 | 13 | int main(int argc, char** argv) { 14 | int mmapFd = open("./mmapFile", O_RDWR); 15 | char* adrs = mmap(NULL, 400*M, PROT_READ| PROT_WRITE, MAP_PRIVATE, mmapFd, 0); 16 | for (random()) 17 | assert(adrs!=MAP_FAILED); 18 | printf("%p\n", adrs); 19 | } -------------------------------------------------------------------------------- /mem/testStack2.c: -------------------------------------------------------------------------------- 1 | //gcc decSP4K.s getSP.s -o testStack 2 | //usage testStack mem|reg 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void seg_fault(int sigNo) { 16 | while(1); 17 | } 18 | 19 | int main(int argc, char** argv) { 20 | char base; 21 | char *stackP=&base; 22 | int i; 23 | struct rlimit rlim; 24 | int usingSP; 25 | if (signal(SIGSEGV, seg_fault)==SIG_ERR) { 26 | perror("SIGSEGV"); 27 | } 28 | 29 | if (argc != 2) exit(-1); 30 | if (strcmp("reg", argv[1]) ==0) 31 | usingSP = 1; 32 | else usingSP = 0; 33 | 34 | getrlimit(RLIMIT_STACK, &rlim); 35 | printf("soft=%dK, hard=%dK\n", 36 | (int)rlim.rlim_cur/1024, 37 | (int)rlim.rlim_max/1024); 38 | printf("pid = %d", getpid()); 39 | getchar(); 40 | while(1) { 41 | if(usingSP) { 42 | __asm__( 43 | "SUB $(4096-8), %rsp;\n" 44 | ); 45 | asm ( 46 | "MOVQ %%rsp, %0;\n" 47 | :"=r"(stackP) 48 | ); 49 | } else stackP -= 4096; 50 | *stackP = 1; 51 | printf("%ldK\n",(&base - stackP)/(1024)); 52 | } 53 | } -------------------------------------------------------------------------------- /showexeName.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) { 7 | //Both dirname() and basename() return pointers to 8 | //null-terminated strings. (Do not pass these pointers to free(3). 9 | char exeBuf[4096]; 10 | char* exeName = basename(argv[0]); 11 | printf("argc = %d\n", argc); 12 | printf("%s\n", argv[0]); 13 | printf("%s\n", exeName); 14 | snprintf(exeBuf, 4096, "%s", exeName); 15 | for (int i=1; i< argc; i++) { 16 | printf("argv[%d] = %s\n", i, argv[i]); 17 | snprintf(&exeBuf[strlen(exeBuf)], 4096-strlen(exeBuf), " %s", argv[i]); 18 | } 19 | printf("%s", exeBuf); 20 | return system(exeBuf); 21 | } 22 | -------------------------------------------------------------------------------- /std.txt: -------------------------------------------------------------------------------- 1 | 687410007,羅習五 2 | -------------------------------------------------------------------------------- /tool.h: -------------------------------------------------------------------------------- 1 | #define NONE "\033[m" 2 | #define RED "\033[0;32;31m" 3 | #define LIGHT_RED "\033[1;31m" 4 | #define GREEN "\033[0;32;32m" 5 | #define LIGHT_GREEN "\033[1;32m" 6 | #define BLUE "\033[0;32;34m" 7 | #define LIGHT_BLUE "\033[1;34m" 8 | #define DARY_GRAY "\033[1;30m" 9 | #define CYAN "\033[0;36m" 10 | #define LIGHT_CYAN "\033[1;36m" 11 | #define PURPLE "\033[0;35m" 12 | #define LIGHT_PURPLE "\033[1;35m" 13 | #define BROWN "\033[0;33m" 14 | #define YELLOW "\033[1;33m" 15 | #define LIGHT_GRAY "\033[0;37m" 16 | #define WHITE "\033[1;37m" 17 | #define RED_BOLD "\x1b[;31;1m" 18 | #define BLU_BOLD "\x1b[;34;1m" 19 | #define YEL_BOLD "\x1b[;33;1m" 20 | #define GRN_BOLD "\x1b[;32;1m" 21 | #define CYAN_BOLD_ITALIC "\x1b[;36;1;3m" 22 | #define RESET "\x1b[0;m" 23 | 24 | const int KB = 1024; 25 | const int MB = 1024 * 1024; 26 | const int GB = 1024 * 1024 * 1024; 27 | 28 | const long long nspersec = 1000000000; 29 | 30 | long long timespec2sec(struct timespec ts) { 31 | long long ns = ts.tv_nsec; 32 | ns += ts.tv_sec * nspersec; 33 | return ns; 34 | //return (double)ns/1000000000.0; 35 | } 36 | 37 | double timeval2sec(struct timeval input) { 38 | long long us = input.tv_sec*1000000; 39 | us += input.tv_usec; 40 | //printf("%ldsec, %ld us\n", input.tv_sec, input.tv_usec); 41 | return (double)us/1000000.0; 42 | } 43 | --------------------------------------------------------------------------------