用户空间和内核空间通讯之【Netlink 中】

原文地址:用户空间和内核空间通讯之【Netlink 中】 作者:wjlkoorey258

今天我们来动手演练一下Netlink的用法,看看它到底是如何实现用户-内核空间的数据通信的。我们依旧是在2.6.21的内核环境下进行开发。

在</usr/include/linux/netlink.h>文件里包含了Netlink协议簇已经定义好的一些预定义协议:

点击(此处)折叠或打开

  1. #define NETLINK_ROUTE        0    /* Routing/device hook                */
  2. #define NETLINK_UNUSED        1    /* Unused number                */
  3. #define NETLINK_USERSOCK    2    /* Reserved for user mode socket protocols     */
  4. #define NETLINK_FIREWALL    3    /* Firewalling hook                */
  5. #define NETLINK_INET_DIAG    4    /* INET socket monitoring            */
  6. #define NETLINK_NFLOG        5    /* netfilter/iptables ULOG */
  7. #define NETLINK_XFRM        6    /* ipsec */
  8. #define NETLINK_SELINUX        7    /* SELinux event notifications */
  9. #define NETLINK_ISCSI        8    /* Open-iSCSI */
  10. #define NETLINK_AUDIT        9    /* auditing */
  11. #define NETLINK_FIB_LOOKUP    10
  12. #define NETLINK_CONNECTOR    11
  13. #define NETLINK_NETFILTER    12    /* netfilter subsystem */
  14. #define NETLINK_IP6_FW        13
  15. #define NETLINK_DNRTMSG        14    /* DECnet routing messages */
  16. #define NETLINK_KOBJECT_UEVENT    15    /* Kernel messages to userspace */
  17. #define NETLINK_GENERIC        16
  18. /* leave room for NETLINK_DM (DM Events) */
  19. #define NETLINK_SCSITRANSPORT    18    /* SCSI Transports */
  20. #define NETLINK_ECRYPTFS    19
  21. #define NETLINK_TEST    20 /* 用户添加的自定义协议 */

如果我们在Netlink协议簇里开发一个新的协议,只要在该文件中定义协议号即可,例如我们定义一种基于Netlink协议簇的、协议号是20的自定义协议,如上所示。同时记得,将内核头文件目录中的netlink.h也做对应的修改,在我的系统中它的路径是:/usr/src/linux-2.6.21/include/linux/netlink.h

接下来我们在用户空间以及内核空间模块的开发过程中就可以使用这种协议了,一共分为三个阶段。

Stage 1:

我们首先实现的功能是用户->内核单向数据通信,即用户空间发送一个消息给内核,然后内核将其打印输出,就这么简单。用户空间的示例代码如下【mynlusr.c】

点击(此处)折叠或打开

  1. #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <string.h>
  8. #include <asm/types.h>
  9. #include <linux/netlink.h>
  10. #include <linux/socket.h>
  11. #define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
  12. int main(int argc, char* argv[])
  13. {
  14. struct sockaddr_nl dest_addr;
  15. struct nlmsghdr *nlh = NULL;
  16. struct iovec iov;
  17. int sock_fd=-1;
  18. struct msghdr msg;
  1. if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,NETLINK_TEST))){ //创建套接字
  2. perror("can‘t create netlink socket!");
  3. return 1;
  4. }
  5. memset(&dest_addr, 0, sizeof(dest_addr));
  6. dest_addr.nl_family = AF_NETLINK;
  7. dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
  8. dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/
  9. //将套接字和Netlink地址结构体进行绑定
  1. if(-1 == bind(sock_fd, (struct sockaddr*)&dest_addr, sizeof(dest_addr))){
  2. perror("can‘t bind sockfd with sockaddr_nl!");
  3. return 1;
  4. }
  5. if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
  6. perror("alloc mem failed!");
  7. return 1;
  8. }
  9. memset(nlh,0,MAX_PAYLOAD);
  10. /* 填充Netlink消息头部 */
  11. nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
  12. nlh->nlmsg_pid = 0;
  13. nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
  14. nlh->nlmsg_flags = 0;
  15. /*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
  16. strcpy(NLMSG_DATA(nlh), argv[1]);
  17. /*这个是模板,暂时不用纠结为什么要这样用。有时间详细讲解socket时再说*/
  18. memset(&iov, 0, sizeof(iov));
  19. iov.iov_base = (void *)nlh;
  20. iov.iov_len = nlh->nlmsg_len;
  21. memset(&msg, 0, sizeof(msg));
  22. msg.msg_iov = &iov;
  23. msg.msg_iovlen = 1;
  24. sendmsg(sock_fd, &msg, 0); //通过Netlink socket向内核发送消息
  25. /* 关闭netlink套接字 */
  26. close(sock_fd);
  27. free(nlh);
  28. return 0;
  29. }

