7国产欧美日韩综合天堂中文久久久久 ,国产69精品久久久久9999,久久五月精品中文字幕http://www.shnenglu.com/momoxiao/category/13037.htmlzh-cnWed, 15 Jun 2011 12:18:08 GMTWed, 15 Jun 2011 12:18:08 GMT60thread 多線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.html小默小默Tue, 14 Jun 2011 12:27:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.htmlhttp://www.shnenglu.com/momoxiao/comments/148668.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148668.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148668.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148668.html多線程

編寫多線程程序時,在設計上要特別小心.
對共享變量,多個執行路徑,要引起足夠重視.
創建多線程:
/*
 * 多線程
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

#define NUM_THREADS 6

void *thread_function(void *arg);

int main(){
    
int res;
    pthread_t a_thread[NUM_THREADS];
    
void *thread_result;
    
int lots_of_threads;

    
for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++){
        printf(
"before pthread_create, lots_of_threads=%d\n",lots_of_threads);
        res 
= pthread_create(&(a_thread[lots_of_threads]),NULL,
                thread_function, (
void *)&lots_of_threads);
        
if(res != 0){
            perror(
"Thread creation failed");
            exit(EXIT_FAILURE);
        }
    }

    printf(
"Waiting for threads to finish\n");

    
for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--){
        res 
= pthread_join(a_thread[lots_of_threads], &thread_result);
        
if(res == 0){
            perror(
"Picked up a thread\n");
        }
        
else{
            perror(
"pthread_join failed\n");
        }
    }

    printf(
"All done\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    
int my_number = *(int *)arg;
    
int rand_num;

    printf(
"thread_funcion is running. Argument was %d\n", my_number);
    rand_num 
= 1+(int)(9.0*rand()/(RAND_MAX+1.0));
    sleep(rand_num);
    printf(
"Bye from %d\n", my_number);
    pthread_exit(NULL);
}

執行結果:
[green@colorfulgreen ch11]$ gcc -D_REENTRANT thread8.c -o thread8 -lpthread
[green@colorfulgreen ch11]$ .
/thread8    
before pthread_create, lots_of_threads
=0
before pthread_create, lots_of_threads
=1
before pthread_create, lots_of_threads
=2
before pthread_create, lots_of_threads
=3
before pthread_create, lots_of_threads
=4
before pthread_create, lots_of_threads
=5
Waiting 
for threads to finish
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
thread_funcion 
is running. Argument was 5
Bye from 
5
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Bye from 
5
Picked up a thread
: Success
Picked up a thread
: Success
All done

從執行結果里,很顯然看到有bug,5個線程的argument全是5.
因為新線程的參數,是使用地址引用傳遞的:
res = pthread_create(&(a_thread[lots_of_threads]),NULL,
                thread_function, (void *)&lots_of_threads);
主線程創建線程循環,很快執行完. 引用地址中的值,在子線程執行前,已經被改成了5.
線程參數改成值傳遞就好了.

--
FROM:Linux程序設計

小默 2011-06-14 20:27 發表評論
]]>
thread 取消線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.html小默小默Tue, 14 Jun 2011 11:45:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.htmlhttp://www.shnenglu.com/momoxiao/comments/148666.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148666.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148666.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148666.html取消一個線程

可以請求一個線程終止,像給它發送一個信號一樣.

1 請求端:

#include <pthread.h>
int pthread_cancel(pthread_t thread);
請求取消指定線程.

2 接收請求端:

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
state: 線程是否接收取消請求.
| PTHREAD_CANCEL_ENABLE 允許線程接收取消請求
| PTHREAD_CANCEL_DISABLE 忽略取消請求
oldstate: 獲取先前的取消狀態,不關心先前狀態傳NULL.

#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
type: 如果接收到取消請求,什么時候采取行動.
| PTHREAD_CANCEL_ASYNCHRONOUS 接收到取消請求后立即采取行動.
| PTHREAD_CANCEL_DEFERRED 接收到取消請求后,等待請求端線程執行以下函數之一,再采取行動.
|    (pthread_join,pthread_cond_wait, pthread_cond_timedwait, pthread_testcancel, sem_wait, sigwait)
oldtype: 獲取先前的取消狀態,不關心先前狀態傳NULL.
取消一個線程:
/*
 * 取消一個線程
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

void *thread_function(void *arg);

int main(){
    
int res;
    pthread_t a_thread;
    
void *thread_result;

    res 
= pthread_create(&a_thread, NULL, thread_function, NULL);
    
if(res != 0){
        perror(
"Thread creation failed");
        exit(EXIT_FAILURE);
    }

    sleep(
3);
    printf(
"Canceling thread\n");
    res 
= pthread_cancel(a_thread);
    
if(res != 0){
        perror(
"Thread cancelation failed");
        exit(EXIT_FAILURE);
    }

    printf(
"Waiting for thread to finished\n");
    res 
= pthread_join(a_thread, &thread_result);
    
if(res != 0){
        perror(
"Thread join failed");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    
int i,res;

    res 
= pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    
if(res != 0){
        perror(
"Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    
if(res != 0){
        perror(
"Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf(
"thread_function is running\n");

    
for(i = 0; i < 10; i++){
        printf(
"Thread is still running (%d)\n", i);
        sleep(
1);
    }

    pthread_exit(
0);
}

運行結果:
$ gcc -D_REENTRANT thread7.c -o thread7 -lpthread
$ .
/thread7
thread_function 
is running
Thread 
is still running (0)
Thread 
is still running (1)
Thread 
is still running (2)
Canceling thread
Waiting 
for thread to finished

--
FROM:Linux程序設計

小默 2011-06-14 19:45 發表評論
]]>
thread 線程屬性 脫離線程http://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.html小默小默Tue, 14 Jun 2011 10:56:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.htmlhttp://www.shnenglu.com/momoxiao/comments/148663.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/06/14/148663.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/148663.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/148663.html線程的屬性

脫離線程:不向主線程返回信息,不需要主線程等待.
通過兩種方法創建:
調用pthread_detach;
修改線程的屬性. <- 這里使用

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
初始化一個線程屬性對象.
pthread_destroy
回收一個線程屬性對象.

#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
這個屬性允許我們無需對線程進行合并:
| PTHREAD_CREATE_JOINABLE 默認.
| PTHREAD_CREATE_DETACHED 不能調用pthread_join來獲得另一個線程的退出狀態.

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
控制線程的調度方式:
| SCHED_OTHER 默認
| SCHED_RP   循環(round_robin) <- 下面2個調度方式具備實時調度功能,需要root權限.
| SCHED_FIFO 先進先出

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
和schedpolicy配合使用,控制SCHED_OTHER線程的調度策略.

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit);
| PTHREAD_EXPLICIT_SCHED 調度由屬性明確設置.
| PTHREAD_INHERIT_SCHED  新線程沿用創建者的屬性.

int pthread_attr_setscope(pthread_attr_t *attr, int scope);
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope);
控制一個線程調度的計算方式,目前Linux只支持PTHREAD_SCOPE_SYSTEM.

int pthread_attr_setstacksize(pthread_attr_t *attr, int scope);
int pthread_attr_getstacksize(const pthread_attr_t *attr, int *scope);
控制線程創建的棧大小,單位字節.可選.
Linux在實現線程時,默認的棧很大,這個屬性有點多余.
創建脫離線程:
/*
 * 線程屬性-創建脫離線程
 * 主線程不等待子線程結束,只通過thread_finished標志來檢測子線程是否已結束,并顯示線程之間仍然共享的變量.
 
*/
#include 
<stdio.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<pthread.h>

void *thread_function(void *arg);

char g_message[] = "Hello World!";
int g_thread_finished = 0;

