2014年9月26日 星期五

[轉] Linux Kernel - Kthread

在kernel中建立thread可以使用kthread_create(),建立一個task,然後在調用wake_up_process(task)讓task真正的運行,如果要kill一個kthread可以使用kthread_stop()。
在kernel中,將kthread_create()和wake_up_process()包裝成kthread_run(),也就是調用了kthread_run()之後,該thread會立刻被執行。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>

MODULE_LICENSE("GPL");

static struct task_struct *brook_tsk;
static int data;
static int kbrook(void *arg);

static int kbrook(void *arg)
{
    unsigned int timeout;
    int *d = (int *) arg;

    for(;;) {
        if (kthread_should_stop()) break;
        printk("%s(): %d\n", __FUNCTION__, (*d)++);
        do {
            set_current_state(TASK_INTERRUPTIBLE);
            timeout = schedule_timeout(10 * HZ);
        } while(timeout);
    }
    printk("break\n");

    return 0;
}

static int __init init_modules(void)
{
    int ret;

    brook_tsk = kthread_create(kbrook, &data, "brook");
    if (IS_ERR(brook_tsk)) {
        ret = PTR_ERR(brook_tsk);
        brook_tsk = NULL;
        goto out;
    }
    wake_up_process(brook_tsk);

    return 0;

out:
    return ret;
}

static void __exit exit_modules(void)
{
    kthread_stop(brook_tsk);
}

module_init(init_modules);
module_exit(exit_modules);


linux/kthread.h
/**
 * kthread_run - create and wake a thread.
 * @threadfn: the function to run until signal_pending(current).
 * @data: data ptr for @threadfn.
 * @namefmt: printf-style name for the thread.
 *
 * Description: Convenient wrapper for kthread_create() followed by
 * wake_up_process().  Returns the kthread or ERR_PTR(-ENOMEM).
 */
#define kthread_run(threadfn, data, namefmt, ...)      \
({            \
 struct task_struct *__k         \
  = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
 if (!IS_ERR(__k))         \
  wake_up_process(__k);        \
 __k;           \
})

2014年9月24日 星期三

[轉] 內核編譯時, 到底用make clean, make mrproper還是make distclean

http://blog.csdn.net/liyayao/article/details/6818061

[轉] linux內核調試kmsg,dmesg

dmesg為我們多用,man dmesg告知dmesg用來顯示和管理kernel ring buffer,那麼後者為何物,以及dmesg顯示何類信息,是本文待闡述的內容。
documentation/trace/ring-buffer-design.txt包含了詳細的設計方案(看來documentation下的內容應是後續查找tutor的首選), 其中細節不是目前所需,但看起來卻是是設計無鎖(lockless)日誌系統的絕佳參考資料。
ring buffer(rb)和kernel ring buffer(krb)是不同的東西,前者泛指一類buffer設計方案,後者特指Linux內核使用的ring buffer。
rb有兩種模式:
1、producer/consumer模式:如果生產的太多,沒有來得及消費,「倉庫」佔滿了,那麼就暫停生產--這種模式可能會丟失最近的事件記錄。
2、overwrite模式:生產者填滿「倉庫」的時候,它仍然繼續生產,並覆蓋最舊的事件記錄--這種模式可能會丟失最舊的事件記錄。
kernel日誌(如printk的數據)視情況發往不同的地方:
- 如果klogd和syslogd都在運行,kernel messages被寫到/var/log/messages的末尾(或者syslogd配置給定的地方),此時和級別無關,所有級別日誌信息都寫入。
- 如果klogd沒有運行,消息不會發往用戶空間(不會寫messages文件?),除非顯式讀取/proc/kmsg(一般通過kmsg)。
讀取krb的首選方案是dmesg,dmesg其實是通過系統調用syslog去讀取的。

1./proc/kmsg
在程序開發過程中,
LOG是廣泛使用的用來記錄程序執行過程的機制,它既可以用於程序調試,也可以用於產品運營中的事件記錄。在Android系統中,提供了簡單、便利的LOG機制,開發人員可以方便地使用。在這一篇文章中,我們簡單介紹在Android驅動LOG的使用和查看方法。

        Android內核是基於Linux Kerne 2.36的,因此,Linux KernelLOG機制同樣適合於Android內核,它就是有名的printk,與C語言的printf齊名。與printf類似,printk提供格式化輸入功能,同時,它也具有所有LOG機制的特點--提供日誌級別過慮功能。
printk()有一個控制日誌級別的字段,如果該字段的日記級別高於console默認的日誌級別那麼才會打印出來(數值越小日誌級別越高,分為從 0-7共計8個日誌級別)。
printk提供了8種日誌級別(<linux/kernel.h>):
#define KERN_EMERG  "<0>"       
#define KERN_ALERT  "<1>"       
#define KERN_CRIT   "<2>"       
#deinfe KERN_ERR    "<3>"       
#deinfe KERN_WARNING    "<4>"       
#deinfe KERN_NOTICE "<5>"       
#deinfe KERN_INFO   "<6>"       
#deinfe KERN_DEBUG  "<7>"       
printk的使用方法:
printk(KERN_ALERT"This is the log printed by printk in linux kernel space.");
KERN_ALERT表示日誌級別,後面緊跟著要格式化字符串。
有一種簡單的改變當前終端的日誌級別的方法:#echo 8 > /proc/sys/kernel/printk。理論上這樣printk就能輸出到終端了。

