/** @internal * * Change or query ownership of the port object. * * @param self pointer to a port object * @param op operation * * @ERRORS * @ERROR EALREADY port already has an owner (or has no owner) */ int su_pthread_port_thread(su_port_t *self, enum su_port_thread_op op) { pthread_t me = pthread_self(); switch (op) { case su_port_thread_op_is_obtained: if (self->sup_thread == 0) return 0; /* No thread has obtained the port */ else if (pthread_equal(self->sup_tid, me)) return 2; /* Current thread has obtained the port */ else return 1; /* A thread has obtained the port */ case su_port_thread_op_release: if (!self->sup_thread || !pthread_equal(self->sup_tid, me)) return errno = EALREADY, -1; self->sup_thread = 0; pthread_mutex_unlock(self->sup_obtained); return 0; case su_port_thread_op_obtain: su_home_threadsafe(su_port_home(self)); pthread_mutex_lock(self->sup_obtained); self->sup_tid = me; self->sup_thread = 1; return 0; default: return errno = ENOSYS, -1; } }
/** * Create a message. * * @relatesalso msg_s * * @param mc message class * @param flags message control flags */ msg_t *msg_create(msg_mclass_t const *mc, int flags) { msg_t *msg = su_home_new(sizeof(*msg) + mc->mc_msize); if (msg) { if ((flags & MSG_FLG_THRDSAFE) && su_home_threadsafe(msg->m_home) < 0) { su_home_unref(msg->m_home); return NULL; } msg->m_refs++; msg->m_tail = &msg->m_chain; msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr); msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa; msg->m_maxsize = 0; flags &= MSG_FLG_USERMASK; msg->m_class = mc; msg->m_oflags = flags; msg->m_object = (void *)(msg + 1); msg->m_object->msg_size = mc->mc_msize; msg->m_object->msg_flags = mc->mc_flags | flags; msg->m_object->msg_common->h_class = (void *)mc; } return msg; }
/** @internal * * Change or query ownership of the port object. * * @param self pointer to a port object * @param op operation * * @ERRORS * @ERROR EALREADY port already has an owner (or has no owner) */ static int su_source_thread(su_port_t *self, enum su_port_thread_op op) { GThread *me = g_thread_self(); switch (op) { case su_port_thread_op_is_obtained: if (self->sup_tid == me) return 2; else if (self->sup_tid) return 1; else return 0; case su_port_thread_op_release: if (self->sup_tid != me) return errno = EALREADY, -1; self->sup_tid = NULL; g_static_mutex_unlock(self->sup_obtained); return 0; case su_port_thread_op_obtain: if (su_home_threadsafe(su_port_home(self)) == -1) return -1; g_static_mutex_lock(self->sup_obtained); self->sup_tid = me; return 0; default: return errno = ENOSYS, -1; } }
/** Create a resolver cache object. * * @param n initial size of cache */ sres_cache_t *sres_cache_new(int n) { sres_cache_t *cache = su_home_new(sizeof *cache); if (cache) { su_home_threadsafe(cache->cache_home); if (sres_htable_resize(cache->cache_home, cache->cache_hash, n) < 0 || sres_heap_resize(cache->cache_home, &cache->cache_heap, 0) < 0) su_home_unref(cache->cache_home), cache = NULL; } return cache; }
static int test_lock(void) { su_home_t home[1] = { SU_HOME_INIT(home) }; BEGIN(); TEST(su_home_mutex_lock(home), -1); TEST(su_home_mutex_unlock(home), -1); TEST(su_home_lock(home), -1); TEST(su_home_trylock(home), -1); TEST(su_home_unlock(home), -1); TEST(su_home_init(home), 0); TEST(su_home_mutex_lock(home), 0); TEST(su_home_trylock(home), -1); TEST(su_home_mutex_unlock(home), 0); TEST(su_home_trylock(home), -1); TEST(su_home_threadsafe(home), 0); TEST(su_home_mutex_lock(home), 0); TEST(su_home_trylock(home), EBUSY); TEST(su_home_mutex_unlock(home), 0); TEST(su_home_lock(home), 0); TEST(su_home_trylock(home), EBUSY); TEST(su_home_unlock(home), 0); TEST(su_home_trylock(home), 0); TEST(su_home_unlock(home), 0); TEST_VOID(su_home_deinit(home)); END(); }
/** @internal Send an event to the application. */ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg, nua_event_t event, int status, char const *phrase, tagi_t const *tags) { su_msg_r sumsg = SU_MSG_R_INIT; size_t e_len, len, xtra, p_len; if (event == nua_r_ack || event == nua_i_none) return event; if (nh == nua->nua_dhandle) nh = NULL; if (nua_log->log_level >= 5) { char const *name = nua_event_name(event) + 4; char const *p = phrase ? phrase : ""; if (status == 0) SU_DEBUG_5(("nua(%p): event %s %s\n", (void *)nh, name, p)); else SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)nh, name, status, p)); } if (event == nua_r_destroy) { if (msg) msg_destroy(msg); if (status >= 200) { nh_destroy(nua, nh); } return event; } if ((event > nua_r_authenticate && event <= nua_r_ack) || event < nua_i_error || (nh && !nh->nh_valid) || (nua->nua_shutdown && event != nua_r_shutdown && !nua->nua_prefs->ngp_shutdown_events)) { if (msg) msg_destroy(msg); return event; } if (tags) { e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags); len = tl_len(tags); xtra = tl_xtra(tags, len); } else { e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0; } p_len = phrase ? strlen(phrase) + 1 : 1; if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) { nua_ee_data_t *ee = su_msg_data(sumsg); nua_event_data_t *e = ee->ee_data; void *p; if (tags) { tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len); void *b = t_end, *end = (char *)b + xtra; t = tl_dup(t, tags, &b); p = b; assert(t == t_end); assert(b == end); (void)end; } else p = e + 1; ee->ee_nua = nua_stack_ref(nua); e->e_event = event; e->e_nh = nh ? nua_handle_ref(nh) : NULL; e->e_status = status; e->e_phrase = strcpy(p, phrase ? phrase : ""); if (msg) e->e_msg = msg, su_home_threadsafe(msg_home(msg)); su_msg_deinitializer(sumsg, nua_event_deinit); su_msg_send_to(sumsg, nua->nua_client, nua_application_event); } return event; }
/** 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(); }