int main(){
    
int res;
    pthread_t a_thread;
    pthread_attr_t thread_attr;

    res 
= pthread_attr_init(&thread_attr);
    
if(res != 0){
        perror(
"Attribute creation failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    
if(res != 0){
        perror(
"Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }

    res 
= pthread_create(&a_thread, &thread_attr,
            thread_function, (
void *)g_message);
    
if(res != 0){
        perror(
"Thread creation failed");
        exit(EXIT_FAILURE);
    }

    (
void)pthread_attr_destroy(&thread_attr);
    
while(!g_thread_finished){
        printf(
"Waiting for thread to say it's finished\n");
        sleep(
1);
    }
    printf(
"Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg){
    printf(
"thread_function is running. Argument was %s\n", (char *)arg);
    sleep(
4);
    printf(
"Second thread setting finished flag, and exit now\n");
    g_thread_finished 
= 1;
    pthread_exit(NULL);
}

執行結果:
$ gcc -D_REENTRANT thread5.c -o thread5 -lpthread  
$ .
/thread5 
Waiting 
for thread to say it's finished
thread_function is running. Argument was Hello World!
Waiting 
for thread to say it's finished
Waiting for thread to say it's finished
Waiting for thread to say it's finished
Second thread setting finished flag, and exit now
Other thread finished, bye
!

--
FROM: Linux程序設計

小默 2011-06-14 18:56 發表評論
]]>
struct sk_buffhttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.html小默小默Thu, 24 Mar 2011 10:07:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.htmlhttp://www.shnenglu.com/momoxiao/comments/142666.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/03/24/142666.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/142666.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/142666.html/home/green/src/list.c
alloc_skb
kfree_skb
skb_put
skb_trim


#############
/home/green/src/list.c
#############
alloc_skb
kfree_skb
skb_put  // used data后部擴展
skb_push // used data前部擴展
skb_pull // used data前部截斷
skb_trim // used data后部截斷
skb_reserve // data+分片后移,只允許對空緩存使用

skb_queue_head_init  // 初始化struct sk_buff_head
skb_queue_head  // list頭部添加一個packet
skb_queue_tail  // list尾部添加一個packet
skb_dequeue      // 移去list頭部第一個packet(返回移除的packet指針,內存沒有收回?)
skb_dequeue_tail // 移去list尾部第一個packet  
skb_queue_purge  // 清空list中的節點
skb_append      // 在list的給定packet后append一個packet
skb_insert      // 在list的給定packet前insert一個packet



#############
alloc_skb
#############
<linux-2.6.36/net/core/skbuff.c>

__alloc_skb()分析:

申請struct skb_buff skb空間, 必須從CACHE中申請(skbuff_fclone_cache或skbuff_head_cache).
申請數據區內存, 使用kmalloc. 數據區包括字節對齊后的size和struct skb_shared_info.
填充skb結構.
填充分片信息struct skb_shared_info shinfo.
如果頭部skb_buff是從skbuff_fclone_cache中申請的,do something... //TODO

********

__alloc_skb()完成時,內存狀態:

skb           struct sk_buff     <-| skb->truesize
              --------------       |
data          size                 |
skb->data                          |
skb->head                          |
              -------------      <-|
              struct skb_shared_info

tail 和 end是偏移量
skb->tail = skb->data - skb->head = 0
skb->end = skb->tail + skb->size

********

head,data是指針,tail,end是偏移量。

<linux-2.6.36/include/linux/skbuff.h>
#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif

struct sk_buff {
    /* These elements must be at the end, see alloc_skb() for details.  */
    sk_buff_data_t      tail;
    sk_buff_data_t      end;
    unsigned char       *head,
    *data;

    unsigned int        truesize;
    atomic_t        users;
};

*********
skb,shinfo的引用計數都是原子類型atomic_t.
volatile只讀內存,不讀寄存器. 


#############
kfree_skb
#############
內存屏障

軟件可通過讀寫屏障強制內存訪問次序.所有在設置讀寫屏障之前發起的內存訪問,必須先于在設置屏障之后發起的內存訪問之前完成,確保內存訪問按程序的順序完成.

smp_mb()    適用于多處理器的內存屏障。
smp_rmb()   適用于多處理器的讀內存屏障。

http://blogold.chinaunix.net/u3/93713/showart_2061476.html


#############
skb_put
#############
BUG() BUGON()

BUG()和BUG_ON()被用來提供斷言,當被調用時會引發oops,導致棧的回溯和錯誤信息的打印.
大部分體系結構把BUG()定義成某種非法操作.
斷言某種情況不該發生:
if(bad_thing):
    BUG();
或者更好的形式:
BUG_ON(bad_thing);

******
frag_list

如果傳輸層將數據包分片了,就會把這些數據包放到skb的frag_list鏈表中.

******
skb_put 在尾部擴展used data area.常被用于給數據塊添加協議尾部.
其實就修改了tail偏移量和len值,別的什么都沒做.
設了倆斷言:
數據包不能有分片;
擴展數據區不能超出skb->end.


#############
skb_trim
#############
struct sk_buff

truesize = skb + data
len = data + 分片
data+len = 分片



小默 2011-03-24 18:07 發表評論
]]>
【轉】Fedora Linux中的日志服務http://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.html小默小默Wed, 02 Mar 2011 13:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.htmlhttp://www.shnenglu.com/momoxiao/comments/141009.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/03/02/141009.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/141009.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/141009.htmlhttp://blog.csdn.net/flagonxia/archive/2009/08/09/4427756.aspx

---

<序言>

我已經寫過兩篇實用型的博文,可以作為參考:

1) 如何將Linux主機設置成syslog服務器;

2) 使用cron和logrotate來管理日志文件。

     這篇文章主要介紹日志服務的基礎知識。涉及日志的服務有兩個,在Fedora9中是rsyslog服務和logrotate服務。前者負責寫入日志,后者負責備份和刪除舊日志,以及更新日志文件。

1. rsyslogd 服務

1.1 查看當前rsyslogd服務的狀態

     在Fedora 9開始,負責寫入日志信息的服務是rsyslogd,它的配置文件為:/etc/rsyslog.conf。我們檢測一下當前這個服務是不是在運行。

     [flagonxia@airhouse etc]$ ps -ef | grep -v grep | grep rsyslog
     root      1584     1  0 10:33 ?        00:00:00 rsyslogd -c 3

      從上面命令的輸出結果看到rsyslogd執行時使用的參數是-c 3。這個輸入參數在文件/etc/sysconfig/rsyslog中指定。

      [flagonxia@airhouse sysconfig]$ less rsyslog
      # Options to syslogd
      # syslogd options are deprecated in rsyslog v3 
      # if you want to use them, switch to compatibility mode 2 by "-c 2"
      SYSLOGD_OPTIONS="-c 3"

      也可以通過另一種方式,查看當前運行級別中,rsyslogd是否運行。

      [flagonxia@airhouse sysconfig]$ sudo chkconfig --list rsyslog
      rsyslog         0:off   1:off   2:on    3:on    4:on    5:on    6:off

      注意,這里的服務名是rsyslog。

1.2 配置文件/etc/rsyslog.conf

1.2.1 配置文件的基本信息

      配置文件/etc/rsyslog.conf中有很多內容,但最主要的是指定需要記錄哪些服務和需要記錄什么等級的信息。

      下面是rsyslog.conf的內容。

      # /etc/rsyslog.conf

      ... ...

      #### RULES ####

      # Log all kernel messages to the console.
      # Logging much else clutters up the screen.
      #kern.*                                                 /dev/console

      # Log anything (except mail) of level info or higher.
      # Don't log private authentication messages!
A    *.info;mail.none;authpriv.none;cron.none                /var/log/messages

      # The authpriv file has restricted access.
      authpriv.*                                              /var/log/secure

      # Log all the mail messages in one place.
B    mail.*                                                  -/var/log/maillog


      # Log cron stuff
      cron.*                                                  /var/log/cron

      # Everybody gets emergency messages
C      *.emerg                                                 *

      # Save news errors of level crit and higher in a special file.
D    uucp,news.crit                                       /var/log/spooler

      # Save boot messages also to boot.log
      local7.*                                                /var/log/boot.log     

     【注釋】

      A:把所有大于info級別的信息都記錄到/var/log/messages中,但不要記錄mail,authpriv和cron服務產生的信息;

      B:把mail產生的信息都記錄到/var/log/maillog中

      C:把所有服務輸出的“大于”emergy級別的信息顯示給每個在線的人,通過wall工具

      D:把uucp和news輸出的大雨crit級別的信息記錄到/var/log/spooler中

1.2.2 信息的等級及其在配置文件中指定的方式

     A 七種信息等級

        1)info

        2)notice

        3)warning或warn

        4)err或error

        5)crit

        6)alert

        7)emerg或panic:導致系統幾乎要死機

     B 信息等級的指定方式

        1). xxx: 表示大于xxx級別的信息

        2).=xxx:表示等于xxx級別的信息

        3).!xxx:表示在xxx之外的等級的信息

2. logrotate服務

2.1 logrotate服務的啟動方式

       logrotate是一個日志管理程序,用來把舊的日志文件刪除(備份),并創建新的日志文件,這個過程稱為“轉儲”。我們可以根據日志的大小,或者根據其使用的天數來轉儲。

       logrotate的執行由crond服務實現。在/etc/cron.daily目錄中,有個文件logrotate,它實際上是個shell script,用來啟動logrotate。logrotate程序每天由cron在指定的時間(/etc/crontab)啟動。

       [flagonxia@airhouse cron.daily]$ less logrotate
       #!/bin/sh

       /usr/sbin/logrotate /etc/logrotate.conf
       EXITVALUE=$?
       if [ $EXITVALUE != 0 ]; then
       /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
       fi
       exit 0

       因此,使用ps是無法查看到logrotate的。如果它沒有起來,就要查看一下crond服務有沒有在運行。

       [flagonxia@airhouse logrotate.d]$ ps -ef | grep -v grep | grep cron
       root      1984     1  0 10:34 ?        00:00:00 crond