Android系統中,printk輸出的日誌信息保存在/proc/kmsg中,使用查看命令:
adb shell cat /proc/kmsg  grep "alarm" //grep "alarm"表示只抓取alarm的信息
或者:
USER-NAME@MACHINE-NAME:~/Android$ adb shell
root@android:/ cat  /proc/kmsg grep "alarm" //grep "alarm"表示只抓取alarm的信息
直接查看/proc/kmsg時讀取了緩衝區中的數據後,將緩衝區中的數據刪除
2.dmesg
今天想要調試android系統,串口debug沒接出來,最後想嘗試一直打印dmesg的方法,修改循環緩衝區的大小,打完dmesg後自動清空。
小記錄下,希望能幫到需要的人:
dmesg 在不刷新緩衝區的情況下獲得緩衝區的內容,並將內容返回給stdout。
dmesg -c 打印dmesg後清空循環緩衝區
dmesg -s 64 設置dmesg循環緩衝區大小為64

2014年9月5日 星期五

[轉] Android智能指針SP WP使用方法介紹

Android手機操作系統既然是開源的操作系統。那麼在具體的文件夾中就會存放著各種相關功能的開源代碼。我們在使用的時候可以根據這些源代碼進行相應的修改就能輕鬆的完成我們所需的功能。在這裡大家就一起來看看Android智能指針的相關源碼解讀以及應用方法。
在Android的源代碼中,經常會看到形如:sp< xxx>、wp< xxx>這樣的類型定義,這其實是Android中的智能指針。智能指針是C++中的一個概念,通過基於引用計數的方法,解決對象的自動釋放的問題。在C++編程中,有兩個很讓人頭痛的問題:一是忘記釋放動態申請的對象從而造成內存洩露;二是對象在一個地方釋放後,又在別的地方被使用,從而引起內存訪問錯誤。
程序員往往需要花費很大精力進行精心設計,以避免這些問題的出現。在使用智能指針後,動態申請的內存將會被自動釋放(有點類似Java的垃圾回收),不需要再使用delete來釋放對象,也不需要考慮一個對象是否已經在其它地方被釋放了,從而使程序編寫工作減輕不少,而程序的穩定性大大提高。
Android智能指針相關的源代碼在下面兩個文件中:

frameworks\base\include\utils\RefBase.h
frameworks\base\libs\utils\RefBase.cpp
Android中定義了兩種智能指針類型,一種是強指針sp(strong pointer),一種是弱指針(weak pointer)。其實稱為強引用和弱引用更合適一些。強指針與一般意義的智能指針概念相同,通過引用計數來記錄有多少使用者在使用一個對象,如果所有使用者都放棄了對該對象的引用,則該對象將被自動銷毀。
弱指針也指向一個對象,但是弱指針僅僅記錄該對象的地址,不能通過弱指針來訪問該對象,也就是說不能通過弱指針來調用對象的成員函數或訪問對象的成員變量。要想訪問弱指針所指向的對象,需首先將弱指針升級為強指針(通過wp類所提供的promote()方法)。弱指針所指向的對象是有可能在其它地方被銷毀的,如果對象已經被銷毀,wp的promote()方法將返回空指針,這樣就能避免出現地址訪問錯的情況。
是不是很神奇?弱指針是怎麼做到這一點的呢?其實說穿了一點也不複雜,原因就在於每一個可以被智能指針引用的對象都同時被附加了另外一個 weakref_impl類型的對象,這個對象中負責記錄對象的強指針引用計數和弱指針引用計數。這個對象是Android智能指針的實現內部使用的,智能指針的使用者看不到這個對象。弱指針操作的就是這個對象,只有當強引用計數和弱引用計數都為0時,這個對象才會被銷毀。
說了這麼多原理,下面該看看到底智能指針該怎麼使用了。假設現在有一個類MyClass,如果要使用智能指針來引用這個類的對象,那麼這個類需滿足下列兩個前提條件:
(1) 這個類是基類RefBase的子類或間接子類;
(2) 這個類必須定義虛構造函數,即它的構造函數需要這樣定義:
  1. virtual ~MyClass(); 
滿足了上述條件的類就可以定義Android智能指針了,定義方法和普通指針類似。比如普通指針是這樣定義:
  1. MyClass* p_obj; 
Android智能指針是這樣定義:
  1. sp< MyClass> p_obj; 
注意不要定義成 sp< MyClass>* p_obj。初學者容易犯這種錯誤,這樣實際上相當於定義了一個指針的指針。儘管在語法上沒有問題,但是最好永遠不要使用這樣的定義。
定義了一個智能指針的變量,就可以像普通指針那樣使用它,包括賦值、訪問對象成員、作為函數的返回值、作為函數的參數等。比如:
  1. p_obj = new MyClass();   
  2. // 注意不要寫成 p_obj = new sp< MyClass> 
  3. sp< MyClass> p_objp_obj2 = p_obj;  
  4. p_obj->func();  
  5. p_obj = create_obj();  
  6. some_func(p_obj); 
注意不要試圖delete一個Android智能指針,即 delete p_obj。不要擔心對象的銷毀問題,智能指針的最大作用就是自動銷毀不再使用的對象。不需要再使用一個對象後,直接將指針賦值為NULL即可:
  1. p_obj = NULL
上面說的都是強指針,弱指針的定義方法和強指針類似,但是不能通過弱指針來訪問對象的成員。下面是弱指針的示例:
  1. wp< MyClass> wp_obj = new MyClass();  
  2. p_obj = wp_obj.promote();   
  3. // 升級為強指針。不過這裡要用.而不是->,真是有負其指針之名啊  
  4. wp_obj = NULL
Android智能指針用起來是很方便,在一般情況下最好使用智能指針來代替普通指針。但是需要知道一個智能指針其實是一個對象,而不是一個真正的指針,因此其運行效率是遠遠比不上普通指針的。所以在對運行效率敏感的地方,最好還是不要使用智能指針為好