Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1263008
  • 博文数量: 185
  • 博客积分: 495
  • 博客等级: 下士
  • 技术积分: 1418
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-02 15:12
个人简介

治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu

文章分类

全部博文(185)

文章存档

2019年(1)

2018年(12)

2017年(5)

2016年(23)

2015年(1)

2014年(22)

2013年(82)

2012年(39)

分类: LINUX

2013-03-15 17:35:14

vsyscall相较于普通的通过INT 80中断完成的系统调用要更快,因此在对于精度要求很高或者时延要求极低的系统调用适合用vsyscall来实现,但是有一个缺点是vsyscall的系统调用不一定有libc的包裹函数,因此使用上比较复杂,但是内核已经为我们映射好了这些vsyscall到线程的地址空间中。废话少说,看代码:

点击(此处)折叠或打开

  1. /*
  2.  *Copyright (c) 2013 GuZheng
  3.  * Author: GuZheng <cengku@gmail.com>
  4.  * Demo of how to use vsyscall func
  5.  *
  6.  * */
  7. /* vsyscall.h header info
  8. #ifndef _ASM_X86_VSYSCALL_H
  9. #define _ASM_X86_VSYSCALL_H

  10. enum vsyscall_num {
  11.         __NR_vgettimeofday,
  12.         __NR_vtime,
  13.         __NR_vgetcpu,
  14. };

  15. #define VSYSCALL_START (-10UL << 20)
  16. #define VSYSCALL_SIZE 1024
  17. #define VSYSCALL_END (-2UL << 20)
  18. #define VSYSCALL_MAPPED_PAGES 1
  19. #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))


  20. #endif
  21. */

  22. #include <asm/vsyscall.h> /*the vsyscall header*/
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <sys/time.h>
  28. #include <time.h>

  29. struct getcpu_cache {
  30.         unsigned long blob[128 / sizeof(long)];
  31. };

  32. int main(int argc, char **argv)
  33. {
  34.         /*这个内核版本有三个vsyscall实现的系统调用
  35.         *gettimeofday,time和getcpu
  36.         *因此先定义三个函数原型的指针,用来接受后面找到的函数的映射地址
  37.         * */
  38.         int (*my_getcpu)(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
  39.         int (*my_gettimeofday)(struct timeval *tv, struct timezone *tz);
  40.         time_t (*my_time)(time_t *calptr);

  41.         int node, cpu;
  42.         time_t tm;
  43.         struct tm *gm;
  44.         struct timeval tv;
  45.         struct timezone tz;
  46.         struct getcpu_cache cache;

  47.         /*根据VSYSCALL_ADDR宏,以及三个函数的偏移就可以找到映射的地址了*/
  48.         char *addr1 = (char *)VSYSCALL_ADDR(__NR_vgettimeofday);
  49.         printf("vgettimeofday addr is%p \n", addr1);
  50.         char *addr2 = (char *)VSYSCALL_ADDR(__NR_vtime);
  51.         printf("vtime addr is %p \n", addr2);
  52.         char *addr3 = (char *)VSYSCALL_ADDR(__NR_vgetcpu);
  53.         printf("vgetcpu addr is %p \n", addr3);

  54.         my_gettimeofday = (int (*)(struct timeval *, struct timezone *))addr1;
  55.         my_gettimeofday(&tv, &tz);
  56.         printf("tv_sec:%d\n", tv.tv_sec);
  57.         printf("tv_usec:%d\n", tv.tv_usec);
  58.         printf("tz_minuteswest:%d\n", tz.tz_minuteswest);
  59.         printf("tz_dsttime:%d\n", tz.tz_dsttime);

  60.         my_time = (time_t (*)(time_t *))addr2;
  61.         time(&tm);
  62.         gm = gmtime(&tm);
  63.         printf("Now is %d-%d-%d %d:%d:%d\n",
  64.                         gm->tm_year + 1900,
  65.                         gm->tm_mon,
  66.                         gm->tm_mday,
  67.                         gm->tm_hour,
  68.                         gm->tm_min,
  69.                         gm->tm_sec);

  70.         my_getcpu = (int (*)(unsigned *, unsigned *, struct getcpu_cache *))addr3;
  71.         my_getcpu(&cpu, &node, &cache);
  72.         printf("numa node:%d, run on cpu:%d\n", node, cpu);


  73.         return 0;
  74. }
方法有点hack,后面补上用内联汇编的正规版本


补上gcc inline asm版本的(你妹的内联asm真心不好写啊!):

点击(此处)折叠或打开

  1. /*
  2.  *Copyright (c) 2013 GuZheng
  3.  * Author: GuZheng <cengku@gmail.com>
  4.  * Demo of how to use vsyscall func
  5.  *
  6.  * */
  7. /* vsyscall.h header info
  8. #ifndef _ASM_X86_VSYSCALL_H
  9. #define _ASM_X86_VSYSCALL_H

  10. enum vsyscall_num {
  11.         __NR_vgettimeofday,
  12.         __NR_vtime,
  13.         __NR_vgetcpu,
  14. };

  15. #define VSYSCALL_START (-10UL << 20)
  16. #define VSYSCALL_SIZE 1024
  17. #define VSYSCALL_END (-2UL << 20)
  18. #define VSYSCALL_MAPPED_PAGES 1
  19. #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr))


  20. #endif
  21. */

  22. #include <asm/vsyscall.h> /*the vsyscall header*/
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <sys/time.h>
  28. #include <time.h>

  29. struct getcpu_cache {
  30.         unsigned long blob[128 / sizeof(long)];
  31. };

  32. int main(int argc, char **argv)
  33. {
  34.         /*这个内核版本有三个vsyscall实现的系统调用
  35.         *gettimeofday,time和getcpu
  36.         *因此先定义三个函数原型的指针,用来接受后面找到的函数的映射地址
  37.         * */
  38.         int (*my_getcpu)(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
  39.         int (*my_gettimeofday)(struct timeval *tv, struct timezone *tz);
  40.         time_t (*my_time)(time_t *calptr);

  41.         int node, cpu;
  42.         time_t tm;
  43.         struct tm *gm;
  44.         struct timeval tv;
  45.         struct timezone tz;
  46.         struct getcpu_cache cache;

  47.         /*根据VSYSCALL_ADDR宏,以及三个函数的偏移就可以找到映射的地址了*/
  48.         char *addr1 = (char *)VSYSCALL_ADDR(__NR_vgettimeofday);
  49.         printf("vgettimeofday addr is%p \n", addr1);
  50.         char *addr2 = (char *)VSYSCALL_ADDR(__NR_vtime);
  51.         printf("vtime addr is %p \n", addr2);
  52.         char *addr3 = (char *)VSYSCALL_ADDR(__NR_vgetcpu);
  53.         printf("vgetcpu addr is %p \n", addr3);

  54.         my_gettimeofday = (int (*)(struct timeval *, struct timezone *))addr1;
  55.         //my_gettimeofday(&tv, &tz);
  56.         __asm__(
  57.                 "movq %1, %%rdx;"
  58.                 "movq %0, %%rax;"
  59.                 "movq %2, %%rcx;"
  60.                 "movq %%rdx, %%rsi;"
  61.                 "movq %%rax, %%rdi;"
  62.                 "call *%%rcx;"
  63.                 :
  64.                 : "r"(&tv), "r"(&tz), "r"(addr1)
  65.                 : "rdx", "rax", "rcx", "rsi", "rdi"
  66.         );
  67.         printf("tv_sec:%d\n", tv.tv_sec);
  68.         printf("tv_usec:%d\n", tv.tv_usec);
  69.         printf("tz_minuteswest:%d\n", tz.tz_minuteswest);
  70.         printf("tz_dsttime:%d\n", tz.tz_dsttime);

  71.         my_time = (time_t (*)(time_t *))addr2;
  72.         //time(&tm);
  73.         __asm__(
  74.                 "movq %0, %%rax;"
  75.                 "movq %1, %%rcx;"
  76.                 "movq %%rax, %%rdi;"
  77.                 "call *%%rcx"
  78.                 :
  79.                 : "r"(&tm), "r"(addr2)
  80.                 : "rax", "rcx", "rdi"
  81.         );
  82.         gm = gmtime(&tm);
  83.         printf("Now is %d-%d-%d %d:%d:%d\n",
  84.                         gm->tm_year + 1900,
  85.                         gm->tm_mon,
  86.                         gm->tm_mday,
  87.                         gm->tm_hour,
  88.                         gm->tm_min,
  89.                         gm->tm_sec);

  90.         my_getcpu = (int (*)(unsigned *, unsigned *, struct getcpu_cache *))addr3;
  91.         //my_getcpu(&cpu, &node, &cache);

  92.         __asm__(
  93.                 "movq %2, %%rdx;"
  94.                 "movq %0, %%rcx;"
  95.                 "movq %1, %%rax;"
  96.                 "movq %3, %%r8;"
  97.                 "movq %%rcx, %%rsi;"
  98.                 "movq %%rax, %%rdi;"
  99.                 "call *%%r8;"
  100.                 :
  101.                 : "r"(&cpu), "r"(&node),"r"(NULL),"r"(addr3)
  102.                 );
  103.         printf("numa node:%d, run on cpu:%d\n", node, cpu);


  104.         return 0;
  105. }


阅读(4515) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~