2.2 logrotate的配置文件/etc/logrotate.conf 

       在執行logrotate時,需要指定其配置文件/etc/logrotate.conf。這個文件定義了如何轉儲日志文件的規則。如下:

       # see "man logrotate" for details
       # rotate log files weekly
       weekly

       # keep 4 weeks worth of backlogs
       rotate 4

       # create new (empty) log files after rotating old ones
       create

       # use date as a suffix of the rotated file
       dateext

       # uncomment this if you want your log files compressed
       #compress

       # RPM packages drop log rotation information into this directory
       include /etc/logrotate.d

       # no packages own wtmp and btmp -- we'll rotate them here
       /var/log/wtmp {
              monthly
              create 0664 root utmp
              rotate 1
        }

        /var/log/btmp {
              missingok
              monthly
              create 0600 root utmp
              rotate 1
         }

         # system-specific logs may be also be configured here.

      這個配置文件的注釋寫得很清楚,沒有必要再羅嗦了。只想強調下面這行,它的作用包含存放在/etc/logrotate.d目錄下面的配置文件,不可或缺。如果你安裝了一個新的服務,它的日志轉儲的規則可以建立一個專門的配置文件,放在/etc/logrotate.d下面。它其實也因為下面的這句話,在logrotate服務啟動時被讀取。

       include /etc/logrotate.d

       這里有個例子:/etc/logrotate.d/syslog

       /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/boot.log /var/log/cron {
             sharedscripts
             postrotate
                  /bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
             endscript
       }

      上面的配置對于/var/log/messages, /var/log/secure, /var/log/mailog/ /var/log/spooler, /var/log/boot.log, /var/log/cron都是適用的。

      注意,prerotate和postrotate必須和sharescripts...endscript一起用。上面的信息表示日志文件轉儲后,重啟rsyslogd服務。

      每個存放在/etc/logrotate.d目錄里的文件,都有上面格式的配置信息。在{}中定義的規則,如果與logrotate.conf中的沖突,以/etc/logrotatate.d/中的文件定義的為準。



小默 2011-03-02 21:23 發表評論
]]>
linux kernel macro likely() unlikely()http://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.html小默小默Thu, 03 Feb 2011 08:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.htmlhttp://www.shnenglu.com/momoxiao/comments/139709.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/02/03/139709.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/139709.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/139709.html<linux/compiler.h> 2.6.36
142 # define likely(x)  __builtin_expect(!!(x), 1)
143 # define unlikely(x)    __builtin_expect(!!(x), 0)

long __buildin_expect(long EXP, C)是GCC的內置函數,用來給編譯器提供分支預測信息:期望EXP==C,返回值是EXP。其中C是編譯時常量。
eg:
if(__buildin_expect(ptr != NULL, 1)) error(); // 期望ptr!=NULL為1;當期望滿足時(返回的ptr != NULL為1)執行error()
if(__buildin_expect(x,0)) foo(); // 期望x==0;當期望未滿足(返回的x為真)時執行foo()

總之:
if(likely(x)) foo();     // 期望x為真,且x為真時執行foo()
if(unlikely(x)) foo(); // 期望x為假,且x為真時執行foo()
也就是說,likely()和unlikely()都是在x為真時執行分支下面的語句;不同的是likely()期望x為真,unlikely期望x為假,

--
ref:
http://blog.richliu.com/2007/02/01/428/



小默 2011-02-03 16:23 發表評論
]]>
implicit declaration of function 'NIPQUAD'http://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.html小默小默Wed, 26 Jan 2011 20:28:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.htmlhttp://www.shnenglu.com/momoxiao/comments/139393.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/01/27/139393.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/139393.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/139393.htmlQ:implicit declaration of function 'NIPQUAD'
A:

http://kerneltrap.org/mailarchive/linux-netdev/2008/10/31/3873584

 Using NIPQUAD() with NIPQUAD_FMT, %d.%d.%d.%d or %u.%u.%u.%u
can be replaced with %pI4

-  dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
-   NIPQUAD(src_ipaddr),
-   NIPQUAD(arpinfo->smsk.s_addr),
-   NIPQUAD(arpinfo->src.s_addr),
+  dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n",
+   &src_ipaddr,
+   &arpinfo->smsk.s_addr,
+   &arpinfo->src.s_addr,
    arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");



小默 2011-01-27 04:28 發表評論
]]>
ldd3讀書筆記http://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.html小默小默Wed, 05 Jan 2011 15:24:00 GMThttp://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.htmlhttp://www.shnenglu.com/momoxiao/comments/138041.htmlhttp://www.shnenglu.com/momoxiao/archive/2011/01/05/138041.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/138041.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/138041.html閱讀全文

小默 2011-01-05 23:24 發表評論
]]>
scull源碼分析 //未完待續,囧http://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.html小默小默Fri, 10 Dec 2010 15:48:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.htmlhttp://www.shnenglu.com/momoxiao/comments/136112.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/12/10/136112.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/136112.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/136112.html# disable/enable debugging#DEBUG = y# 當DEBUG變量等于y時。兩個比較變量用括...  閱讀全文

小默 2010-12-10 23:48 發表評論
]]>
蓋樓 http://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.html小默小默Tue, 09 Nov 2010 14:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.htmlhttp://www.shnenglu.com/momoxiao/comments/133126.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/11/09/133126.html#Feedback25http://www.shnenglu.com/momoxiao/comments/commentRss/133126.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/133126.html

小默 2010-11-09 22:18 發表評論
]]>
killhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.html小默小默Mon, 16 Aug 2010 16:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.htmlhttp://www.shnenglu.com/momoxiao/comments/123645.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123645.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123645.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123645.htmlkill(傳送信號給指定的進程,使用 kill -l 命令可查看linux系統中信號。)

相關函數
raise,signal

表頭文件
#include<sys/types.h>
#include<signal.h>

定義函數
int kill(pid_t pid,int sig);

函數說明
kill()可以用來送參數sig指定的信號給參數pid指定的進程。

參數pid有幾種情況:
pid>0 將信號傳給進程識別碼為pid 的進程。
pid=0 將信號傳給和目前進程相同進程組的所有進程
pid=-1 將信號廣播傳送給系統內所有的進程
pid<0 將信號傳給進程組識別碼為pid絕對值的所有進程

返回值
執行成功則返回0,如果有錯誤則返回-1。

錯誤代碼
EINVAL 參數sig 不合法
ESRCH 參數pid 所指定的進程或進程組不存在 
EPERM 權限不夠無法傳送信號給指定進程


小默 2010-08-17 00:18 發表評論
]]>
SIGHUPhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.html小默小默Mon, 16 Aug 2010 16:05:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.htmlhttp://www.shnenglu.com/momoxiao/comments/123642.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/17/123642.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123642.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123642.html
On POSIX-compliant platforms, SIGHUP is a signal sent to a process when its controlling terminal is closed. (It was originally designed to notify the process of a serial line drop). SIGHUP is a symbolic constant defined in theheader file signal.h.

小默 2010-08-17 00:05 發表評論
]]>
waithttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.html小默小默Mon, 16 Aug 2010 15:42:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.htmlhttp://www.shnenglu.com/momoxiao/comments/123640.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123640.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123640.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123640.htmlwait(等待子進程中斷或結束)

相關函數
waitpid,fork

表頭文件
#include<sys/types.h>
#include<sys/wait.h>

定義函數
pid_t wait (int * status);

函數說明
wait()會暫時停止目前進程的執行,直到有信號來到或子進程結束。如果在調用wait()時子進程已經結束,則wait()會立即返回子進程結束狀態值。子進程的結束狀態值會由參數status 返回,而子進程的進程識別碼也會一快返回。如果不在意結束狀態值,則參數status 可以設成NULL。子進程的結束狀態值請參考下面的waitpid()。

返回值
如果執行成功則返回子進程識別碼(PID),如果有錯誤發生則返回-1。失敗原因存于errno 中。

==============
EINTR ,A signal interrupted this function


小默 2010-08-16 23:42 發表評論
]]>
forkhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.html小默小默Mon, 16 Aug 2010 15:27:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.htmlhttp://www.shnenglu.com/momoxiao/comments/123639.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/16/123639.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/123639.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/123639.html頭文件:
#include <unistd.h>

函數定義:
int fork( void );

返回值:
子進程中返回0,父進程中返回子進程ID,出錯返回-1

函數說明:
一個現有進程可以調用fork函數創建一個新進程。由fork創建的新進程被稱為子進程(child process)。fork函數被調用一次但返回兩次。兩次返回的唯一區別是子進程中返回0值而父進程中返回子進程ID。
子進程是父進程的副本,它將獲得父進程數據空間、堆、棧等資源的副本。注意,子進程持有的是上述存儲空間的“副本”,這意味著父子進程間不共享這些存儲空間,它們之間共享的存儲空間只有代碼段。



小默 2010-08-16 23:27 發表評論
]]>
gcc math.h -lmhttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.html小默小默Thu, 05 Aug 2010 01:04:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.htmlhttp://www.shnenglu.com/momoxiao/comments/122265.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/08/05/122265.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/122265.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/122265.html-l表示使用庫,m為數學庫。
=================
Linux程序設計中的一個例子:
#include <sys/types.h>
#include 
<sys/resource.h>
#include 
<sys/time.h>
#include 
<unistd.h>
#include 
<stdio.h>
#include 
<math.h>

/// 向一個臨時文件寫一個字符串10000次,然后進行一些數學運算,目的是制造一些CPU負荷
void work()
{
    FILE 
*f;
    
int i;
    
double x = 4.5;

    f 
= tmpfile(); // 創建臨時文件
    for(i = 0; i < 10000; i++){
        fprintf(f, 
"Do some output\n");
        
if(ferror(f)){ //TODO ferror?
            fprintf(stderr, "Error writing to temporary file\n");
            exit(
1);
        }
    }

    
for(i = 0; i < 1000000; i++)
        x 
= log(x*+ 3.21);
}

