/** Convert the header @a h to a string allocated from @a home. */ char *sip_header_as_string(su_home_t *home, sip_header_t const *h) { ssize_t len; char *rv, s[128]; if (h == NULL) return NULL; len = sip_header_field_e(s, sizeof(s), h, 0); if (len >= 0 && (size_t)len < sizeof(s)) return su_strdup(home, s); if (len == -1) len = 2 * sizeof(s); else len += 1; for (rv = su_alloc(home, len); rv; rv = su_realloc(home, rv, len)) { ssize_t n = sip_header_field_e(rv, len, h, 0); if (n > -1 && n + 1 <= len) break; if (n > -1) /* glibc >2.1 */ len = n + 1; else /* glibc 2.0 */ len *= 2; } return rv; }
static void sdp_printf(sdp_printer_t *p, const char *fmt, ...) { va_list ap; while (p->pr_ok) { int n; va_start(ap, fmt); n = vsnprintf(p->pr_buffer + p->pr_used, p->pr_bsiz - p->pr_used, fmt, ap); va_end(ap); if (n > -1 && (size_t)n < p->pr_bsiz - p->pr_used) { p->pr_used += n; break; } else { if (p->pr_owns_buffer) { p->pr_buffer = su_realloc(p->pr_home, p->pr_buffer, 2 * p->pr_bsiz); if (p->pr_buffer) { p->pr_bsiz = 2 * p->pr_bsiz; continue; } p->pr_owns_buffer = 0; } else if (p->pr_may_realloc) { char *buffer; size_t size; if (p->pr_bsiz < SDP_BLOCK) size = SDP_BLOCK; else size = 2 * p->pr_bsiz; buffer = su_alloc(p->pr_home, size); if (buffer) { p->pr_owns_buffer = 1; p->pr_buffer = memcpy(buffer, p->pr_buffer, p->pr_bsiz); p->pr_bsiz = size; continue; } } p->pr_ok = 0; p->pr_buffer = "Memory exhausted"; } } }
/** Increase the list size for next item, if necessary. */ static int su_vector_make_place(su_vector_t *vector, usize_t index) { if (vector->v_size <= vector->v_len + 1) { size_t newsize = 2 * vector->v_size * sizeof(vector->v_list[0]); void **list; if (newsize < vector->v_size * sizeof(vector->v_list[0])) /* overflow */ return -1; if (vector->v_list != (void **)(vector + 1) && index == vector->v_len) { if (!(list = su_realloc(vector->v_home, vector->v_list, newsize))) return 0; } else { if (!(list = su_alloc(vector->v_home, newsize))) return 0; memcpy(list, vector->v_list, index * sizeof(vector->v_list[0])); memcpy(list + index + 1, vector->v_list + index, (vector->v_len - index) * sizeof(vector->v_list[0])); if (vector->v_list != (void **)(vector + 1)) { su_free(vector->v_home, vector->v_list); } } vector->v_list = list; vector->v_size *= 2; } else { memmove(vector->v_list + index + 1, vector->v_list + index, (vector->v_len - index) * sizeof(vector->v_list[0])); } vector->v_len++; return 1; }
static int test_auto(void) { BEGIN(); int i; su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)]; char *b = NULL; su_home_stat_t hs[1]; TEST_1(!su_home_auto(tmphome, sizeof tmphome[0])); TEST_1(su_home_auto(tmphome, sizeof tmphome)); for (i = 0; i < 8192; i++) TEST_1(su_alloc(tmphome, 12)); TEST_VOID(su_home_deinit(tmphome)); TEST_1(su_home_auto(tmphome, sizeof tmphome)); su_home_init_stats(tmphome); for (i = 1; i < 8192; i++) { TEST_1(b = su_realloc(tmphome, b, i)); b[i - 1] = '\125'; } for (i = 1; i < 8192; i++) { TEST(b[i - 1], '\125'); } for (i = 1; i < 8192; i++) { TEST_1(b = su_realloc(tmphome, b, i)); b[i - 1] = '\125'; if ((i % 32) == 0) TEST_1(b = su_realloc(tmphome, b, 1)); } su_home_get_stats(tmphome, 0, hs, sizeof *hs); TEST64(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number, 8191 + 8191 + 8191 / 32); TEST64(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number, 8191 + 8191 + 8191 / 32 - 1); /* This test depends on macro SU_HOME_AUTO_SIZE() calculating offsetof(su_block_t, sub_nodes[7]) correctly with ((3 * sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof(void *)) + 7) */ TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload); su_free(tmphome, b); for (i = 1; i < 8192; i++) TEST_1(b = su_alloc(tmphome, 1)); TEST_VOID(su_home_deinit(tmphome)); END(); }
/** Test basic memory home operations */ static int test_alloc(void) { exhome_t *h0, *h1, *h2, *h3; su_home_t home[1] = { SU_HOME_INIT(home) }; su_home_t home0[1]; enum { N = 40 }; void *m0[N], *m1[N], *m; char *c, *c0, *p0, *p1; int i; enum { destructed_once = 1 }; int d0, d1a, d1, d2, d3; BEGIN(); /* su_home_init() was not initializing suh_locks */ memset(home0, 0xff, sizeof home0); TEST(su_home_init(home0), 0); TEST_VOID(su_home_deinit(home0)); TEST_1(h0 = su_home_new(sizeof(*h0))); TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1))); d0 = d1a = d1 = d2 = d3 = 0; h0->p = &d0; h1->p = &d1a; TEST(su_home_destructor(h0->home, exdestructor), 0); TEST(su_home_destructor(h1->home, exdestructor), 0); TEST_1(h2 = su_home_ref(h0->home)); su_home_unref(h0->home); TEST(d0, 0); for (i = 0; i < 128; i++) TEST_1(su_alloc(h0->home, 16)); for (i = 0; i < 128; i++) TEST_1(su_alloc(h1->home, 16)); su_home_unref(h1->home); TEST(d1a, destructed_once); TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1))); TEST(su_home_destructor(h1->home, exdestructor), 0); h1->p = &d1; for (i = 0; i < 128; i++) TEST_1(su_alloc(h1->home, 16)); for (i = 0; i < 128; i++) TEST_1(su_alloc(h2->home, 16)); su_home_unref(h2->home); /* Should call destructor of cloned home, too */ TEST(d0, destructed_once); TEST(d1, destructed_once); TEST_1(h0 = su_home_new(sizeof(*h0))); TEST_1(h1 = su_home_clone(h0->home, sizeof(*h1))); TEST_1(h2 = su_home_clone(h1->home, sizeof(*h2))); TEST_1(h3 = su_home_clone(h2->home, sizeof(*h3))); TEST(su_home_threadsafe(h0->home), 0); for (i = 0; i < N; i++) { TEST_1(m0[i] = su_zalloc(h3->home, 20)); TEST_1(m1[i] = su_zalloc(h2->home, 20)); } TEST_1(m = su_zalloc(h2->home, 20)); TEST_1(su_in_home(h2->home, m)); TEST_1(!su_in_home(h2->home, (char *)m + 1)); TEST_1(!su_in_home(h2->home, (void *)(intptr_t)su_in_home)); TEST_1(!su_in_home(h3->home, m)); TEST_1(!su_in_home(NULL, m)); TEST_1(!su_in_home(h3->home, NULL)); TEST(su_home_move(home, NULL), 0); TEST(su_home_move(NULL, home), 0); TEST(su_home_move(home, h3->home), 0); TEST(su_home_move(h2->home, h3->home), 0); TEST(su_home_move(h1->home, h2->home), 0); su_home_preload(home, 1, 1024 + 2 * 8); TEST_1(c = su_zalloc(home, 64)); p0 = c; p1 = c + 1024; c0 = c; TEST_P(c = su_realloc(home, c0, 127), c0); TEST_1(c = c0 = su_zalloc(home, 1024 - 128)); TEST_1(p0 <= c); TEST_1(c < p1); TEST_P(c = su_realloc(home, c, 128), c0); TEST_P(c = su_realloc(home, c, 1023 - 128), c0); TEST_P(c = su_realloc(home, c, 1024 - 128), c0); TEST_1(c = su_realloc(home, c, 1024)); TEST_1(c = su_realloc(home, c, 2 * 1024)); TEST_P(c = su_realloc(home, p0, 126), p0); TEST_1(c = su_realloc(home, p0, 1024)); TEST_P(c = su_realloc(home, c, 0), NULL); su_home_check(home); su_home_deinit(home); su_home_check(h2->home); su_home_zap(h2->home); su_home_check(h0->home); su_home_zap(h0->home); { su_home_t h1[1]; memset(h1, 0, sizeof h1); TEST(su_home_init(h1), 0); TEST(su_home_threadsafe(h1), 0); TEST_1(su_home_ref(h1)); TEST_1(su_home_ref(h1)); TEST(su_home_destructor(h1, test_destructor), 0); TEST_1(!su_home_unref(h1)); TEST_1(!su_home_unref(h1)); TEST_1(su_home_unref(h1)); TEST(h1->suh_size, 13); } /* Test su_home_parent() */ TEST_1(h0 = su_home_new(sizeof *h0)); TEST_1(h1 = su_home_clone(h0->home, sizeof *h1)); TEST_1(h2 = su_home_clone(h1->home, sizeof *h2)); TEST_1(h3 = su_home_clone(h2->home, sizeof *h3)); TEST_P(su_home_parent(h0->home), NULL); TEST_P(su_home_parent(h1->home), h0); TEST_P(su_home_parent(h2->home), h1); TEST_P(su_home_parent(h3->home), h2); TEST(su_home_move(h0->home, h1->home), 0); TEST_P(su_home_parent(h2->home), h0); TEST_P(su_home_parent(h3->home), h2); TEST(su_home_move(h0->home, h2->home), 0); TEST_P(su_home_parent(h3->home), h0); su_home_move(NULL, h0->home); TEST_P(su_home_parent(h0->home), NULL); TEST_P(su_home_parent(h1->home), NULL); TEST_P(su_home_parent(h2->home), NULL); TEST_P(su_home_parent(h3->home), NULL); su_home_unref(h0->home); su_home_unref(h1->home); su_home_unref(h2->home); su_home_unref(h3->home); END(); }
/** @internal * * Register a #su_wait_t object. The wait object, a callback function and * an argument pointer is stored in the port object. The callback function * will be called when the wait object is signaled. * * Please note if identical wait objects are inserted, only first one is * ever signalled. * * @param self pointer to port * @param root pointer to root object * @param waits pointer to wait object * @param callback callback function pointer * @param arg argument given to callback function when it is invoked * @param priority relative priority of the wait object * (0 is normal, 1 important, 2 realtime) * * @return * Positive index of the wait object, * or -1 upon an error. */ int su_devpoll_port_register(su_port_t *self, su_root_t *root, su_wait_t *wait, su_wakeup_f callback, su_wakeup_arg_t *arg, int priority) { int i, j, n; struct su_devpoll *ser; struct su_devpoll **indices = self->sup_indices; struct su_devpoll **devpoll_by_socket = self->sup_devpoll_by_socket; su_home_t *h = su_port_home(self); struct pollfd pollfd[1]; assert(su_port_own_thread(self)); if (wait->fd < 0) return su_seterrno(EINVAL); n = self->sup_size_indices; if (n >= SU_WAIT_MAX) return su_seterrno(ENOMEM); ser = indices[0]; if (!ser) { i = self->sup_max_index, j = i == 0 ? 15 : i + 16; if (j >= self->sup_size_indices) { /* Reallocate index table */ n = n < 1024 ? 2 * n : n + 1024; indices = su_realloc(h, indices, n * sizeof(indices[0])); if (!indices) return -1; self->sup_indices = indices; self->sup_size_indices = n; } /* Allocate registrations */ ser = su_zalloc(h, (j - i) * (sizeof *ser)); if (!ser) return -1; indices[0] = ser; for (i++; i <= j; i++) { ser->ser_id = i; ser->ser_next = i < j ? ser + 1 : NULL; indices[i] = ser++; } self->sup_max_index = j; ser = indices[0]; } if ((size_t)wait->fd >= self->sup_n_devpoll_by_socket) { size_t n_devpoll_by_socket = ((size_t)wait->fd + 32) / 32 * 32; devpoll_by_socket = su_realloc(h, devpoll_by_socket, n_devpoll_by_socket * (sizeof devpoll_by_socket[0])); if (devpoll_by_socket == NULL) return -1; memset(&devpoll_by_socket[self->sup_n_devpoll_by_socket], 0, (char *)&devpoll_by_socket[n_devpoll_by_socket] - (char *)&devpoll_by_socket[self->sup_n_devpoll_by_socket]); self->sup_devpoll_by_socket = devpoll_by_socket; self->sup_n_devpoll_by_socket = n_devpoll_by_socket; } if (devpoll_by_socket[wait->fd]) /* XXX - we should lift this limitation with epoll, too */ return errno = EEXIST, -1; i = ser->ser_id; pollfd->fd = wait->fd; pollfd->events = wait->events & ~POLLREMOVE; pollfd->revents = 0; if (write(self->sup_devpoll, pollfd, (sizeof pollfd)) != (sizeof pollfd)) { return errno = EIO, -1; } indices[0] = ser->ser_next; devpoll_by_socket[wait->fd] = ser; ser->ser_next = NULL; *ser->ser_wait = *wait; ser->ser_cb = callback; ser->ser_arg = arg; ser->ser_root = root; self->sup_registers++; self->sup_n_registrations++; return i; /* return index */ }
/** @internal * * Register a @c su_wait_t object. The wait object, a callback function and * an argument pointer is stored in the port object. The callback function * will be called when the wait object is signaled. * * Please note if identical wait objects are inserted, only first one is * ever signalled. * * @param self pointer to port * @param root pointer to root object * @param waits pointer to wait object * @param callback callback function pointer * @param arg argument given to callback function when it is invoked * @param priority relative priority of the wait object * (0 is normal, 1 important, 2 realtime) * * @return * Positive index of the wait object, * or -1 upon an error. */ int su_poll_port_register(su_port_t *self, su_root_t *root, su_wait_t *wait, su_wakeup_f callback, su_wakeup_arg_t *arg, int priority) { int i, j, n; assert(su_port_own_thread(self)); n = self->sup_n_waits; if (n >= SU_WAIT_MAX) return su_seterrno(ENOMEM); if (n >= self->sup_size_waits) { su_home_t *h = self->sup_home; /* Reallocate size arrays */ int size; int *indices; int *reverses; su_wait_t *waits; su_wakeup_f *wait_cbs; su_wakeup_arg_t **wait_args; su_root_t **wait_tasks; if (self->sup_size_waits == 0) size = su_root_size_hint; else size = 2 * self->sup_size_waits; if (size < SU_WAIT_MIN) size = SU_WAIT_MIN; /* Too large */ if (-3 - size > 0) return (errno = ENOMEM), -1; indices = su_realloc(h, self->sup_indices, (size + 1) * sizeof(*indices)); if (indices) { self->sup_indices = indices; if (self->sup_size_waits == 0) indices[0] = -1; for (i = self->sup_size_waits + 1; i <= size; i++) indices[i] = -1 - i; } reverses = su_realloc(h, self->sup_reverses, size * sizeof(*waits)); if (reverses) { for (i = self->sup_size_waits; i < size; i++) reverses[i] = -1; self->sup_reverses = reverses; } waits = su_realloc(h, self->sup_waits, size * sizeof(*waits)); if (waits) self->sup_waits = waits; wait_cbs = su_realloc(h, self->sup_wait_cbs, size * sizeof(*wait_cbs)); if (wait_cbs) self->sup_wait_cbs = wait_cbs; wait_args = su_realloc(h, self->sup_wait_args, size * sizeof(*wait_args)); if (wait_args) self->sup_wait_args = wait_args; /* Add sup_wait_roots array, if needed */ wait_tasks = su_realloc(h, self->sup_wait_roots, size * sizeof(*wait_tasks)); if (wait_tasks) self->sup_wait_roots = wait_tasks; if (!(indices && reverses && waits && wait_cbs && wait_args && wait_tasks)) { return -1; } self->sup_size_waits = size; } i = -self->sup_indices[0]; assert(i <= self->sup_size_waits); if (priority > 0) { /* Insert */ for (n = self->sup_n_waits; n > 0; n--) { j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1); self->sup_indices[j] = n; self->sup_reverses[n] = j; self->sup_waits[n] = self->sup_waits[n-1]; self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1]; self->sup_wait_args[n] = self->sup_wait_args[n-1]; self->sup_wait_roots[n] = self->sup_wait_roots[n-1]; } self->sup_pri_offset++; } else { /* Append - no need to move anything */ n = self->sup_n_waits; } self->sup_n_waits++; self->sup_indices[0] = self->sup_indices[i]; /* Free index */ self->sup_indices[i] = n; self->sup_reverses[n] = i; self->sup_waits[n] = *wait; self->sup_wait_cbs[n] = callback; self->sup_wait_args[n] = arg; self->sup_wait_roots[n] = root; self->sup_registers++; /* Just like epoll, we return -1 or positive integer */ return i; }
tagi_t* luasofia_tags_table_to_taglist(lua_State *L, int index, su_home_t *home) { int i = 0; int maxtags = TAGS_LIST_SIZE; tagi_t* tags = su_zalloc(home, sizeof(tagi_t) * maxtags); if(!lua_istable(L, index)) { tags[0].t_tag = NULL; tags[0].t_value = 0; return tags; } /* put the tag table at the stack */ lua_rawgeti(L, LUA_REGISTRYINDEX, tag_table_ref); if (lua_isnil(L, -1)) { su_free(home, tags); luaL_error(L, "Failed to get tag table!"); } if (index < 0) index--; /* first key */ lua_pushnil(L); while(lua_next(L, index) != 0) { /* 'key' at index -2 and 'value' at index -1 */ tag_type_t t_tag = NULL; tag_value_t return_value; char const *s = NULL; /* if 'value' is nil not use this tag */ if(lua_isnil(L, -1)) { /* remove 'value' and 'key' is used on the next iteration */ lua_pop(L, 1); continue; } s = lua_tostring(L, -1); /* lookup key in the tag table and push tag_type_t */ lua_pushvalue(L, -2); lua_rawget(L, -4); t_tag = lua_touserdata(L, -1); lua_pop(L, 1); if(t_scan(t_tag, home, s, &return_value) == -1) { su_free(home, tags); luaL_error(L, "Tag '%s' doesn't exist!", lua_tostring(L, -2)); } tags[i].t_tag = t_tag; tags[i++].t_value = return_value; if(i == maxtags - 1) { maxtags *= 2; tags = su_realloc(home, tags, sizeof(tagi_t) * maxtags); } /* remove 'value' and 'key' is used on the next iteration */ lua_pop(L, 1); } /* remove tag table from stack */ lua_pop(L, 1); tags[i].t_tag = NULL; tags[i].t_value = 0; return tags; }