root/opal/mca/pmix/pmix4x/pmix/src/hwloc/hwloc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_flags
  2. pmix_hwloc_get_topology
  3. pmix_hwloc_cleanup
  4. parse_map_line
  5. use_hole
  6. find_hole
  7. enough_space

   1 /*
   2  * Copyright (c) 2014-2018 Intel, Inc. All rights reserved.
   3  * Copyright (c) 2017      Cisco Systems, Inc.  All rights reserved
   4  * Copyright (c) 2017      Inria.  All rights reserved.
   5  * $COPYRIGHT$
   6  *
   7  * Additional copyrights may follow
   8  *
   9  * $HEADER$
  10  */
  11 
  12 #include <src/include/pmix_config.h>
  13 #include <pmix_common.h>
  14 
  15 #include <stdio.h>
  16 #include <stdlib.h>
  17 #include <stdint.h>
  18 #include <assert.h>
  19 #include <errno.h>
  20 #ifdef HAVE_UNISTD_H
  21 #include <unistd.h>
  22 #endif  /* HAVE_UNISTD_H */
  23 #include <string.h>
  24 #include <sys/mman.h>
  25 #ifdef HAVE_SYS_STAT_H
  26 #include <sys/stat.h>
  27 #endif
  28 #if HAVE_FCNTL_H
  29 #include <fcntl.h>
  30 #endif
  31 
  32 #include "src/util/error.h"
  33 #include "src/util/fd.h"
  34 #include "src/util/path.h"
  35 #include "src/mca/bfrops/bfrops_types.h"
  36 #include "src/server/pmix_server_ops.h"
  37 #include "hwloc-internal.h"
  38 
  39 #if PMIX_HAVE_HWLOC
  40 
  41 #if HWLOC_API_VERSION >= 0x20000
  42 #include <hwloc/shmem.h>
  43 #endif
  44 
  45 
  46 PMIX_EXPORT hwloc_topology_t pmix_hwloc_topology = NULL;
  47 static bool external_topology = false;
  48 
  49 #if HWLOC_API_VERSION >= 0x20000
  50 static size_t shmemsize = 0;
  51 static size_t shmemaddr;
  52 static char *shmemfile = NULL;
  53 static int shmemfd = -1;
  54 
  55 static int parse_map_line(const char *line,
  56                           unsigned long *beginp,
  57                           unsigned long *endp,
  58                           pmix_hwloc_vm_map_kind_t *kindp);
  59 static int use_hole(unsigned long holebegin,
  60                     unsigned long holesize,
  61                     unsigned long *addrp,
  62                     unsigned long size);
  63 static int find_hole(pmix_hwloc_vm_hole_kind_t hkind,
  64                      size_t *addrp,
  65                      size_t size);
  66 static int enough_space(const char *filename,
  67                         size_t space_req,
  68                         uint64_t *space_avail,
  69                         bool *result);
  70 #endif
  71 
  72 static int set_flags(hwloc_topology_t topo, unsigned int flags)
  73 {
  74     #if HWLOC_API_VERSION < 0x20000
  75             flags = HWLOC_TOPOLOGY_FLAG_IO_DEVICES;
  76     #else
  77             int ret = hwloc_topology_set_io_types_filter(topo, HWLOC_TYPE_FILTER_KEEP_IMPORTANT);
  78             if (0 != ret) return ret;
  79     #endif
  80     if (0 != hwloc_topology_set_flags(topo, flags)) {
  81         return PMIX_ERR_INIT;
  82     }
  83     return PMIX_SUCCESS;
  84 }
  85 #endif // have_hwloc
  86 
  87 pmix_status_t pmix_hwloc_get_topology(pmix_info_t *info, size_t ninfo)
  88 {
  89 #if PMIX_HAVE_HWLOC
  90     size_t n;
  91     bool save_xml_v1 = false;
  92     bool save_xml_v2 = false;
  93 #if HWLOC_API_VERSION < 0x20000
  94     bool save_xml_v2_reqd = false;
  95 #endif
  96     bool share_topo = false;
  97     bool share_reqd = false;
  98     pmix_kval_t *kp2;
  99     char *xml;
 100     int sz;
 101     pmix_status_t rc;
 102 #if HWLOC_API_VERSION >= 0x20000
 103     pmix_hwloc_vm_hole_kind_t hole = VM_HOLE_BIGGEST;
 104 #endif
 105 
 106     if (NULL == info || 0 == ninfo) {
 107         if (0 != hwloc_topology_init(&pmix_hwloc_topology)) {
 108             return PMIX_ERR_INIT;
 109         }
 110 
 111         if (0 != set_flags(pmix_hwloc_topology, 0)) {
 112             hwloc_topology_destroy(pmix_hwloc_topology);
 113             return PMIX_ERR_INIT;
 114         }
 115 
 116         if (0 != hwloc_topology_load(pmix_hwloc_topology)) {
 117             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 118             hwloc_topology_destroy(pmix_hwloc_topology);
 119             return PMIX_ERR_NOT_SUPPORTED;
 120         }
 121         return PMIX_SUCCESS;
 122     }
 123 
 124     /* check for directives */
 125     for (n=0; n < ninfo; n++) {
 126         if (0 == strncmp(info[n].key, PMIX_TOPOLOGY, PMIX_MAX_KEYLEN)) {
 127             /* if the pointer is NULL, then they want us to
 128              * get the topology - it not NULL, then they
 129              * are giving us the topology */
 130             if (NULL != pmix_hwloc_topology) {
 131                 /* cannot have two topologies */
 132                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 133                 return PMIX_ERR_BAD_PARAM;
 134             }
 135             if (NULL != info[n].value.data.ptr) {
 136                 pmix_hwloc_topology = (hwloc_topology_t)info[n].value.data.ptr;
 137                 external_topology = true;
 138             } else {
 139                 if (0 != hwloc_topology_init(&pmix_hwloc_topology)) {
 140                     return PMIX_ERR_INIT;
 141                 }
 142 
 143                 if (0 != set_flags(pmix_hwloc_topology, 0)) {
 144                     hwloc_topology_destroy(pmix_hwloc_topology);
 145                     return PMIX_ERR_INIT;
 146                 }
 147 
 148                 if (0 != hwloc_topology_load(pmix_hwloc_topology)) {
 149                     PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 150                     hwloc_topology_destroy(pmix_hwloc_topology);
 151                     return PMIX_ERR_NOT_SUPPORTED;
 152                 }
 153             }
 154         } else if (0 == strncmp(info[n].key, PMIX_HWLOC_XML_V1, PMIX_MAX_KEYLEN)) {
 155             /* if the string pointer is NULL or empty, then they
 156              * want us to create it and store it for later sharing.
 157              * if non-NULL, then this is the topology we are to use */
 158             if (NULL == info[n].value.data.string) {
 159                 save_xml_v1 = true;
 160             } else if (NULL != pmix_hwloc_topology) {
 161                 /* cannot have two topologies */
 162                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 163                 return PMIX_ERR_BAD_PARAM;
 164             } else {
 165                 /* load the topology */
 166                 if (0 != hwloc_topology_init(&pmix_hwloc_topology)) {
 167                     return PMIX_ERROR;
 168                 }
 169                 if (0 != hwloc_topology_set_xmlbuffer(pmix_hwloc_topology,
 170                                                       info[n].value.data.string,
 171                                                       strlen(info[n].value.data.string))) {
 172                     hwloc_topology_destroy(pmix_hwloc_topology);
 173                     return PMIX_ERROR;
 174                 }
 175                 /* since we are loading this from an external source, we have to
 176                  * explicitly set a flag so hwloc sets things up correctly
 177                  */
 178                 if (0 != set_flags(pmix_hwloc_topology, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) {
 179                     hwloc_topology_destroy(pmix_hwloc_topology);
 180                     return PMIX_ERROR;
 181                 }
 182                 /* now load the topology */
 183                 if (0 != hwloc_topology_load(pmix_hwloc_topology)) {
 184                     hwloc_topology_destroy(pmix_hwloc_topology);
 185                     return PMIX_ERROR;
 186                 }
 187                 /* store the string */
 188                 kp2 = PMIX_NEW(pmix_kval_t);
 189                 if (NULL == kp2) {
 190                     return PMIX_ERR_NOMEM;
 191                 }
 192                 kp2->key = strdup(info[n].key);
 193                 PMIX_VALUE_XFER(rc, kp2->value, &info[n].value);
 194                 if (PMIX_SUCCESS != rc) {
 195                     PMIX_ERROR_LOG(rc);
 196                     PMIX_RELEASE(kp2);
 197                     return rc;
 198                 }
 199                 pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 200             }
 201         } else if (0 == strncmp(info[n].key, PMIX_HWLOC_XML_V2, PMIX_MAX_KEYLEN)) {
 202             /* if the string pointer is NULL or empty, then they
 203              * want us to create it and store it for later sharing.
 204              * if non-NULL, then this is the topology we are to use */
 205             if (NULL == info[n].value.data.string) {
 206                 save_xml_v2 = true;
 207 #if HWLOC_API_VERSION < 0x20000
 208                 save_xml_v2_reqd = PMIX_INFO_REQUIRED(&info[n]);
 209 #endif
 210             } else if (NULL != pmix_hwloc_topology) {
 211                 /* cannot have two topologies */
 212                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 213                 return PMIX_ERR_BAD_PARAM;
 214             } else {
 215                 /* load the topology */
 216                 if (0 != hwloc_topology_init(&pmix_hwloc_topology)) {
 217                     return PMIX_ERROR;
 218                 }
 219                 if (0 != hwloc_topology_set_xmlbuffer(pmix_hwloc_topology,
 220                                                       info[n].value.data.string,
 221                                                       strlen(info[n].value.data.string))) {
 222                     hwloc_topology_destroy(pmix_hwloc_topology);
 223                     return PMIX_ERROR;
 224                 }
 225                 /* since we are loading this from an external source, we have to
 226                  * explicitly set a flag so hwloc sets things up correctly
 227                  */
 228                 if (0 != set_flags(pmix_hwloc_topology, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) {
 229                     hwloc_topology_destroy(pmix_hwloc_topology);
 230                     return PMIX_ERROR;
 231                 }
 232                 /* now load the topology */
 233                 if (0 != hwloc_topology_load(pmix_hwloc_topology)) {
 234                     hwloc_topology_destroy(pmix_hwloc_topology);
 235                     return PMIX_ERROR;
 236                 }
 237                 /* store the string */
 238                 kp2 = PMIX_NEW(pmix_kval_t);
 239                 if (NULL == kp2) {
 240                     return PMIX_ERR_NOMEM;
 241                 }
 242                 kp2->key = strdup(info[n].key);
 243                 PMIX_VALUE_XFER(rc, kp2->value, &info[n].value);
 244                 if (PMIX_SUCCESS != rc) {
 245                     PMIX_ERROR_LOG(rc);
 246                     PMIX_RELEASE(kp2);
 247                     return rc;
 248                 }
 249                 pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 250             }
 251         } else if (0 == strncmp(info[n].key, PMIX_TOPOLOGY_FILE, PMIX_MAX_KEYLEN)) {
 252             if (NULL == info[n].value.data.string) {
 253                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 254                 return PMIX_ERR_BAD_PARAM;
 255             } else if (NULL != pmix_hwloc_topology) {
 256                 /* cannot have two topologies */
 257                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 258                 return PMIX_ERR_BAD_PARAM;
 259             } else {
 260                 if (0 != hwloc_topology_init(&pmix_hwloc_topology)) {
 261                     return PMIX_ERR_NOT_SUPPORTED;
 262                 }
 263                 if (0 != hwloc_topology_set_xml(pmix_hwloc_topology, info[n].value.data.string)) {
 264                     hwloc_topology_destroy(pmix_hwloc_topology);
 265                     return PMIX_ERR_NOT_SUPPORTED;
 266                 }
 267                 /* since we are loading this from an external source, we have to
 268                  * explicitly set a flag so hwloc sets things up correctly
 269                  */
 270                 if (0 != set_flags(pmix_hwloc_topology, HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)) {
 271                     hwloc_topology_destroy(pmix_hwloc_topology);
 272                     return PMIX_ERR_NOT_SUPPORTED;
 273                 }
 274                 if (0 != hwloc_topology_load(pmix_hwloc_topology)) {
 275                     hwloc_topology_destroy(pmix_hwloc_topology);
 276                      return PMIX_ERR_NOT_SUPPORTED;
 277                 }
 278                 /* store the filename */
 279                 kp2 = PMIX_NEW(pmix_kval_t);
 280                 if (NULL == kp2) {
 281                     return PMIX_ERR_NOMEM;
 282                 }
 283                 kp2->key = strdup(info[n].key);
 284                 PMIX_VALUE_XFER(rc, kp2->value, &info[n].value);
 285                 if (PMIX_SUCCESS != rc) {
 286                     PMIX_ERROR_LOG(rc);
 287                     PMIX_RELEASE(kp2);
 288                     return rc;
 289                 }
 290                 pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 291             }
 292         } else if (0 == strncmp(info[n].key, PMIX_HWLOC_SHARE_TOPO, PMIX_MAX_KEYLEN)) {
 293             share_topo = PMIX_INFO_TRUE(&info[n]);
 294             share_reqd = PMIX_INFO_IS_REQUIRED(&info[n]);
 295         } else if (0 == strncmp(info[n].key, PMIX_HWLOC_HOLE_KIND, PMIX_MAX_KEYLEN)) {
 296 #if HWLOC_API_VERSION >= 0x20000
 297             if (0 == strcasecmp(info[n].value.data.string, "none")) {
 298                 hole = VM_HOLE_NONE;
 299             } else if (0 == strcasecmp(info[n].value.data.string, "begin")) {
 300                 hole = VM_HOLE_BEGIN;
 301             } else if (0 == strcasecmp(info[n].value.data.string, "biggest")) {
 302                 hole = VM_HOLE_BIGGEST;
 303             } else if (0 == strcasecmp(info[n].value.data.string, "libs")) {
 304                 hole = VM_HOLE_IN_LIBS;
 305             } else if (0 == strcasecmp(info[n].value.data.string, "heap")) {
 306                 hole = VM_HOLE_AFTER_HEAP;
 307             } else if (0 == strcasecmp(info[n].value.data.string, "stack")) {
 308                 hole = VM_HOLE_BEFORE_STACK;
 309             } else {
 310                 PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 311                 return PMIX_ERR_BAD_PARAM;
 312             }
 313 #endif
 314         }
 315     }
 316 
 317     if (save_xml_v1) {
 318         /* create the XML string */
 319 #if HWLOC_API_VERSION >= 0x20000
 320         if (0 != hwloc_topology_export_xmlbuffer(pmix_hwloc_topology, &xml, &sz, HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)) {
 321             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 322             return PMIX_ERR_NOT_SUPPORTED;
 323         }
 324 #else
 325         if (0 != hwloc_topology_export_xmlbuffer(pmix_hwloc_topology, &xml, &sz)) {
 326             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 327             return PMIX_ERR_NOT_SUPPORTED;
 328         }
 329 #endif
 330         /* store it */
 331         kp2 = PMIX_NEW(pmix_kval_t);
 332         if (NULL == kp2) {
 333             return PMIX_ERR_NOMEM;
 334         }
 335         kp2->key = strdup(PMIX_HWLOC_XML_V1);
 336         PMIX_VALUE_LOAD(kp2->value, xml, PMIX_STRING);
 337         hwloc_free_xmlbuffer(pmix_hwloc_topology, xml);
 338         pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 339     }
 340     if (save_xml_v2) {
 341         /* create the XML string */
 342 #if HWLOC_API_VERSION >= 0x20000
 343         if (0 != hwloc_topology_export_xmlbuffer(pmix_hwloc_topology, &xml, &sz, 0)) {
 344             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 345             return PMIX_ERR_NOT_SUPPORTED;
 346         }
 347         /* store it */
 348         kp2 = PMIX_NEW(pmix_kval_t);
 349         if (NULL == kp2) {
 350             return PMIX_ERR_NOMEM;
 351         }
 352         kp2->key = strdup(PMIX_HWLOC_XML_V1);
 353         PMIX_VALUE_LOAD(kp2->value, xml, PMIX_STRING);
 354         hwloc_free_xmlbuffer(pmix_hwloc_topology, xml);
 355         pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 356 #else
 357         if (save_xml_v2_reqd) {
 358             PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 359             return PMIX_ERR_NOT_SUPPORTED;
 360         }
 361 #endif
 362     }
 363 
 364     if (share_topo) {
 365 #if HWLOC_API_VERSION < 0x20000
 366         if (share_reqd) {
 367             return PMIX_ERR_NOT_SUPPORTED;
 368         }
 369 #else
 370         pmix_status_t rc;
 371         bool space_available = false;
 372         uint64_t amount_space_avail = 0;
 373 
 374         if (VM_HOLE_NONE == hole) {
 375             return PMIX_SUCCESS;
 376         }
 377 
 378         /* get the size of the topology shared memory segment */
 379         if (0 != hwloc_shmem_topology_get_length(pmix_hwloc_topology, &shmemsize, 0)) {
 380             if (share_reqd) {
 381                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 382                 return PMIX_ERR_NOT_SUPPORTED;
 383             }
 384             return PMIX_SUCCESS;
 385         }
 386 
 387         if (PMIX_SUCCESS != (rc = find_hole(hole, &shmemaddr, shmemsize))) {
 388             /* we couldn't find a hole, so don't use the shmem support */
 389             if (share_reqd) {
 390                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 391                 return PMIX_ERR_NOT_SUPPORTED;
 392             }
 393             return PMIX_SUCCESS;
 394         }
 395         /* create the shmem file in our session dir so it
 396          * will automatically get cleaned up */
 397         asprintf(&shmemfile, "%s/hwloc.sm", pmix_server_globals.tmpdir);
 398         /* let's make sure we have enough space for the backing file */
 399         if (PMIX_SUCCESS != (rc = enough_space(shmemfile, shmemsize,
 400                                                &amount_space_avail,
 401                                                &space_available))) {
 402             free(shmemfile);
 403             shmemfile = NULL;
 404             if (share_reqd) {
 405                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 406                 return PMIX_ERR_NOT_SUPPORTED;
 407             } else {
 408                 return PMIX_SUCCESS;
 409             }
 410         }
 411         if (!space_available) {
 412             free(shmemfile);
 413             shmemfile = NULL;
 414             if (share_reqd) {
 415                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 416                 return PMIX_ERR_NOT_SUPPORTED;
 417             } else {
 418                 return PMIX_SUCCESS;
 419             }
 420         }
 421         /* enough space is available, so create the segment */
 422         if (-1 == (shmemfd = open(shmemfile, O_CREAT | O_RDWR, 0600))) {
 423             free(shmemfile);
 424             shmemfile = NULL;
 425             if (share_reqd) {
 426                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 427                 return PMIX_ERR_NOT_SUPPORTED;
 428             } else {
 429                 return PMIX_SUCCESS;
 430             }
 431         }
 432         /* ensure nobody inherits this fd */
 433         pmix_fd_set_cloexec(shmemfd);
 434         /* populate the shmem segment with the topology */
 435         if (0 != (rc = hwloc_shmem_topology_write(pmix_hwloc_topology, shmemfd, 0,
 436                                                   (void*)shmemaddr, shmemsize, 0))) {
 437             unlink(shmemfile);
 438             free(shmemfile);
 439             shmemfile = NULL;
 440             close(shmemfd);
 441             shmemfd = -1;
 442             if (share_reqd) {
 443                 PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
 444                 return PMIX_ERR_NOT_SUPPORTED;
 445             } else {
 446                 return PMIX_SUCCESS;
 447             }
 448         }
 449         /* store the rendezvous info */
 450         kp2 = PMIX_NEW(pmix_kval_t);
 451         if (NULL == kp2) {
 452             return PMIX_ERR_NOMEM;
 453         }
 454         kp2->key = strdup(PMIX_HWLOC_SHMEM_FILE);
 455         PMIX_VALUE_CREATE(kp2->value, 1);
 456         PMIX_VALUE_LOAD(kp2->value, shmemfile, PMIX_STRING);
 457         if (PMIX_SUCCESS != rc) {
 458             PMIX_ERROR_LOG(rc);
 459             PMIX_RELEASE(kp2);
 460             return rc;
 461         }
 462         pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 463         kp2 = PMIX_NEW(pmix_kval_t);
 464         if (NULL == kp2) {
 465             return PMIX_ERR_NOMEM;
 466         }
 467         kp2->key = strdup(PMIX_HWLOC_SHMEM_ADDR);
 468         PMIX_VALUE_CREATE(kp2->value, 1);
 469         PMIX_VALUE_LOAD(kp2->value, &shmemaddr, PMIX_SIZE);
 470         if (PMIX_SUCCESS != rc) {
 471             PMIX_ERROR_LOG(rc);
 472             PMIX_RELEASE(kp2);
 473             return rc;
 474         }
 475         pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 476         kp2 = PMIX_NEW(pmix_kval_t);
 477         if (NULL == kp2) {
 478             return PMIX_ERR_NOMEM;
 479         }
 480         kp2->key = strdup(PMIX_HWLOC_SHMEM_SIZE);
 481         PMIX_VALUE_CREATE(kp2->value, 1);
 482         PMIX_VALUE_LOAD(kp2->value, &shmemsize, PMIX_SIZE);
 483         if (PMIX_SUCCESS != rc) {
 484             PMIX_ERROR_LOG(rc);
 485             PMIX_RELEASE(kp2);
 486             return rc;
 487         }
 488         pmix_list_append(&pmix_server_globals.gdata, &kp2->super);
 489 
 490 
 491 #endif
 492     }
 493 
 494     return PMIX_SUCCESS;
 495 #else  // PMIX_HAVE_HWLOC
 496     return PMIX_SUCCESS;
 497 #endif
 498 }
 499 
 500 void pmix_hwloc_cleanup(void)
 501 {
 502 #if PMIX_HAVE_HWLOC
 503 #if HWLOC_API_VERSION >= 0x20000
 504     if (NULL != shmemfile) {
 505         unlink(shmemfile);
 506         free(shmemfile);
 507     }
 508     if (0 <= shmemfd) {
 509         close(shmemfd);
 510     }
 511 #endif
 512     if (NULL != pmix_hwloc_topology && !external_topology) {
 513         hwloc_topology_destroy(pmix_hwloc_topology);
 514     }
 515 #endif
 516     return;
 517 }
 518 
 519 #if PMIX_HAVE_HWLOC
 520 #if HWLOC_API_VERSION >= 0x20000
 521 
 522 static int parse_map_line(const char *line,
 523                           unsigned long *beginp,
 524                           unsigned long *endp,
 525                           pmix_hwloc_vm_map_kind_t *kindp)
 526 {
 527     const char *tmp = line, *next;
 528     unsigned long value;
 529 
 530     /* "beginaddr-endaddr " */
 531     value = strtoull(tmp, (char **) &next, 16);
 532     if (next == tmp) {
 533         return PMIX_ERROR;
 534     }
 535 
 536     *beginp = (unsigned long) value;
 537 
 538     if (*next != '-') {
 539         return PMIX_ERROR;
 540     }
 541 
 542      tmp = next + 1;
 543 
 544     value = strtoull(tmp, (char **) &next, 16);
 545     if (next == tmp) {
 546         return PMIX_ERROR;
 547     }
 548     *endp = (unsigned long) value;
 549     tmp = next;
 550 
 551     if (*next != ' ') {
 552         return PMIX_ERROR;
 553     }
 554     tmp = next + 1;
 555 
 556     /* look for ending absolute path */
 557     next = strchr(tmp, '/');
 558     if (next) {
 559         *kindp = VM_MAP_FILE;
 560     } else {
 561         /* look for ending special tag [foo] */
 562         next = strchr(tmp, '[');
 563         if (next) {
 564             if (!strncmp(next, "[heap]", 6)) {
 565                 *kindp = VM_MAP_HEAP;
 566             } else if (!strncmp(next, "[stack]", 7)) {
 567                 *kindp = VM_MAP_STACK;
 568             } else {
 569                 char *end;
 570                 if ((end = strchr(next, '\n')) != NULL) {
 571                     *end = '\0';
 572                 }
 573                 *kindp = VM_MAP_OTHER;
 574             }
 575         } else {
 576             *kindp = VM_MAP_ANONYMOUS;
 577         }
 578     }
 579 
 580     return PMIX_SUCCESS;
 581 }
 582 
 583 #define ALIGN2MB (2*1024*1024UL)
 584 
 585 static int use_hole(unsigned long holebegin,
 586                     unsigned long holesize,
 587                     unsigned long *addrp,
 588                     unsigned long size)
 589 {
 590     unsigned long aligned;
 591     unsigned long middle = holebegin+holesize/2;
 592 
 593     if (holesize < size) {
 594         return PMIX_ERROR;
 595     }
 596 
 597     /* try to align the middle of the hole on 64MB for POWER's 64k-page PMD */
 598     #define ALIGN64MB (64*1024*1024UL)
 599     aligned = (middle + ALIGN64MB) & ~(ALIGN64MB-1);
 600     if (aligned + size <= holebegin + holesize) {
 601         *addrp = aligned;
 602         return PMIX_SUCCESS;
 603     }
 604 
 605     /* try to align the middle of the hole on 2MB for x86 PMD */
 606     aligned = (middle + ALIGN2MB) & ~(ALIGN2MB-1);
 607     if (aligned + size <= holebegin + holesize) {
 608         *addrp = aligned;
 609         return PMIX_SUCCESS;
 610     }
 611 
 612     /* just use the end of the hole */
 613     *addrp = holebegin + holesize - size;
 614     return PMIX_SUCCESS;
 615 }
 616 
 617 static int find_hole(pmix_hwloc_vm_hole_kind_t hkind,
 618                      size_t *addrp, size_t size)
 619 {
 620     unsigned long biggestbegin = 0;
 621     unsigned long biggestsize = 0;
 622     unsigned long prevend = 0;
 623     pmix_hwloc_vm_map_kind_t prevmkind = VM_MAP_OTHER;
 624     int in_libs = 0;
 625     FILE *file;
 626     char line[96];
 627 
 628     file = fopen("/proc/self/maps", "r");
 629     if (!file) {
 630         return PMIX_ERROR;
 631     }
 632 
 633     while (fgets(line, sizeof(line), file) != NULL) {
 634         unsigned long begin=0, end=0;
 635         pmix_hwloc_vm_map_kind_t mkind=VM_MAP_OTHER;
 636 
 637         if (!parse_map_line(line, &begin, &end, &mkind)) {
 638             switch (hkind) {
 639                 case VM_HOLE_BEGIN:
 640                     fclose(file);
 641                     return use_hole(0, begin, addrp, size);
 642 
 643                 case VM_HOLE_AFTER_HEAP:
 644                     if (prevmkind == VM_MAP_HEAP && mkind != VM_MAP_HEAP) {
 645                         /* only use HEAP when there's no other HEAP after it
 646                          * (there can be several of them consecutively).
 647                          */
 648                         fclose(file);
 649                         return use_hole(prevend, begin-prevend, addrp, size);
 650                     }
 651                     break;
 652 
 653                 case VM_HOLE_BEFORE_STACK:
 654                     if (mkind == VM_MAP_STACK) {
 655                         fclose(file);
 656                         return use_hole(prevend, begin-prevend, addrp, size);
 657                     }
 658                     break;
 659 
 660                 case VM_HOLE_IN_LIBS:
 661                     /* see if we are between heap and stack */
 662                     if (prevmkind == VM_MAP_HEAP) {
 663                         in_libs = 1;
 664                     }
 665                     if (mkind == VM_MAP_STACK) {
 666                         in_libs = 0;
 667                     }
 668                     if (!in_libs) {
 669                         /* we're not in libs, ignore this entry */
 670                         break;
 671                     }
 672                     /* we're in libs, consider this entry for searching the biggest hole below */
 673                     /* fallthrough */
 674 
 675                 case VM_HOLE_BIGGEST:
 676                     if (begin-prevend > biggestsize) {
 677                         biggestbegin = prevend;
 678                         biggestsize = begin-prevend;
 679                     }
 680                     break;
 681 
 682                     default:
 683                         assert(0);
 684             }
 685         }
 686 
 687         while (!strchr(line, '\n')) {
 688             if (!fgets(line, sizeof(line), file)) {
 689                 goto done;
 690             }
 691         }
 692 
 693         if (mkind == VM_MAP_STACK) {
 694           /* Don't go beyond the stack. Other VMAs are special (vsyscall, vvar, vdso, etc),
 695            * There's no spare room there. And vsyscall is even above the userspace limit.
 696            */
 697           break;
 698         }
 699 
 700         prevend = end;
 701         prevmkind = mkind;
 702 
 703     }
 704 
 705   done:
 706     fclose(file);
 707     if (hkind == VM_HOLE_IN_LIBS || hkind == VM_HOLE_BIGGEST) {
 708         return use_hole(biggestbegin, biggestsize, addrp, size);
 709     }
 710 
 711     return PMIX_ERROR;
 712 }
 713 
 714 static int enough_space(const char *filename,
 715                         size_t space_req,
 716                         uint64_t *space_avail,
 717                         bool *result)
 718 {
 719     uint64_t avail = 0;
 720     size_t fluff = (size_t)(.05 * space_req);
 721     bool enough = false;
 722     char *last_sep = NULL;
 723     /* the target file name is passed here, but we need to check the parent
 724      * directory. store it so we can extract that info later. */
 725     char *target_dir = strdup(filename);
 726     int rc;
 727 
 728     if (NULL == target_dir) {
 729         rc = PMIX_ERR_OUT_OF_RESOURCE;
 730         goto out;
 731     }
 732     /* get the parent directory */
 733     last_sep = strrchr(target_dir, PMIX_PATH_SEP[0]);
 734     *last_sep = '\0';
 735     /* now check space availability */
 736     if (PMIX_SUCCESS != (rc = pmix_path_df(target_dir, &avail))) {
 737         goto out;
 738     }
 739     /* do we have enough space? */
 740     if (avail >= space_req + fluff) {
 741         enough = true;
 742     }
 743 
 744 out:
 745     if (NULL != target_dir) {
 746         free(target_dir);
 747     }
 748     *result = enough;
 749     *space_avail = avail;
 750     return rc;
 751 }
 752 #endif
 753 
 754 #endif  // PMIX_HAVE_HWLOC

/* [<][>][^][v][top][bottom][index][help] */