/// main 函數先調用 work, 再調用 getrusage 函數查看它使用了多少 CPU 時間。把這些資料顯示在屏幕上。
int main()
{
    
struct rusage r_usage;
    
struct rlimit r_limit;
    
int priority;

    work();
    getrusage(RUSAGE_SELF, 
&r_usage); // 只返回當前程序的 CPU 占用時間

    printf(
"CPU usage: User = %ld.%06ld, System = %ld.%06ld\n",
           r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec,    
// r_usage.ru_utime 程序本身執行它的指令所消耗的時間
           r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);   // r_usage.ru_stime OS由于這個程序而消耗的 CPU 時間

    
/// 調用 getpriority 和 getrlimit 函數分別查出自己的當前優先級和文件長度限制
    priority = getpriority(PRIO_PROCESS, getpid()); // PRIO_PROCESS 表示后面是進程標識符
    printf("Current priority = %d\n", priority);
    getrlimit(RLIMIT_FSIZE, 
&r_limit); // 讀取以字節計的文件長度限制到 r_limit 中
    printf("Current FSIZE limit: soft = %ld, hard = %ld\n",
              r_limit.rlim_cur, r_limit.rlim_max);  
// rlim_cur 軟限制, rlimt_max 硬限制

    
/// 通過 setrlimit 函數設置了一個文件長度限制。
    r_limit.rlim_cur = 2048;    // 軟限制2M
    r_limit.rlim_max = 4096;    // 硬限制4M
    printf("Setting a 2K file size limit\n");
    setrlimit(RLIMIT_FSIZE, 
&r_limit);

    
/// 然后再次調用 work 失敗,因為它嘗試創建的文件尺寸過大。
    work();

    exit(
0);

}

編譯:
[green@colorfulgreen environ]$ gcc limits.c -o limits

報錯:
/tmp/ccxW94yi.o: In function `work':
limits.c:(.text+0xaf): undefined reference to `log'
collect2: ld returned 1 exit status

編譯時加上 -lm 選項:
[green@colorfulgreen environ]$ gcc limits.c -lm -o limits

Done.
============
PS:為嘛這個編輯器插入代碼時最前面不能有下面這幾行T_T
/**
  * 資源限制
**/








小默 2010-08-05 09:04 發表評論
]]>
硬盤安裝 Fedore13 Livehttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.html小默小默Sat, 17 Jul 2010 23:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.htmlhttp://www.shnenglu.com/momoxiao/comments/120668.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120668.html#Feedback1http://www.shnenglu.com/momoxiao/comments/commentRss/120668.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120668.html昨晚無聊把Fedora裝本上了,記一下,免得每次都得上網找。

1. grldr 放在C盤
2. boot.ini 最后添加一行 c:\grldr="GRUB"
3. ISO安裝鏡像中提取 LiveOS目錄,/isolinux/vmlinuz0,/isolinux/initrd0.img 放在FAT32分區盤根目錄中。
4. 重啟進入grub
kernel (hd0,7)/isolinux/vmlinuz0 root=live:LABEL=FILE liveimg rhgb rootfstype=auto
initrd (hd0,7)/isolinux/initrd0.img
boot

其中(hd0,7)是第3步中的FAT32分區盤,卷標為FILE

小默 2010-07-18 07:20 發表評論
]]>
fedora13 mp3 rmvbhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.html小默小默Sat, 17 Jul 2010 20:21:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.htmlhttp://www.shnenglu.com/momoxiao/comments/120665.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120665.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/120665.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120665.htmlrpm -ivh http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm
yum install gstreamer-plugins-bad gstreamer-ffmpeg gstreamer-plugins-ugly -y


小默 2010-07-18 04:21 發表評論
]]>
Grub磁盤分區表示方法http://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.html小默小默Sat, 17 Jul 2010 18:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.htmlhttp://www.shnenglu.com/momoxiao/comments/120660.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/07/18/120660.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/120660.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/120660.html

http://www.linux-wiki.cn/index.php?title=Grub磁盤分區表示方法&variant=zh-cn
==============================================

Grub指定分區的方法和Linux、Windows等系統不一樣,它的主要特點為:

  • Grub在表示方式上并不區分普通的IDE硬盤、當下流行的SATA硬盤和SCSI硬盤等,在Grub中,硬盤會被識別為hd#,#是從0開始的硬盤編號,而軟盤被類似地識別為fd#。
  • Grub的硬盤編號和分區編號都是從0開始的,這一點linux不同。

按照以上兩個特點,假設有一塊硬盤(hd0),那么(hd0,0) (hd0,1) (hd0,2) (hd0,3)依次表示它的四個主分區,而隨后的(hd0,4)...則是邏輯分區 Image:Example.jpg

通常情況下,裝有Windows的硬盤中,通常是按照一個主分區(hd0,0),一個擴展分區(hd0,1)該擴展分區下是若干邏輯分區。這樣(hd0,0)對應C盤,(hd0,4)對應D盤,依此類推。

如果您還不能確定你需要的那個分區,可以在輸入過程中按下Tab鍵實現命令補全。比如你在輸入一條root語句:

root (hd0,

此時按下Tab鍵,grub將列出可用的分區編號和分區類型(grub還不能識別ntfs分區,顯示為不知道類型的分區)。你可以依照這個提示來完成命令的輸入。

如果不能確定ISO文件的位置,可使用find 文件名.iso(find debian-40r2-i386-CD-1.iso)

==============================

試了下Tab鍵命令補全。。。竊喜ing。。。


小默 2010-07-18 02:20 發表評論
]]>
volume group "volgroup00" not foundhttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.html小默小默Sat, 26 Jun 2010 02:49:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.htmlhttp://www.shnenglu.com/momoxiao/comments/118758.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/26/118758.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118758.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118758.htmlhttp://www.csource.org/bbs/thread-1140084-1-1.html 
by SharkBones

前段時間也遇到和lz類似的問題,出現這種情況可能是有以下幾個原因:
1.編譯內核時未添加相應的硬件支持,比如對于SCSI或IDE硬盤的支持,這些硬件驅動都是以模塊的形式編譯進內核。
2.編譯時的選項不正確對LVM,RAID的支持應該是以模塊的形式編譯進內核,而不是Built-in,否則可能就會出現lz所說的情況。
建議樓主用cpio解壓你的initrd-2.6.31.4-*.img,檢查一下解壓后的lib目錄里是否有相應的支持LVM的內核模塊,如果沒有,那就是編譯時內核選項不正確,需要重新編譯了。

=============================

那為啥還提供Build-in選項。。。悲劇。。。
呃,想起來了,貌似只有yes,no,module;yes,no.沒有module,no。。。

==============================

好吧# make defconfig 好了,傳說中Linus的配置 >_<
貌似又悲劇了。。。


