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

进程

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;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章