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
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
 herr_t
 ss_init_func(MPI_Comm communicator      /* Library communicator defining the maximal set of MPI tasks that can be involved in
                                          * various collective SSlib function calls. However, many collective SSlib functions
                                          * can operate on a subset of this communicator. If SSlib is implicitly initialized
                                          * then MPI_COMM_WORLD is assumed. When SSlib is compiled without MPI support then the
                                          * COMMUNICATOR argument is just an integer that's ignored by this function. */
         )
 {
     SS_ENTER(ss_init_func, herr_t);
     ss_prop_t           *tfile_props=NULL;
     MPI_Comm            selfcomm=SS_COMM_SELF;
     size_t              nbits;
     int                 self=0, ntasks=1;

     /* This is `static' so that we can edit the default path directly in the library binary if necessary. */
     static char         cfile_name[2048] = SS_INSTALL_SYSCONFDIR "/include/sslib.conf\0"
                                            "*** PRECEDING STRING IS 2048 BYTES TOTAL ***";

     if (sslib_g.initialized) SS_ERROR_FMT(INIT, ("the library is already initialized"));
     sslib_g.command_fd = -1;
     sslib_g.warnings = fdopen(2, "w");

 #ifdef HAVE_PARALLEL
     MPI_Comm_rank(communicator, &self);
     MPI_Comm_size(communicator, &ntasks);
     if (MPI_Comm_dup(communicator, &(sslib_g.comm))) SS_ERROR(MPI);
 #endif

     /* Set the HDF5 automatic error reporting. We can't do this directly with H5Eset_auto() because the SS_LEAVE() macro will
      * clobber that. */
     SS_ASSERT(1==sslib_g.call_depth); /*not really necessary, but will catch any potential problems from changing SS_LEAVE() */
     _efunc = ss_err_print;
     _edata = &ss_err_cntl_g;

     /* Initialize the job-wide serial numbers. The high order bits are the MPI rank number of this task within the library
      * communicator and the low order bits are initialized to zero. Whenever you need a unique number, just increment the
      * serial number. */
     for (nbits=0; nbits<8*sizeof(sslib_g.serial) && (size_t)(ntasks-1)>>nbits!=0; nbits++) /*void*/;
     sslib_g.serial = (size_t)self << (8*sizeof(sslib_g.serial) - nbits);

     /* Configure the library first by reading the configuration file and then by processing the SSLIB_DEBUG environment
      * variable. If the library isn't installed yet then the configuration file will be located in the source directory,
      * so look in the installation directory first, then the source directory. If the file can't be found then complain but
      * don't fail. */
     if (access(cfile_name, F_OK)<0) {
         strncpy(cfile_name, SS_INSTALL_SRCDIR "/sslib/lib/sslib.conf", sizeof cfile_name);
         if (access(cfile_name, F_OK)<0) {
 #ifndef PRODUCTION_COMPILE
             fprintf(sslib_g.warnings, "SSlib-%d: unable to find sslib.conf file in %s or %s.\n",
                     self, SS_INSTALL_SYSCONFDIR "/include/", cfile_name);
             fprintf(sslib_g.warnings, "SSlib-%d: The libss binary can be edited to fix the search path.\n", self);
 #endif
             cfile_name[0] = '\0';
         }
     }
     if (cfile_name[0] && ss_config(communicator, cfile_name)<0) SS_ERROR(FAILED);
     if (ss_debug_env(communicator, NULL)<0) SS_ERROR(FAILED);

 #ifdef HAVE_PARALLEL
     /* Create the MPI error handler and set it for this communicator. We save the error handler handle because we'll also use
      * it when setting the error handler for other communicators, such as scope communicators. */
     if (!sslib_g.ignore_mpierror) {
 #if 1 /*from MPICH header file*/
         MPI_Errhandler_create(ss_err_mpierror, &(sslib_g.ehandler));
         MPI_Errhandler_set(sslib_g.comm, sslib_g.ehandler);
 #else /*from "MPI: The Complete Reference: Vol 1" by Mark Snir et al*/
         MPI_Comm_create_errhandler(ss_err_mpierror, &(sslib_g.ehandler));
         MPI_Comm_set_errhandler(sslib_g.comm, sslib_g.ehandler);
 #endif
     }
 #else
     sslib_g.comm = SS_COMM_SELF;
 #endif /*HAVE_PARALLEL*/

     /* Initialize subsystems -- we can be pretty lazy here because most of them auto initialize properly. The only time they
      * don't get initialized as they should is when a subsystem exports a global variable and that global variable is used by
      * some other subsystem before any function of that subsystem is called. */
     if (ss_mpi_init()<0) SS_ERROR(FAILED);
     if (ss_pers_init()<0) SS_ERROR(FAILED);
     if (ss_attr_init()<0) SS_ERROR(FAILED);

     /* Initialize Library-Wide 2-Phase I/O Defaults and process the SSLIB_2PIO environment variable. */
     if (ss_blob_set_2pio(NULL, NULL)<0) SS_ERROR(FAILED);

     /* Create a transient file on each task */
     if (NULL==(tfile_props=ss_prop_new(SS_PERTASK_FILENAME ".props"))) SS_ERROR(FAILED);
     if (ss_prop_add(tfile_props, "comm", H5T_NATIVE_MPI_COMM, &selfcomm)<0) SS_ERROR(FAILED);
     if (NULL==(sslib_g.temp.file=ss_file_create(SS_PERTASK_FILENAME, H5F_ACC_TRANSIENT, tfile_props))) SS_ERROR(FAILED);
     if (NULL==(sslib_g.temp.tscope=ss_file_topscope(sslib_g.temp.file, NULL))) SS_ERROR(FAILED);
     if (ss_prop_dest(tfile_props)<0) SS_ERROR(FAILED);
     tfile_props = NULL;

     /* Print the welcome banner */
     if (sslib_g.banner && 0==ss_mpi_comm_rank(communicator)) fprintf(stderr, "SSlib-0: %s\n", sslib_g.banner);

     /* All was successful. Consider the library initialized. Stuff after here uses the SSlib API. */
     sslib_g.initialized = TRUE;

  SS_CLEANUP:
     if (tfile_props) ss_prop_dest(tfile_props);
     SS_LEAVE(0);
 }