小默 2010-06-26 10:49 發表評論
]]>
【轉】proc文件系統分析(四)http://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.html小默小默Tue, 22 Jun 2010 22:10:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.htmlhttp://www.shnenglu.com/momoxiao/comments/118521.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/23/118521.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118521.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118521.html(六) 對proc文件默認操作的分析 
現在,我們已經基本清楚了proc文件系統對自己proc_dir_entry結構的管理了。下面我們回過頭來,再看一下在文件注冊函數中的一段代碼: 
if (S_ISDIR(dp->mode)) { 
if (dp->proc_iops == NULL) { 
dp->proc_fops = &proc_dir_operations; 
dp->proc_iops = &proc_dir_inode_operations; 
} 
dir->nlink++; 
} else if (S_ISLNK(dp->mode)) { 
if (dp->proc_iops == NULL) 
dp->proc_iops = &proc_link_inode_operations; 
} else if (S_ISREG(dp->mode)) { 
if (dp->proc_fops == NULL) 
dp->proc_fops = &proc_file_operations; 
} 
我在前面已經提過,這段代碼根據注冊的proc文件類型的不同,為proc_dir_entry結構設置了不同的操作函數集。也就是說,我們使用封裝的create_proc_entry函數在proc文件系統中注冊文件時,可以不用去管這些操作函數集,因為該結構總是自動地設置了相應的proc_iops和proc_fops操作函數。下面我們就對這些默認的操作進行一個分析,因為這對我們了解proc文件系統和VFS的結構非常重要。 
1 對普通文件的操作 
我們首先看一下普通proc文件的函數集,根據代碼段: 
if (S_ISREG(dp->mode)) { 
if (dp->proc_fops == NULL) 
dp->proc_fops = &proc_file_operations; 
} 
我們可以看到,對于普通的proc文件,只設置了文件操作,即proc_file_operations,從這一點上可以看出,對于普通的proc文件,只缺省提供了文件操作,因此,在必要的時候,我們必須手工設置需要的索引節點操作函數集,比如inode_operations中的權限檢查函數permission等等。 
對于proc_file_operations,我們可以看到,只實現了三個函數: 
static struct file_operations proc_file_operations = { 
llseek: proc_file_lseek, 
read: proc_file_read, 
write: proc_file_write, 
}; 
下面我們簡單的看一下它們實現的功能: 
(1)llseek: proc_file_lseek 
這個函數,用來實現lseek系統調用,其功能是設置file結構的->f_pos域,因此,根據第三個參數orig的不同,將f_pos設置為相應的值,該函數非常簡單,因此不作過多的介紹。 
(2)read: proc_file_read 
這個函數是file_operations結構中的成員,在后面我們將看到,在proc_dir_entry結構中實現的file_operations和inode_operations將鏈接至VFS的inode中,因此,該函數將用來實現read系統調用。在這個函數中,首先根據file結構,得到相應的inode,然后由 
struct proc_dir_entry * dp; 
dp = (struct proc_dir_entry *) inode->u.generic_ip; 
而得到proc_dir_entry結構,然后,開始調用該proc_dir_entry結構中的函數,向用戶空間返回指定大小的數據,我們看一下下面的代碼片斷: 
if (dp->get_info) { 
/* 
* Handle backwards compatibility with the old net 
* routines. 
*/ 
n = dp->get_info(page, &start, *ppos, count); 
if (n read_proc) { 
n = dp->read_proc(page, &start, *ppos, 
count, &eof, dp->data); 
} else 
break; 
由此我們看出,該函數的實現依賴于proc_dir_entry結構中的get_info和read_proc函數,因此,如果我們要注冊自己的proc文件,在不設置自己的proc_fops操作函數集的時候,必須實現上面兩個函數中的一個,否則,這個缺省的proc_file_read函數將做不了任何工作。示意圖如下: 
在這個函數中,實現了從內核空間向用戶空間傳遞數據的功能,其中使用了許多技巧,在這里就不作討論了,具體實現可以參考源碼。 
(3)write: proc_file_write 
與上面的函數類似,我們可以看到proc_file_write函數同樣依賴于proc_dir_entry中的write_proc(file, buffer, count, dp->data)函數,它的實現非常簡單: 
static ssize_t 
proc_file_write(struct file * file, const char * buffer, 
size_t count, loff_t *ppos) 
{ 
struct inode *inode = file->f_dentry->d_inode; 
struct proc_dir_entry * dp; 
dp = (struct proc_dir_entry *) inode->u.generic_ip; 
if (!dp->write_proc) 
return -EIO; 
/* FIXME: does this routine need ppos? probably... */ 
return dp->write_proc(file, buffer, count, dp->data); 
} 
我們看到,它只是簡單地檢測了->write_proc函數是否存在,如果我們在proc_dir_entry結構中實現了這個函數,那么就調用它,否則,就退出。 
根據上面的討論,我們看到,對于普通文件的操作函數,proc文件系統為我們提供了一個簡單的封裝,因此,我們只要在proc_dir_entry中實現相關的讀寫操作即可。 
但是,如果我們想提供讀寫操作之外的函數,那么我們就可以定義自己的file_operations函數集,并且在proc文件注冊后,將它鏈接到proc_dir_entry的proc_fops上,這樣,就可以使用自己的函數集了。 
2 對鏈接文件的操作 
根據代碼段: 
else if (S_ISLNK(dp->mode)) { 
if (dp->proc_iops == NULL) 
dp->proc_iops = &proc_link_inode_operations; 
我們可以看出,對于鏈接文件,proc文件系統為它設置了索引節點操作proc_iops。因為我們知道,一個符號鏈接,只擁有inode結構,而沒有文件結構,所以,為它提供proc_link_inode_operations函數集就可以了。 
下面我們看一下,這個函數集的內容: 
static struct inode_operations proc_link_inode_operations = { 
readlink: proc_readlink, 
follow_link: proc_follow_link, 
}; 
這個函數集實現了和鏈接相關的兩個函數,我們分別來看一下: 
(1)readlink: proc_readlink 
該函數用來實現readlink系統調用,它的功能是獲得目標文件的文件名,我們在前面看到,對于一個鏈接文件,在注冊時已經將鏈接目標的文件放在了proc_dir_entry結構的->data域中(參考前面介紹的函數proc_symlink),因此,我們只要將->data中的數據返回就可以了,它的代碼如下: 
static int proc_readlink(struct dentry *dentry, char *buffer, int buflen) 
{ 
char *s= 
((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; 
return vfs_readlink(dentry, buffer, buflen, s); 
} 
我們看到,這個函數使用一個指針指向->data,然后,使用VFS函數vfs_readlink將數據返回到用戶空間,非常的簡單。 
(2)follow_link: proc_follow_link 
這個函數代碼如下: 
static int proc_follow_link(struct dentry *dentry, struct nameidata *nd) 
{ 
char *s= 
((struct proc_dir_entry *)dentry->d_inode->u.generic_ip)->data; 
return vfs_follow_link(nd, s); 
} 
和上面介紹的函數類似,它同樣利用VFS的函數實現其功能,對于vfs_follow_link,可以參考fs/namei.c文件。其結構如下圖所示: 
3 對目錄文件的操作 
最后我們看一下proc文件系統對目錄文件的操作函數集,在文件注冊的時候,有如下代碼: 
if (S_ISDIR(dp->mode)) { 
if (dp->proc_iops == NULL) { 
dp->proc_fops = &proc_dir_operations; 
dp->proc_iops = &proc_dir_inode_operations; 
} 
dir->nlink++; 
} 
從中我們可以看到,在proc文件系統中注冊目錄文件的時候,它會檢查是否該proc_dir_entry結構已經注冊了proc_iops函數集,如果沒有,那么就為proc_fops和proc_iops設置相應的缺省函數集。下面我們對它們分別進行討論: 
1.對目錄的文件操作proc_dir_operations: 
static struct file_operations proc_dir_operations = { 
read: generic_read_dir, 
readdir: proc_readdir, 
}; 
這個函數集的主要功能,是在由proc_dir_entry結構構成的proc文件樹中解析目錄。下面我們對這兩個函數進行一個簡單的分析: 
(1)read: generic_read_dir 
我們知道,對于read系統調用,當其參數文件句柄指向目錄的時候,將返回EISDIR錯誤。因此,目錄文件的read函數將完成這個工作。generic_read_dir函數是VFS提供的通用函數,可以參考fs/read_write.c文件: 
ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos){ 
return –EISDIR; 
} 
這個函數很簡單,只要返回錯誤碼就可以了。 
(2)readdir: proc_readdir 
這個函數用來實現readdir系統調用,它從目錄文件中讀出dirent結構到內存中。我們可以參考fs/readdir.c中的filldir()函數。 
2.對目錄文件索引節點的操作函數:proc_dir_inode_operations 
首先,我們看一下proc_dir_inode_operations的定義: 
/* 
* proc directories can do almost nothing.. 
*/ 
static struct inode_operations proc_dir_inode_operations = { 
lookup: proc_lookup, 
}; 
我們看到,對于目錄文件的索引節點,只定義了一個函數lookup。因為我們在前面對VFS進行分析的時候知道,以下操作,是只在目錄節點中定義的: 
int (*create) (struct inode *,struct dentry *,int); 
struct dentry * (*lookup) (struct inode *,struct dentry *); 
int (*link) (struct dentry *,struct inode *,struct dentry *); 
int (*unlink) (struct inode *,struct dentry *); 
int (*symlink) (struct inode *,struct dentry *,const char *); 
int (*mkdir) (struct inode *,struct dentry *,int); 
int (*rmdir) (struct inode *,struct dentry *); 
int (*mknod) (struct inode *,struct dentry *,int,int); 
int (*rename) (struct inode *, struct dentry *, 
struct inode *, struct dentry *); 
但是經過我們對proc文件系統的分析,我們知道,proc文件系統中的文件都是在內核代碼中通過proc_dir_entry實現的,因此,它不提供目錄索引節點的create,link,unlink,symlink,mkdir,rmdir,mknod,rename方法,也就是說,用戶是不能通過shell命令在/proc目錄中對proc文件進行改名,刪除,建子目錄等操作的。這也算是proc文件系統的一種保護策略。 
而在內核中,則使用proc_mkdir,proc_mknod等函數,在核心內通過代碼來維護proc文件樹。由此可以看出虛擬文件系統的一些特性。對目錄文件的默認操作,可以參見下面的示意圖: 
下面我們就來看一下唯一定義的函數lookup: proc_lookup,到底實現了什么功能。 
在進行具體分析之前,我們先考慮一個問題,我們知道,proc文件系統維護了自己的proc_dir_entry結構,因此提供了create_proc_entry,remove_proc_entry等等函數,并且為了方便實現對proc文件的讀寫功能,特意在proc_dir_entry結構中設置了get_info,read_proc和write_proc函數指針(我們在前面介紹過,這三個函數被封裝在proc_file_operations中),并且,提供了自己的inode_operations和file_operations,分別是proc_iops 和proc_fops。也就是說,我們在建立proc文件以及為proc文件建立操作函數的時候,似乎可以不用考慮VFS的實現,只要建立并注冊該proc_dir_entry結構,然后實現其proc_iops 和proc_fops(或者get_info,read_proc和write_proc)就可以了。 
但是我們知道,在linux系統中,所有的子系統都是與VFS層交互,而VFS是通過inode結構進行管理的,并且在其上的操作(文件和索引節點的操作)也是通過該inode結構的inode_operations和file_operations實現的。因此,proc文件系統必須將自己的文件與VFS的inode鏈接起來。 
那么proc文件系統是在何時,通過何種方法將自己的proc_dir_entry結構和VFS的inode聯系在一起的,并且將對inode的inode_operations和file_operations操作定位到自己結構中的proc_iops 和proc_fops上呢?通過我們對lookup: proc_lookup的分析,就會明白這一過程。 
我們先看一下它的代碼: 
struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) 
{ 
struct inode *inode; 
struct proc_dir_entry * de; 
int error; 
error = -ENOENT; 
inode = NULL; 
de = (struct proc_dir_entry *) dir->u.generic_ip; 
if (de) { 
for (de = de->subdir; de ; de = de->next) { 
if (!de || !de->low_ino) 
continue; 
if (de->namelen != dentry->d_name.len) 
continue; 
if (!memcmp(dentry->d_name.name, 
de->name, de->namelen)) { 
int ino = de->low_ino; 
error = -EINVAL; 
inode = proc_get_inode(dir->i_sb, ino, de); 
break; 
} 
} 
} 
if (inode) { 
dentry->d_op = &proc_dentry_operations; 
d_add(dentry, inode); 
return NULL; 
} 
return ERR_PTR(error); 
} 
這個函數的參數是struct inode * dir和struct dentry *dentry,它的功能是查找由dentry指定的文件,是否在由dir指定的目錄中。 
我們知道,proc文件系統通過proc_dir_entry結構維護文件信息,并且該結構與相應的inode->u.generic_ip聯系,因此,這個函數首先通過struct inode * dir得到了相應目錄文件的proc_dir_entry結構,并使用指針de指向它,然后,開始在該結構的孩子中查找指定的dentry。 
判斷是否找到的條件很簡單,就是de->namelen等于 dentry->d_name.len,并且dentry->d_name.name等于de->name,根據程序流程,如果沒有找到,那么將返回-ENOENT錯誤(使用inode指針作為判斷條件),如果找到該文件,那么就根據ino = de->low_ino(要注意的是,這時候的de已經指向由dentry確定的proc_dir_entry結構了。)調用函數: 
inode = proc_get_inode(dir->i_sb, ino, de); 
這個proc_get_inode的功能很容易猜到,就是從由超級塊i_sb確定的文件系統中,得到索引節點號為ino的inode。因此考慮兩種情況,第一種情況,這個索引節點已經被讀入緩存了,那么直接返回該inode即可。第二種情況是,指定ino的索引節點不在緩存中,那么就需要調用相應的函數,將該索引節點從邏輯文件系統中讀入inode中。 
下面我們就來分析一下proc_get_inode函數,尤其注意上面所說的第二種情況,因為這正是inode和proc_dir_entry建立聯系并重定位操作函數集的時機。先看一下源碼: 
struct inode * proc_get_inode(struct super_block * sb, int ino, 
struct proc_dir_entry * de) 
{ 
struct inode * inode; 
/* 
* Increment the use count so the dir entry can't disappear. 
*/ 
de_get(de); 
#if 1 
/* shouldn't ever happen */ 
if (de && de->deleted) 
printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count)); 
#endif 
inode = iget(sb, ino); 
if (!inode) 
goto out_fail; 
inode->u.generic_ip = (void *) de; /* link the proc_dir_entry to inode */ 
/* 
* set up other fields in the inode 
*/ 
if (de) { 
if (de->mode) { 
inode->i_mode = de->mode; 
inode->i_uid = de->uid; 
inode->i_gid = de->gid; 
} 
if (de->size) 
inode->i_size = de->size; 
if (de->nlink) 
inode->i_nlink = de->nlink; 
if (de->owner) 
__MOD_INC_USE_COUNT(de->owner); 
if (S_ISBLK(de->mode)||S_ISCHR(de->mode)||S_ISFIFO(de->mode)) 
init_special_inode(inode,de->mode,kdev_t_to_nr(de->rdev)); 
else { 
if (de->proc_iops) 
inode->i_op = de->proc_iops; 
if (de->proc_fops) 
inode->i_fop = de->proc_fops; 
} 
} 
out: 
return inode; 
out_fail: 
de_put(de); 
goto out; 
} 
我們根據程序流程,分析它的功能: 
1.使用de_get(de)增加proc_dir_entry結構de的引用計數。 
2.使用VFS的iget(sb, ino)函數,從sb指定的文件系統中得到節點號為ino的索引節點,并使用指針inode指向它。如果沒有得到,則直接跳到標號out_fail,減少de的引用計數后退出。 
因此我們要了解一下iget,這個函數由VFS提供,可以參考源文件fs/inode.c和頭文件include/linux/fs.h,在fs.h頭文件中,有如下定義: 
static inline struct inode *iget(struct super_block *sb, unsigned long ino) 
{ 
return iget4(sb, ino, NULL, NULL); 
} 
因此該函數是由fs/inode.c中的iget4實現的。主要步驟是,首先根據sb和ino得到要查找的索引節點的哈希鏈表,然后調用find_inode函數在該鏈表中查找該索引節點。如果找到了,那么就增加該索引節點的引用計數,并將其返回;否則,調用get_new_inode函數,以便從邏輯文件系統中讀出該索引節點。 
而get_new_inode函數也很簡單,它分配一個inode結構,并試圖重新查找指定的索引節點,如果還是沒有找到,那么就給新分配的索引節點加入到哈希鏈表和使用鏈表中,并設置一些基本信息,如i_ino,i_sb,i_dev等,并且,將其引用計數i_count初始化為1。然后,調用超級塊sb的read_inode函數,來作邏輯文件系統自己特定的工作,但對于proc文件系統來說,read_inode函數基本沒有實質性的功能,可參考前文對該函數的分析。最后,返回這個新建的索引節點。 
3.這時,我們已經得到了指定的inode(或者是從緩存中返回,或者是利用get_new_inode函數剛剛創建),那么就使用語句 
inode->u.generic_ip = (void *) de; 
將proc_dir_entry結構de與相應的索引節點鏈接起來。因此,我們就可以在其他時刻,利用proc文件索引節點的->u.generic_ip得到相應的proc_dir_entry結構了。 
對于新創建的inode來說,將其->u.generic_ip域指向(void *) de沒什么問題,因為該域還沒有被賦值,但是如果這個inode是從緩存中得到的,那么,說明該域已經指向了一個proc_dir_entry結構,這樣直接賦值,會不會引起問題呢? 
這有兩種情況,第一種情況,它指向的proc_dir_entry結構沒有發生過變化,那么,由于索引節點是由ino確定的,而且在一個文件系統中,確保了索引節點號ino的唯一性,因此,使用inode->u.generic_ip = (void *) de語句對其重新進行賦值,不會發生任何問題。 
另一種情況是在這之前,程序曾調用remove_proc_entry要將該proc_dir_entry結構刪除,那么由于它的引用計數count不等于零,因此,該結構不會被釋放,而只是打上了刪除標記。所以這種情況下,該賦值語句也不會引起問題。 
我們知道,當inode的i_count變為0的時候,會調用sb的proc_delete_inode函數,這個函數將inode的i_state設置為I_CLEAR,這可以理解為將該inode刪除了,并調用de_put,減少并檢查proc_dir_entry的引用計數,如果到零,也將其釋放。因此我們看到,引用計數的機制使得VFS的inode結構和proc的proc_dir_entry結構能夠保持同步,也就是說,對于一個存在于緩存中的的inode,必有一個proc_dir_entry結構存在。 
4.這時,我們已經得到了inode結構,并且將相應的proc_dir_entry結構de與inode鏈接在了一起。因此,就可以根據de的信息,對inode的一些域進行填充了。其中最重要的是使用語句: 
if (de->proc_iops) 
inode->i_op = de->proc_iops; 
if (de->proc_fops) 
inode->i_fop = de->proc_fops; 
將inode的操作函數集重定向到proc_dir_entry結構提供的函數集上。這是因為我們可以通過proc_dir_entry結構進行方便的設置和調整,但最終要將文件提交至VFS進行管理。正是在這種思想下,proc文件系統提供提供了一套封裝函數,使得我們可以只對proc_dir_entry結構進行操作,而忽略與VFS的inode的聯系。 
5.最后,成功地返回所要的inode結構。 
(七) 小結 
至此,已經對proc文件系統進行了一個粗略的分析,從文件系統的注冊,到proc_dir_entry結構的管理,以及與VFS的聯系等等。下面我們對proc文件系統的整體結構作一個總結。 
proc文件系統使用VFS接口,注冊自己的文件類型,并且通過注冊時提供的proc_read_super函數,創建自己的超級塊,然后裝載vfsmount結構。在proc文件系統內部,則使用proc_dir_entry結構來維護自己的文件樹,并且通過目錄文件的lookup函數,將proc_dir_entry結構與VFS的inode結構建立聯系。 


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u2/74524/showart_1129842.html


