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
 herr_t
 ss_scope_open(ss_scope_t *scope,        /* A link to a scope object, probably the result of a /find/ operation. */
               unsigned flags,           /* Various bit flags to control common scope open switches. */
               ss_prop_t *props          /* Scope opening properties (see Scope Properties). */
               )
 {
     SS_ENTER(ss_scope_open, herr_t);
     MPI_Comm            comm=SS_COMM_NULL;
     hbool_t             comm_duped=FALSE;
     ss_gfile_t          *gfile=NULL;
     unsigned            tableidx;
     ss_table_t          *table=NULL;
     const char          *scopename=NULL;

     SS_ASSERT_MEM(scope, ss_scope_t);
     if (NULL==(scopename = ss_string_ptr(SS_SCOPE_P(scope,name)))) scopename="NONAME";


     /* Check that the scope is not already open. This will only catch an error if this task had the scope open, but
      * quite often it is possible that the scope was opened only on some other task(s). The usual mistake is that all tasks
      * open the file with MPI_COMM_SELF, in which case synchronizations don't work properly. */
     if (SS_SCOPE(scope)->m.comm != SS_COMM_NULL) SS_ERROR_FMT(PERM, ("already open: %s", scopename));

 #ifndef NDEBUG
     {
         /* These things should have been set when the scope was booted. */
         SS_ASSERT(SS_SCOPE(scope)->m.gid>0);
         SS_ASSERT(SS_SCOPE(scope)->m.strings);
         for (tableidx=0; tableidx<SS_PERS_NCLASSES; tableidx++) {
             if (tableidx!=SS_MAGIC_SEQUENCE(SS_MAGIC(ss_scope_t)) && NULL!=SS_PERS_CLASS(tableidx)) {
                 SS_ASSERT(SS_SCOPE(scope)->m.table[tableidx]);
             }
         }
     }
 #endif

     /* Check FLAGS compatibility with the file */
     if (NULL==(gfile=SS_GFILE_LINK(scope)) || !gfile->topscope) SS_ERROR(NOTFOUND);
     SS_ASSERT(gfile && gfile->topscope);
     flags &= (H5F_ACC_RDWR|H5F_ACC_DEBUG); /*weed out flags except those we support*/
     flags |= (gfile->flags & H5F_ACC_TRANSIENT);
     if ((flags & H5F_ACC_RDWR) && 0==(gfile->flags & H5F_ACC_RDWR))
         SS_ERROR_FMT(PERM, ("scope cannot be writable in a read-only file: %s", scopename));

     /* Obtain the communicator */
     if (!props || NULL==ss_prop_get(props, "comm", H5T_NATIVE_MPI_COMM, &comm)) {
         SS_STATUS_OK;
         comm = SS_SCOPE(gfile->topscope)->m.comm;
         comm_duped = FALSE;
     } else if (NULL==ss_prop_get(props, "duped", H5T_NATIVE_HBOOL, &comm_duped)) {
         SS_STATUS_OK;
         comm_duped = FALSE;
     }

     /* Read all the table data for this scope. We could have delayed this but all tasks will need to have the data anyway when
      * they synchronize, which will almost certainly happen before the file is closed.  We also have the problem that MPI-IO
      * doesn't guarantee that a reader task will see data that was recently written by some other task (some file systems such
      * as POSIX do in fact garantee this, while others such as PVFS don't).  If the file is read only, then we could easily
      * delay the reading of the table until it's actually needed, but even then how often really is it that a scope will be
      * opened on multiple tasks but some table not ever accessed? */
     for (tableidx=0; tableidx<SS_PERS_NCLASSES; tableidx++) {
         if (NULL==SS_PERS_CLASS(tableidx)) continue;
         if (NULL==(table=ss_scope_table(scope, tableidx, NULL))) SS_ERROR_FMT(FAILED, ("scope=\"%s\"", scopename));
         if (ss_table_read(table, scope)<0) SS_ERROR_FMT(FAILED, ("scope=\"%s\"", scopename));
     }

     /* Assign the communicator to the scope to mark it as being opened */
     SS_SCOPE(scope)->m.comm = comm;
     SS_SCOPE(scope)->m.comm_duped = comm_duped;
     SS_SCOPE(scope)->m.flags = flags;

  SS_CLEANUP:
     if (comm_duped && comm!=SS_COMM_NULL) ss_mpi_comm_free(&comm);

     SS_LEAVE(0);
 }