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
 herr_t
 ss_file_close(ss_file_t *file           /* The file to be closed */
               )
 {
     SS_ENTER(ss_file_close, herr_t);
     ss_gfile_t          *gfile=NULL;                    /* GFile array entry for the file owning the FILE object */
     ss_table_t          *table=NULL;                    /* A persistent object table */
     ss_scope_t          topscope=SS_SCOPE_NULL;         /* The top scope of FILE */
     ss_scope_t          *reg=NULL;                      /* Object registry entry */
     int                 nopen=0;                        /* Number of File objects explicitly open in this file */
     size_t              gfile_idx, nreg, reg_idx;
     htri_t              is_same;

     /* File must be explicitly open in order to be closed */
     if (ss_file_isopen(file, NULL)<=0) SS_ERROR_FMT(PERM, ("FILE is not an open file"));
     if (NULL==(gfile = SS_GFILE_LINK(file))) SS_ERROR(NOTFOUND);
     if (gfile->cur_open<=0) SS_ERROR_FMT(PERM, ("FILE is not explicitly open"));
     if (NULL==ss_file_topscope(file, &topscope)) SS_ERROR(FAILED);

     /* Flush the file before we even try anything else. We can skip this for a transient file. */
     if (!ss_file_istransient(file)) {
         if (ss_file_synchronize(file, NULL)<0) SS_ERROR(FAILED);
         if (ss_file_flush(file, NULL)<0) SS_ERROR(FAILED);
     }

     /* Look some things up before we start destroying data structures */
     if (NULL==(gfile=SS_GFILE_LINK(&topscope))) SS_ERROR(FAILED);

     /* Close the file for real if this is the last file that explicitly references the underlying HDF5 file. Do not
      * decrement the gfile->cur_open yet because some functions below will need to know that the file isn't completely
      * closed yet (e.g., ss_pers_deref()). */
     if (1==gfile->cur_open) {
         /* Find all top-level scopes that use this as a registry and remove that association */
         for (gfile_idx=0; NULL!=(gfile=SS_GFILE_IDX(gfile_idx)); gfile_idx++) {
             if (gfile->cur_open>0) {
                 nreg = gfile->reg_nused;
                 reg =  gfile->reg;
                 reg_idx = 0;
                 while (reg_idx++<nreg) {
                     if ((is_same=SS_PERS_EQ(&topscope, reg))<0) SS_ERROR(FAILED);
                     if (is_same) {
                         --nreg;
                         memmove(reg, reg+1, nreg*sizeof(*reg));
                         reg[nreg] = SS_SCOPE_NULL;
                         gfile->reg_nused -= 1;
                     } else {
                         reg++;
                     }
                 }
             }
         }

         /* Remove all this file's registries */
         gfile = SS_GFILE_LINK(&topscope);
         if (gfile->reg_nused) {
             gfile->reg_nused = 0;
             gfile->reg_nalloc = 0;
             gfile->reg = SS_FREE(gfile->reg);
         }

         /* Close all open scopes in the closing file. This removes the objects from memory (some of which may occupy a
          * substantial amount of memory) but leaves the relatively small indirect index mapping information so that any
          * persistent object that still points into the closing file will be able to convert indirect object links into direct
          * object links if necessary. It would be nice to be able to also close any File objects that might have been
          * explicitly opened, but alas, our current collectivity might not match that by which the contained File object was
          * opened and hence must be closed; but we can warn about that with some extra work. */
         if (NULL==(table=ss_scope_table(&topscope, SS_MAGIC(ss_scope_t), NULL))) SS_ERROR(FAILED);
         if (ss_table_scan(table, &topscope, 0, ss_file_close1_cb, &nopen)<0) SS_ERROR(FAILED);
         SS_ASSERT(nopen>0); /* because this file, which is File zero of the top scope, is explicitly open yet */
         if (nopen>1) SS_ERROR_FMT(USAGE, ("%d file%s still open in %s", nopen-1, 2==nopen?"":"s", gfile->name));

         /* Destroy the global blob table for this file */
         if (ss_blob_desttab(gfile->gblob)<0) SS_ERROR(FAILED);
         gfile->gblob = NULL;

         /* Close the HDF5 file (fid==1 implies transient file). This is where all those scope groups and table datasets get
          * closed since in the interest of less collectivity those functions just dropped the handles instead of closing them.
          * See the H5F_CLOSE_STRONG property in ss_file_open(). */
         if (gfile->fid>1 && H5Fclose(gfile->fid)<0) SS_ERROR(HDF5);
         gfile->fid = 0;

         /* Release other resources */
         if (gfile->dxpl_independent>0 && H5Pclose(gfile->dxpl_independent)<0) SS_ERROR(HDF5);
         gfile->dxpl_independent = 0;
         if (gfile->dxpl_collective>0 && H5Pclose(gfile->dxpl_collective)<0) SS_ERROR(HDF5);
         gfile->dxpl_collective = 0;
     }

     /* Decrement file open counter */
     --gfile->cur_open;

  SS_CLEANUP:
     SS_LEAVE(0);
 }