上面的代码逻辑已经非常清晰了,都是socket编程的API,唯一不同的是我们这次编程是针对Netlink协议簇的。这里我们提前引入了BSD层的消息结构体struct msghdr{},定义在<include/linux/socket.h>文件里,以及其数据块struct iovec{}定义在<include/linux/uio.h>头文件里。这里就不展开了,大家先记住这个用法就行。以后有时间再深入到socket的骨子里去转悠一番。

另外,需要格外注意的就是Netlink的地址结构体和其消息头结构中pid字段为0的情况,很容易让人产生混淆,再总结一下:


0


netlink地址结构体.nl_pid


1、内核发出的多播报文

2、消息的接收方是内核,即从用户空间发往内核的消息


netlink消息头体. nlmsg_pid


来自内核主动发出的消息

这个例子仅是从用户空间到内核空间的单向数据通信,所以Netlink地址结构体中我们设置了dest_addr.nl_pid = 0,说明我们的报文的目的地是内核空间;在填充Netlink消息头部时,我们做了nlh->nlmsg_pid = 0这样的设置。

需要注意几个宏的使用:

NLMSG_SPACE(MAX_PAYLOAD),该宏用于返回不小于MAX_PAYLOAD且4字节对齐的最小长度值,一般用于向内存系统申请空间是指定所申请的内存字节数,和NLMSG_LENGTH(len)所不同的是,前者所申请的空间里不包含Netlink消息头部所占的字节数,后者是消息负载和消息头加起来的总长度。

NLMSG_DATA(nlh),该宏用于返回Netlink消息中数据部分的首地址,在写入和读取消息数据部分时会用到它。

它们之间的关系如下:

内核空间的示例代码如下【mynlkern.c】:

点击(此处)折叠或打开

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/skbuff.h>
  4. #include <linux/init.h>
  5. #include <linux/ip.h>
  6. #include <linux/types.h>
  7. #include <linux/sched.h>
  8. #include <net/sock.h>
  9. #include <linux/netlink.h>
  10. MODULE_LICENSE("GPL");
  11. MODULE_AUTHOR("Koorey King");
  12. struct sock *nl_sk = NULL;
  13. static void nl_data_ready (struct sock *sk, int len)
  14. {
  15. struct sk_buff *skb;
  16. struct nlmsghdr *nlh = NULL;
  17. while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
  18. {
  19. nlh = (struct nlmsghdr *)skb->data;
  20. printk("%s: received netlink message payload: %s \n", __FUNCTION__, (char*)NLMSG_DATA(nlh));
  21. kfree_skb(skb);
  22. }
  23. printk("recvied finished!\n");
  24. }
  25. static int __init myinit_module()
  26. {
  27. printk("my netlink in\n");
  28. nl_sk = netlink_kernel_create(NETLINK_TEST,0,nl_data_ready,THIS_MODULE);
  29. return 0;
  30. }
  31. static void __exit mycleanup_module()
  32. {
  33. printk("my netlink out!\n");
  34. sock_release(nl_sk->sk_socket);
  35. }
  36. module_init(myinit_module);
  37. module_exit(mycleanup_module);

在内核模块的初始化函数里我们用

nl_sk =
netlink_kernel_create(NETLINK_TEST,0,nl_data_ready,THIS_MODULE);

创建了一个内核态的socket,第一个参数我们扩展的协议号;第二个参数为多播组号,目前我们用不上,将其置为0;第三个参数是个回调函数,即当内核的Netlink socket套接字收到数据时的处理函数;第四个参数就不多说了。

在回调函数nl_data_ready()中,我们不断的从socket的接收队列去取数据,一旦拿到数据就将其打印输出。在协议栈的INET层,用于存储数据的是大名鼎鼎的sk_buff结构,所以我们通过nlh = (struct nlmsghdr *)skb->data;可以拿到netlink的消息体,然后通过NLMSG_DATA(nlh)定位到netlink的消息负载。

将上述代码编译后测试结果如下:

Stage 2:

我们将上面的代码稍加改造就可以实现用户<->内核双向数据通信。

首先是改造用户空间的代码:

