aura  0.1
 All Data Structures Functions Variables Modules Pages
export.c
1 #include <aura/aura.h>
2 #include <search.h>
3 
4 struct aura_export_table *aura_etable_create(struct aura_node *owner, int n)
5 {
6  /* man hsearch: recommends at least 25% more to avoid collisions */
7  int nel = n + (n / 4);
8  slog(4, SLOG_DEBUG, "etable: Creating etable for %d elements, %d hash entries", n, nel);
9  struct aura_export_table *tbl = calloc(1,
10  sizeof(struct aura_export_table) +
11  n * sizeof(struct aura_object));
12  if (!tbl)
13  return NULL;
14 
15  hcreate_r(nel, &tbl->index);
16  tbl->owner = owner;
17  tbl->next = 0;
18  tbl->size = n;
19 
20  return tbl;
21 }
22 
23 
24 void aura_etable_add(struct aura_export_table *tbl,
25  const char *name,
26  const char *argfmt,
27  const char *retfmt)
28 {
29  int ret;
30  ENTRY e, *ep;
31  int arg_valid = 1;
32  int ret_valid = 1;
33  struct aura_object *target;
34 
35  if (tbl->next >= tbl->size)
36  BUG(tbl->owner, "Internal BUG: Insufficient export table storage");
37 
38  target = aura_etable_find(tbl, name);
39  if (target != NULL)
40  BUG(tbl->owner, "Internal BUG: Duplicate export table entry: %s", name);
41 
42  target = &tbl->objects[tbl->next];
43  target->id = tbl->next++;
44  if (!name) {
45  BUG(tbl->owner, "Internal BUG: object name can't be nil");
46  } else {
47  target->name = strdup(name);
48  }
49 
50  if (argfmt)
51  target->arg_fmt = strdup(argfmt);
52  if (retfmt)
53  target->ret_fmt = strdup(retfmt);
54 
55  if ((argfmt && !target->arg_fmt) ||
56  (retfmt && !target->ret_fmt))
57  BUG(tbl->owner, "Internal allocation error");
58 
59  if (argfmt)
60  target->arg_pprinted = aura_fmt_pretty_print(argfmt, &arg_valid, &target->num_args);
61 
62  if (retfmt)
63  target->ret_pprinted = aura_fmt_pretty_print(retfmt, &ret_valid, &target->num_rets);
64 
65  target->valid = arg_valid && ret_valid;
66  if (!target->valid) {
67  slog(0, SLOG_WARN, "Object %d (%s) has corrupt export table",
68  target->id, target->name);
69  }
70  /* Calculate the sizes required */
71  target->arglen = aura_fmt_len(tbl->owner, argfmt);
72  target->retlen = aura_fmt_len(tbl->owner, retfmt);
73 
74  /* Add this shit to index */
75  e.key = target->name;
76  e.data = (char *) target;
77  ret = hsearch_r(e, ENTER, &ep, &tbl->index);
78  if (!ret)
79  BUG(tbl->owner, "Internal BUG: Error adding entry to hash table");
80 
81 }
82 
83 struct aura_object *aura_etable_find(struct aura_export_table *tbl,
84  const char *name)
85 {
86  int ret;
87  ENTRY e, *ep;
88  struct aura_object *target = NULL;
89 
90  if (!tbl)
91  return NULL;
92 
93  e.key = (char *) name;
94  e.data = NULL;
95  ret = hsearch_r(e, FIND, &ep, &tbl->index);
96  if (ret)
97  target = (struct aura_object *) ep->data;
98  return target;
99 }
100 
101 struct aura_object *aura_etable_find_id(struct aura_export_table *tbl,
102  int id)
103 {
104  if (id >= tbl->next)
105  return NULL;
106  return &tbl->objects[id];
107 }
108 
109 #define format_matches(one, two) \
110  ((!one && !two) || \
111  (one && two && strcmp(one, two)))
112 
113 static int object_is_equal(struct aura_object *one, struct aura_object *two)
114 {
115  /* Objects are considered equal if: */
116 
117  /* Names match */
118  if (strcmp(one->name, two->name) != 0)
119  return 0; /* Nope */
120 
121  /* Argument formats match */
122  if (!format_matches(one->arg_fmt, two->arg_fmt))
123  return 0;
124 
125  /* Ret formats match */
126  if (!format_matches(one->ret_fmt, two->ret_fmt))
127  return 0;
128 
129  return 1;
130 }
131 
132 static int migrate_object(struct aura_object *src, struct aura_object *dst)
133 {
134  if (!src || !dst)
135  return 0;
136 
137  if (object_is_equal(src, dst)) {
138  dst->calldonecb = src->calldonecb;
139  dst->arg = src->arg;
140  slog(4, SLOG_DEBUG, "etable: Successful migration of obj %d->%d (%s)",src->id, dst->id, dst->name);
141  return 1;
142  }
143  return 0;
144 }
145 static void etable_migrate(struct aura_export_table *old, struct aura_export_table *new)
146 {
147  int i;
148  struct aura_node *node;
149  /* Sanity checking */
150  if (!old || !new) /* Nothing to migrate */
151  return;
152  if (old->owner != new->owner)
153  BUG(old->owner, "BUG during export table migration: etable owners are not equal!");
154 
155  node = old->owner;
156 
157  /* Migration is a complex process. We need to scan tables to see if there are any
158  * differences (e.g. If the node was down for a firmware update) and move all the callbacks and
159  * their arguments to the new table before nuking the old one.
160  *
161  * If return format or arguments formats have changed, we
162  * will NOT migrate anything. This is better than keeping in a potentially broken state.
163  *
164  * The algo is somewhat smart:
165  * We first try one-to-one mapping with the same id, since it's more likely to be the case 99% of the time.
166  * If that fails - we do a hash-search of the name in the new table, and try to migrate our callbacks there
167  *
168  */
169  for(i=0; i < old->next; i++) {
170  struct aura_object *src = &old->objects[i];
171  struct aura_object *dst = &new->objects[i];
172 
173  /* One-to-one mapping */
174  if (migrate_object(src, dst))
175  continue;
176 
177  /* Try hash-search */
178  dst = aura_etable_find(new, src->name);
179  if (migrate_object(src, dst))
180  continue;
181 
182  if (src->calldonecb) {
183  /* Migration failed, object had a callback set.
184  We need to notify the application about a potential problem
185  */
186  if (node->object_migration_failed_cb)
187  node->object_migration_failed_cb(node, src,
188  node->object_migration_failed_arg);
189  else {
190  slog(1, SLOG_WARN,
191  "Migration of callbacks for object %s failed\n", src->name);
192  slog(1, SLOG_WARN,
193  "Set aura_object_migration_failed_cb() callback to disable this warning\n");
194  }
195  }
196  }
197 }
198 
199 void aura_etable_activate(struct aura_export_table *tbl)
200 {
201  struct aura_node *node = tbl->owner;
202 
203  if (aura_get_status(node) == AURA_STATUS_ONLINE) {
204  slog(0, SLOG_FATAL, "Internal BUG: Attemped to change export table when transport is online");
205  aura_panic(node);
206  }
207 
208  if (node->is_opening)
209  BUG(node, "Transport BUG: Do not call aura_etable_activate in open()");
210 
211  if (node->etable_changed_cb)
212  node->etable_changed_cb(node, node->tbl, tbl, node->etable_changed_arg);
213 
214  if (node->tbl) {
215  etable_migrate(node->tbl, tbl);
216  aura_etable_destroy(node->tbl);
217  }
218  node->tbl = tbl;
219 
220 
221 }
222 
223 void aura_etable_destroy(struct aura_export_table *tbl)
224 {
225  /* Iterate over the table and free all the strings */
226  int i;
227 
228  for (i=0; i < tbl->next; i++) {
229  struct aura_object *tmp;
230  tmp=&tbl->objects[i];
231  free(tmp->name);
232  if (tmp->arg_fmt)
233  free(tmp->arg_fmt);
234  if (tmp->ret_fmt)
235  free(tmp->ret_fmt);
236  if (tmp->arg_pprinted)
237  free(tmp->arg_pprinted);
238  if (tmp->ret_pprinted)
239  free(tmp->ret_pprinted);
240  }
241  /* Get rid of the table itself */
242  hdestroy_r(&tbl->index);
243  free(tbl);
244 }
static int aura_get_status(struct aura_node *node)
Definition: inlines.h:41