/* * This function is run in the context of the serializer. * It runs the task with a simple call and reschedules based on the result. */ static int run_task(void *data) { RAII_VAR(struct ast_sip_sched_task *, schtd, ao2_bump(data), ao2_cleanup); int res; int delay; ao2_lock(schtd); schtd->last_start = ast_tvnow(); schtd->is_running = 1; schtd->run_count++; ao2_unlock(schtd); res = schtd->task(schtd->task_data); ao2_lock(schtd); schtd->is_running = 0; schtd->last_end = ast_tvnow(); /* * Don't restart if the task returned 0 or if the interval * was set to 0 while the task was running */ if (!res || !schtd->interval) { schtd->interval = 0; ao2_unlock(schtd); ao2_unlink(tasks, schtd); return -1; } if (schtd->flags & AST_SIP_SCHED_TASK_VARIABLE) { schtd->interval = res; } if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) { delay = schtd->interval; } else { delay = schtd->interval - (ast_tvdiff_ms(schtd->last_end, schtd->last_start) % schtd->interval); } schtd->current_scheduler_id = ast_sched_add(scheduler_context, delay, push_to_serializer, (const void *)schtd); if (schtd->current_scheduler_id < 0) { schtd->interval = 0; ao2_unlock(schtd); ao2_unlink(tasks, schtd); return -1; } ao2_unlock(schtd); return 0; }
/* * \brief Send a pvt in with no locks held and get all locks * * \note NO locks should be held prior to calling this function * \note The pvt must have a ref held before calling this function * \note if outchan or outowner is set != NULL after calling this function * those channels are locked and reffed. * \note Batman. */ static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner) { struct ast_channel *chan = NULL; struct ast_channel *owner = NULL; for (;;) { ao2_lock(p); if (p->chan) { chan = p->chan; ast_channel_ref(chan); } if (p->owner) { owner = p->owner; ast_channel_ref(owner); } ao2_unlock(p); /* if we don't have both channels, then this is very easy */ if (!owner || !chan) { if (owner) { ast_channel_lock(owner); } else if(chan) { ast_channel_lock(chan); } ao2_lock(p); } else { /* lock both channels first, then get the pvt lock */ ast_channel_lock_both(chan, owner); ao2_lock(p); } /* Now that we have all the locks, validate that nothing changed */ if (p->owner != owner || p->chan != chan) { if (owner) { ast_channel_unlock(owner); owner = ast_channel_unref(owner); } if (chan) { ast_channel_unlock(chan); chan = ast_channel_unref(chan); } ao2_unlock(p); continue; } break; } *outowner = p->owner; *outchan = p->chan; }
/*! \brief Return the bridged channel of a Local channel */ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge) { struct local_pvt *p = ast_channel_tech_pvt(bridge); struct ast_channel *bridged = bridge; if (!p) { ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n", ast_channel_name(chan), ast_channel_name(bridge)); return NULL; } ao2_lock(p); if (ast_test_flag(p, LOCAL_BRIDGE)) { /* Find the opposite channel */ bridged = (bridge == p->owner ? p->chan : p->owner); /* Now see if the opposite channel is bridged to anything */ if (!bridged) { bridged = bridge; } else if (ast_channel_internal_bridged_channel(bridged)) { bridged = ast_channel_internal_bridged_channel(bridged); } } ao2_unlock(p); return bridged; }
static enum ast_timer_event timerfd_timer_get_event(int handle) { enum ast_timer_event res; struct timerfd_timer *our_timer, find_helper = { .handle = handle, }; if (handle == -1) { ast_log(LOG_ERROR, "Attempting to get event from timerfd handle -1"); return -1; } if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1; } ao2_lock(our_timer); if (our_timer->is_continuous) { res = AST_TIMING_EVENT_CONTINUOUS; } else { res = AST_TIMING_EVENT_EXPIRED; } ao2_unlock(our_timer); ao2_ref(our_timer, -1); return res; }
static struct stasis_app_command *exec_command_on_condition( struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, app_command_can_exec_cb can_exec_fn) { int retval; struct stasis_app_command *command; command_fn = command_fn ? : noop_cb; command = command_create(command_fn, data); if (!command) { return NULL; } ao2_lock(control->command_queue); if (can_exec_fn && (retval = can_exec_fn(control))) { ao2_unlock(control->command_queue); command_complete(command, retval); return command; } ao2_link_flags(control->command_queue, command, OBJ_NOLOCK); ast_cond_signal(&control->wait_cond); ao2_unlock(control->command_queue); return command; }
static int timerfd_timer_set_rate(int handle, unsigned int rate) { struct timerfd_timer *our_timer, find_helper = { .handle = handle, }; int res = 0; if (handle == -1) { ast_log(LOG_ERROR, "Attempting to set rate on timerfd handle -1"); return -1; } if (!(our_timer = ao2_find(timerfd_timers, &find_helper, OBJ_POINTER))) { ast_log(LOG_ERROR, "Couldn't find timer with handle %d\n", handle); return -1; } ao2_lock(our_timer); our_timer->saved_timer.it_value.tv_sec = 0; our_timer->saved_timer.it_value.tv_nsec = rate ? (long) (1000000000 / rate) : 0L; our_timer->saved_timer.it_interval.tv_sec = our_timer->saved_timer.it_value.tv_sec; our_timer->saved_timer.it_interval.tv_nsec = our_timer->saved_timer.it_value.tv_nsec; if (!our_timer->is_continuous) { res = timerfd_settime(handle, 0, &our_timer->saved_timer, NULL); } ao2_unlock(our_timer); ao2_ref(our_timer, -1); return res; }
void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint) { struct distributor_dialog_data *dist; ao2_wrlock(dialog_associations); dist = ao2_find(dialog_associations, dlg, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (!dist) { if (endpoint) { dist = ao2_alloc(sizeof(*dist), NULL); if (dist) { dist->dlg = dlg; dist->endpoint = endpoint; ao2_link_flags(dialog_associations, dist, OBJ_NOLOCK); ao2_ref(dist, -1); } } } else { ao2_lock(dist); dist->endpoint = endpoint; if (!dist->serializer && !dist->endpoint) { ao2_unlink_flags(dialog_associations, dist, OBJ_NOLOCK); } ao2_unlock(dist); ao2_ref(dist, -1); } ao2_unlock(dialog_associations); }
struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target) { RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup); if (target < 0) { user = ao2_callback(lot->parked_users, 0, NULL, NULL); } else { user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target); } if (!user) { return NULL; } ao2_lock(user); if (user->resolution != PARK_UNSET) { /* Abandon. Something else has resolved the parked user before we got to it. */ ao2_unlock(user); return NULL; } ao2_unlink(lot->parked_users, user); user->resolution = PARK_ANSWERED; ao2_unlock(user); parking_lot_remove_if_unused(user->lot); /* Bump the ref count by 1 since the RAII_VAR will eat the reference otherwise */ ao2_ref(user, +1); return user; }
int ast_unreal_answer(struct ast_channel *ast) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int isoutbound; int res = -1; if (!p) { return -1; } ao2_ref(p, 1); ao2_lock(p); isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p); if (isoutbound) { /* Pass along answer since somebody answered us */ struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; res = unreal_queue_frame(p, isoutbound, &answer, ast, 1); } else { ast_log(LOG_WARNING, "Huh? %s is being asked to answer?\n", ast_channel_name(ast)); } ao2_unlock(p); ao2_ref(p, -1); return res; }
int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f) { struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast); int res = -1; if (!p) { return -1; } /* Just queue for delivery to the other side */ ao2_ref(p, 1); ao2_lock(p); switch (f->frametype) { case AST_FRAME_VOICE: case AST_FRAME_VIDEO: if (got_optimized_out(ast, p)) { break; } /* fall through */ default: res = unreal_queue_frame(p, AST_UNREAL_IS_OUTBOUND(ast, p), f, ast, 1); break; } ao2_unlock(p); ao2_ref(p, -1); return res; }
void control_mark_done(struct stasis_app_control *control) { /* Locking necessary to sync with other threads adding commands to the queue. */ ao2_lock(control->command_queue); control->is_done = 1; ao2_unlock(control->command_queue); }
static void *pthread_timer_open(void) { struct pthread_timer *timer; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return NULL; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (ast_pipe_nonblock(timer->pipe)) { ao2_ref(timer, -1); return NULL; } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link_flags(pthread_timers, timer, OBJ_NOLOCK); ao2_unlock(pthread_timers); return timer; }
static int pthread_timer_disable_continuous(int handle) { struct pthread_timer *timer; if (!(timer = find_timer(handle, 0))) { errno = EINVAL; return -1; } ao2_lock(timer); if (timer->continuous) { timer->continuous = 0; if (read_pipe(timer, 1) != 0) { /* Let the errno from read_pipe propagate up */ ao2_unlock(timer); ao2_ref(timer, -1); return -1; } } ao2_unlock(timer); ao2_ref(timer, -1); return 0; }
struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func, enum ast_named_lock_type lock_type, const char *keyspace, const char *key) { struct ast_named_lock *lock = NULL; int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2; char *concat_key = ast_alloca(concat_key_buff_len); sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */ ao2_lock(named_locks); lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); if (lock) { ao2_unlock(named_locks); ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type); return lock; } lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type); if (lock) { strcpy(lock->key, concat_key); /* Safe */ ao2_link_flags(named_locks, lock, OBJ_NOLOCK); } ao2_unlock(named_locks); return lock; }
/*! \brief Function called when a contact is added */ static void mwi_contact_added(const void *object) { const struct ast_sip_contact *contact = object; struct ao2_iterator *mwi_subs; struct mwi_subscription *mwi_sub; const char *endpoint_id = ast_sorcery_object_get_id(contact->endpoint); if (ast_strlen_zero(contact->endpoint->subscription.mwi.mailboxes)) { return; } ao2_lock(unsolicited_mwi); mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK | OBJ_UNLINK); if (mwi_subs) { for (; (mwi_sub = ao2_iterator_next(mwi_subs)); ao2_cleanup(mwi_sub)) { unsubscribe(mwi_sub, NULL, 0); } ao2_iterator_destroy(mwi_subs); } create_mwi_subscriptions_for_endpoint(contact->endpoint, NULL, 0); ao2_unlock(unsolicited_mwi); mwi_contact_updated(object); }
static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct local_pvt *p = ast_channel_tech_pvt(newchan); if (!p) { return -1; } ao2_lock(p); if ((p->owner != oldchan) && (p->chan != oldchan)) { ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); ao2_unlock(p); return -1; } if (p->owner == oldchan) { p->owner = newchan; } else { p->chan = newchan; } /* Do not let a masquerade cause a Local channel to be bridged to itself! */ if (!ast_check_hangup(newchan) && ((p->owner && ast_channel_internal_bridged_channel(p->owner) == p->chan) || (p->chan && ast_channel_internal_bridged_channel(p->chan) == p->owner))) { ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n"); ao2_unlock(p); ast_queue_hangup(newchan); return -1; } ao2_unlock(p); return 0; }
static int local_write(struct ast_channel *ast, struct ast_frame *f) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res = -1; int isoutbound; if (!p) { return -1; } /* Just queue for delivery to the other side */ ao2_ref(p, 1); /* ref for local_queue_frame */ ao2_lock(p); isoutbound = IS_OUTBOUND(ast, p); if (isoutbound && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) { check_bridge(ast, p); } if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) { res = local_queue_frame(p, isoutbound, f, ast, 1); } else { ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n", ast_channel_name(ast)); res = 0; } ao2_unlock(p); ao2_ref(p, -1); return res; }
static int pthread_timer_set_rate(void *data, unsigned int rate) { struct pthread_timer *timer = data; if (rate > MAX_RATE) { ast_log(LOG_ERROR, "res_timing_pthread only supports timers at a " "max rate of %d / sec\n", MAX_RATE); errno = EINVAL; return -1; } ao2_lock(timer); if ((timer->rate = rate)) { timer->interval = roundf(1000.0 / ((float) rate)); timer->start = ast_tvnow(); timer->state = TIMER_STATE_TICKING; } else { timer->interval = 0; timer->start = ast_tv(0, 0); timer->state = TIMER_STATE_IDLE; } timer->tick_count = 0; ao2_unlock(timer); return 0; }
static int register_contact_transport_remove_cb(void *data) { struct contact_transport_monitor *monitor = data; struct ast_sip_contact *contact; struct ast_sip_aor *aor; aor = ast_sip_location_retrieve_aor(monitor->aor_name); if (!aor) { ao2_ref(monitor, -1); return 0; } ao2_lock(aor); contact = ast_sip_location_retrieve_contact(monitor->contact_name); if (contact) { ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to transport shutdown\n", contact->uri, monitor->aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact->uri, monitor->aor_name, contact->user_agent); ao2_ref(contact, -1); } ao2_unlock(aor); ao2_ref(aor, -1); ao2_ref(monitor, -1); return 0; }
int AST_OPTIONAL_API_NAME(ast_websocket_add_protocol)(const char *name, ast_websocket_callback callback) { struct websocket_protocol *protocol; ao2_lock(protocols); /* Ensure a second protocol handler is not registered for the same protocol */ if ((protocol = ao2_find(protocols, name, OBJ_KEY | OBJ_NOLOCK))) { ao2_ref(protocol, -1); ao2_unlock(protocols); return -1; } if (!(protocol = ao2_alloc(sizeof(*protocol), protocol_destroy_fn))) { ao2_unlock(protocols); return -1; } if (!(protocol->name = ast_strdup(name))) { ao2_ref(protocol, -1); ao2_unlock(protocols); return -1; } protocol->callback = callback; ao2_link_flags(protocols, protocol, OBJ_NOLOCK); ao2_unlock(protocols); ao2_ref(protocol, -1); ast_verb(2, "WebSocket registered sub-protocol '%s'\n", name); return 0; }
static void *pthread_timer_open(void) { struct pthread_timer *timer; int i; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return NULL; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (pipe(timer->pipe)) { ao2_ref(timer, -1); return NULL; } for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) { int flags = fcntl(timer->pipe[i], F_GETFL); flags |= O_NONBLOCK; fcntl(timer->pipe[i], F_SETFL, flags); } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link(pthread_timers, timer); ao2_unlock(pthread_timers); return timer; }
static int pthread_timer_open(void) { struct pthread_timer *timer; int fd; if (!(timer = ao2_alloc(sizeof(*timer), pthread_timer_destructor))) { errno = ENOMEM; return -1; } timer->pipe[PIPE_READ] = timer->pipe[PIPE_WRITE] = -1; timer->state = TIMER_STATE_IDLE; if (pipe(timer->pipe)) { ao2_ref(timer, -1); return -1; } ao2_lock(pthread_timers); if (!ao2_container_count(pthread_timers)) { ast_mutex_lock(&timing_thread.lock); ast_cond_signal(&timing_thread.cond); ast_mutex_unlock(&timing_thread.lock); } ao2_link(pthread_timers, timer); ao2_unlock(pthread_timers); fd = timer->pipe[PIPE_READ]; ao2_ref(timer, -1); return fd; }
/*! * \brief Send a message to the given application. * \param app App to send the message to. * \param message Message to send. */ void app_send(struct stasis_app *app, struct ast_json *message) { stasis_app_cb handler; char eid[20]; void *data; if (ast_json_object_set(message, "asterisk_id", ast_json_string_create( ast_eid_to_str(eid, sizeof(eid), &ast_eid_default)))) { ast_log(AST_LOG_WARNING, "Failed to append EID to outgoing event %s\n", ast_json_string_get(ast_json_object_get(message, "type"))); } /* Copy off mutable state with lock held */ ao2_lock(app); handler = app->handler; data = ao2_bump(app->data); ao2_unlock(app); /* Name is immutable; no need to copy */ if (handler) { handler(data, app->name, message); } else { ast_verb(3, "Inactive Stasis app '%s' missed message\n", app->name); } ao2_cleanup(data); }
/*! \brief Hangup a call through the local proxy channel */ static int local_hangup(struct ast_channel *ast) { struct local_pvt *p = ast_channel_tech_pvt(ast); int res; if (!p) { return -1; } /* give the pvt a ref to fulfill calling requirements. */ ao2_ref(p, +1); res = ast_unreal_hangup(&p->base, ast); if (!res) { int unlink; ao2_lock(p); unlink = !p->base.owner && !p->base.chan; ao2_unlock(p); if (unlink) { ao2_unlink(locals, p); } } ao2_ref(p, -1); return res; }
static int manager_optimize_away(struct mansession *s, const struct message *m) { const char *channel; struct local_pvt *p; struct local_pvt *found; struct ast_channel *chan; channel = astman_get_header(m, "Channel"); if (ast_strlen_zero(channel)) { astman_send_error(s, m, "'Channel' not specified."); return 0; } chan = ast_channel_get_by_name(channel); if (!chan) { astman_send_error(s, m, "Channel does not exist."); return 0; } p = ast_channel_tech_pvt(chan); ast_channel_unref(chan); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION); ao2_unlock(found); ao2_ref(found, -1); astman_send_ack(s, m, "Queued channel to be optimized away"); } else { astman_send_error(s, m, "Unable to find channel"); } return 0; }
int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq) { struct local_pvt *p; struct local_pvt *found; int res = -1; /* Sanity checks. */ if (!ast || !masq) { return -1; } ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); ast_channel_unlock(ast); found = p ? ao2_find(locals, p, 0) : NULL; if (found) { ao2_lock(found); if (found->type == LOCAL_CALL_ACTION_DIALPLAN && found->base.owner && found->base.chan && !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) { ast_channel_ref(masq); found->type = LOCAL_CALL_ACTION_MASQUERADE; found->action.masq = masq; res = 0; } ao2_unlock(found); ao2_ref(found, -1); } return res; }
struct ast_channel *ast_local_get_peer(struct ast_channel *ast) { struct local_pvt *p = ast_channel_tech_pvt(ast); struct local_pvt *found; struct ast_channel *peer; if (!p) { return NULL; } found = p ? ao2_find(locals, p, 0) : NULL; if (!found) { /* ast is either not a local channel or it has alredy been hungup */ return NULL; } ao2_lock(found); if (ast == p->base.owner) { peer = p->base.chan; } else if (ast == p->base.chan) { peer = p->base.owner; } else { peer = NULL; } if (peer) { ast_channel_ref(peer); } ao2_unlock(found); ao2_ref(found, -1); return peer; }
/*! * \brief Callback handler for Stasis application messages. */ static void app_handler(void *data, const char *app_name, struct ast_json *message) { struct event_session *session = data; int res; const char *msg_type = S_OR( ast_json_string_get(ast_json_object_get(message, "type")), ""); const char *msg_application = S_OR( ast_json_string_get(ast_json_object_get(message, "application")), ""); /* Determine if we've been replaced */ if (strcmp(msg_type, "ApplicationReplaced") == 0 && strcmp(msg_application, app_name) == 0) { ao2_find(session->websocket_apps, msg_application, OBJ_UNLINK | OBJ_NODATA); } res = ast_json_object_set(message, "application", ast_json_string_create(app_name)); if(res != 0) { return; } ao2_lock(session); if (session->ws_session) { ast_ari_websocket_session_write(session->ws_session, message); } ao2_unlock(session); }
/* Called with ast locked */ static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen) { int res = 0; struct local_pvt *p = NULL; struct ast_channel *otherchan = NULL; ast_chan_write_info_t *write_info; if (option != AST_OPTION_CHANNEL_WRITE) { return -1; } write_info = data; if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) { ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n"); return -1; } if (!strcmp(write_info->function, "CHANNEL") && !strncasecmp(write_info->data, "hangup_handler_", 15)) { /* Block CHANNEL(hangup_handler_xxx) writes to the other local channel. */ return 0; } /* get the tech pvt */ if (!(p = ast_channel_tech_pvt(ast))) { return -1; } ao2_ref(p, 1); ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */ /* get the channel we are supposed to write to */ ao2_lock(p); otherchan = (write_info->chan == p->owner) ? p->chan : p->owner; if (!otherchan || otherchan == write_info->chan) { res = -1; otherchan = NULL; ao2_unlock(p); goto setoption_cleanup; } ast_channel_ref(otherchan); /* clear the pvt lock before grabbing the channel */ ao2_unlock(p); ast_channel_lock(otherchan); res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value); ast_channel_unlock(otherchan); setoption_cleanup: if (p) { ao2_ref(p, -1); } if (otherchan) { ast_channel_unref(otherchan); } ast_channel_lock(ast); /* Lock back before we leave */ return res; }
/*! \brief Thread function that executes for multiplexed threads */ static void *multiplexed_thread_function(void *data) { struct multiplexed_thread *multiplexed_thread = data; int fds = multiplexed_thread->pipe[0]; ao2_lock(multiplexed_thread); ast_debug(1, "Starting actual thread for multiplexed thread '%p'\n", multiplexed_thread); while (multiplexed_thread->thread != AST_PTHREADT_STOP) { struct ast_channel *winner = NULL, *first = multiplexed_thread->chans[0]; int to = -1, outfd = -1; /* Move channels around so not just the first one gets priority */ memmove(multiplexed_thread->chans, multiplexed_thread->chans + 1, sizeof(struct ast_channel *) * (multiplexed_thread->service_count - 1)); multiplexed_thread->chans[multiplexed_thread->service_count - 1] = first; multiplexed_thread->waiting = 1; ao2_unlock(multiplexed_thread); winner = ast_waitfor_nandfds(multiplexed_thread->chans, multiplexed_thread->service_count, &fds, 1, NULL, &outfd, &to); multiplexed_thread->waiting = 0; ao2_lock(multiplexed_thread); if (outfd > -1) { int nudge; if (read(multiplexed_thread->pipe[0], &nudge, sizeof(nudge)) < 0) { if (errno != EINTR && errno != EAGAIN) { ast_log(LOG_WARNING, "read() failed for pipe on multiplexed thread '%p': %s\n", multiplexed_thread, strerror(errno)); } } } if (winner && winner->bridge) { ast_bridge_handle_trip(winner->bridge, NULL, winner, -1); } } multiplexed_thread->thread = AST_PTHREADT_NULL; ast_debug(1, "Stopping actual thread for multiplexed thread '%p'\n", multiplexed_thread); ao2_unlock(multiplexed_thread); ao2_ref(multiplexed_thread, -1); return NULL; }