Skip to content

Commit 88f0483

Browse files
committed
MT#55283 revamp calls_merge once again
Maybe this makes sense now Change-Id: I94c668969aaffd3582d94f8872106f073bb939ba
1 parent cf38ee0 commit 88f0483

4 files changed

Lines changed: 116 additions & 70 deletions

File tree

daemon/call.c

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5544,59 +5544,65 @@ call_t *call_get(const str *callid) {
55445544
return ret;
55455545
}
55465546

5547-
// obtain a reference to a second call while holding a lock to another call
5548-
// intermittently releases lock on the first call!
5549-
// return return another reference to the same call
5550-
call_t *call_get2(call_t *call1, const str *callid2) {
5551-
call_t *ret = NULL;
55525547

5553-
rwlock_unlock_w(&call1->master_lock);
5548+
// list of call IDs must be non empty
5549+
// returns all calls with lock and reference held
5550+
// returns empty list on failure
5551+
// returned list might be shorter if duplicate objects were found
5552+
// log info and memory arena point to the first call in the list
5553+
call_q calls_get(const str_q *call_ids) {
5554+
call_q ret = TYPED_GQUEUE_INIT;
5555+
5556+
if (!call_ids->length)
5557+
return ret; // empty queue
55545558

55555559
while (true) {
55565560
RWLOCK_R(&rtpe_callhash_lock);
55575561

5558-
ret = t_hash_table_lookup(rtpe_callhash, callid2);
5559-
if (!ret)
5560-
goto out;
5562+
for (auto_iter(l, call_ids->head); l; l = l->next) {
5563+
const str *callid = l->data;
55615564

5562-
if (ret == call1) {
5563-
obj_hold(ret);
5564-
goto out;
5565-
}
5565+
__auto_type call = t_hash_table_lookup(rtpe_callhash, callid);
5566+
if (!call)
5567+
goto err;
55665568

5567-
rwlock_lock_w(&call1->master_lock);
5569+
// O(n^2)
5570+
if (t_queue_find(&ret, call))
5571+
continue;
55685572

5569-
if (!rwlock_trylock_w(&ret->master_lock)) {
5570-
obj_hold(ret);
5571-
return ret;
5573+
if (rwlock_trylock_w(&call->master_lock))
5574+
goto retry;
5575+
5576+
obj_hold(call);
5577+
t_queue_push_tail(&ret, call);
55725578
}
55735579

5574-
rwlock_unlock_w(&call1->master_lock);
5575-
// try again
5580+
// success
5581+
break;
5582+
5583+
retry:
5584+
call_q_unlock_release(&ret);
55765585
}
55775586

5578-
out:
5579-
rwlock_lock_w(&call1->master_lock);
5587+
log_info_call(ret.head->data);
55805588

55815589
return ret;
5590+
5591+
err:
5592+
call_q_unlock_release(&ret);
5593+
return ret; // empty queue
55825594
}
55835595

5596+
55845597
static gboolean fragment_move(str *key, fragment_q *q, void *c) {
55855598
call_t *call = c;
55865599
t_hash_table_insert(call->sdp_fragments, key, q);
55875600
return TRUE;
55885601
}
55895602

55905603
// both calls must be locked and a reference held. call2 reference will be released if successful
5591-
bool call_merge(call_t *call, call_t *call2) {
5592-
if (!call2)
5593-
return true;
5594-
5595-
if (call == call2) {
5596-
obj_put(call2);
5597-
return true;
5598-
}
5599-
5604+
__attribute__((nonnull(1, 2)))
5605+
static bool call_merge(call_t *call, call_t *call2) {
56005606
// chcek for tag collisions: duplicate tags are a failure
56015607
for (auto_iter(l, call2->monologues.head); l; l = l->next) {
56025608
if (t_hash_table_lookup(call->tags, &l->data->tag))
@@ -5702,6 +5708,29 @@ bool call_merge(call_t *call, call_t *call2) {
57025708
return true;
57035709
}
57045710

5711+
5712+
// all calls must be unique, locked, with a reference held
5713+
// returns a single merged call on success, with the list having been cleared out
5714+
call_t *calls_merge(call_q *calls) {
5715+
__auto_type ret = t_queue_pop_head(calls);
5716+
if (!ret)
5717+
return NULL;
5718+
5719+
while (calls->length) {
5720+
__auto_type call = t_queue_pop_head(calls);
5721+
bool ok = call_merge(ret, call);
5722+
if (!ok) {
5723+
// return to list and bail
5724+
t_queue_push_head(calls, call);
5725+
t_queue_push_head(calls, ret);
5726+
return NULL;
5727+
}
5728+
}
5729+
5730+
return ret;
5731+
}
5732+
5733+
57055734
/* returns call with master_lock held in W, or possibly NULL iff opmode == OP_ANSWER */
57065735
call_t *call_get_opmode(const str *callid, enum ng_opmode opmode) {
57075736
if (opmode == OP_OFFER)
@@ -6652,3 +6681,13 @@ void call_unlock_release(call_t *c) {
66526681
rwlock_unlock_w(&c->master_lock);
66536682
obj_put(c);
66546683
}
6684+
6685+
6686+
void call_q_unlock_release(call_q *calls) {
6687+
while (calls->length) {
6688+
__auto_type call = t_queue_pop_head(calls);
6689+
if (!call)
6690+
continue;
6691+
call_unlock_release(call);
6692+
}
6693+
}

daemon/call_interfaces.c

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,19 +1451,29 @@ static const char *media_block_match(call_t **call, struct call_monologue **mono
14511451
return NULL;
14521452
}
14531453

1454-
static const char *medias_match(call_t **call, medias_q *medias,
1454+
static const char *medias_match(call_q *calls, medias_q *medias,
14551455
sdp_ng_flags *flags, ng_command_ctx_t *ctx)
14561456
{
14571457
call_ng_process_flags(flags, ctx);
14581458

14591459
if (!flags->call_id.s)
14601460
return "No call-id in message";
1461-
*call = call_get(&flags->call_id);
1462-
if (!*call)
1463-
return "Unknown call-ID";
1461+
1462+
g_auto(str_q) call_ids = TYPED_GQUEUE_INIT;
1463+
t_queue_push_tail(&call_ids, &flags->call_id);
1464+
1465+
if (flags->to_call_id.len)
1466+
t_queue_push_tail(&call_ids, &flags->to_call_id);
1467+
1468+
*calls = calls_get(&call_ids);
1469+
if (!calls->length)
1470+
return "Unknown call-ID(s)";
1471+
1472+
1473+
call_t *call = calls->head->data;
14641474

14651475
if (flags->all == ALL_ALL) {
1466-
for (__auto_type l = (*call)->medias.head; l; l = l->next) {
1476+
for (__auto_type l = call->medias.head; l; l = l->next) {
14671477
struct call_media *media = l->data;
14681478
if (!media || (media->monologue->tagtype != FROM_TAG &&
14691479
media->monologue->tagtype != TO_TAG))
@@ -1478,7 +1488,7 @@ static const char *medias_match(call_t **call, medias_q *medias,
14781488

14791489
/* is a single ml given? */
14801490
struct call_monologue *ml = NULL;
1481-
const char *err = media_match(*call, &ml, flags);
1491+
const char *err = media_match(call, &ml, flags);
14821492
if (err)
14831493
return err;
14841494
if (ml) {
@@ -1495,7 +1505,7 @@ static const char *medias_match(call_t **call, medias_q *medias,
14951505
/* handle from-tag list */
14961506
for (__auto_type l = flags->from_tags.head; l; l = l->next) {
14971507
str *s = l->data;
1498-
struct call_monologue *mlf = call_get_monologue(*call, s);
1508+
struct call_monologue *mlf = call_get_monologue(call, s);
14991509
if (!mlf) {
15001510
ilog(LOG_WARN, "Given from-tag " STR_FORMAT_M " not found", STR_FMT_M(s));
15011511
} else {
@@ -2177,14 +2187,14 @@ const char *call_subscribe_request_ng(ng_command_ctx_t *ctx) {
21772187
const char *err = NULL;
21782188
g_auto(sdp_ng_flags) flags;
21792189
char rand_buf[65];
2180-
g_autoptr(call_t) call = NULL;
2190+
g_auto(call_q) calls = TYPED_GQUEUE_INIT;
21812191
g_auto(medias_q) mq = TYPED_GQUEUE_INIT;
21822192
g_auto(str) sdp_out = STR_NULL;
21832193
parser_arg output = ctx->resp;
21842194
const ng_parser_t *parser = ctx->parser_ctx.parser;
21852195

21862196
/* get source monologue */
2187-
err = medias_match(&call, &mq, &flags, ctx);
2197+
err = medias_match(&calls, &mq, &flags, ctx);
21882198
if (err)
21892199
return err;
21902200

@@ -2206,6 +2216,8 @@ const char *call_subscribe_request_ng(ng_command_ctx_t *ctx) {
22062216
rand_hex_str(flags.to_tag.s, flags.to_tag.len / 2);
22072217
}
22082218

2219+
g_autoptr(call_t) call = t_queue_pop_head(&calls);
2220+
22092221
struct call_monologue *dest_ml = call_get_or_create_monologue(call, &flags.to_tag);
22102222

22112223
int ret = monologue_subscribe_request(&mq, dest_ml, &flags);
@@ -2372,8 +2384,6 @@ const char *call_unsubscribe_ng(ng_command_ctx_t *ctx) {
23722384

23732385
static const char *call_inject_ng(ng_command_ctx_t *ctx, bool start) {
23742386
g_auto(sdp_ng_flags) flags;
2375-
g_autoptr(call_t) call = NULL;
2376-
g_autoptr(call_t) call2 = NULL;
23772387
parser_arg input = ctx->req;
23782388
const ng_parser_t *parser = ctx->parser_ctx.parser;
23792389

@@ -2394,29 +2404,29 @@ static const char *call_inject_ng(ng_command_ctx_t *ctx, bool start) {
23942404
if (!parser->dict_get_str(input, "source-call-id", &source_call_id))
23952405
source_call_id = flags.call_id;
23962406

2397-
call = call_get(&flags.call_id);
2398-
if (!call)
2399-
return "Unknown call-ID";
2407+
g_auto(str_q) call_ids = TYPED_GQUEUE_INIT;
2408+
t_queue_push_tail(&call_ids, &flags.call_id);
2409+
t_queue_push_tail(&call_ids, &source_call_id);
24002410

2401-
call2 = call_get2(call, &source_call_id);
2402-
if (!call2)
2403-
return "Unknown source call-ID";
2411+
g_auto(call_q) calls = calls_get(&call_ids);
2412+
if (!calls.length)
2413+
return "Unknown call-ID(s)";
2414+
2415+
g_autoptr(call_t) call = calls_merge(&calls);
2416+
if (!call)
2417+
return "Failed to merge two calls into one";
24042418

24052419
struct call_monologue *dst_ml = call_get_monologue(call, &flags.to_tag);
24062420
if (!dst_ml)
24072421
return "To-tag not found";
24082422

2409-
struct call_monologue *src_ml = call_get_monologue(call2, &source_tag);
2423+
struct call_monologue *src_ml = call_get_monologue(call, &source_tag);
24102424
if (!src_ml)
24112425
return "Source-tag not found";
24122426

24132427
if (src_ml == dst_ml)
24142428
return "Trying to inject to self";
24152429

2416-
if (!call_merge(call, call2))
2417-
return "Failed to merge two calls into one";
2418-
call2 = NULL;
2419-
24202430
int ret = start
24212431
? monologue_inject_start(src_ml, dst_ml, &flags)
24222432
: monologue_inject_stop(src_ml, dst_ml, &flags);
@@ -2438,33 +2448,24 @@ const char *call_inject_stop_ng(ng_command_ctx_t *ctx) {
24382448

24392449
const char *call_connect_ng(ng_command_ctx_t *ctx) {
24402450
g_auto(sdp_ng_flags) flags;
2441-
g_autoptr(call_t) call = NULL;
2442-
g_autoptr(call_t) call2 = NULL;
2451+
g_auto(call_q) calls = TYPED_GQUEUE_INIT;
24432452
g_auto(medias_q) medias = TYPED_GQUEUE_INIT;
24442453

2445-
const char *err = medias_match(&call, &medias, &flags, ctx);
2454+
const char *err = medias_match(&calls, &medias, &flags, ctx);
24462455
if (err)
24472456
return err;
24482457

24492458
if (!flags.to_tag.s)
24502459
return "No to-tag in message";
24512460

2452-
if (flags.to_call_id.len) {
2453-
call2 = call_get2(call, &flags.to_call_id);
2454-
if (!call2)
2455-
return "Unknown to-tag call-ID";
2456-
}
2457-
else
2458-
call2 = obj_get(call);
2461+
g_autoptr(call_t) call = calls_merge(&calls);
2462+
if (!call)
2463+
return "Failed to merge two calls into one (tag collision)";
24592464

2460-
struct call_monologue *dest_ml = call_get_or_create_monologue(call2, &flags.to_tag);
2465+
struct call_monologue *dest_ml = call_get_or_create_monologue(call, &flags.to_tag);
24612466
if (!dest_ml)
24622467
return "To-tag not found";
24632468

2464-
if (!call_merge(call, call2))
2465-
return "Failed to merge two calls into one (tag collision)";
2466-
call2 = NULL; // reference released
2467-
24682469
dialogue_connect(&medias, dest_ml, &flags);
24692470

24702471
call_unlock_release_update(&call);

include/call.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -881,10 +881,10 @@ struct call_media *call_make_transform_media(struct call_monologue *ml, const st
881881
const str *media_id, const endpoint_t *remote, const str *interface);
882882
__attribute__((nonnull(1)))
883883
call_t *call_get(const str *callid);
884-
__attribute__((nonnull(1, 2)))
885-
call_t *call_get2(call_t *, const str *);
886884
__attribute__((nonnull(1)))
887-
bool call_merge(call_t *, call_t *);
885+
call_q calls_get(const str_q *);
886+
__attribute__((nonnull(1)))
887+
call_t *calls_merge(call_q *);
888888
__attribute__((nonnull(2, 3)))
889889
int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q *streams, sdp_ng_flags *flags);
890890
__attribute__((nonnull(1, 2, 3, 4)))
@@ -943,9 +943,14 @@ TYPED_GHASHTABLE(subscription_store_ht, struct call_media, struct media_subscrip
943943
media_direct_hash, media_direct_eq, NULL, media_subscription_free)
944944

945945

946+
__attribute__((nonnull(1)))
946947
void call_unlock_release(call_t *c);
947948
G_DEFINE_AUTOPTR_CLEANUP_FUNC(call_t, call_unlock_release)
948949

950+
__attribute__((nonnull(1)))
951+
void call_q_unlock_release(call_q *);
952+
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(call_q, call_q_unlock_release);
953+
949954

950955

951956
#include "str.h"

lib/str.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ typedef struct _str str;
2222

2323
TYPED_GQUEUE(charp, char)
2424
TYPED_GQUEUE(str, str)
25+
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(str_q, str_q_clear)
2526

2627

2728

0 commit comments

Comments
 (0)