pastebin - collaborative debugging tool
rovema.kpaste.net RSS


linux_vdso_myclockgettime1.c - fast clock_gettime implementation
Posted by Anonymous on Wed 28th Sep 2022 16:49
raw | new post
view followups (newest first): linux_vdso_myclockgettime1.c - fast clock_gettime implementation by Anonymous

  1.  
  2. /*
  3.  * linux_vdso_myclockgettime1.c - use Linux VDSO
  4.  * shortcut for |clock_gettime()|, even if userland (g)libc
  5.  * does not have support for VDSO
  6.  *
  7.  * Compile with:
  8.  * $ clang -std=c99 -g -m32 -Wall -Wextra linux_vdso_myclockgettime1.c \
  9.  *      -lpthread -o linux_vdso_myclockgettime1
  10.  *
  11.  * Written by Roland Mainz <roland.mainz@nrubsig.org>
  12.  *
  13.  */
  14.  
  15. #define _XOPEN_SOURCE 600
  16.  
  17. #include <stdio.h>
  18. #include <stddef.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <elf.h>
  22. #include <time.h>
  23. #include <pthread.h>
  24. #include <sys/auxv.h>
  25.  
  26. #if (_XOPEN_SOURCE < 600)
  27. #error _XOPEN_SOURCE wrong version
  28. #endif
  29.  
  30. #if (__PTRDIFF_WIDTH__ == 32)
  31. typedef Elf32_Ehdr      ElfXX_Ehdr;
  32. typedef Elf32_Shdr      ElfXX_Shdr;
  33. typedef Elf32_Sym       ElfXX_Sym;
  34. #elif (__PTRDIFF_WIDTH__ == 64)
  35. typedef Elf64_Ehdr      ElfXX_Ehdr;
  36. typedef Elf64_Shdr      ElfXX_Shdr;
  37. typedef Elf64_Sym       ElfXX_Sym;
  38. #else
  39. #error Unsupported __PTRDIFF_WIDTH__
  40. #endif
  41.  
  42. /* debug */
  43. #if 1
  44. #define D(x) x
  45. #else
  46. #define D(x)
  47. #endif
  48.  
  49. static
  50. void *get_linux_vdso_sym(const char *funcname)
  51. {
  52.         const char      *dynstr = NULL;
  53.         void            *ret = NULL;
  54.         unsigned char   *vdso_addr;
  55.         ssize_t         i;
  56.         size_t          si;
  57.         const char      *name;
  58.         ElfXX_Ehdr      *elf_header;
  59.         ElfXX_Shdr      *section_header;
  60.         ElfXX_Shdr      *s;
  61.         ElfXX_Shdr      *ss_;
  62.         ElfXX_Sym       *sym;
  63.  
  64.         /*
  65.          * valgrind can disable |AT_SYSINFO_EHDR| - see
  66.          * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html
  67.          */
  68.         vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR);
  69.         if (!vdso_addr) {
  70.                 D((void)fprintf(stderr, "get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n"));
  71.                 return NULL;
  72.         }
  73.    
  74.         elf_header = (ElfXX_Ehdr *)vdso_addr;
  75.         section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
  76.  
  77.         for (i=0L; i < elf_header->e_shnum; i++) {
  78.                 s = &section_header[i];
  79.                 ss_ = &section_header[elf_header->e_shstrndx];
  80.                 name = (const char*)(vdso_addr + ss_->sh_offset + s->sh_name);
  81.  
  82.                 if (strcmp(name, ".dynstr") == 0) {
  83.                         dynstr = (const char *)(vdso_addr + s->sh_offset);
  84.                         break;
  85.                 }
  86.         }
  87.  
  88.         for (i=0L; i < elf_header->e_shnum; i++) {
  89.                 s = &section_header[i];
  90.                 ss_ = &section_header[elf_header->e_shstrndx];
  91.                 name = (const char*)(vdso_addr + ss_->sh_offset + s->sh_name);
  92.  
  93.                 /* Not .dynsym ? Then look at next section... */
  94.                 if (strcmp(name, ".dynsym"))
  95.                         continue;
  96.  
  97.                 for (si=0L; si < (s->sh_size/s->sh_entsize); si++) {
  98.                         sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]);
  99.                         name = dynstr + sym->st_name;
  100.  
  101.                         D((void)fprintf(stderr, "get_linux_vdso_sym: symbol=|%s| vs. |%s|\n",
  102.                                 funcname, name));
  103.                         if (!strcmp(name, funcname)) {
  104.                                 ret = (void *)(vdso_addr + sym->st_value);
  105.                                 break;
  106.                         }
  107.                 }
  108.                 if (ret)
  109.                         break;
  110.         }
  111.  
  112.         return ret;
  113. }
  114.  
  115. typedef int (clock_gettime_func_t)(clockid_t clk_id, struct timespec *tp);
  116.  
  117. static pthread_once_t my_clock_gettime_func_is_initialized = PTHREAD_ONCE_INIT;
  118. clock_gettime_func_t *my_clock_gettime_func = NULL;
  119.  
  120. void my_clock_gettime_func_init(void)
  121. {
  122.         my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("clock_gettime");
  123.         if (!my_clock_gettime_func)
  124.                 my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("__vdso_clock_gettime");
  125.  
  126.         D((void)fprintf(stderr, "my_clock_gettime_func_init: "
  127.                 "my_clock_gettime_func = 0x%lx (%s)\n",
  128.                 (long)my_clock_gettime_func,
  129.                 (my_clock_gettime_func?
  130.                         "Using fast codepath":
  131.                         "Using slow codepath")));
  132.         if (!my_clock_gettime_func) {
  133.                 (void)fprintf(stderr, "my_clock_gettime_func_init: "
  134.                         "WARNING: aux symbol for clock_gettime not found"
  135.                         ", using slow libc codepath.\n");
  136.         }
  137. }
  138.  
  139.  
  140. /*
  141.  * my_clock_gettime() - our "public" interface
  142.  *
  143.  * Notes:
  144.  * - The first call might be slower because the call to
  145.  * |my_clock_gettime_func_init()|
  146.  */
  147. int my_clock_gettime(clockid_t clk_id, struct timespec *tp)
  148. {
  149.         (void)pthread_once(&my_clock_gettime_func_is_initialized,
  150.                 my_clock_gettime_func_init);
  151.  
  152.         if (my_clock_gettime_func) {
  153.                 /* our own "fast" codepath */
  154.                 return (*my_clock_gettime_func)(clk_id, tp);
  155.         }
  156.         else
  157.         {
  158.                 /* libc codepath, whatever they use - might be VDSO, might be syscall */
  159.                 return clock_gettime(clk_id, tp);
  160.         }
  161. }
  162.  
  163. static
  164. void test_my_clock_gettime1(void)
  165. {
  166.         /*
  167.          * dummy call to |my_clock_gettime()| to force initalisation
  168.          * via |my_clock_gettime_func_init()|
  169.          */
  170.         struct timespec dummy;
  171.         (void)my_clock_gettime(CLOCK_REALTIME, &dummy);
  172.        
  173. #define PRINT_CLOCK(clock) \
  174.         { \
  175.                 struct timespec tp1, tp2; \
  176.                 /* \
  177.                  * first libc implementation, then our implementation, \
  178.                  * so that the difference is the call time of our \
  179.                  * codepath. Requires |my_clock_gettime_func_init()| \
  180.                  * to run before this sequence!! \
  181.                  */ \
  182.                 (void)clock_gettime((clock), &tp1); \
  183.                 (void)my_clock_gettime((clock), &tp2); \
  184.                 (void)printf( \
  185.                         "%-20s libc_impl = \t(%-10ld\t%-10ld), " \
  186.                         "our_impl = \t(%-10ld\t%-10ld)\n", \
  187.                         #clock ":", \
  188.                         (long)tp1.tv_sec, (long)tp1.tv_nsec, \
  189.                         (long)tp2.tv_sec, (long)tp2.tv_nsec); \
  190.         }
  191.  
  192.         PRINT_CLOCK(CLOCK_REALTIME);
  193.         PRINT_CLOCK(CLOCK_MONOTONIC);
  194. }
  195.  
  196. int main(int ac, char *av[])
  197. {
  198.         (void)ac;
  199.         (void)av;
  200.        
  201.         test_my_clock_gettime1();
  202.  
  203.         return EXIT_SUCCESS;
  204. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at