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
 ss_pers_t *
 ss_pers_new(ss_scope_t *scope,          /* The scope that will own this new object. */
             unsigned tableid,           /* A magic number whose sequence part defines a table */
             const ss_persobj_t *init,   /* Optional initial data of type ss_persobj_t or a type derived therefrom. The type must
                                          * be appropriate for the class of object being created. This argument can be used to
                                          * copy a persistent object. ISSUE: Should this be a link instead? */
             unsigned flags,             /* Creation flags, like SS_ALLSAME */
             ss_pers_t *buf,             /* Optional buffer for return value */
             ss_prop_t UNUSED *props     /* Additional properties (none defined yet) */
             )
 {
     SS_ENTER(ss_pers_new, ss_pers_tP);
     ss_persobj_t *persobj = NULL;
     ss_pers_t *objlink = NULL;
     size_t idxtype;
     ss_table_t *table=NULL;
     ss_pers_class_t *pc=NULL;

     tableid = SS_MAGIC_SEQUENCE(tableid);
     if (NULL==(pc=SS_PERS_CLASS(tableid))) SS_ERROR(NOTFOUND);

     /* Obtain a pointer to the table for this object. */
     if (NULL==(table = ss_scope_table(scope, tableid, NULL))) SS_ERROR(FAILED);

     /* Obtain memory for the object and initialize it.  When declaring a single new object with SS_ALLSAME we can
      * immediately give it a permanent home, evicting any temporary object that might be there, because we know all tasks have
      * the same number of permanent objects. */
     idxtype = flags & SS_ALLSAME ? 0 : SS_TABLE_INDIRECT;
     if (NULL==(persobj=ss_table_newobj(table, idxtype, init, NULL))) SS_ERROR(FAILED);
     persobj->dirty = TRUE;

     /* If an initial value was supplied then we may have to reallocate some of the resources in the new object so that they're
      * not shared between the new object and the initial object. We do this in place (hence the NULL first argument). */
     if (init && ss_val_copy(NULL, persobj, pc->valinfo_nused, pc->valinfo)<0) SS_ERROR(FAILED);

     /* If all tasks are supplying the same data then mark the object as synchronized because it will save us some work when we
      * actually do attempt to synchronize later.  We mark it with SS_ALLSAME (which is true but distinct from the constant
      * `TRUE') to indicate that we never actually synchronized but rather we just "know" that the object is in a synchronized
      * state.  It's not possible to avoid this little complication because the rule is that all synchronized objects have a
      * last-synchronized checksum stored with them but we can't compute the checksum yet because we're just now creating an
      * empty object that the user will fill in shortly.  See also ss_table_synchronize(). */
     if (flags & SS_ALLSAME) {
         persobj->synced = SS_ALLSAME;
     }

     /* Create a link to the object. This will be our return value */
     if (NULL==(objlink=ss_pers_refer(scope, persobj, buf))) SS_ERROR(FAILED);

  SS_CLEANUP:
     SS_LEAVE(objlink);
 }