[07] Unix程序環境
==================================
1、 程序終止
atexit()函數注冊終止處理程式。
exit()或return語句:
終止處理程式->終止處理程式->标準I/O清除->_exit()->進入核心。
_exit()直接進入核心。
2、 環境表
extern char **environ;
例:
for( i=0; environ[i] != NULL; i++)
{
printf( "env[%d]: %s\n", i, environ[i] );
}
3、 C程式存儲空間布局
* 正文 即代碼段
* 初始化資料段 如:int maxcount = 99;
* bss(非初始化資料) 如:long sun[1000];
* 棧 自動變量及函數調用所需的資訊
* 堆 動态存取配置設定,在bss頂端,棧的底端。
-----------------------------------------------------------
高位址 棧 -> .... <- 堆 bss 初始資料 正文 低位址
注: 可用size指令檢視text data bss資訊。
4、 存儲器配置設定
alloca()是在棧中配置設定空間,函數調用結束後空間自動釋放,但有些系統不支援。
5、 環境變量
char * getenv(char * name);
int putenv( const char * str );
int setenv(const char * name, const char * value, int rewrite );
void unsetenv(const char *name );
注:environ表及字串存放在棧的頂部,當調用上述函數時,可能需将其移到至堆中。
6、 setjmp和longjmp
#include <setjmp.h>
jmp_buf jmpbuffer;
......
_@: setjmp( jmpbuffer);
call my_function();
my_function(){
longjmp(jmpbuffer, 1 );
}
注:
* 代碼中,在_@處調用setjmp函數,然後經過多層調用至my_function函數,
在該函數中調用longjmp(,1)函數,責程式調整至_@處。
即:反繞過上層的所有棧幀,跳至_@所在處的棧狀态。
* setjmp傳回值: 如果直接調用,則傳回0, 否則傳回longjmp的第二個參數。
7、 getrlimit和setrlimit
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit( int resource, struct rlimit * rlptr );
int setrlimit( int resource, const struct rlimit * rlptr );
[08] 程序控制
1、 程序辨別
程序ID:
0 交換程序swapper
1 init,在自舉結束後由核心調用。它不會終止,但是它是普通使用者程序,以超級使用者權限運作。
2 頁精靈程序,pagedaemon
函數:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
git_t getegid(void);
2、 fork函數
fork() : 建立子程序。
pid_t fork(void);
* 調用fork後,子程序和父程序繼續執行fork之後的代碼。
* fork傳回兩次,子程序傳回0,父程序傳回子程序ID。
* fork之後,無法知道父程序和子程序哪個先執行。
int main()
if( (pdi = fork()) < 0 )
error();
else if( pid == 0 ){//子程序
else{ //父程序
…… //父子程序繼續執行fork之後的代碼
兩種fork用法
* fork之後,父子程序各自執行自己的代碼。在網絡伺服器中常見。
* 程序執行不同的程式。fork後,子程序調用exec函數。
3、 vfork
vfork()建立一個新程序。
與fork差別:
* vfork保證子程序先于父程序執行,
* vfork子程序在父程序的位址空間内執行。
4、 wait和waitpid函數
5、 競态條件
多個程序企圖對共享資料進行處理,但結果取決于程序的運作順序。
6、 6個exec函數對比
--------------------------------------------------------------
函數 path name 參數表 argv[] environ envp[]
execl * * *
execlp * * *
execle * * *
execv * * *
execvp * * *
execve * * *
p 取filename做參數
l 取參數表
v 表示去argv[]數組
e 表示取envp[]數組
[10] 信号
=================================
1、 概念
信号:軟體中斷,以SIG開頭,在<signal.h>中定義。
三種方式處理信号:
* 忽略此信号,但SIGKILL和SIGSTOP不能被忽略,因為他向超級使用者提供了一種使程序終止或停止的可靠方法。如果忽略某些硬體異常産生的信号,則程序的行為未知。
* 捕捉信号,要通知核心在某信号發生時,調用一個使用者函數。
* 執行系統預設動作。
2、 signal函數
#include <signal.h>
void (*signal (int signo, void (*func)(int))) (int );
* 傳回值 void (*signal)(int);
傳回老的信号處理程式指針。
* 參數
signo: 信号表示
void (*func)(int); 新的信号處理程式,
若為SIG_IGN - 忽略此信号
若為SIG_DFL - 系統預設操作
用typedef方法定義signal函數:
typedef void Sigfunc(int);
Sigfunc *signal( int, Sigfunc *);
當程序調用fork時,子程序繼承了父程序的信号處理方式。因為子程序開始時複制了父程序的存儲映像,所有信号捕捉函數的位址在子程序中式有意義的。
3、kill和raise函數
int kill( pid_t pid, int signo );
int raise(int signo );
* kill 将信号發送給程序或程序組
pid>0 将信号發送給該程序
pid==0 将信号發送給程序組ID等于發送程序的程序組ID,而且發生程序有許可權向其發送信号的所有程序。
pid<0 将信号發送給程序組ID等于pid絕對值,與pid==0類似。
* raise 程序向自身發送信号
4、alarm和pause函數
alarm: 設定一時間段,當超過該時間時,産生SIGALRM信号,預設動作時終止該程序。
unsigned int alarm( unsigned int seconds );
* seconds 是秒數。
* 每個程序隻能有一個鬧鐘時間,如果調用alarm時,以前以為該程序設定過鬧鐘時間,而且還沒有逾時,則該鬧鐘時間的餘留值作為本次alarm函數調用的傳回值。以前登記的鬧鐘時間被新值替換。
int pause(void)
注:
隻有執行了一個信号處理程式并從其傳回,pause才傳回-1, errno設為EINTR。
(書中有很多alarm例子,說明使用信号所要注意的地方)
5、 信号集
用sigset_t類型表示一信号集。
int sigemptyset(sigset_t * set );
int sigfillset(sigset_t *set );
int sigaddset(sigset_t *set, int signo );
int sigdelset(sigset_t *set, int signo );
----傳回值: 成功 0, 錯誤 -1
int sigismember( conset sigset_t *set, int signo );
----傳回值: 真 1, 假 0
6、 sigprocmask函數
功能:檢測或更改程序的信号屏蔽字。
int sigprocmask(int how, const sigset_t *set, sigset_t *oset );
* 若oset非空, oset為目前信号屏蔽字
* 若set非空, how訓示如何修改目前信号屏蔽字。
* how:
* SIG_BLOCK 或操作
* SIG_UNBLOCK 與
* SIG_SETMASK 指派操作
7、 sigpending函數
功能:傳回調用程序的被阻塞不能遞送和目前未決的信号集。
int sigpending(sigset_t *set );
8、 sigaction函數
功能,取代了signal函數。
int sigaction(int signo, const struct sigaction *act, \
struct sigaction * oact );
struct sigaction{
void (*sa_handler)();
sigset_t sa_mask;
int sa_flags;
};
sa_handler 信号捕捉函數
sa_mask 調用sa_handler之前需要添加的信号屏蔽字,調用結束後,程序的信号屏蔽字再恢複為原先值。
sa_flags 信号處理選項。
9、 sigsetjmp和siglongjmp
int sigsetjmp( sigjmp_buf env, int savemask );
void siglongjmp( sigjmp_buf env, int val );
差別:
當savemask 為非0時,sigsetjmp在env中儲存程序的目前屏蔽字,調用siglongjmp時,siglongjmp從中恢複儲存的信号屏蔽字。
而,setjmp和longjmp并不保證該操作。
10、sigsuspend函數
#include<signal.h>
int sigsuspend(const sigset_t sigmask );
程序的信号屏蔽字設定為sigmask,在捕捉到一個信号或發生了一個會終止該程序的信号之前,該程序也被挂起。如果捕捉到一個信号而且從該信号處理程式傳回,則sigsuspend傳回,并且該程序的信号屏蔽字設定為調用sigsuspend之前的值。
[11] 終端
[12] 進階I/O
====================================
1、 非阻塞I/O
對一個給定的描述符有兩種方法對其指定非阻塞I/O
* 如果是調用open以擷取描述符,則可以指定O_NONBLOCK标志
* 對于已經打開的描述符,調用fcntl打開O_NONBLOCK檔案狀态标志。
2、 記錄鎖
功能: 一個程序正在讀或者修改檔案的某個部分時,可以阻止其他程序修改同一檔案區。它鎖定的隻是檔案的一個區域,也可是整個檔案。
fcntl記錄鎖
#include <fcntl.h>
int fcntl ( int filedes, int cmd, struct flock * flockptr );
參數:
* cmd /* F_GETLK, F_SETLK, F_SETLKW */
F_GETLK 如果存在一把鎖,則把現存的鎖的資訊寫到flockptr指向的結構中。若不存在,則将l_type設定為F_UNLCK,其他域儲存不變。
F_SETLK 設定由flockptr所描述的鎖。或者用于清除所描述的記錄鎖(設定l_type為F_UNLCK)。
F_SETLKW 這是F_SETLK得阻塞版本。
* flockptr 以下結構指針
struct flock {
short l_type; /* F_RDLCK, F_WRLCK, F_UNLCK */
off_t l_start; /* offset in bytes, ralative to l_whence */
short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_len; /* length, in bytes; 0 means lock to EOF */
pid_t l_pid; /* returned with F_GETLK */
[注]
1、當程序終止,鎖全部釋放,當描述符被關閉時,該描述符的鎖也被釋放。
2、fork後,子程序不繼承父程序的記錄鎖
3、exec後,新程式可以繼續原執行程式的鎖
[13] 精靈程序
================================
1. 程式設計規則
- 調用fork,然後父程序調用exit。
用處: 1.如果該精靈程序有Shell啟動,那麼父程序終止,是的Shell認為該條指令已經執行完成。
2.保證了子程序不是一個程序組的首程序,它程序了父程序的程序組ID。
- 調用setsid建立一個新的會話期。
1.是程序成為對話期首程序。 2.成為一個新程序組的首程序。 3.沒有控制終端。
- 将工作目錄更改為跟目錄。
- 将檔案方式建立屏蔽字設定為0。
1.去除由父程序繼承得來的屏蔽字。
- 關閉不需要的檔案描述符。這與具體的精靈程序有關。
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>
int daemon_init(void)
{
pid_t pid;
if( (pid = fork() )<0 )
return -1;
else if( pid!=0 )
exit(0); //parent goes bye-bye
setsid();
chdir("/");
umask(0); //clear file mode creation mask
return 0;
}
[14] 程序間通信
1、 管道
int pipe( int filedes[2]);
filedes[0]為讀而打開,filedes[1]為寫而打開。filedes[1]的輸出是filedes[0]的輸入。
14.6----