~ubuntu-branches/ubuntu/trusty/syslog-ng/trusty-proposed

« back to all changes in this revision

Viewing changes to src/nvtable.c

  • Committer: Bazaar Package Importer
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2010-03-28 19:47:36 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100328194736-1ob7kh1qr0fy8b9k
Tags: 3.1.0-1
* New upstream release.
* Fix path of syslog logfile (closes: #575722) and use tty10 instead of
  vc/10 to log on console.
* Provide syslog-ng in initscript (closes: #575723).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "nvtable.h"
 
2
#include "messages.h"
 
3
 
 
4
#include <string.h>
 
5
#include <stdlib.h>
 
6
 
 
7
const gchar *null_string = "";
 
8
 
 
9
NVHandle
 
10
nv_registry_get_handle(NVRegistry *self, const gchar *name)
 
11
{
 
12
  gpointer p;
 
13
 
 
14
  p = g_hash_table_lookup(self->name_map, name);
 
15
  if (p)
 
16
    return GPOINTER_TO_UINT(p);
 
17
  return 0;
 
18
}
 
19
 
 
20
NVHandle
 
21
nv_registry_alloc_handle(NVRegistry *self, const gchar *name)
 
22
{
 
23
  gpointer p;
 
24
  NVHandleDesc stored;
 
25
  gsize len;
 
26
 
 
27
  p = g_hash_table_lookup(self->name_map, name);
 
28
  if (p)
 
29
    return GPOINTER_TO_UINT(p);
 
30
 
 
31
  len = strlen(name);
 
32
  if (len == 0)
 
33
    {
 
34
      msg_error("Name-value pairs cannot have a zero-length name",
 
35
                evt_tag_str("value", name),
 
36
                NULL);
 
37
      return 0;
 
38
    }
 
39
  else if (len > 255)
 
40
    {
 
41
      msg_error("Value names cannot be longer than 255 characters, this value will always expand to the emptry string",
 
42
                evt_tag_str("value", name),
 
43
                NULL);
 
44
      return 0;
 
45
    }
 
46
  else if (self->names->len >= 65535)
 
47
    {
 
48
      msg_error("Hard wired limit of 65535 name-value pairs have been reached, all further name-value pair will expand to nothing",
 
49
                evt_tag_str("value", name),
 
50
                NULL);
 
51
      return 0;
 
52
    }
 
53
  /* flags (2 bytes) || length (1 byte) || name (len bytes) || NUL */
 
54
  /* memory layout: flags || length || name (NUL terminated) */
 
55
  stored.flags = 0;
 
56
  stored.name_len = len;
 
57
  stored.name = g_strdup(name);
 
58
  g_array_append_val(self->names, stored);
 
59
  g_hash_table_insert(self->name_map, stored.name, GUINT_TO_POINTER(self->names->len));
 
60
  return self->names->len;
 
61
}
 
62
 
 
63
/**
 
64
 * nv_registry_add_alias:
 
65
 * @handle: a NV handle to be aliased
 
66
 * @alias: must be a caller allocated string pointing to the alias of "handle"
 
67
 **/
 
68
void
 
69
nv_registry_add_alias(NVRegistry *self, NVHandle handle, const gchar *alias)
 
70
{
 
71
  g_hash_table_insert(self->name_map, (gchar *) alias, GUINT_TO_POINTER((glong) handle));
 
72
}
 
73
 
 
74
void
 
75
nv_registry_set_handle_flags(NVRegistry *self, NVHandle handle, guint16 flags)
 
76
{
 
77
  NVHandleDesc *stored;
 
78
 
 
79
  if (G_UNLIKELY(!handle))
 
80
    return;
 
81
 
 
82
  stored = &g_array_index(self->names, NVHandleDesc, handle - 1);
 
83
  stored->flags = flags;
 
84
}
 
85
 
 
86
NVRegistry *
 
87
nv_registry_new(const gchar **static_names)
 
88
{
 
89
  NVRegistry *self = g_new0(NVRegistry, 1);
 
90
  gint i;
 
91
 
 
92
  self->name_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
 
93
  self->names = g_array_new(FALSE, FALSE, sizeof(NVHandleDesc));
 
94
  for (i = 0; static_names[i]; i++)
 
95
    {
 
96
      nv_registry_alloc_handle(self, static_names[i]);
 
97
    }
 
98
  return self;
 
99
}
 
100
 
 
101
void
 
102
nv_registry_free(NVRegistry *self)
 
103
{
 
104
  gint i;
 
105
 
 
106
  for (i = 0; i < self->names->len; i++)
 
107
    g_free(g_array_index(self->names, NVHandleDesc, i).name);
 
108
  g_array_free(self->names, TRUE);
 
109
  g_hash_table_destroy(self->name_map);
 
110
  g_free(self);
 
111
}
 
112
 
 
113
/* clonable LogMessage support with shared data pointers */
 
114
 
 
115
#define NV_TABLE_DYNVALUE_HANDLE(x)  ((x) >> 16)
 
116
#define NV_TABLE_DYNVALUE_OFS(x)  ((x) & 0xFFFF)
 
117
 
 
118
 
 
119
static inline gchar *
 
120
nv_table_get_bottom(NVTable *self)
 
121
{
 
122
  return nv_table_get_top(self) - (self->used << NV_TABLE_SCALE);
 
123
}
 
124
 
 
125
static inline gchar *
 
126
nv_table_get_ofs_table_top(NVTable *self)
 
127
{
 
128
  return (gchar *) &self->data[self->num_static_entries * sizeof(self->static_entries[0]) + self->num_dyn_entries * sizeof(guint32)];
 
129
}
 
130
 
 
131
static inline NVEntry *
 
132
nv_table_get_entry_at_ofs(NVTable *self, guint16 ofs)
 
133
{
 
134
  if (!ofs)
 
135
    return NULL;
 
136
  return (NVEntry *) (nv_table_get_top(self) - (ofs << NV_TABLE_SCALE));
 
137
}
 
138
 
 
139
static inline guint32 *
 
140
nv_table_get_dyn_entries(NVTable *self)
 
141
{
 
142
  return (guint32 *) &self->static_entries[self->num_static_entries];
 
143
}
 
144
 
 
145
static inline gboolean
 
146
nv_table_alloc_check(NVTable *self, gsize alloc_size)
 
147
{
 
148
  if (nv_table_get_bottom(self) - alloc_size < nv_table_get_ofs_table_top(self))
 
149
    return FALSE;
 
150
  return TRUE;
 
151
}
 
152
 
 
153
/* return the offset to a newly allocated payload string */
 
154
static inline NVEntry *
 
155
nv_table_alloc_value(NVTable *self, gsize alloc_size)
 
156
{
 
157
  NVEntry *entry;
 
158
 
 
159
  alloc_size = NV_TABLE_BOUND(alloc_size);
 
160
  /* alloc error, NVTable should be realloced */
 
161
  if (!nv_table_alloc_check(self, alloc_size))
 
162
    return NULL;
 
163
  self->used += alloc_size >> NV_TABLE_SCALE;
 
164
  entry = (NVEntry *) (nv_table_get_top(self) - (self->used << NV_TABLE_SCALE));
 
165
  entry->alloc_len = alloc_size >> NV_TABLE_SCALE;
 
166
  entry->indirect = FALSE;
 
167
  entry->referenced = FALSE;
 
168
  return entry;
 
169
}
 
170
 
 
171
/* we only support single indirection */
 
172
const gchar *
 
173
nv_table_resolve_indirect(NVTable *self, NVEntry *entry, gssize *length)
 
174
{
 
175
  const gchar *referenced_value;
 
176
  gssize referenced_length;
 
177
 
 
178
  referenced_value = nv_table_get_value(self, entry->vindirect.handle, &referenced_length);
 
179
  if (entry->vindirect.ofs > referenced_length)
 
180
    return null_string;
 
181
 
 
182
  /* here we assume that indirect references are only looked up with
 
183
   * non-zero terminated strings properly handled, thus the caller has
 
184
   * to supply a non-NULL value_len */
 
185
 
 
186
  *length = MIN(entry->vindirect.ofs + entry->vindirect.len, referenced_length) - entry->vindirect.ofs;
 
187
  return referenced_value + entry->vindirect.ofs;
 
188
}
 
189
 
 
190
static const inline gchar *
 
191
nv_table_resolve_entry(NVTable *self, NVEntry *entry, gssize *length)
 
192
{
 
193
  if (!entry->indirect)
 
194
    {
 
195
      if (length)
 
196
        *length = entry->vdirect.value_len;
 
197
      return entry->vdirect.data + entry->name_len + 1;
 
198
    }
 
199
  else
 
200
    return nv_table_resolve_indirect(self, entry, length);
 
201
}
 
202
 
 
203
NVEntry *
 
204
nv_table_get_entry_slow(NVTable *self, NVHandle handle, guint32 **dyn_slot)
 
205
{
 
206
  guint16 ofs;
 
207
  gint l, h, m;
 
208
  guint32 *dyn_entries = nv_table_get_dyn_entries(self);
 
209
  guint32 mv;
 
210
 
 
211
  if (!self->num_dyn_entries)
 
212
    {
 
213
      *dyn_slot = NULL;
 
214
      return NULL;
 
215
    }
 
216
 
 
217
  /* open-coded binary search */
 
218
  *dyn_slot = NULL;
 
219
  l = 0;
 
220
  h = self->num_dyn_entries - 1;
 
221
  ofs = 0;
 
222
  while (l <= h)
 
223
    {
 
224
      m = (l+h) >> 1;
 
225
      mv = NV_TABLE_DYNVALUE_HANDLE(dyn_entries[m]);
 
226
      if (mv == handle)
 
227
        {
 
228
          *dyn_slot = &dyn_entries[m];
 
229
          ofs = NV_TABLE_DYNVALUE_OFS(dyn_entries[m]);
 
230
          break;
 
231
        }
 
232
      else if (mv > handle)
 
233
        {
 
234
          h = m - 1;
 
235
        }
 
236
      else
 
237
        {
 
238
          l = m + 1;
 
239
        }
 
240
    }
 
241
 
 
242
  return nv_table_get_entry_at_ofs(self, ofs);
 
243
}
 
244
 
 
245
static gboolean
 
246
nv_table_reserve_table_entry(NVTable *self, NVHandle handle, guint32 **dyn_slot)
 
247
{
 
248
  if (G_UNLIKELY(!(*dyn_slot) && handle > self->num_static_entries))
 
249
    {
 
250
      /* this is a dynamic value */
 
251
      guint32 *dyn_entries = nv_table_get_dyn_entries(self);;
 
252
      gint l, h, m, ndx;
 
253
      gboolean found = FALSE;
 
254
 
 
255
      if (!nv_table_alloc_check(self, sizeof(dyn_entries[0])))
 
256
        return FALSE;
 
257
 
 
258
      l = 0;
 
259
      h = self->num_dyn_entries - 1;
 
260
      ndx = -1;
 
261
      while (l <= h)
 
262
        {
 
263
          guint16 mv;
 
264
 
 
265
          m = (l+h) >> 1;
 
266
          mv = NV_TABLE_DYNVALUE_HANDLE(dyn_entries[m]);
 
267
 
 
268
          if (mv == handle)
 
269
            {
 
270
              ndx = m;
 
271
              found = TRUE;
 
272
              break;
 
273
            }
 
274
          else if (mv > handle)
 
275
            {
 
276
              h = m - 1;
 
277
            }
 
278
          else
 
279
            {
 
280
              l = m + 1;
 
281
            }
 
282
        }
 
283
      /* if we find the proper slot we set that, if we don't, we insert a new entry */
 
284
      if (!found)
 
285
        ndx = l;
 
286
 
 
287
      g_assert(ndx >= 0 && ndx <= self->num_dyn_entries);
 
288
      if (ndx < self->num_dyn_entries)
 
289
        {
 
290
          memmove(&dyn_entries[ndx + 1], &dyn_entries[ndx], (self->num_dyn_entries - ndx) * sizeof(dyn_entries[0]));
 
291
        }
 
292
 
 
293
      *dyn_slot = &dyn_entries[ndx];
 
294
 
 
295
      /* we set ofs to zero here, which means that the NVEntry won't
 
296
         be found even if the slot is present in dyn_entries */
 
297
      **dyn_slot = (handle << 16) + 0;
 
298
      if (!found)
 
299
        self->num_dyn_entries++;
 
300
    }
 
301
  return TRUE;
 
302
}
 
303
 
 
304
static inline void
 
305
nv_table_set_table_entry(NVTable *self, NVHandle handle, guint16 ofs, guint32 *dyn_slot)
 
306
{
 
307
  if (G_LIKELY(handle <= self->num_static_entries))
 
308
    {
 
309
      /* this is a statically allocated value, simply store the offset */
 
310
      self->static_entries[handle-1] = ofs;
 
311
    }
 
312
  else
 
313
    {
 
314
      /* this is a dynamic value */
 
315
      *dyn_slot = (handle << 16) + ofs;
 
316
    }
 
317
}
 
318
 
 
319
static gboolean
 
320
nv_table_make_direct(NVHandle handle, NVEntry *entry, gpointer user_data)
 
321
{
 
322
  NVTable *self = (NVTable *) (((gpointer *) user_data)[0]);
 
323
  NVHandle ref_handle = GPOINTER_TO_UINT(((gpointer *) user_data)[1]);
 
324
 
 
325
  if (entry->indirect && entry->vindirect.handle == ref_handle)
 
326
    {
 
327
      const gchar *value;
 
328
      gssize value_len;
 
329
 
 
330
      value = nv_table_resolve_indirect(self, entry, &value_len);
 
331
      if (!nv_table_add_value(self, handle, entry->vindirect.name, entry->name_len, value, value_len, NULL))
 
332
        {
 
333
          /* nvtable full, but we can't realloc it ourselves,
 
334
           * propagate this back as a failure of
 
335
           * nv_table_add_value() */
 
336
 
 
337
          return TRUE;
 
338
        }
 
339
    }
 
340
  return FALSE;
 
341
}
 
342
 
 
343
gboolean
 
344
nv_table_add_value(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, const gchar *value, gsize value_len, gboolean *new_entry)
 
345
{
 
346
  NVEntry *entry;
 
347
  guint16 ofs;
 
348
  guint32 *dyn_slot;
 
349
 
 
350
  if (new_entry)
 
351
    *new_entry = FALSE;
 
352
  entry = nv_table_get_entry(self, handle, &dyn_slot);
 
353
  if (G_UNLIKELY(!entry && !new_entry && value_len == 0))
 
354
    {
 
355
      /* we don't store zero length matches unless the caller is
 
356
       * interested in whether a new entry was created. It is used by
 
357
       * the SDATA support code to decide whether a previously
 
358
       * not-present SDATA was set */
 
359
      return TRUE;
 
360
    }
 
361
  if (G_UNLIKELY(entry && !entry->indirect && entry->referenced))
 
362
    {
 
363
      gpointer data[2] = { self, GUINT_TO_POINTER((glong) handle) };
 
364
 
 
365
      if (nv_table_foreach_entry(self, nv_table_make_direct, data))
 
366
        {
 
367
          /* we had to stop iteration, which means that we were unable
 
368
           * to allocate enough space for making indirect entries
 
369
           * direct */
 
370
          return FALSE;
 
371
        }
 
372
    }
 
373
  if (G_UNLIKELY(entry && (((guint) entry->alloc_len << NV_TABLE_SCALE)) >= value_len + NV_ENTRY_DIRECT_HDR + name_len + 2))
 
374
    {
 
375
      gchar *dst;
 
376
      /* this value already exists and the new value fits in the old space */
 
377
      if (!entry->indirect)
 
378
        {
 
379
          dst = entry->vdirect.data + entry->name_len + 1;
 
380
 
 
381
          entry->vdirect.value_len = value_len;
 
382
          memcpy(dst, value, value_len);
 
383
          dst[value_len] = 0;
 
384
        }
 
385
      else
 
386
        {
 
387
          /* this was an indirect entry, convert it */
 
388
          entry->indirect = 0;
 
389
          entry->vdirect.value_len = value_len;
 
390
          entry->name_len = name_len;
 
391
          memcpy(entry->vdirect.data, name, name_len + 1);
 
392
          memcpy(entry->vdirect.data + name_len + 1, value, value_len);
 
393
          entry->vdirect.data[entry->name_len + 1 + value_len] = 0;
 
394
        }
 
395
      return TRUE;
 
396
    }
 
397
  else if (!entry && new_entry)
 
398
    *new_entry = TRUE;
 
399
 
 
400
  /* check if there's enough free space: size of the struct plus the
 
401
   * size needed for a dynamic table slot */
 
402
  if (!nv_table_reserve_table_entry(self, handle, &dyn_slot))
 
403
    return FALSE;
 
404
  entry = nv_table_alloc_value(self, NV_ENTRY_DIRECT_HDR + name_len + value_len + 2);
 
405
  if (G_UNLIKELY(!entry))
 
406
    {
 
407
      return FALSE;
 
408
    }
 
409
 
 
410
  ofs = (nv_table_get_top(self) - (gchar *) entry) >> NV_TABLE_SCALE;
 
411
  entry->vdirect.value_len = value_len;
 
412
  if (handle >= self->num_static_entries)
 
413
    {
 
414
      /* we only store the name for non-builtin values */
 
415
      entry->name_len = name_len;
 
416
      memcpy(entry->vdirect.data, name, name_len + 1);
 
417
    }
 
418
  else
 
419
    entry->name_len = 0;
 
420
  memcpy(entry->vdirect.data + entry->name_len + 1, value, value_len);
 
421
  entry->vdirect.data[entry->name_len + 1 + value_len] = 0;
 
422
 
 
423
  nv_table_set_table_entry(self, handle, ofs, dyn_slot);
 
424
  return TRUE;
 
425
}
 
426
 
 
427
gboolean
 
428
nv_table_add_value_indirect(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, NVHandle ref_handle, guint8 type, guint16 rofs, guint16 rlen, gboolean *new_entry)
 
429
{
 
430
  NVEntry *entry, *ref_entry;
 
431
  guint32 *dyn_slot;
 
432
  guint16 ofs;
 
433
 
 
434
  if (new_entry)
 
435
    *new_entry = FALSE;
 
436
  ref_entry = nv_table_get_entry(self, ref_handle, &dyn_slot);
 
437
  if (ref_entry && ref_entry->indirect)
 
438
    {
 
439
      const gchar *ref_value;
 
440
      gssize ref_length;
 
441
 
 
442
      /* NOTE: uh-oh, the to-be-referenced value is already an indirect
 
443
       * reference, this is not supported, copy the stuff */
 
444
 
 
445
      ref_value = nv_table_resolve_indirect(self, ref_entry, &ref_length);
 
446
 
 
447
      if (rofs > ref_length)
 
448
        {
 
449
          rlen = 0;
 
450
          rofs = 0;
 
451
        }
 
452
      else
 
453
        {
 
454
          rlen = MIN(rofs + rlen, ref_length) - rofs;
 
455
        }
 
456
      return nv_table_add_value(self, handle, name, name_len, ref_value + rofs, rlen, new_entry);
 
457
    }
 
458
 
 
459
  entry = nv_table_get_entry(self, handle, &dyn_slot);
 
460
  if (!entry && !new_entry && (rlen == 0 || !ref_entry))
 
461
    {
 
462
      /* we don't store zero length matches unless the caller is
 
463
       * interested in whether a new entry was created. It is used by
 
464
       * the SDATA support code to decide whether a previously
 
465
       * not-present SDATA was set */
 
466
 
 
467
      return TRUE;
 
468
    }
 
469
  if (entry && !entry->indirect && entry->referenced)
 
470
    {
 
471
      gpointer data[2] = { self, GUINT_TO_POINTER((glong) handle) };
 
472
 
 
473
      if (!nv_table_foreach_entry(self, nv_table_make_direct, data))
 
474
        return FALSE;
 
475
    }
 
476
  if (entry && (((guint) entry->alloc_len << NV_TABLE_SCALE) >= NV_ENTRY_INDIRECT_HDR + name_len + 1))
 
477
    {
 
478
      /* this value already exists and the new reference  fits in the old space */
 
479
      ref_entry->referenced = TRUE;
 
480
      entry->vindirect.handle = ref_handle;
 
481
      entry->vindirect.ofs = rofs;
 
482
      entry->vindirect.len = rlen;
 
483
      entry->vindirect.type = type;
 
484
      if (!entry->indirect)
 
485
        {
 
486
          /* previously a non-indirect entry, convert it */
 
487
          entry->indirect = 1;
 
488
          if (handle >= self->num_static_entries)
 
489
            {
 
490
              entry->name_len = name_len;
 
491
              memcpy(entry->vindirect.name, name, name_len + 1);
 
492
            }
 
493
          else
 
494
            {
 
495
              entry->name_len = 0;
 
496
            }
 
497
        }
 
498
      return TRUE;
 
499
    }
 
500
  else if (!entry && new_entry)
 
501
    *new_entry = TRUE;
 
502
 
 
503
  if (!nv_table_reserve_table_entry(self, handle, &dyn_slot))
 
504
    return FALSE;
 
505
  entry = nv_table_alloc_value(self, NV_ENTRY_INDIRECT_HDR + name_len + 1);
 
506
  if (!entry)
 
507
    {
 
508
      return FALSE;
 
509
    }
 
510
 
 
511
  ofs = (nv_table_get_top(self) - (gchar *) entry) >> NV_TABLE_SCALE;
 
512
  entry->vindirect.handle = ref_handle;
 
513
  entry->vindirect.ofs = rofs;
 
514
  entry->vindirect.len = rlen;
 
515
  entry->vindirect.type = type;
 
516
  entry->indirect = 1;
 
517
  ref_entry->referenced = TRUE;
 
518
  if (handle >= self->num_static_entries)
 
519
    {
 
520
      entry->name_len = name_len;
 
521
      memcpy(entry->vindirect.name, name, name_len + 1);
 
522
    }
 
523
  else
 
524
    entry->name_len = 0;
 
525
 
 
526
  nv_table_set_table_entry(self, handle, ofs, dyn_slot);
 
527
  return TRUE;
 
528
}
 
529
 
 
530
static gboolean
 
531
nv_table_call_foreach(NVHandle handle, NVEntry *entry, gpointer user_data)
 
532
{
 
533
  NVTable *self = (NVTable *) ((gpointer *) user_data)[0];
 
534
  NVRegistry *registry = (NVRegistry *) ((gpointer *) user_data)[1];
 
535
  NVTableForeachFunc func = ((gpointer *) user_data)[2];
 
536
  gpointer func_data = ((gpointer *) user_data)[3];
 
537
  const gchar *value;
 
538
  gssize value_len;
 
539
 
 
540
  value = nv_table_resolve_entry(self, entry, &value_len);
 
541
  return func(handle, nv_registry_get_handle_name(registry, handle, NULL), value, value_len, func_data);
 
542
}
 
543
 
 
544
gboolean
 
545
nv_table_foreach(NVTable *self, NVRegistry *registry, NVTableForeachFunc func, gpointer user_data)
 
546
{
 
547
  gpointer data[4] = { self, registry, func, user_data };
 
548
 
 
549
  return nv_table_foreach_entry(self, nv_table_call_foreach, data);
 
550
}
 
551
 
 
552
gboolean
 
553
nv_table_foreach_entry(NVTable *self, NVTableForeachEntryFunc func, gpointer user_data)
 
554
{
 
555
  guint32 *dyn_entries;
 
556
  NVEntry *entry;
 
557
  gint i;
 
558
 
 
559
  for (i = 0; i < self->num_static_entries; i++)
 
560
    {
 
561
      entry = nv_table_get_entry_at_ofs(self, self->static_entries[i]);
 
562
      if (!entry)
 
563
        continue;
 
564
 
 
565
      if (func(i + 1, entry, user_data))
 
566
        return TRUE;
 
567
    }
 
568
 
 
569
  dyn_entries = nv_table_get_dyn_entries(self);
 
570
  for (i = 0; i < self->num_dyn_entries; i++)
 
571
    {
 
572
      entry = nv_table_get_entry_at_ofs(self, NV_TABLE_DYNVALUE_OFS(dyn_entries[i]));
 
573
 
 
574
      if (!entry)
 
575
        continue;
 
576
 
 
577
      if (func(NV_TABLE_DYNVALUE_HANDLE(dyn_entries[i]), entry, user_data))
 
578
        return TRUE;
 
579
    }
 
580
 
 
581
  return FALSE;
 
582
}
 
583
 
 
584
 
 
585
NVTable *
 
586
nv_table_new(gint num_static_entries, gint num_dyn_values, gint init_length)
 
587
{
 
588
  NVTable *self;
 
589
  gsize alloc_length;
 
590
 
 
591
  alloc_length = NV_TABLE_BOUND(init_length) + NV_TABLE_BOUND(sizeof(NVTable) + num_static_entries * sizeof(self->static_entries[0]) + num_dyn_values * sizeof(guint32));
 
592
  self = (NVTable *) g_malloc(alloc_length);
 
593
 
 
594
  self->size = alloc_length >> NV_TABLE_SCALE;
 
595
  self->used = 0;
 
596
  self->num_dyn_entries = 0;
 
597
  self->num_static_entries = NV_TABLE_BOUND_NUM_STATIC(num_static_entries);
 
598
  self->ref_cnt = 1;
 
599
  memset(&self->static_entries[0], 0, self->num_static_entries * sizeof(self->static_entries[0]));
 
600
  return self;
 
601
}
 
602
 
 
603
NVTable *
 
604
nv_table_realloc(NVTable *self)
 
605
{
 
606
  gint old_size = self->size;
 
607
  NVTable *new = NULL;
 
608
 
 
609
  if (self->ref_cnt == 1)
 
610
    {
 
611
      self = g_realloc(self, old_size << (NV_TABLE_SCALE + 1));
 
612
 
 
613
      self->size <<= 1;
 
614
      memmove(NV_TABLE_ADDR(self, self->size - self->used),
 
615
              NV_TABLE_ADDR(self, old_size - self->used),
 
616
              self->used << NV_TABLE_SCALE);
 
617
    }
 
618
  else
 
619
    {
 
620
      new = g_malloc(old_size << (NV_TABLE_SCALE + 1));
 
621
 
 
622
      /* we only copy the header in this case */
 
623
      memcpy(new, self, sizeof(NVTable) + self->num_static_entries * sizeof(self->static_entries[0]) + self->num_dyn_entries * sizeof(guint32));
 
624
      self->size <<= 1;
 
625
      new->ref_cnt = 1;
 
626
 
 
627
      memmove(NV_TABLE_ADDR(new, new->size - new->used),
 
628
              NV_TABLE_ADDR(self, old_size - self->used),
 
629
              self->used << NV_TABLE_SCALE);
 
630
 
 
631
      nv_table_unref(self);
 
632
      self = new;
 
633
    }
 
634
  return self;
 
635
}
 
636
 
 
637
NVTable *
 
638
nv_table_ref(NVTable *self)
 
639
{
 
640
  self->ref_cnt++;
 
641
  return self;
 
642
}
 
643
 
 
644
void
 
645
nv_table_unref(NVTable *self)
 
646
{
 
647
  if (--self->ref_cnt == 0)
 
648
    {
 
649
      g_free(self);
 
650
    }
 
651
}
 
652
 
 
653
/**
 
654
 * nv_table_clone:
 
655
 * @self: payload to clone
 
656
 * @additional_space: specifies how much additional space is needed in
 
657
 *                    the newly allocated clone
 
658
 *
 
659
 **/
 
660
NVTable *
 
661
nv_table_clone(NVTable *self, gint additional_space)
 
662
{
 
663
  NVTable *new;
 
664
  gint new_size;
 
665
 
 
666
  if (nv_table_get_bottom(self) - nv_table_get_ofs_table_top(self) < additional_space)
 
667
    new_size = self->size;
 
668
  else
 
669
    new_size = self->size + (NV_TABLE_BOUND(additional_space) >> NV_TABLE_SCALE);
 
670
 
 
671
  new = g_malloc(new_size << NV_TABLE_SCALE);
 
672
  memcpy(new, self, sizeof(NVTable) + self->num_static_entries * sizeof(self->static_entries[0]) + self->num_dyn_entries * sizeof(guint32));
 
673
  new->size = new_size;
 
674
  new->ref_cnt = 1;
 
675
 
 
676
  memcpy(NV_TABLE_ADDR(new, new->size - new->used),
 
677
          NV_TABLE_ADDR(self, self->size - self->used),
 
678
          self->used << NV_TABLE_SCALE);
 
679
  return new;
 
680
}