点击(此处)折叠或打开

  1. #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <string.h>
  8. #include <asm/types.h>
  9. #include <linux/netlink.h>
  10. #include <linux/socket.h>
  11. #define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
  12. int main(int argc, char* argv[])
  13. {
  14. struct sockaddr_nl dest_addr;
  15. struct nlmsghdr *nlh = NULL;
  16. struct iovec iov;
  17. int sock_fd=-1;
  18. struct msghdr msg;
  19. if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,NETLINK_TEST))){
  20. perror("can‘t create netlink socket!");
  21. return 1;
  22. }
  23. memset(&dest_addr, 0, sizeof(dest_addr));
  24. dest_addr.nl_family = AF_NETLINK;
  25. dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
  26. dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/
  27. if(-1 == bind(sock_fd, (struct sockaddr*)&dest_addr, sizeof(dest_addr))){
  28. perror("can‘t bind sockfd with sockaddr_nl!");
  29. return 1;
  30. }
  31. if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
  32. perror("alloc mem failed!");
  33. return 1;
  34. }
  35. memset(nlh,0,MAX_PAYLOAD);
  36. /* 填充Netlink消息头部 */
  37. nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
  38. nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
  39. nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
  40. nlh->nlmsg_flags = 0;
  41. /*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
  42. strcpy(NLMSG_DATA(nlh), argv[1]);
  43. /*这个是模板,暂时不用纠结为什么要这样用。*/
  44. memset(&iov, 0, sizeof(iov));
  45. iov.iov_base = (void *)nlh;
  46. iov.iov_len = nlh->nlmsg_len;
  47. memset(&msg, 0, sizeof(msg));
  48. msg.msg_iov = &iov;
  49. msg.msg_iovlen = 1;
  50. sendmsg(sock_fd, &msg, 0); //通过Netlink socket向内核发送消息
  51. //接收内核消息的消息
  52. printf("waiting message from kernel!\n");
  53.     memset((char*)NLMSG_DATA(nlh),0,1024);
  54.     recvmsg(sock_fd,&msg,0);
  55.     printf("Got response: %s\n",NLMSG_DATA(nlh));
  56. /* 关闭netlink套接字 */
  57. close(sock_fd);
  58. free(nlh);
  59. return 0;
  60. }

内核空间的修改如下:

点击(此处)折叠或打开

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/skbuff.h>
  4. #include <linux/init.h>
  5. #include <linux/ip.h>
  6. #include <linux/types.h>
  7. #include <linux/sched.h>
  8. #include <net/sock.h>
  9. #include <net/netlink.h> /*该文头文件里包含了linux/netlink.h,因为我们要用到net/netlink.h中的某些API函数,nlmsg_pug()*/
  10. MODULE_LICENSE("GPL");
  11. MODULE_AUTHOR("Koorey King");
  12. struct sock *nl_sk = NULL;
  13. //向用户空间发送消息的接口
  14. void sendnlmsg(char *message,int dstPID)
  15. {
  16.     struct sk_buff *skb;
  17.     struct nlmsghdr *nlh;
  18.     int len = NLMSG_SPACE(MAX_MSGSIZE);
  19.     int slen = 0;
  20.  
  21.     if(!message || !nl_sk){
  22.         return;
  23.     }
  24.  
  25.     // 为新的 sk_buffer申请空间
  26.     skb = alloc_skb(len, GFP_KERNEL);
  27.     if(!skb){
  28.         printk(KERN_ERR "my_net_link: alloc_skb Error./n");
  29.         return;
  30.     }
  31.  
  32.     slen = strlen(message)+1;
  33.  
  34.     //用nlmsg_put()来设置netlink消息头部
  35.     nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);
  36.  
  37.     // 设置Netlink的控制块
  38.     NETLINK_CB(skb).pid = 0; // 消息发送者的id标识,如果是内核发的则置0
  39.     NETLINK_CB(skb).dst_group = 0; //如果目的组为内核或某一进程,该字段也置0
  40.  
  41.     message[slen] = ‘\0‘;
  42.     memcpy(NLMSG_DATA(nlh), message, slen+1);
  43.  
  44.     //通过netlink_unicast()将消息发送用户空间由dstPID所指定了进程号的进程
  45.     netlink_unicast(nl_sk,skb,dstPID,0);
  46.     printk("send OK!\n");
  47.     return;
  48. }
  49. static void nl_data_ready (struct sock *sk, int len)
  50. {
  51. struct sk_buff *skb;
  52. struct nlmsghdr *nlh = NULL;
  53. while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
  54. {
  55. nlh = (struct nlmsghdr *)skb->data;
  56. printk("%s: received netlink message payload: %s \n", __FUNCTION__, (char*)NLMSG_DATA(nlh));
  57. kfree_skb(skb);
  58. sendnlmsg("I see you",nlh->nlmsg_pid); //发送者的进程ID我们已经将其存储在了netlink消息头部里的nlmsg_pid字段里,所以这里可以拿来用。
  59. }
  60. printk("recvied finished!\n");
  61. }
  62. static int __init myinit_module()
  63. {
  64. printk("my netlink in\n");
  65. nl_sk = netlink_kernel_create(NETLINK_TEST,0,nl_data_ready,THIS_MODULE);
  66. return 0;
  67. }
  68. static void __exit mycleanup_module()
  69. {
  70. printk("my netlink out!\n");
  71. sock_release(nl_sk->sk_socket);
  72. }
  73. module_init(myinit_module);
  74. module_exit(mycleanup_module);

重新编译后,测试结果如下:

Stage 3:

前面我们提到过,如果用户进程希望加入某个多播组时才需要调用bind()函数。前面的示例中我们没有这个需求,可还是调了bind(),心头有些不爽。在前几篇博文里有关于socket编程时几个常见API的详细解释和说明,不明白的童鞋可以回头去复习一下。

因为Netlink是面向无连接的数据报的套接字,所以我们还可以用sendto()和recvfrom()来实现数据的收发,这次我们不再调用bind()。将Stage 2的例子稍加改造一下,用户空间的修改如下:

点击(此处)折叠或打开

  1. #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <string.h>
  8. #include <asm/types.h>
  9. #include <linux/netlink.h>
  10. #include <linux/socket.h>
  11. #define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
  12. int main(int argc, char* argv[])
  13. {
  14. struct sockaddr_nl dest_addr;
  15. struct nlmsghdr *nlh = NULL;
  16. //struct iovec iov;
  17. int sock_fd=-1;
  18. //struct msghdr msg;
  19. if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,NETLINK_TEST))){
  20. perror("can‘t create netlink socket!");
  21. return 1;
  22. }
  23. memset(&dest_addr, 0, sizeof(dest_addr));
  24. dest_addr.nl_family = AF_NETLINK;
  25. dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
  26. dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/
  27. /*不再调用bind()函数了
  28.    if(-1 == bind(sock_fd, (struct sockaddr*)&dest_addr, sizeof(dest_addr))){
  29.           perror("can‘t bind sockfd with sockaddr_nl!");
  30.           return 1;
  31.    }*/
  32.  
  33. if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
  34. perror("alloc mem failed!");
  35. return 1;
  36. }
  37. memset(nlh,0,MAX_PAYLOAD);
  38. /* 填充Netlink消息头部 */
  39. nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
  40. nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
  41. nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
  42. nlh->nlmsg_flags = 0;
  43. /*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
  44. strcpy(NLMSG_DATA(nlh), argv[1]);
  45. /*这个模板就用不上了。*/
  46.    /*
  47.    memset(&iov, 0, sizeof(iov));
  48.    iov.iov_base = (void *)nlh;
  49.    iov.iov_len = nlh->nlmsg_len;
  50.    memset(&msg, 0, sizeof(msg));
  51.    msg.msg_iov = &iov;
  52.    msg.msg_iovlen = 1;
  53.    */
  54. //sendmsg(sock_fd, &msg, 0); //不再用这种方式发消息到内核
  55. sendto(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),sizeof(dest_addr));
  56. //接收内核消息的消息
  57. printf("waiting message from kernel!\n");
  58. //memset((char*)NLMSG_DATA(nlh),0,1024);
  59.    memset(nlh,0,MAX_PAYLOAD); //清空整个Netlink消息头包括消息头和负载
  60. //recvmsg(sock_fd,&msg,0);
  61. recvfrom(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),NULL);
  62. printf("Got response: %s\n",NLMSG_DATA(nlh));
  63. /* 关闭netlink套接字 */
  64. close(sock_fd);
  65. free(nlh);
  66. return 0;
  67. }

内核空间的代码完全不用修改,我们仍然用netlink_unicast()从内核空间发送消息到用户空间。

重新编译后,测试结果如下:

和Stage 2中代码运行效果完全一样。也就是说,在开发Netlink程序过程中,如果没牵扯到多播机制,那么用户空间的socket代码其实是不用执行bind()系统调用的,但此时就需要用sendto()和recvfrom()完成数据的发送和接收的任务;如果执行了bind()系统调用,当然也可以继续用sendto()和recvfrom(),但给它们传递的参数就有所区别。这时候一般使用sendmsg()和recvmsg()来完成数据的发送和接收。大家根据自己的实际情况灵活选择。

未完,待续…

时间: 2024-08-06 12:29:44

用户空间和内核空间通讯之【Netlink 中】的相关文章

用户空间和内核空间通讯之【Netlink 上】

