歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> 關於Unix

/proc文件系統入門

理解/proc文件系統 理解/proc文件系統 ◆ 介紹/proc 在過去那些糟糕的日子裡,只能通過直接訪問內核內存(/dev/kmem)獲取進程數據,比如運行ps(1)命令時。為了實現這種訪問,需要超級用戶權限,而且步驟相當復雜。Sun公司從 UNIX SVR4開始解決了進程數據訪問 理解/proc文件系統

理解/proc文件系統  


◆ 介紹/proc

在過去那些糟糕的日子裡,只能通過直接訪問內核內存(/dev/kmem)獲取進程數據,比如運行ps(1)命令時。為了實現這種訪問,需要超級用戶權限,而且步驟相當復雜。Sun公司從UNIX SVR4開始解決了進程數據訪問問題,現在,可以簡單地通過/proc訪問進程數據。

/proc文件系統不是普通意義上的文件系統,它是一個到運行中進程地址空間的訪問接口。通過/proc,可以用標准Unix系統調用(比如open()、read()、write()、ioctl()等等)訪問進程地址空間。事實上,Solaris ps(1)命令正是利用/proc獲取進程狀態。

S (l) 進程狀態:

O 正在運行
S 休眠: 進程正在等待某個事件發生/完成
R 可運行: 進程位於運行隊列中
Z 僵屍狀態: 進程結束了,但是其父進程未處理SIGCHLD信號
T 進程暫停: 可能是任務控制信號所致,或者正在被
跟蹤調試

/proc下的大文件對應運行中進程的地址空間,不是標准Unix文件。事實上每個文件名對應運行中進程的PID,文件屬主、屬組對應進程擁有者的real-uid和primary-gid。權限控制與普通Unix文件一樣。文件大小是最令人迷惑的地方,事實上相當好理解,對應進程內存映像大小,並不真正占用硬盤空間,所以你不必擔心空間浪費的問題。不要企圖刪除這些文件!觀察圖A中列舉的/proc例子:

--------------------------------------------------------------------------

$ ls -l /proc
total 43384
-rw------- 1 root root 0 Apr 2 20:07 00000
-rw------- 1 root root 393216 Apr 2 20:07 00001
-rw------- 1 root root 0 Apr 2 20:07 00002
-rw------- 1 root root 0 Apr 2 20:07 00003
-rw------- 1 root root 1695744 Apr 2 20:07 00081
-rw------- 1 root root 1597440 Apr 2 20:07 00083
-rw------- 1 root root 1777664 Apr 2 20:08 00096
-rw------- 1 root root 1683456 Apr 2 20:08 00099
-rw------- 1 root root 1589248 Apr 2 20:08 00101
-rw------- 1 root root 1445888 Apr 2 20:08 00116
-rw------- 1 root root 1404928 Apr 2 20:08 00126
-rw------- 1 root root 798720 Apr 2 20:08 00135
-rw------- 1 root root 1368064 Apr 2 20:08 00195
-rw------- 1 root root 1585152 Apr 2 20:08 00197
-rw------- 1 root root 1368064 Apr 2 20:08 00200
-rw------- 1 root other 225280 Apr 2 20:08 00201
-rw------- 1 root root 1454080 Apr 2 20:08 00203
-rw------- 1 root root 1519616 Apr 2 20:14 00243
-rw------- 1 rthomas wheel 1499136 Apr 2 20:14 00245
-rw------- 1 rthomas wheel 806912 Apr 2 20:16 00261
$

圖A: /proc例子

--------------------------------------------------------------------------

操作/proc下文件的方式和操作普通Unix文件一樣,可以使用所有你熟悉的系統調用,包括ioctl()。在內核中,針對/proc下文件的vnode操作被轉向procfs。這意味著操作vnode的系統調用(比如lookuppn())實際上最終轉向procfs-savvy系統調用(比如prlookup())。

◆ /proc能告訴我什麼

Solaris下使用/proc的工具相當完善,位於/usr/proc/bin目錄中。這些工具提供了一種訪問任意指定進程臨界數據的簡捷辦法。比如,想知道一個進程已經打開了多少文件,你可以使用crash(1M)(見鬼,我不會),但是你是root嗎?不必擔心,可以用/usr/proc/bin/pfiles獲取這種信息,圖B演示了pfiles(1)命令的使用:

--------------------------------------------------------------------------

[scz@ /export/home/scz]> ps
PID TTY TIME CMD
637 pts/3 0:00 bash
[scz@ /export/home/scz]> pfiles 637
637: -bash
Current rlimit: 64 file descriptors
0: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
1: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
2: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
3: S_IFDOOR mode:0444 dev:191,0 ino:1618164880 uid:0 gid:0 size:0
O_RDONLY|O_LARGEFILE FD_CLOEXEC door to nscd[213]
63: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR FD_CLOEXEC
[scz@ /export/home/scz]>

圖B: 使用pfiles(1)命令

--------------------------------------------------------------------------

正如上面演示的,/usr/proc/bin下的命令使用很簡單,只需要在命令行上指定PID。然而,留心權限許可設置,與所有普通Unix文件一樣,你無權訪問那些權限設置上禁止訪問的指定PID的進程數據。

花點事件看看proc(1)手冊頁,熟悉其中介紹的命令,你將學會列舉指定進程相關的庫、進程信號設置、進程信任設置,你甚至可以暫停、重啟進程。

◆ 編寫/proc工具

/proc的魅力在於它包含了你可能想知道的關於一個進程的任何信息,你只需要簡單地從中獲取。/usr/include/sys/procfs.h文件中定義了兩個結構,prstatus和prpsinfo,從中可以獲取指定進程的很多信息。下面是個例子,開發者想知道他的應用程序究竟占用了多少內存。簡單!ls /proc就可以知道了。但是,他還想知道更多細節,他需要知道總的映像大小、常駐部分的大小、堆區(heap)大小、棧區(stack)大小。此外,他希望能夠定期跟蹤這些數據信息,類似vmstat(1M)那種方式。如上所述,聽起來象是一個令人生畏的任務。

譯者: Solaris 2.6開始這兩個結構定義在/usr/include/sys/old_procfs.h文件中

然而,通過使用/proc文件系統,我們可以使這項編程挑戰變得容易些。我們寫的這個工具稱做memlook,將顯示指定PID對應的內存統計信息。此外,可以在命令行上指定一個時間間隔,以便定期重新檢測內存利用信息。圖C演示了一次簡單的輸出:

--------------------------------------------------------------------------

$ memlook 245
PID IMAGE RSS HEAP STACK
245 1499136 1044480 24581 8192
$

圖C: memlook的輸出舉例

--------------------------------------------------------------------------

下面是memlook.c的源代碼

--------------------------------------------------------------------------
/*
* @(#)memlook.c 1.0 10 Nov 1997
* Robert Owen Thomas
[email protected]
* memlook.c -- A process memory utilization reporting tool.
*
* gcc -Wall -O3 -o memlook memlook.c
*/
#pragma ident "@(#)memlook.c 1.0 10 Nov 1997 Robert Owen Thomas
[email protected]"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <sys/param.h>
#include <unistd.h>
#include <fcntl.h>

int counter = 10;

int showUsage ( const char * );
void getInfo ( int, int );

int main ( int argc, char * argv[] )
{
int fd, pid, timeloop = 0;
char pidpath[BUFSIZ]; /* /usr/include/stdio.h: #define BUFSIZ 1024 */

switch ( argc )
{
case 2:
break;
case 3:
timeloop = atoi( argv[2] );
break;
default:
showUsage( argv[0] );
break;
} /* end of switch */
pid = atoi( argv[1] );
sprintf( pidpath, "/proc/%-d", pid ); /* -表示向左靠 */
if ( ( fd = open( pidpath, O_RDONLY ) ) < 0 )
{
perror( pidpath );
exit( 1 );
}
if ( 0 < timeloop )
{
for ( ; ; )
{
getInfo( fd, pid );
sleep( timeloop );
}
}
getInfo( fd, pid );
close( fd );
exit( 0 );
} /* end of main */

int showUsage ( const char * progname )
{
fprintf( stderr, "%s: usage: %s < PID > [time delay]\n", progname, progname );
exit( 3 );
} /* end of showUsage */

void getInfo ( int fd, int pid )
{
prpsinfo_t prp;
prstatus_t prs;

if ( ioctl( fd, PIOCPSINFO, &prp ) < 0 )
{
perror( "ioctl" );
exit( 5 );
}
if ( ioctl( fd, PIOCSTATUS, &prs ) < 0 )
{
perror( "ioctl" );
exit( 7 );
}
if ( counter > 9 )
{
fprintf( stdout, "PID\tIMAGE\t\tRSS\t\tHEAP\t\tSTACK\n" );
counter = 0;
}
fprintf( stdout, "%u\t%-9u\t%-9u\t%-15u\t%-15u\n", pid,
( unsigned int )prp.pr_bysize, ( unsigned int )prp.pr_byrssize,
( unsigned int )prs.pr_brksize, ( unsigned int )prs.pr_stksize );
counter++;
} /* end of getInfo */
--------------------------------------------------------------------------

譯者: 作者這裡利用了ioctl(),而不是直接讀取/proc下文件,這樣做的好處在於即使系統升級後/proc布局改變,內核中相應ioctl cmd支持也隨之改變,對於應用層的開發者,接口一樣,源代碼可平穩移植。事實上從作者前面舉例來看, memlook.c是在Solaris 2.6以前的版本上開發的,但我並未修改就可以直接用在Solaris 2.6上,雖然此時/proc布局已經發生重大變化。

仔細閱讀prstatus和prpsinfo結構,尋找那些你敢興趣的成員。在未能真正掌握這種技術之前不要針對/proc文件系統使用write()或者ioctl()。針對特定進程胡亂做write()調用,結果未知。

◆ 結論

當痛苦調試程序或者試圖獲取指定進程狀態的時候,/proc文件系統將是你強有力的支持者。通過它可以創建更強大的工具,獲取更多信息。

轉載:http://www.51tech.net/news_html/1607.htm

Copyright © Linux教程網 All Rights Reserved