小默 2010-06-23 06:10 發表評論
]]>
『轉』文件結構體struct file(Linux 2.6.23內核)http://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.html小默小默Thu, 17 Jun 2010 15:14:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.htmlhttp://www.shnenglu.com/momoxiao/comments/118121.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/17/118121.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/118121.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/118121.htmlstruct file結構體定義在/linux/include/linux/fs.h(Linux 2.6.11內核)中,其原型是:
struct file {
        /*
         * fu_list becomes invalid after file_free is called and queued via
         * fu_rcuhead for RCU freeing
         */
        union {
                struct list_head        fu_list;
                struct rcu_head         fu_rcuhead;
        } f_u;
        struct path             f_path;
#define f_dentry        f_path.dentry
#define f_vfsmnt        f_path.mnt
        const struct file_operations    *f_op;
        atomic_t                f_count;
        unsigned int            f_flags;
        mode_t                  f_mode;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;
        unsigned long           f_version;
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
        /* needed for tty driver, and maybe others */
        void                    *private_data;
#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
};
文件結構體代表一個打開的文件,系統中的每個打開的文件在內核空間都有一個關聯的struct file。它由內核在打開文件時創建,并傳遞給在文件上進行操作的任何函數。在文件的所有實例都關閉后,內核釋放這個數據結構。在內核創建和驅動源碼中,struct file的指針通常被命名為file或filp。一下是對結構中的每個數據成員的解釋:
一、
union {
    struct list_head fu_list;
    struct rcu_head rcuhead;
}f_u;
其中的struct list_head定義在 linux/include/linux/list.h中,原型為:
struct list_head {
        struct list_head *next, *prev;
};
用于通用文件對象鏈表的指針。
struct rcu_head定義在linux/include/linux/rcupdate.h中,其原型為:
/**
* struct rcu_head - callback structure for use with RCU
* @next: next update requests in a list
* @func: actual update function to call after the grace period.
*/
struct rcu_head {
        struct rcu_head *next;
        void (*func)(struct rcu_head *head);
};
RCU(Read-Copy Update)是Linux 2.6內核中新的鎖機制,具體在這里有介紹:
http://www.ibm.com/developerworks/cn/linux/l-rcu/
二、
struct path             f_path;
被定義在linux/include/linux/namei.h中,其原型為:
struct path {
        struct vfsmount *mnt;
        struct dentry *dentry;
};
在早些版本的內核中并沒有此結構,而是直接將path的兩個數據成員作為struct file的數據成員,
struct vfsmount *mnt的作用是指出該文件的已安裝的文件系統,
struct dentry *dentry是與文件相關的目錄項對象。
三、
const struct file_operations    *f_op;
被定義在linux/include/linux/fs.h中,其中包含著與文件關聯的操作,如:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。當打開一個文件時,內核就創建一個與該文件相關聯的struct file結構,其中的*f_op就指向的是
具體對該文件進行操作的函數。例如用戶調用系統調用read來讀取該文件的內容時,那么系統調用read最終會陷入內核調用sys_read函數,而sys_read最終會調用于該文件關聯的struct file結構中的f_op->read函數對文件內容進行讀取。
四、
atomic_t                f_count;
atomic_t被定義為:
typedef struct { volatile int counter; } atomic_t;
volatile修飾字段告訴gcc不要對該類型的數據做優化處理,對它的訪問都是對內存的訪問,而不是對寄存器的訪問。 
本質是int類型,之所以這樣寫是讓編譯器對基于該類型變量的操作進行嚴格的類型檢查。此處f_count的作用是記錄對文件對象的引用計數,也即當前有多少個進程在使用該文件。
五、
unsigned int            f_flags;
當打開文件時指定的標志,對應系統調用open的int flags參數。驅動程序為了支持非阻塞型操作需要檢查這個標志。
六、
mode_t                  f_mode;
對文件的讀寫模式,對應系統調用open的mod_t mode參數。如果驅動程序需要這個值,可以直接讀取這個字段。
mod_t被定義為:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t         mode_t;
七、
loff_t                  f_pos;
當前的文件指針位置,即文件的讀寫位置。
loff_t被定義為:
typedef long long       __kernel_loff_t;
typedef __kernel_loff_t         loff_t;
八、
struct fown_struct      f_owner;
struct fown_struct在linux/include/linux/fs.h被定義,原型為:
struct fown_struct {
        rwlock_t lock;          /* protects pid, uid, euid fields */
        struct pid *pid;        /* pid or -pgrp where SIGIO should be sent */
        enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
        uid_t uid, euid;        /* uid/euid of process setting the owner */
        int signum;             /* posix.1b rt signal to be delivered on IO */
};
該結構的作用是通過信號進行I/O時間通知的數據。
九、
unsigned int            f_uid, f_gid;
標識文件的所有者id,所有者所在組的id.
十、
struct file_ra_state    f_ra;
struct file_ra_state結構被定義在/linux/include/linux/fs.h中,原型為:
struct file_ra_state {
        pgoff_t start;                  /* where readahead started */
        unsigned long size;             /* # of readahead pages */
        unsigned long async_size;       /* do asynchronous readahead when
                                           there are only # of pages ahead */
                                           
