--- tags : Linux kernel Design --- # 2019q1 Homework1 (lab0) contibuted by < W > :::warning 請注意看作業要求,填入 GitHub 帳號名稱 :notes: jserv ::: ## 開發環境 ``` Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 8 On-line CPU(s) list: 0-7 Thread(s) per core: 2 Core(s) per socket: 4 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 94 Model name: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz Stepping: 3 CPU MHz: 1015.293 CPU max MHz: 3500.0000 CPU min MHz: 800.0000 BogoMIPS: 5184.00 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 6144K NUMA node0 CPU(s): 0-7 ``` ## queue.h ```clike typedef struct { list_ele_t *head; /* Linked list of elements */ /* You will need to add more fields to this structure to efficiently implement q_size and q_insert_tail */ list_ele_t *tail; int size; } queue_t; ``` 在struct裡 ==tail== 和 ==size== ,使一些function可以在O(1)裡完成 ## queue.c ### **q_new()** ```clike queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); /* What if malloc returned NULL? */ if (q) { q->head = NULL; q->tail = NULL; q->size = 0; } return q; } ``` 如果malloc成功就把新產生的 ==queue_t== 初始化 ### **q_free()** ```clike void q_free(queue_t *q) { if (!q) return; /* How about freeing the list elements and the strings? */ /* Free queue structure */ list_ele_t *ele = NULL, *ele_tmp = NULL; for (ele = q->head; ele != NULL; ele = ele_tmp) { free(ele->value); ele_tmp = ele->next; free(ele); } free(q); } ``` 從head開始依序將每個node的value及整個node free ### **q_insert_head()** ```clike bool q_insert_head(queue_t *q, char *s) { /* What should you do if the q is NULL? */ if (!q) return false; list_ele_t *newh; newh = malloc(sizeof(list_ele_t)); if (!newh) return false; newh->value = malloc((strlen(s) + 1) * sizeof(char)); if (!newh->value) { free(newh); return false; } strcpy(newh->value, s); newh->value[strlen(s)] = '\0'; /* Don't forget to allocate space for the string and copy it */ /* What if either call to malloc returns NULL? */ newh->next = q->head; q->head = newh; if (q->size == 0) q->tail = newh; q->size++; return true; } ``` 只要有一個malloc不成功就要將整個新產生的node跟裡面的value要求的空間free掉 若malloc都成功,先將s字串複製一份到value,並再字串尾加上 '\0' 然後將 ==next== 指向 ==head== 指的node,接著把自己丟給 ==head== 若此node是第一個產生的node,也把自己丟給 ==tail== 將 size +1 ### **q_insert_tail()** ```clike 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) return false; list_ele_t *newh; newh = malloc(sizeof(list_ele_t)); if (!newh) return false; newh->value = malloc((strlen(s) + 1) * sizeof(char)); if (!newh->value) { free(newh); return false; } strcpy(newh->value, s); newh->value[strlen(s)] = '\0'; newh->next = NULL; if (q->tail != NULL) q->tail->next = newh; q->tail = newh; if (q->size == 0) q->head = newh; q->size++; return true; } ``` 只要有一個malloc不成功就要將整個新產生的node跟裡面的value要求的空間free掉 若malloc都成功,先將s字串複製一份到value,並再字串尾加上 '\0' 然後將 ==next== 指向 NULL 接著 ==判斷一下tail是否有node,若不判斷直接寫 q->tail->next 會產生錯誤== ( 因為若是 q->tail 指向 NULL 就沒能指向 next 指標 ) 接著把自己丟給 ==tail== 若此node是第一個產生的node,也把自己丟給 ==head== 將 size +1 (p.s.) 因為在.h檔新增的tail,使此function可以實現在O(1)裡完成 要是沒有紀錄tail,此function為了找到最尾端,勢必要將整個list從頭找到尾,此時需要O(n) ### **q_remove_head()** ```clike bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { /* You need to fix up this code. */ if (!q || q->size == 0) return false; if (sp != NULL) { strncpy(sp, q->head->value, bufsize - 1); sp[bufsize - 1] = '\0'; } list_ele_t *ele_tmp = NULL; ele_tmp = q->head; q->head = q->head->next; free(ele_tmp->value); free(ele_tmp); q->size--; return true; } ``` 首先若q指向NULL或目前沒有任何node => 此指令不能運作 接著若是sp指向non_NULL就將要刪除的node的value依據bufsize的長度限制複製進去 但若是sp指向NULL則不用複製 接著用一個 ==ele_tmp== 先把head指向的地方複製一份放著 並將head指向目前指向的node的next 接著運用ele_tmp將原先指向的node的value和整個node清掉 將 size -1 ### **q_size()** ```clike 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) return 0; return q->size; } ``` 回傳目前有幾個node 因為在.h檔新增的size使我們每經過一步操作都可以隨時掌握node的數量 此時可以實現在O(1)回傳node的數量 ### **q_reverse()** ```clike void q_reverse(queue_t *q) { /* You need to write the code for this function */ if (!q) return; list_ele_t *ele_next = NULL, *ele_prev = NULL, *ele_cur = NULL; for (ele_cur = q->head; ele_cur; ele_cur = ele_next) { ele_next = ele_cur->next; ele_cur->next = ele_prev; ele_prev = ele_cur; } q->tail = q->head; q->head = ele_prev; return; } ``` 說明待補,需要圖片輔助 :cry: ## 遇到的問題 此次作業除了上述問題,其實還有一個更根本的問題,從github clone下來的初始檔案並非正常的,運用指令 $cppcheck *.[ch] (此指令的意思是對所有.c .h檔做cppcheck) ``` Checking console.c ... 1/9 files checked 26% done Checking console.h ... 2/9 files checked 30% done Checking harness.c ... [harness.c:147]: (error) Address of auto-variable 'new_block->payload' returned 3/9 files checked 41% done Checking harness.h ... Checking harness.h: INTERNAL... 4/9 files checked 43% done Checking qtest.c ... 5/9 files checked 69% done Checking queue.c ... Checking queue.c: INTERNAL... 6/9 files checked 76% done Checking queue.h ... 7/9 files checked 80% done Checking report.c ... 8/9 files checked 95% done Checking report.h ... 9/9 files checked 100% done ``` 我們可以發現在harness.c的第147行會發生錯誤 ```clike 147 return p; ``` 再看看我們的錯誤指令 ==Address of auto-variable 'new_block->payload' returned== 上網查了一下 [auto-variable](https://zh.wikipedia.org/wiki/%E8%87%AA%E5%8A%A8%E5%8F%98%E9%87%8F) 是局部變數/區域變數的意思 我們再往上找 ```clike void *test_malloc(size_t size) { if (noallocate_mode) { report_event(MSG_FATAL, "Calls to malloc disallowed"); return NULL; } if (fail_allocation()) { report_event(MSG_WARN, "Malloc returning NULL"); return NULL; } block_ele_t *new_block = malloc(size + sizeof(block_ele_t) + sizeof(size_t)); if (new_block == NULL) { report_event(MSG_FATAL, "Couldn't allocate any more memory"); error_occurred = true; } new_block->magic_header = MAGICHEADER; new_block->payload_size = size; *find_footer(new_block) = MAGICFOOTER; void *p = (void *) &new_block->payload; /* 這裡 */ memset(p, FILLCHAR, size); new_block->next = allocated; new_block->prev = NULL; if (allocated) allocated->prev = new_block; allocated = new_block; allocated_count++; return p; } ``` 再往上找 payload ```clike typedef struct BELE { struct BELE *next; struct BELE *prev; size_t payload_size; size_t magic_header; /* Marker to see if block seems legitimate */ unsigned char payload[0]; /* Also place magic number at tail of every block */ } block_ele_t; ``` 發現他是一個 unsigned char[0] 待補