This source file includes following definitions.
- file_exists
 
- is_compatible_architecture
 
- get_candidate_lib_dirs
 
- free_candidate_lib_dirs
 
- find_libhwloc_path
 
- get_core_count
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 #include <ctype.h>
  43 #if !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(CROSS_MINGW32) && !defined(CROSS_MINGW64)
  44 # include <dlfcn.h>
  45 #endif
  46 #include <limits.h>
  47 #include <stdint.h>
  48 #include <stdbool.h>
  49 #include <stdio.h>
  50 #include <stdlib.h>
  51 #include <string.h>
  52 #include <sys/stat.h>
  53 #include <unistd.h>
  54 #include "dps8_sir.h"
  55 
  56 #if defined(__HAIKU__)
  57 # include <OS.h>
  58 #endif
  59 
  60 #if !defined(CHAR_BIT)
  61 # define CHAR_BIT 8
  62 #endif
  63 
  64 #if !defined(HAS_INCLUDE)
  65 # if defined __has_include
  66 #  define HAS_INCLUDE(inc) __has_include(inc)
  67 # else
  68 #  define HAS_INCLUDE(inc) 0
  69 # endif
  70 #endif
  71 
  72 #if !defined(__HAIKU__)
  73 # if HAS_INCLUDE(<elf.h>)
  74 #  include <elf.h>
  75 # endif
  76 # if HAS_INCLUDE(<hwloc.h>)
  77 #  include <hwloc.h>
  78 # endif
  79 #endif
  80 
  81 #if !defined(HWLOC_OBJ_CORE)
  82 # define HWLOC_OBJ_CORE 5
  83 #endif
  84 
  85 #if defined(EI_CLASS) && defined(EI_NIDENT) && defined(ELFCLASS32) && \
  86     defined(ELFCLASS64) && defined(ELFMAG) && defined(SELFMAG)
  87 # define USE_ELF_H
  88 #endif
  89 
  90 #if defined(FREE)
  91 # undef FREE
  92 #endif 
  93 #define FREE(p) do  \
  94   {                 \
  95     free((p));      \
  96     (p) = NULL;     \
  97   } while(0)
  98 
  99 bool dps8_topo_used = false;
 100 
 101 #if !defined(__HAIKU__)
 102 static inline int
 103 file_exists (const char *path)
     
 104 {
 105   struct stat st;
 106   return 0 == stat(path, &st);
 107 }
 108 #endif
 109 
 110 #if !defined(__HAIKU__)
 111 static inline int
 112 is_compatible_architecture (const char *path)
     
 113 {
 114 # if !defined(USE_ELF_H)
 115   (void)path;
 116   return 1;
 117 # else
 118   FILE *f = fopen(path, "rb");
 119   if (NULL == f) {
 120 #  if defined(TOPO_TESTING)
 121     (void)fprintf(stderr, "WARNING: Unable to open '%s'!\r\n", path);
 122 #  endif
 123     return 0;
 124   }
 125 
 126   unsigned char e_ident[EI_NIDENT];
 127   if (EI_NIDENT != fread(e_ident, 1, EI_NIDENT, f)) {
 128 #  if defined(TOPO_TESTING)
 129     (void)fprintf(stderr, "WARNING: Bad header in '%s'!\r\n", path);
 130 #  endif
 131     fclose(f);
 132     return 0;
 133   }
 134   fclose(f);
 135 
 136   if (0 != memcmp(e_ident, ELFMAG, SELFMAG)) {
 137 #  if defined(TOPO_TESTING)
 138     (void)fprintf(stderr, "WARNING: Bad header in '%s'!\r\n", path);
 139 #  endif
 140     return 0;
 141   }
 142 
 143   const uint32_t bits = (int)sizeof(void *) * CHAR_BIT;
 144 
 145   if (64 == bits) {
 146     
 147     if (EI_NIDENT >= EI_CLASS && ELFCLASS64 == e_ident[EI_CLASS]) { 
 148 #  if defined(TOPO_TESTING)
 149       (void)fprintf(stderr, "NOTICE: '%s' is valid 64-bit ELF.\r\n", path);
 150 #  endif
 151       return 1;
 152     }
 153   } else if (32 == bits) {
 154     
 155     if (EI_NIDENT >= EI_CLASS && ELFCLASS32 == e_ident[EI_CLASS]) { 
 156 #  if defined(TOPO_TESTING)
 157       (void)fprintf(stderr, "NOTICE: '%s' is valid 32-bit ELF.\r\n", path);
 158 #  endif
 159       return 1;
 160     }
 161   }
 162 #  if defined(TOPO_TESTING)
 163   (void)fprintf(stderr, "WARNING: '%s' could not be validated!\r\n", path);
 164 #  endif
 165   return 0;
 166 # endif
 167 }
 168 #endif
 169 
 170 #if !defined(__HAIKU__) && !defined(__NetBSD__)
 171 static char **
 172 get_candidate_lib_dirs (int32_t *n_dirs)
     
 173 {
 174   size_t count = 0;
 175   char **dirs = NULL;
 176   const char *ld_path = getenv("LD_LIBRARY_PATH");
 177 
 178   if (ld_path && *ld_path) {
 179     char *copy = strdup(ld_path);
 180     if (NULL == copy) {
 181       
 182       return NULL;
 183     }
 184 
 185     char *token = strtok(copy, ":");
 186     while (token) {
 187       count++;
 188       token = strtok(NULL, ":");
 189     }
 190     FREE(copy);
 191   }
 192 
 193   const char *defaults[] = {
 194       "/lib",
 195       "/lib64",
 196       "/usr/lib",
 197       "/usr/lib64",
 198       "/usr/lib/64",
 199       "/usr/local/lib",
 200       "/opt/lib",
 201       "/opt/local/lib",
 202       "/opt/freeware/lib",
 203       "/boot/system/lib",
 204       "/opt/hwloc/lib",
 205       "/usr/local/hwloc",
 206       "/home/linuxbrew/.linuxbrew/lib",
 207       "/usr/pkg/lib",
 208       "/usr/lib/32",
 209       "/usr/lib/aarch64-linux-gnu",
 210       "/usr/lib/arm-linux-gnueabihf",
 211   };
 212 
 213   uint32_t n_defaults = sizeof(defaults) / sizeof(defaults[0]);
 214   count += n_defaults;
 215 
 216   FILE *fp = fopen("/proc/self/maps", "r");
 217   char *temp_paths[SIR_MAXPATH];
 218   uint32_t temp_count = 0;
 219   if (fp) {
 220     char line[SIR_MAXPATH];
 221     while (fgets(line, sizeof(line), fp) && temp_count < SIR_MAXPATH) {
 222       char *path = strstr(line, "/");
 223       if (path && strstr(path, ".so")) {
 224         char *dir_end = strrchr(path, '/');
 225         if (dir_end) {
 226           *dir_end = '\0';
 227           int is_dup = 0;
 228           for (uint32_t i = 0; i < temp_count; i++) {
 229             if (0 == strcmp(temp_paths[i], path)) {
 230               is_dup = 1;
 231               break;
 232             }
 233           }
 234           if (!is_dup) {
 235             temp_paths[temp_count++] = strdup(path);
 236             if (NULL == temp_paths[temp_count - 1]) {
 237               for (uint32_t i = 0; i < temp_count - 1; i++)
 238                 FREE(temp_paths[i]);
 239               fclose(fp);
 240               return NULL;
 241             }
 242           }
 243         }
 244       }
 245     }
 246     fclose(fp);
 247     count += temp_count;
 248   }
 249 
 250   dirs = malloc(sizeof(char *) * (count + 1));
 251   if (NULL == dirs) {
 252     for (uint32_t i = 0; i < temp_count; i++)
 253       FREE(temp_paths[i]);
 254     return NULL;
 255   }
 256 
 257   int32_t index = 0;
 258 
 259   if (ld_path && *ld_path) {
 260     char *copy = strdup(ld_path);
 261     if (NULL == copy) {
 262       FREE(dirs);
 263       for (uint32_t i = 0; i < temp_count; i++)
 264         FREE(temp_paths[i]);
 265       return NULL;
 266     }
 267     char *token = strtok(copy, ":");
 268     while (token) {
 269       dirs[index++] = strdup(token);
 270       if (NULL == dirs[index - 1]) {
 271         for (int32_t i = 0; i < index - 1; i++)
 272           FREE(dirs[i]);
 273         FREE(dirs);
 274         FREE(copy);
 275         for (uint32_t i = 0; i < temp_count; i++)
 276           FREE(temp_paths[i]);
 277         return NULL;
 278       }
 279       token = strtok(NULL, ":");
 280     }
 281     FREE(copy);
 282   }
 283 
 284   for (uint32_t i = 0; i < temp_count; i++) {
 285     dirs[index++] = temp_paths[i];
 286   }
 287 
 288   for (uint32_t i = 0; i < n_defaults; i++) {
 289     dirs[index++] = strdup(defaults[i]);
 290     if (NULL == dirs[index - 1]) {
 291       for (int32_t j = 0; j < index - 1; j++)
 292         FREE(dirs[j]);
 293       FREE(dirs);
 294       return NULL;
 295     }
 296   }
 297 
 298   dirs[index] = NULL;
 299   *n_dirs = index;
 300   return dirs;
 301 }
 302 #endif
 303 
 304 #if !defined(__HAIKU__)
 305 static inline void
 306 free_candidate_lib_dirs (char **dirs)
     
 307 {
 308   if (NULL == dirs)
 309     return;
 310 
 311   for (uint32_t i = 0; dirs[i] != NULL; i++)
 312     FREE(dirs[i]);
 313 
 314   FREE(dirs);
 315 }
 316 #endif
 317 
 318 
 319 #if !defined(__HAIKU__) && !defined(__MINGW64__) && !defined(__MINGW32__) && \
 320     !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32) && !defined(__NetBSD__)
 321 static char *
 322 find_libhwloc_path (void)
     
 323 {
 324   const char *candidates[] = {
 325       "libhwloc.so.15",
 326       "libhwloc.so.5",
 327       "libhwloc.so",
 328       "libhwloc.15.dylib",
 329       "libhwloc.5.dylib",
 330       "libhwloc.dylib",
 331       NULL
 332   };
 333 
 334   int32_t n_dirs = 0;
 335   char *found = NULL;
 336   char **dirs = get_candidate_lib_dirs(&n_dirs);
 337 
 338   if (NULL == dirs)
 339     return NULL;
 340 
 341   for (uint32_t i = 0; candidates[i] != NULL; i++) {
 342     for (uint32_t j = 0; j < n_dirs; j++) {
 343       char fullpath[SIR_MAXPATH];
 344       (void)snprintf(fullpath, sizeof(fullpath), "%s/%s", dirs[j], candidates[i]);
 345       if (file_exists(fullpath) && is_compatible_architecture(fullpath)) {
 346         found = strdup(fullpath);
 347         break;
 348       }
 349     }
 350     if (NULL != found)
 351       break;
 352   }
 353 
 354   free_candidate_lib_dirs(dirs);
 355   return found;
 356 }
 357 #endif
 358 
 359 
 360 typedef void *dl_hwloc_topology_t;
 361 typedef int (*fp_hwloc_topology_init) (dl_hwloc_topology_t *);
 362 typedef int (*fp_hwloc_topology_load) (dl_hwloc_topology_t);
 363 typedef void (*fp_hwloc_topology_destroy) (dl_hwloc_topology_t);
 364 typedef int (*fp_hwloc_get_type_depth) (dl_hwloc_topology_t, int);
 365 typedef unsigned (*fp_hwloc_get_nbobjs_by_depth) (dl_hwloc_topology_t, int);
 366 
 367 
 368 uint32_t
 369 get_core_count(void)
     
 370 {
 371   static uint32_t num_cores = 0;
 372 #if defined(__HAIKU__)
 373   const uint32_t maxnodes = 1024;
 374 
 375   dps8_topo_used = true;
 376   cpu_topology_node_info* topology = malloc(sizeof(cpu_topology_node_info) * maxnodes);
 377   if (NULL == topology)
 378     return 0; 
 379 
 380   uint32_t nodecount = maxnodes;
 381   status_t status = get_cpu_topology_info(topology, &nodecount);
 382 
 383   if (B_OK == status) {
 384     for (uint32_t i = 0; i < nodecount; i++) {
 385       if (B_TOPOLOGY_CORE == topology[i].type)
 386         num_cores++;
 387     }
 388     return num_cores;
 389   } else {
 390     return 0;
 391   }
 392 
 393   FREE(topology);
 394 #elif defined(__MINGW32__) || defined(__MINGW64__) || defined(CROSS_MINGW32) || defined(CROSS_MINGW64)
 395   dps8_topo_used = true;
 396   return 0;
 397 #elif defined(__NetBSD__)
 398   dps8_topo_used = true;
 399   return 0;
 400 #else
 401   char *lib_path = find_libhwloc_path();
 402 
 403   if (NULL == lib_path)
 404     return 0; 
 405 
 406   void *handle = dlopen(lib_path, RTLD_LAZY);
 407   FREE(lib_path);
 408   if (NULL == handle) {
 409 # if defined(TOPO_TESTING)
 410     char *dl_error = dlerror();
 411     if (dl_error && *dl_error)
 412       (void)fprintf(stderr, "ERROR: dlopen: %s\r\n", dl_error);
 413 # endif
 414     return 0;
 415   }
 416   (void)dlerror();
 417 
 418   dps8_topo_used = true;
 419 
 420   fp_hwloc_topology_init hwloc_topology_init =
 421     (fp_hwloc_topology_init)dlsym(handle, "hwloc_topology_init");
 422   if (NULL == hwloc_topology_init) {
 423 # if defined(TOPO_TESTING)
 424     char *dl_error = dlerror();
 425     if (dl_error && *dl_error)
 426       (void)fprintf(stderr, "ERROR: no hwloc_topology_init: %s\r\n", dl_error);
 427 # endif
 428     (void)dlclose(handle);
 429     return 0;
 430   }
 431 
 432   fp_hwloc_topology_load hwloc_topology_load =
 433     (fp_hwloc_topology_load)dlsym(handle, "hwloc_topology_load");
 434   if (NULL == hwloc_topology_load) {
 435 # if defined(TOPO_TESTING)
 436     char *dl_error = dlerror();
 437     if (dl_error && *dl_error)
 438       (void)fprintf(stderr, "ERROR: no hwloc_topology_load: %s\r\n", dl_error);
 439 # endif
 440     (void)dlclose(handle);
 441     return 0;
 442   }
 443 
 444   fp_hwloc_topology_destroy hwloc_topology_destroy =
 445     (fp_hwloc_topology_destroy)dlsym(handle, "hwloc_topology_destroy");
 446   if (NULL == hwloc_topology_destroy) {
 447 # if defined(TOPO_TESTING)
 448     char *dl_error = dlerror();
 449     if (dl_error && *dl_error)
 450       (void)fprintf(stderr, "ERROR: no hwloc_topology_destroy: %s\r\n", dl_error);
 451 # endif
 452     (void)dlclose(handle);
 453     return 0;
 454   }
 455 
 456   fp_hwloc_get_type_depth hwloc_get_type_depth =
 457     (fp_hwloc_get_type_depth)dlsym(handle, "hwloc_get_type_depth");
 458   if (NULL == hwloc_get_type_depth) {
 459 # if defined(TOPO_TESTING)
 460     char *dl_error = dlerror();
 461     if (dl_error && *dl_error)
 462       (void)fprintf(stderr, "ERROR: no hwloc_get_type_depth: %s\r\n", dl_error);
 463 # endif
 464     (void)dlclose(handle);
 465     return 0;
 466   }
 467 
 468   fp_hwloc_get_nbobjs_by_depth hwloc_get_nbobjs_by_depth =
 469     (fp_hwloc_get_nbobjs_by_depth)dlsym(handle, "hwloc_get_nbobjs_by_depth");
 470   if (NULL == hwloc_get_nbobjs_by_depth) {
 471 # if defined(TOPO_TESTING)
 472     char *dl_error = dlerror();
 473     if (dl_error && *dl_error)
 474       (void)fprintf(stderr, "ERROR: no hwloc_get_nbobjs_by_depth: %s\r\n", dl_error);
 475 # endif
 476     (void)dlclose(handle);
 477     return 0;
 478   }
 479 
 480   dl_hwloc_topology_t topology;
 481   if (0 != hwloc_topology_init(&topology)) {
 482 # if defined(TOPO_TESTING)
 483     (void)fprintf(stderr, "ERROR: hwloc_topology_init failure.\r\n");
 484 # endif
 485     (void)dlclose(handle);
 486     return 0;
 487   }
 488 
 489   if (0 != hwloc_topology_load(topology)) {
 490 # if defined(TOPO_TESTING)
 491     (void)fprintf(stderr, "ERROR: hwloc_topology_load failure.\r\n");
 492     hwloc_topology_destroy(topology);
 493 # endif
 494     (void)dlclose(handle);
 495     return 0;
 496   }
 497 
 498   int32_t core_depth = hwloc_get_type_depth(topology, HWLOC_OBJ_CORE);
 499   if (-1 == core_depth) {
 500 # if defined(TOPO_TESTING)
 501     (void)fprintf(stderr, "ERROR: hwloc_get_type_depth failure.\r\n");
 502     hwloc_topology_destroy(topology);
 503 # endif
 504     (void)dlclose(handle);
 505     return 0;
 506   }
 507 
 508   num_cores = hwloc_get_nbobjs_by_depth(topology, core_depth);
 509   hwloc_topology_destroy(topology);
 510   (void)dlclose(handle);
 511 #endif
 512 #if defined(_AIX)
 513   if (num_cores < 2)
 514     return 0;
 515 #endif
 516   return num_cores;
 517 }