原文地址:用户空间和内核空间通讯之[Netlink 上] 作者:wjlkoorey258 引言 Alan Cox在内核1.3版本的开发阶段最先引入了Netlink,刚开始时Netlink是以字符驱动接口的方式提供内核与用户空间的双向数据通信:随后,在2.1内核开发过程中,Alexey Kuznetsov将Netlink改写成一个更加灵活.且易于扩展的基于消息通信接口,并将其应用到高级路由子系统的基础框架里.自那时起,Netlink就成了Linux内核子系统和用户态的应用程序通信的主要手段之一.

用户空间和内核空间通讯Netlink

http://pan.baidu.com/s/1i386MWX 用户空间和内核空间通讯Netlink

用户空间和内核空间通讯之【proc文件系统】

今天我们介绍另一种用户内核空间通信的方法:proc文件系统. proc文件系统作为linux提供的一种虚拟文件系统并不占用实际外围存储空间,它仅存在于内存中,系统断电即消失.proc文件系统最开始的设计主要是为满足内核向用户态进程报告其状态而设计,并没有为输入做规定和说明.随着发展,现在的proc文件系统已经演变成一个"用户-内核"空间半双工的通信方式了(虽然目前已经开始有点混乱了,但某些早期开发的软件代码中还在继续使用这个文件系统).用户不但可以从proc文件系统中读取内核的相关状态

如何看待Linux操作系统的用户空间和内核空间

作为中央核心处理单元的CPU,除了生产工艺的不断革新进步外,在处理数据和响应速度方面也需要有权衡.稍有微机原理基础的人都知道Intel X86体系的CPU提供了四种特权模式ring0~ring3,其中ring0特权最高,ring3的特权最低,之所以要做这样的区分一个主要目的是保护资源,通俗来讲要保护的资源无非就是"内存.I/O端口以及执行特殊机器指令的能力".任何一个时刻,x86 CPU都是在一定的特权模式下运行.同样,对于ARM体系的CPU 一共有七种运行模式,分别是:用户模式(us

Operating System-Thread(3)用户空间和内核空间实现线程

本文主要内容: 操作系统用户空间和内核空间简介 在用户空间实现线程 在内核空间实现线程 用户空间和内核空间线程混合使用 一.用户空间和内核空间简介 用户空间:User space,内核空间:Kernel Space.这两个是操作系统的重要概念之一,今天为了线程做一下简单的介绍: 内核空间用于运行操作系统核心组件,比如内存管理组件,IO交互组件,文件管理.中断管理组件等,同时驱动程序(Driver)也运行在内核空间. 用户空间,用于运行普通应用程序. 示意图: 二,在用户空间实现线程 用户空间的线

用户空间与内核空间,进程上下文与中断上下文[总结]

用户空间与内核空间,进程上下文与中断上下文[总结] 最近有研究到zabbix监控,就得清楚cpu各个指标的含义, 1,简单回顾下cpu及计算机组成: 计算机五大部件: 运算器 控制器 存储器 输入/输出设备. 2,cpu 进程的内核态和用户态 我们知道现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为 了保证用户进程不能直接操作内核,

Linux内存管理--用户空间和内核空间【转】

本文转载自:http://blog.csdn.net/yusiguyuan/article/details/12045255 关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用户空间与内核空间.用户空间从0到3G(0xc0000000),内核空间占据3G到4G.用户进程通常情况下只能访问用户空间的虚拟地址,不能访问内核空间的虚拟地址.例外情况只有用户进程进行系统调用(代表用户进程在内核态执行)等时刻可以访问到内核空间. 用户空间对应进程,所以每当进程切换,用户空间就会跟着

【转】linux 用户空间与内核空间——高端内存详解

摘要:Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中.用户空间的内存映射采用段页式,而内核空间有自己的规则:本文旨在探讨内核空间的地址映射. Linux内核地址空间划分 通常32位Linux内核虚拟地址空间划分0~3G为用户空间,3~4G为内核空间(注意,内核可以使用的线性地址只有1G).注意这里是32位内核地址空间划分,64位

经典的线程池--用户空间与内核空间实现的对比

经典的线程池模型是一组线程抢一个资源链表的模型,程序启动了一组线程,让它们等待信号waitQ的到来.同时又初始化一个资源链表,当某个线程往资源链表中添加一个资源时,它同时使用信号通知线程池.线程池中的线程接到信号后,就从资源链表中取出资源进行处理. 接下来,我们先来观察一下用户空间线程池的创建过程吧! 1 int 2 init (xlator_t *this) 3 { 4 iot_conf_t *conf = NULL; 5 int ret = -1; 6 int i = 0; 7 8 if (