        unsigned long ra_pages;         /* Maximum readahead window */
        unsigned long mmap_hit;         /* Cache hit stat for mmap accesses */
        unsigned long mmap_miss;        /* Cache miss stat for mmap accesses */
        unsigned long prev_index;       /* Cache last read() position */
        unsigned int prev_offset;       /* Offset where last read() ended in a page */
};
文件預讀狀態,文件預讀算法使用的主要數據結構,當打開一個文件時,f_ra中出了perv_page(默認為-1)和ra_apges(對該文件允許的最大預讀量)這兩個字段外,其他的所有西端都置為0。
十一、
unsigned long           f_version;
記錄文件的版本號,每次使用后都自動遞增。
十二、
#ifdef CONFIG_SECURITY
        void                    *f_security;
#endif
此處我的理解是如果在編譯內核時配置了安全措施,那么struct file結構中就會有void *f_security數據項,用來描述安全措施或者是記錄與安全有關的信息。
十三、
void *private_data;
系統在調用驅動程序的open方法前將這個指針置為NULL。驅動程序可以將這個字段用于任意目的,也可以忽略這個字段。驅動程序可以用這個字段指向已分配的數據,但是一定要在內核釋放file結構前的release方法中清除它。
十四、
#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
被用在fs/eventpoll.c來鏈接所有鉤到這個文件上。其中f_ep_links是文件的事件輪詢等待者鏈表的頭,f_ep_lock是保護f_ep_links鏈表的自旋鎖。
十五、struct address_space    *f_mapping;
struct address_space被定義在/linux/include/linux/fs.h中,此處是指向文件地址空間的指針。
  在驅動開發中,文件讀/寫模式mode、標志f_flags都是設備驅動關心的內容,而私有數據指針private_data在折本驅動中被廣泛使用,大多被指向設備驅動自定義用于描述設備的結構體。 
驅動程序中常用如下類似的代碼來檢測用戶打開文件的讀寫方式:
if (file->f_mode & FMODE_WRITE) //用戶要求可寫
  {
  }
  if (file->f_mode & FMODE_READ) //用戶要求可讀
  {
  }
下面的代碼可用于判斷以阻塞還是非阻塞方式打開設備文件:
  if (file->f_flags & O_NONBLOCK) //非阻塞
      pr_debug("open:non-blocking\n");
  else //阻塞
      pr_debug("open:blocking\n");
參考:
Linux設備驅動開發詳解
深入理解linux內核

小默 2010-06-17 23:14 發表評論
]]>
warning: Clock skew detected. Your build may be incomplete.http://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.html小默小默Tue, 15 Jun 2010 07:33:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.htmlhttp://www.shnenglu.com/momoxiao/comments/117967.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/15/117967.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117967.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117967.html怎么檢測的? //TODO

“在系統啟動時,Linux操作系統將時間從CMOS中讀到系統時間變量中,以后修改時間通過修改系統時間實現。為了保持系統時間與CMOS時間的一致性,Linux每隔一段時間會將系統時間寫入CMOS。由于該同步是每隔一段時間(大約是11分鐘)進行的,在我們執行date -s后,如果馬上重起機器,修改時間就有可能沒有被寫入CMOS。如果要確保修改生效可以執行命令clock -w。“
[root@colorfulgreen rkit]# date 
Thu Jun 
10 20:50:30 CST 2010
[root@colorfulgreen rkit]# date 
-6/15/2010 //修改時間-指由Linux操作系統維護的時間
Tue Jun 15 00:00:00 CST 2010
[root@colorfulgreen rkit]# date 
-15:20:00
Tue Jun 
15 15:20:00 CST 2010
[root@colorfulgreen rkit]# date
Tue Jun 
15 15:20:04 CST 2010
[root@colorfulgreen rkit]# clock 
-//強制把系統時間寫入CMOS
[root@colorfulgreen rkit]# date
Tue Jun 
15 15:20:20 CST 2010
[root@colorfulgreen rkit]# 



小默 2010-06-15 15:33 發表評論
]]>
【轉】SELinux targeted policy relabel is required.http://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.html小默小默Sun, 13 Jun 2010 01:48:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.htmlhttp://www.shnenglu.com/momoxiao/comments/117767.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/13/117767.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117767.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117767.htmlhttp://www.centos.org/modules/newbb/viewtopic.php?topic_id=15960

小默 2010-06-13 09:48 發表評論
]]>
Ubuntu 登錄密碼忘記 & root密碼設置http://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.html小默小默Sat, 05 Jun 2010 23:53:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.htmlhttp://www.shnenglu.com/momoxiao/comments/117253.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/06/117253.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/117253.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/117253.html剛裝好Ubuntu 8.04可以剛才設置的密碼忘記了
用了以下方法恢復了系統的登陸密碼:
1、重新啟動,按ESC鍵進入Boot Menu,選擇recovery mode(一般是第二個選項)。
2、在#號提示符下用cat /etc/shadow,查看剛才設置的用戶名
3、輸入passwd "用戶名"(引號是必須的)。
4、輸入新的密碼.
5、重新啟動,用新密碼登錄。

================

首先設置root密碼,利用現有管理員帳戶登陸Ubuntu,在終端執行命令:sudo passwd root,接著輸入密碼和root密碼,重復密碼。這樣就有了可用的root用戶。



小默 2010-06-06 07:53 發表評論
]]>
ps lkmhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.html小默小默Tue, 01 Jun 2010 12:23:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.htmlhttp://www.shnenglu.com/momoxiao/comments/116924.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116924.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116924.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116924.html
#include <linux/module.h>
#include 
<linux/init.h>
#include 
<linux/list.h>
#include 
<linux/sched.h>

#define METHOD 1

static int list_init(void)
{
    
struct task_struct *task, *p;
    
struct list_head *pos;

    
int count;

    
char *method;



    count 
= 0;

    p 
= NULL;

    task 
= NULL;

    method 
= NULL;

    task 
= &init_task;


    
switch(METHOD){

        
case 1:

            method 
= "list_for_each";

            
break;

        
case 2:

            method 
= "for_each_process";

            
break;

        
case 3:

            method 
= "list_for_each_entry";

            
break;

    }



    printk(
"The method is %s\n",method);


    printk(KERN_ALERT
"PID\tCOMM\n");




    
if(METHOD == 1){

        list_for_each(pos,
&task->tasks){

            p 
= list_entry(pos,struct task_struct,tasks);

            count
++;

            printk(KERN_ALERT
"%d\t%s\n",p->pid,p->comm);

        }

    }

    
else if(METHOD == 2){

        for_each_process(task){

        count
++;

        printk(KERN_ALERT
"%d\t%s\n",task->pid,task->comm);

        }

    }

    
else if(METHOD == 3){

        list_for_each_entry(p,
&task->tasks,tasks){

        count
++;

        printk(KERN_ALERT 
"%d\t%s\n",p->pid,p->comm);

        }

    }



    printk(
"系統當前共有 %d 個進程!\n",count);



    
return 0;


}



static void list_exit(void)

{

    printk(KERN_ALERT 
"GOOD BYE!\n");

}



module_init(list_init);

module_exit(list_exit);



MODULE_AUTHOR(
"...");

MODULE_LICENSE(
"GPL");


Makefile:
obj-m := pslkm.o

KERNELDIR 
?= /lib/modules/$(shell uname -r)/build

PWD :
= $(shell pwd)

all:

    make 
-C $(KERNELDIR) M=$(PWD) modules

clean:

    make 
-C $(KERNELDIR) M=$(PWD) clean




小默 2010-06-01 20:23 發表評論
]]>
paramhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.html小默小默Tue, 01 Jun 2010 12:21:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.htmlhttp://www.shnenglu.com/momoxiao/comments/116923.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116923.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116923.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116923.html
#include<linux/module.h>
#include
<linux/kernel.h>
#include 
<linux/init.h>


static int module_int = 100;


module_param(module_int,
int,S_IRUSR);




int __init para_init(void)
{
    printk(
"My linux kernel module\n");
    printk(
"module_int = %d\n",module_int);
    
return 0;
}

void __exit para_exit(void)
{
    printk(
"My linux kernel module was removed.\n");
}

module_init(para_init);
module_exit(para_exit);

MODULE_LICENSE(
"GPL");



//向內核注冊模塊所提供的新功能
//module_init(lkp_init); 
//注銷由模塊提供的所有功能
//module_exit(lkp_cleanup);

//MODULE_LICENSE("GPL");



Makefile:
KERNELBUILD := /lib/modules/$(shell uname -r)/build



obj
-+= para.o



default: para



para:

    make 
-C $(KERNELBUILD) M=$(shell pwd) modules



clean:

    rm 
-f  *.ko *.o hide

    rm 
-*mod* Module*




小默 2010-06-01 20:21 發表評論
]]>
mallochttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.html小默小默Tue, 01 Jun 2010 12:20:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.htmlhttp://www.shnenglu.com/momoxiao/comments/116922.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116922.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116922.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116922.html//malloc.c
#include 
<linux/module.h>
#include 
<linux/slab.h>
#include 
<linux/vmalloc.h>
MODULE_LICENSE(
"GPL");
unsigned 
char *pagemem;
unsigned 
char *kmallocmem;
unsigned 
char *vmallocmem;

int __init mem_module_init(void)
{
//最好每次內存申請都檢查申請是否成功
//下面這段僅僅作為演示的代碼沒有檢查
//pagemem = (unsigned char*)get_free_page(0);
//printk("<1>pagemem addr=%x", pagemem);

kmallocmem 
= (unsigned char*)kmalloc(1000);
printk(
"<1>kmallocmem addr=%x", kmallocmem);

vmallocmem 
= (unsigned char*)vmalloc(1000000);
printk(
"<1>vmallocmem addr=%x", vmallocmem);

return 0;
}

void __exit mem_module_exit(void)
{
//free_page(pagemem);
kfree(kmallocmem);
vfree(vmallocmem);
}

module_init(mem_module_init);
module_exit(mem_module_exit);

Makefile:
obj-m := malloc.o
KDIR :
= /lib/modules/$(shell uname -r)/build
PWD :
= $(shell pwd)

default:
    $(MAKE) 
-C $(KDIR) SUBDIRS=$(PWD) modules




小默 2010-06-01 20:20 發表評論
]]>
free pageshttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.html小默小默Tue, 01 Jun 2010 12:18:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.htmlhttp://www.shnenglu.com/momoxiao/comments/116921.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/06/01/116921.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116921.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116921.html#include <linux/module.h>
#include 
<linux/kernel.h>
#include 
<linux/gfp.h>
#include 
<linux/mm.h>

int __init freepage_init()
{
    unsigned 
long page;

    page 
= __get_free_pages(GFP_KERNEL,3);  //8 page
    if(!page){
        
//no enough space
        return -ENOMEM;
    }

    printk(
"<1>the vaddr of the first page is <%lx>..",page);

    free_pages(page,
3);

    
return 0;
}

void __exit freepage_exit()
{
    
return;
}

module_init(freepage_init);
module_exit(freepage_exit);

MODULE_LICENSE(
"GPL");
Makefile:
obj-m := freepage.o
KDIR :
= /lib/modules/$(shell uname -r)/build
PWD :
= $(shell pwd)

default:
    $(MAKE) 
-C $(KDIR) SUBDIRS=$(PWD) modules




小默 2010-06-01 20:18 發表評論
]]>
【轉】使用 /sys 文件系統訪問 Linux 內核http://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.html小默小默Mon, 31 May 2010 07:33:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.htmlhttp://www.shnenglu.com/momoxiao/comments/116813.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/05/31/116813.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116813.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116813.html閱讀全文

小默 2010-05-31 15:33 發表評論
]]>
[zz]Ubuntu hostshttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.html小默小默Wed, 26 May 2010 01:35:00 GMThttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.htmlhttp://www.shnenglu.com/momoxiao/comments/116355.htmlhttp://www.shnenglu.com/momoxiao/archive/2010/05/26/116355.html#Feedback0http://www.shnenglu.com/momoxiao/comments/commentRss/116355.htmlhttp://www.shnenglu.com/momoxiao/services/trackbacks/116355.htmlUbuntu系統的Hosts只需修改/etc/hosts文件,在目錄中還有一個hosts.conf文件,剛開始還以為只需要修改這個就可以了,結果發現是需要修改hosts。修改完之后要重啟網絡。
具體過程如下:
1、修改hosts
sudo gedit /etc/hosts
2、添加解析記錄( . )
完整案例:127.0.0.1 localhost.localdomain localhost
簡潔記錄:127.0.0.1 localhost
3、保存后重啟網絡
sudo /etc/init.d/networking restart


小默 2010-05-26 09:35 發表評論
]]>
伊人久久一区二区三区无码| 久久伊人精品青青草原高清| 日本WV一本一道久久香蕉| 国内精品久久国产| 麻豆AV一区二区三区久久| 久久精品国产亚洲AV香蕉| 精品国产福利久久久| 精品久久久久久国产免费了| 久久精品国产精品亜洲毛片| 中文字幕久久亚洲一区| 精品综合久久久久久888蜜芽| 亚洲国产精品久久久久网站| 伊人久久大香线蕉无码麻豆| 久久ZYZ资源站无码中文动漫| 久久精品国产精品亜洲毛片| 欧美熟妇另类久久久久久不卡| 亚洲成色999久久网站| 日韩精品久久久久久久电影| a高清免费毛片久久| 亚洲国产精品无码久久久久久曰 | 久久久久亚洲精品天堂| 老司机国内精品久久久久| 欧美黑人激情性久久| 久久亚洲国产中v天仙www | 四虎亚洲国产成人久久精品| 久久精品亚洲中文字幕无码麻豆| 久久99精品九九九久久婷婷| 久久久久99精品成人片直播| 人妻丰满?V无码久久不卡| 成人国内精品久久久久影院| 2021最新久久久视精品爱| 国产91色综合久久免费| 久久久久免费精品国产| 久久播电影网| 久久99精品国产99久久6男男| 欧美黑人激情性久久| 精品久久久久久久久久久久久久久| 久久天天躁狠狠躁夜夜96流白浆| 性高朝久久久久久久久久| 精品乱码久久久久久夜夜嗨| 久久久久中文字幕|