進程
1. 替換進程鏡像
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char*arg, ..., (char*)0);
int execlp(const char *file, const char*arg, ..., (char*)0);
int execle(const char *path, const char*arg, ..., char * const envp[]);
int execv(const char *path, char *constargv[]);
int execvp(const char *file, char *constargv[]);
int execve(const char *file, char *const argv[], char *const envp[]);
1) execl、execlp、execle參數可變,以空指針結束;execv、execvp第二個參數爲一字符串數組。
2) 函數會把argv參數傳遞給main函數。
3) 以p結尾的函數會搜索PATH環境變量來查找新程序,不存在則使用絕對路徑來傳遞給函數。
4) exec函數不會返回調用它的函數。
2. 複製進程對象
#include <unistd.h>
#include<sys/types.h>
pid_t fork(void);
新進程與原進程一模一樣,執行代碼完全一樣,只是有自己的數據空間、環境以及文件描述符。
返回值:
-1:創建失敗;
0:當前進程爲子進程;
非零:當前進程爲父進程。
3. 進程等待
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*stat_loc);
pid_t waitpid(pid_t pid, int* stat_loc, int options);
int waitid(idtype_tidtype, id_t id, siginfo_t *infop, int options);
暫停父進程知道子進程結束爲止。
stat_loc:
WIFEXITED |
子進程正常結束,WIFEXITD(stat_loc)取非零值 |
WEXITSTATUS |
WEXITSTATUS(stat_loc)非零時,爲進程退出碼 |
WIFSIGNALED |
如果子進程因一個爲捕獲的信號終止,WIFSIGNALED(stat_loc)非零 |
WTERMSIG |
WTERMSIG(stat_loc)非零,則爲信號代碼 |
WCOREDUMP |
子進程意外終止,WCOREDUMP(stat_loc)取非零 |
WIFSTOPPED |
WIFSTOPPED(stat_loc)非零,則爲一個信號代碼 |
4. exit
退出進程。
進程通訊、信號
Linux 提供的大多數信號類型是供內核使用的,只有少數的幾種信號可以用作在進程之間傳送。下面給出常用的信號和它們的意義:
SIGHUP
當終止一個終端時,內核就把這一種信號發送給該終端所控制的所有進程。通常情況
下,一個進程組的控制終端是該用戶擁有的終端,但不完全是如此。當進程組的首進程結
束時,就會向該進程組的所有進程發送這種信號。這就可以保證當一個用戶退出使用時,
其後臺進程被終止,除非有其它方面的安排。
SIGINT
當一個用戶按了中斷鍵(一般爲Ctrl+C)後,內核就向與該終端有關聯的所有進程發
送這種信號。它提供了中止運行程序的簡便方法。
SIGQUIT
這種信號與SIGINT 非常相似,當用戶按了退出鍵時(爲ASCII 碼FS,通常爲Ctrl+\),
內核就發送出這種信號。SIGQUIT 將形成POSIX 標準所描述的非正常終止。我們稱這種
UNIX 實現的實際操作爲核心轉貯(core dump),並用信息“Quit (coredump)”指出這一操
作的發生。這時,該進程的映象被轉貯到一個磁盤文件中,供調試之用。
SIGILL
當一個進程企圖執行一條非法指令時,內核就發出這種信號。例如,在沒有相應硬件
支撐的條件下,企圖執行一條浮點指令時,則會引起這種信號的發生。SIGILL 和SIGQUIT
一樣,也形成非正常終止。
SIGTRAP
這是一種由調試程序使用的專用信號。由於他的專用行和特殊性,我們不再對它作進一步的討論。SIGTRAP 也形成非正常終止。
SIGFPE
當產生浮點錯誤時(比如溢出),內核就發出這種信號,它導致非正常終止。
SIGKILL
這是一個相當特殊的信號,它從一個進程發送到另一個進程,使接收到該信號的進程
終止。內核偶爾也會發出這種信號。SIGKILL 的特點是,它不能被忽略和捕捉,只能通過
用戶定義的相應中斷處理程序而處理該信號。因爲其它的所有信號都能被忽略和捕捉,所
以只有這種信號能絕對保證終止一個進程。
SIGALRM
當一個定時器到時的時候,內核就向進程發送這個信號。定時器是由改進程自己用系
統調用alarm()設定的。
SIGTERM
這種信號是由系統提供給普通程序使用的,按照規定,它被用來終止一個進程。
SIGSTOP
這個信號使進程暫時中止運行,系統將控制權轉回正在等待運行的下一個進程。
SIGUSR1 和SIGUSR2
和SIGTERM 一樣,這兩種信號不是內核發送的,可以用於用戶所希望的任何目的。
SIGCHLD
子進程結束信號。UNIX 中用它來實現系統調用exit()和wait()。執行exit()時,就向子進程的父進程發送SIGCHLD 信號,如果這時父進程政在執行wait(),則它被喚醒;如果這時候父進程不是執行wait(),則此父進程不會捕捉SIGCHLD 信號,因此該信號不起作用,子進程進入過渡狀態(如果父進程忽略SIGCHLD,子進程就結束而不會進入過渡狀態)。這個機制對大多數UNIX 程序員來說是相當重要的。
信號與處理
1. 發送信號
#include <unistd.h>
unsigned int alarm(unisigned int seconds);在seconds後發送一個SIGALRM信號
intkill(pid_t pid, int sig);發送信號到指定進程
2. 信號處理
int signal(int sig, __sighandler_t handler);
sig: 指明瞭所要處理的信號類型,它可以取除了SIGKILL 和SIGSTOP 外的任何一種信號。
handler:可以取以下三種值:
1) 一個返回值爲整數的函數地址。
此函數必須在signal()被調用前聲明,handler 中爲這個函數的名字。當接收到一個類型爲sig 的信號時,就執行handler 所指定的函數。這個函數應有如下形式的定義:
int func(int sig);
sig 是傳遞給它的唯一參數。執行了signal()調用後,進程只要接收到類型爲sig 的信號,
不管其正在執行程序的哪一部分,就立即執行func()函數。當func()函數執行結束後,控制
權返回進程被中斷的那一點繼續執行。
2) SIG_IGN
這個符號表示忽略信號。執行了相應的signal()調用好,進程會忽略類型爲sig 的信號。
3) SIG_DFL
這個符號表示恢復系統對信號的默認處理。
進程間通信(管道)
1. #include <unistd.h>
Int pipe(intfd[2]);
功能:獲取兩個管道描述符;
返回值:-1表示失敗,0表示成功。
2. 標準I/O函數中的管道
#include<stdio.h>
FILE *popen(constchar *cmdstring, const char *type);
int pclose(FILE*pf);
popen的功能:創建一個管道,然後調用fork產生一個子進程,調用exec執行cmdstring命令,關閉管道不使用短,執行shell以運行命令,然後等待命令終止。
參數:
cmdstring :需要執行的shell命令。
type:若爲”r”,命令連接至標準輸出;若爲”w”,命令連接至標準輸入。
3.
多線程
1. 創建一個線程的函數:
#include<pthread.h>
intpthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg);
返回值:若是成功建立線程返回0,否則返回錯誤的編號
參數:
pthread_t*restrict tidp 要創建的線程的線程id指針
constpthread_attr_t *restrict attr 創建線程時的線程屬性
void* (start_rtn)(void)返回值是void類型的指針函數
void *restrictarg start_rtn的形參
一般可以這樣用:
pthread_create(&id2,NULL, (void*)myThread1, NULL);
2. 等待一個線程的結束:pthread_join()函數,以阻塞的方式等待thread指定的線程結束
#include<pthread.h>
int pthread_join(pthread_t thread, void**retval);
返回值:
0代表成功。 失敗,返回的則是錯誤號
參數:
thread:線程標識符,即線程ID,標識唯一線程。
retval:用戶定義的指針,用來存儲被等待線程的返回值。
3. 退出線程
void pthread_exit(void *retval);
4. 取消線程
int pthread_cancel(pthread_t thread);
5. system
system()會調用fork()產生子進程,由子進程來調用/bin/sh-c string來執行參數string字符串所代表的命令,此命>令執行完後隨即返回原調用的進程。在調用system()期間SIGCHLD 信號會被暫時擱置,SIGINT和SIGQUIT 信號則會被忽略。
#i nclude<stdlib.h>
int system(const char *string);
返回值:
-1:出現錯誤
0:調用成功但是沒有出現子進程
>0:成功退出的子進程的id
參數:
String:命令行
內核驅動程序
1. 內核驅動程序主要框架
內核驅動的開始的函數必須有爲:
module_init(function)加載,和module_exit(function)卸載內核。
內核驅動的函數頭都被定義到linux/或者asm/中。
2. module_init( x);
driver initialization entry point.
參數:
x function tobe run at kernel boot time or module insertion
3. module_exit( x);
driver exit entry point.
參數:
x: function to be runwhen driver is removed
4. outb() I/O 上寫入 8 位數據 ( 1 字節 );
inb() 從I/O端口讀取一個字節(即八位)
inw 從I/O端口讀取一個字(即兩個字節,十六位)
outw() I/O 上寫入 16 位數據 ( 2 字節 );
outl () I/O 上寫入 32 位數據 ( 4 字節)。
void outb (unsigned char data, unsigned short port);
byte inb(word port);返回一個字節;
void outw (unsigned short data, unsigned short port);
word inw(word port);返回兩個字節;
void outl (unsigned long data, unsigned short port);
5. 每個設備都對應一個結構體:
struct file_operations {
struct module *owner;//指向擁有這個模塊的指針,該成員用來在它的操作還在是使用的時候不允許卸載該模塊。
//通常情況下簡單初始化爲THIS_MODULE。
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 *);//該操作用來發送數據給設備。
ssize_t (*aio_read) (struct kiocb *, conststruct iovec *, unsigned long, loff_t); //該操作用來初始化一個異步的讀操作。
ssize_t (*aio_write) (struct kiocb *, conststruct iovec *, unsigned long, loff_t);//該操作用來初始化一個異步的寫操作。
int (*readdir) (struct file *, void *,filldir_t);//該操作用來讀取目錄。
unsigned int (*poll) (struct file *, structpoll_table_struct *);//該操作用來查詢一個或者多個文件描述符的讀或寫是會否堵塞。
int (*ioctl) (struct inode *, struct file*, unsigned int, unsigned long);//該操作用來提供發出設備特定命令的方法。
long(*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *,unsigned int, unsigned long);
int (*mmap) (struct file *, structvm_area_struct *);//該操作用來請求將設備內存映射到進程的地址空間。
int (*open) (struct inode *, struct file*);//該操作用來打開設備文件,也是對設備進行的第一個操作。
int (*flush) (struct file *, fl_owner_tid);
int (*release) (struct inode *, struct file*);//該操作用來釋放文件結構。可以爲空。
int (*fsync) (struct file *, struct dentry*, int datasync);
int (*aio_fsync) (struct kiocb *, intdatasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, structfile_lock *);
ssize_t (*sendpage) (struct file *, structpage *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(structfile *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp,unsigned long arg);
int (*flock) (struct file *, int, structfile_lock *);
ssize_t (*splice_write)(structpipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *,loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, structfile_lock **);
int (*fsetattr)(struct file *, struct iattr*);
};
6. 將內核數據複製到用戶空間中
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n;
}