您的位置:首页 > 运维架构 > Linux

Linux进程、线程、内核操作函数

2013-03-31 13:58 501 查看

进程

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: