TZY
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 2019q3 Homework2 (lab0) contribyted by < `nckuoverload` > ###### tags: `sysprog2019` ## 作業要求 * 在 GitHub 上 fork [lab0-c](https://github.com/sysprog21/lab0-c) * 參閱 [GitHub 設定指引](http://wiki.csie.ncku.edu.tw/github) * ==詳細閱讀 [C Programming Lab](http://www.cs.cmu.edu/~213/labs/cprogramminglab.pdf)== (英文閱讀正是我們想強化的議題,你應該在共筆上摘要題目要求),依據指示著手修改 `queue.[ch]` 和連帶的檔案,測試後用 Git 管理各項修改。 * 在提交程式前,務必詳閱 [如何寫好 Git Commit Message](https://blog.louie.lu/2017/03/21/%E5%A6%82%E4%BD%95%E5%AF%AB%E4%B8%80%E5%80%8B-git-commit-message/) * 不用理會 [Autolab](http://www.autolabproject.com/) 和檔案下載的描述,這兩者都是 CMU 專屬 * 除了修改程式,也要編輯「[作業區](https://hackmd.io/@sysprog/BkZ4h5xPB)」,增添開發紀錄和 GitHub 連結,提及如何逐步達到要求,以及如何改善效能 - [x] 解釋自動評分系統運作的原理 - [x] 提及 `qtest` 的行為和裡頭的技巧,特別是 signal handler - [ ] 解析 Valgrind 的運作原理和針對本程式的使用 - [ ] 根據 [dudect](https://github.com/oreparaz/dudect) 工具以及提出的對應論文 [Dude, is my code constant time?](https://eprint.iacr.org/2016/1123.pdf),探討一種以實驗而非理論驗證時間複雜度的方法 - [ ] 留意 `MAGICHEADER`, `MAGICFREE`, `MAGICFOOTER`, `FILLCHAR` 等巨集的使用,並探討其動機和用法 * 截止日期: * Oct 2, 2019 (含) 之前 * 越早在 GitHub 上有動態、越早接受 code review,評分越高 ## 實驗環境 Operating System: `Ubuntu 16.04 64bit` Compiler: `gcc 8.3.0` ## 測試結果 ```shell $ python ./scripts/driver.py -A --- Trace Points --- trace-01-ops 6/6 --- trace-02-ops 6/6 --- trace-03-ops 6/6 --- trace-04-ops 6/6 --- trace-05-ops 6/6 --- trace-06-string 7/7 please new a queue first --- trace-07-robust 7/7 --- trace-08-robust 7/7 --- trace-09-robust 7/7 --- trace-10-malloc 7/7 --- trace-11-malloc 7/7 --- trace-12-malloc 7/7 --- trace-13-perf 7/7 --- trace-14-perf 7/7 --- trace-15-perf 7/7 --- TOTAL 100/100 ``` ## 實作紀錄 ### queue_t 在`queue.h`中,修改`queue_t`結構。 新增`list_ele_t *tail;`用來指向尾巴。 新增`int size;`用來記錄目前的長度。 ```cpp typedef struct { list_ele_t *head; /* Linked list of elements */ list_ele_t *tail; int size; } queue_t; ``` ### q_new() 首先是建立一個queue ,過程沒太大問題,要注意`malloc` 有可能會返回`NULL` ,所以在第29行要針對這個情況特別處理。 ```cpp=25 queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); /* What if malloc returned NULL? */ if (q == NULL) { free(q); return NULL; } q->head = NULL; q->tail = NULL; q->size = 0; return q; } ``` ### q_free() 釋放佇列,主要使用一個loop 去對每一個節點做處理。 ```cpp=40 void q_free(queue_t *q) { /* How about freeing the list elements and the strings? */ /* Free queue structure */ // free(q-> value); if (q == NULL) { return; } list_ele_t *tmp = q->head; while (q->head != NULL) { tmp = q->head; // free(q->head->value); q->head = q->head->next; free(tmp->value); free(tmp); } free(q); } ``` ### q_insert_head(queue_t *q, char *s) 和`_insert_tail()` 可以搭配一起來看,主要在第一個`if` 判斷該佇列是否為空,第二、三個判斷`malloc` 是否返回`NULL` (在測資中,會針對這個部分做測試)。 從頭插入的部分主要是新增一個節點,並將該節點指向原本的head ,並將佇列的head 指向該節點,並且size 增加。 ```cpp=66 bool q_insert_head(queue_t *q, char *s) { if (q == NULL) { return false; } list_ele_t *newh; /* What should you do if the q is NULL? */ newh = malloc(sizeof(list_ele_t)); if (newh == NULL) { free(newh); return false; } /* Don't forget to allocate space for the string and copy it */ /* What if either call to malloc returns NULL? */ newh->next = q->head; newh->value = malloc(sizeof(char) * (strlen(s) + 1)); if (newh->value == NULL) { free(newh->value); free(newh); return false; } strcpy(newh->value, s); if (q->head == NULL) { q->tail = newh; } q->head = newh; q->size += 1; return true; } ``` ### q_insert_tail(queue_t *q, char *s) 和`q_insert_head()` 相似,前三個判斷式相同效果,但應該有更好的寫法。 從尾端插入的部分,主要是將原本的尾端指向即將插入的節點,並將佇列中的`tail` 改成指向即將插入的節點。 ```cpp=104 bool q_insert_tail(queue_t *q, char *s) { /* You need to write the complete code for this function */ /* Remember: It should operate in O(1) time */ if (q == NULL) { return false; } list_ele_t *newQ; newQ = malloc(sizeof(list_ele_t)); if (newQ == NULL) { free(newQ); return false; } newQ->value = malloc(sizeof(char) * (strlen(s) + 1)); if (newQ->value == NULL) { free(newQ->value); free(newQ); return false; } strcpy(newQ->value, s); q->tail->next = newQ; q->tail = newQ; newQ->next = NULL; q->size += 1; return true; } ``` ### q_remove_head(queue_t *q, char *sp, size_t bufsize) 主要要注意測試中,有兩種測試方式,一個為`rh [str]` 和`rhq` ,前者主要會和輸入的字串做判斷,在這個部分要特別注意**輸入字串的大小是否大於佇列中第一個節點的大小**,在第147行針對這個部分做處理,如果超過不處理的話會造成溢出(overflow)。 ```cpp=139 bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { /* You need to fix up this code. */ if (q == NULL || q->size == 0) { return false; } if (bufsize != 0) { memset(sp, '\0', bufsize); if (strlen(q->head->value) > bufsize) { strncpy(sp, q->head->value, bufsize - 1); } else { strcpy(sp, q->head->value); } } list_ele_t *tmp = q->head; q->head = q->head->next; free(tmp->value); free(tmp); q->size--; return true; } ``` ### q_size(queue_t *q) 使用額外的`int size` 來儲存佇列大小,為了符合題目的$O(1)$。 ```cpp=165 int q_size(queue_t *q) { /* You need to write the code for this function */ /* Remember: It should operate in O(1) time */ if (q == NULL) { return 0; } return q->size; } ``` ### q_reverse(queue_t *q) 總共寫了兩個版本,原先使用類似bubble sort 的演算法來做倒轉,簡單來說就是模擬bubble sort 最壞情況,每一個迴圈讓一個節點移到適當的位置,並讓其他節點往前移一個位置,複雜度為$O(n^2)$。但這樣做的話在test 會一直因為時間超過而無法通過。 第二個版本主要是多用了三個暫存變數,每一次將一個節點的指標轉向,並在最後處理`q`的`head` 和`tail`。也是很直觀的做法,但一開始因為題目敘述理解錯誤,誤解為不能多使用額外空間設置變數來處理。 ```cpp=182 void q_reverse(queue_t *q) { /* You need to write the code for this function */ if (q == NULL || q->size < 2) { return; } list_ele_t *temp; list_ele_t *now = q->head->next; list_ele_t *pre = q->head; while (now != NULL) { temp = now->next; now->next = pre; pre = now; now = temp; } q->tail = q->head; q->head = pre; q->tail->next = NULL; } ``` ## 討論 ### 解釋自動評分系統運作的原理 主要使用Makefile 來自動評分,Makefile 寫起來類似shell script 但又不盡相同,詳細可以參考[這篇範例](https://mropengate.blogspot.com/2018/01/makefile.html),或是網路上應該有許多其他解說。 在原始的Makefile 中,主要是編譯後,呼叫`scripts/driver.py` 來評分,所以也可以在`~/lab0-c` 中直接使用`python driver.py` 來評分。 `driver.py` 又可以使用四個參數來使用。 `h` : 主要用來說明有哪些參數,類似一般使用的help 。 `p` : 可以選擇用哪個檔案來評分。 (不太確定式不是這個意思) `t` : 可以選擇要選第幾個腳本來測試,腳本都在`~/lab0-c/traces` 底下。 `v` : 有0~3的級別,可以選擇要顯示多少測試的腳本資料。 `A` : 自動評分,功能等同於使用 `make test` 。 `--valgrind` : 如果直接搜尋會找到 [Wikipedia](https://en.wikipedia.org/wiki/Valgrind) 的解說,是一款GNU 的工具,用來處理記憶體除錯。稍後會再針對這部分解釋。 ### 提及 `qtest` 的行為和裡頭的技巧,特別是 signal handler 在 `qtest.c` 中,會有許多 method 用來做測試,每一個都會使用 `exception_setup() exception_cancel()` 兩個來對 exception 做處理,同時裡面也有使用到 signal 的機制。 首先會先執行 `queue_init()` 並且呼叫兩個 signal ,`SIGSEGV` 用來處理記憶體部分的例外狀況;`SIGALRM` 用來處理執行時間的例外狀況。 之後以 `do_new()` 為例,在第107行的部分,當要執行 `q_new()` 前,會先執行 `exception_setup(true)` ,用來開啟 signal ,並且在執行完成後使用 `exception_cancel()` 關閉。 `exception_setup()` 和 `exception_cancel()` 都在 `harness.c` 中。以下將分別敘述。 - exception_setup(): 這邊可以分成兩個流程來說明,分別是正常運作和 `exception` 發生時的狀況。 - 正常運作: 在正常運作下,會從 `do_new()` 等執行 `exception_setup()` 跳入,因為是正常情況,所以 `sigsetjmp()` 並不會被執行,會直接跳到253 行執行,`jmp_ready` 參數主要是用來紀錄在 exception 發生後,是否可以執行 jump 。並且這時候會在257 行給予一個執行時間,程式必須在時間內完成,否則會觸發 signal 並且丟出 `sigalrmhandler` 讓 `qtest.c` 中的 `sigalrmhandler()` 去處理例外。並且會將狀態恢復到未執行 `q_new()` 前的狀態繼續往下執行。 - 例外狀況: 如果有發生例外狀況,因為一開始有先使用 `sigsetjmp` 來保存 stack 環境等,所以會把剩下的時間返回,並且將錯誤訊息印出,之後在兩個 handler 中都有使用到 `trigger_exception()` 去處理,`trigger_exception()` 會使用 `siglongjmp` 將環境恢復到原本儲存的狀態(尚未進入會發生例外狀況的 method 前的狀態)。 ```cpp=239 bool exception_setup(bool limit_time) { if (sigsetjmp(env, 1)) { /* Got here from longjmp */ jmp_ready = false; if (time_limited) { alarm(0); time_limited = false; } if (error_message) { report_event(MSG_ERROR, error_message); } error_message = ""; return false; } else { /* Got here from initial call */ jmp_ready = true; if (limit_time) { alarm(time_limit); time_limited = true; } return true; } } ``` - exception_cancel(): 當 method 順利執行完後,把 signal 關閉。 ```cpp=267 void exception_cancel() { if (time_limited) { alarm(0); time_limited = false; } jmp_ready = false; error_message = ""; } ``` 小結, `qtest.c` 因為不能確保每次執行實作者在 `queue.c` 中實作的 method 都是可靠的,所以每次要進入 `queue.c` 的方法前,都會先使用 `sigsetjmp` 保存狀態,並且開啟 signal ,如果例外狀況沒發生,則會使用 `exception_cancel()` 去關閉所有上述機制。如果例外狀況發生,則會使用 `trigger_exception()` 中的 `siglongjmp()` 來恢復到進入有問題方法前的環境。 - 實驗 很簡單的實驗,可以把限制時間長度的 signal 關閉,並且把 `q_reverse` 的部分改回第一版本氣泡排序法去執行,可以發現並不會有時間錯誤的問題出現,在第13個測試 `trace-13-perf.cmd` 正常情況下會發生錯誤。 - `q_reverse()` using bubble sorting ```cpp void q_reverse(queue_t *q) { /* You need to write the code for this function */ if (q == NULL) { return; } int temp = q->size; list_ele_t *t; for (int i = 0; i < q->size; i++) { temp--; t = q->head; for (int z = 0; z < temp; z++) { *(t->value) ^= *(t->next->value); *(t->next->value) ^= *(t->value); *(t->value) ^= *(t->next->value); t = t->next; } } } ``` ### 未完成 - [ ] 解析 Valgrind 的運作原理和針對本程式的使用 - [ ]根據 dudect 工具以及提出的對應論文 Dude, is my code constant time?,探討一種以實驗而非理論驗證時間複雜度的方法 - [ ]留意 MAGICHEADER, MAGICFREE, MAGICFOOTER, FILLCHAR 等巨集的使用,並探討其動機和用法 ## 參考資料

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully