發表文章

目前顯示的是 2017的文章

rule of three

rule of three or rule of five (額外多move). 此rule是根據rules of thumb in C++所產生 主要是為了預防再做資源管理時發生不可預期的錯誤, 所建議的撰寫規則. 如下為一個經由給定(=)後所產生的double free問題. #include <iostream> #include <string> class ResourceFreeFailed { private: char * m_str; public: ~ ResourceFreeFailed() { delete [] m_str; } ResourceFreeFailed() = default ; ResourceFreeFailed( const char * pstr) : m_str( new char [ 128 ]) { std :: strcpy(m_str, pstr); } }; int main () { ResourceFreeFailed c( "resource" ); { // d will release resource of c ResourceFreeFailed d; // ERROR: assign c to d d = c; } // c will release resource, but someting is wrong return 0 ; } [1][2]定義了兩種情況,在撰寫class時候需要記得此規則: 撰寫的class有需要自己做資源管理(resource management) 當撰寫以下其中一個成員函數時,需要一併明確定義其他成員函數 destructor copy constructor copy assignment operator move constructor (C+

Pointer to Implementor(PIMPL)

概念 最近看到PIMPL的設計, 基於好奇就看了網路上的資訊. PIMPL主要的概念根據[1][2][3]可以分為兩點 (1)進一步的隱藏私有部分的成員變數及函數. 可以把所需的變數通通包在class Impl 裡面. (2)對於程式需要新增/刪除成員變數的時候,由於已改成Impl的方式.可以減少自己程式重新編譯的時間以及避免影響使用這些函式庫的程式因為ABI關係也重新編譯. 程式範例 work.hpp為一個外層handle的class. 主要是透過public的函數作為一個介面來呼叫實作在Impl的Class程式. line8~9是使用forward declaration.[4][5][6].所以必須使用pointer或reference的方式宣告Impl work.hpp 1 class Handle 2 { 3 public : 4 Handle(); 5 void CallA (); 6 7 private : 8 class Impl ; 9 Impl * m_Impl; 10 }; Line 4~8為Impl類別的實作. line 17則是handle類別透過CallA介面去呼叫實際實行的部分. work.cpp 1 #include < iostream > 2 #include "work.hpp" 3 4 class Handle :: Impl 5 { 6 public : 7 void DoA() { std :: cout << "Do A\n"; } 8 }; 9 10 Handle :: Handle() 11 { 12 m_Impl = new Impl; 13 } 14 15 void Handle :: CallA() 16 { 17 m_Impl -> DoA(); 18 } 19 20 int main() 21

RAII 概念(Resource acquisition is initialization)

RAII 概念 RAII(Resource acquisition is initialization)中文即是"資源取得或分配即是在初始化". 看起來有點攏統. 個人的理解是RAII是用於object上的一個寫法. 物件建立的時候, 資源取得的是時候是經由constructor來初始. 結束的時候便透過destructor來釋放. 這樣的好處就是可以確保資源在物件的生命週期內是存在的. 結束的時候就會釋放掉資源. 閉免掉memory leak的問題或因為資源的關係導致程式運作不正常 C++程式範例 底下以[3]的程式作為範例, 如下所示. bad()會造成程式lock住. 而改為RAII的good()方式可以避免掉這問題. std :: mutex m; void bad() { m.lock(); // 直接取的 lock f(); // (1) 當有例外發生(exception), 程式鎖死 if ( ! everything_ok()) return ; // (2) 程式直接返回, 程式鎖死 m.unlock(); // 釋放lock } void good() { // 使用class包住lock. 而這邊不需像上述使用unlock. // 因為object結束會呼叫解構子. 會做unlok std :: lock_guard < std :: mutex > lk(m); f(); // (1) 當例外造成, lock object也會結束 if ( ! everything_ok()) return ; // (2) 程式返回, lock object也會結束 } // 正常結束, lock object也會結束 C結合RAII 因為之前寫C的時候, 每次都會為了malloc()跟free(), 讓程式碼不簡潔或造成編譯問題. (1) 如程式有重複的release資源的code. (2) 透過goto方式集中資源釋放, 但導致在goto之後的變數宣告無法初始數值 #include<stdio.h> #include<stdlib.

linux : kernel modules 簡介

Linux modules 基本上linux modules在編譯時候可以分為builtin modules與external modules. builtin module: 在make mennuconfig把要builtin的module設置為y. 編譯的時候就會在對應目錄產生built-in.o的檔案. 這些檔案便會被包入在image裡面. external module: 在make mennuconfig把要builtin的module設置為m. 編譯的時候就會在對應目錄產生kernel/time/test_udelay.ko的檔案. 這些檔案便會被放置在/lib/modules/$(uname -r) Modules 操作指令 顯示已安裝模組列表 root@yijyun-server:~# lsmod | head Module Size Used by usbhid 49152 0 usb_storage 69632 0 crct10dif_pclmul 16384 0 ppdev 20480 0 單一模組安裝&移除 藉由insmod與rmmod去針對單一模組進行安裝與移除 insmod [filename] [module options...] insmod /lib/modules/4.4.0-64-generic/kernel/drivers/hid/usbhid/usbhid.ko rmmod [modulename] rmmod usbhid 相依性的模組安裝&移除 藉由modprode去針對此模組進行安裝與移除. 安裝與刪除中會去移除相依性的模組 modprobe [modulename] [module parameters...] root@yijyun-server:~# modprobe cfg80211 modprobe -r [modulename...] root@yijyun-server:~# modprobe -r cfg80211 modules相關資訊 module是否為builtin 透

CMake 編寫

在linux底下除了make(makefile), 就是使用cmake(CMakeLists.txt)來編譯程式或套件(packages). 這邊用範例的方式來記錄用法 Example 1: 簡易的hello world專案 Example 2: 多層階層的專案(hierarchical CMakeLists.txt) Example 3: 建立靜態與動態程式庫(static and dynamic libraries) Example 4: 使用外部函式庫 Example 1: 簡易的hello world專案 [Top] 簡易的hello world範例, 編譯一個執行檔, 以下為project底下的檔案列表 . ├── CMakeLists.txt ├── build └── hello _ world.c CMakeLists.txt裡面填寫所要編譯相關規則. build是一個空目錄, 進去此目錄後, 下達cmake相關指令後, 把編譯的檔案放置此處 以下為CMakeLists.txt內容 1 2 3 4 5 # recommend to add these two lines cmake_minimum_required ( VERSION 2.8.9 ) project ( hello_world ) add_executable ( hello_world hello_world.c ) 行2是規定所需要的最低cmake版本. 行3是專案名稱. 行5則是編譯一個名稱為hello_world執行檔,其source檔案為hello_world.c #編譯 $ mkdir build ; cd build; cmake ..; make #執行程式 $ ./hello_world hello world! Example 2: 多層階層的專案(hierarchical CMakeLists.txt) [Top] 階層的CMakeLists.txt範例 . ├── CMakeLists.txt ├── src1 │   ├── CMakeLists.txt │   └── foo.cpp └── src2 ├── CMakeList

gcc 編譯錯誤

1: 錯誤: recompile with -fPIC [1] ... [ 14%] Linking CXX shared library ../lib/libvgltrans_test2.so /usr/bin/ld: /opt/libjpeg-turbo/lib64/libturbojpeg.a(libturbojpeg_la-jdmarker.o): relocation R_AARCH64_ADR_PREL_PG_HI21 against external symbol `__stack_chk_guard@@GLIBC_2.17' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: /opt/libjpeg-turbo/lib64/libturbojpeg.a(libturbojpeg_la-jdmarker.o)(.text+0xa0c): unresolvable R_AARCH64_ADR_PREL_PG_HI21 relocation against symbol `__stack_chk_guard@@GLIBC_2.17' /usr/bin/ld: final link failed: Bad value collect2: error: ld returned 1 exit status ... Makefile:127: recipe for target 'all' failed make: *** [all] Error 2 解決: 以上述例子, 從新編譯此套件所需的libturbojpeg. 在編譯過程加入 -fPIC Reference recompile with -fPIC

linux : firmware 簡介

我以為device要可以運作, 只要在linux安裝相關的driver即可 最近看到原來device除了driver之外, 還是需要firmware這東西才可以運作... 稍微做個筆記.... Firmware 基本上device要可以正常運作是需要driver和firmware. driver可以看成是系統跟device溝通的橋樑. firmware則是執行在device上面的程式. Firmware除了可以預先寫死在device上外,另一方式就是driver初始化device的時候. 從系統讀取firmware, 在寫入到device. Firmware讀取流程 linux放置firmware的地方為/lib/firmware. 讀取firmware的時候就是透過此. (1) 流程參考[2] Driver跟kernel要求 "ar9170.fw" kernel傳遞event給udev來要求firmware udev執行對應的script,把firmware傳送至kernel所創建的一個特殊檔案 kernel從此特殊檔案讀取firmware, 再把資料傳送給driver driver再把資料傳給device (2) 流程參考[3][5] 1), kernel(driver): - calls request_firmware(&fw_entry, $FIRMWARE, device) - kernel searchs the fimware image with name $FIRMWARE directly in the below search path of root filesystem: User customized search path by module parameter 'path'[1] "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE,

Linux: udev 介紹

在談論udev之前,先要知道/dev這目錄. /dev在linux用途是存放device node(file-like device nodes). 程式可以透過device node來與系統上的裝置溝通. e.g. /dev/input/mice 為滑鼠 那誰負責管理/dev底下的device node? 沒錯,那就是udev最主要的工作. kernel會把裝置相關的events(add/remove/etc.)傳送至udev(藉由netlink). udev根據寫好的rules,在/dev底下建立對應的device node. 而這些rules會根據裝置的屬性去撰寫相關設定條件. 針對符合規則的裝置做對應的處理 到這時候應該會好奇要怎麼去得知道裝置的屬性呢? 而這邊就要談到 /sys (file type: sysfs), 這個是由kernel所維護的device資訊, kernel會把連接上的裝置資訊給放在這邊. udev在建立device node的時候也會參考這邊相關的屬性 e.g. udevadm info -a --name /dev/input/mice or udevadm info -a --path $(udevadm info --query=path --name=/dev/input/mice) 接下來談的部分是udev rules. 基本上rule是由 match keys 和 assignment keys 這兩個部分構成. match key主要是作為條件判斷用. assignment keys則是用來設定數值與執行相關操作. 每一條rule至少都要有一個 match key 和 assignment key. 在 rule 中的這些keys則使用逗號(,)來做隔離, 並不允許由多行的keys來成一條rule. 這意味著udev rule file中的每一行就是一條rule . KERNEL=="sda", ATTR{size}=="234441648", NAME="sda", SYMLINK+=disk/by-id/ata-VBOX_HARDDISK_VBa2440069-7fdbc2ad 這一個例子是判斷KERNEL是否符合

Git 常用指令

Repository clone git://Repository 可以透過clone或init建立repository git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git or git init test_folder add git://repository 在一個Repository加入新的Repository. 範例: 在一個linux Repository(linux org)加入另一個來源不同的linux Ropository(TI) git remote add ti-linux git://git.ti.com/ti-linux-kernel/ti-linux-kernel.git subtree [add|merge|pull|push|split] --prefix=&lt prefix &gt [&lt commit &gt|&lt repository &gt &lt ref &gt|&lt commit...&gt] 在此repository加入一個已存在的repository,使其成為subfolder. 通常可以看作是把子專案放在大專案底下 範例:新增一個已存在repository於當前repository底下的src子目錄(prefix=src) git subtree add --prefix=src ../src master remote -v 顯示有連接到的remote repository url git remote -v Branch branch -vv 查看remote branch與local branch對應關係. git branch -vv or git remote show origin Restore reset <--hard|--soft|-mixed> commit-id 還原至某個commit id狀態 --hard: working tree, index/cache, Repository全部還原 --soft:保留working