diff options
author | Lubos Dolezel <lubos@dolezel.info> | 2015-07-07 23:08:03 +0200 |
---|---|---|
committer | Lubos Dolezel <lubos@dolezel.info> | 2015-07-07 23:08:03 +0200 |
commit | 38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3 (patch) | |
tree | 14186c138dbd8c90dc94f41484c4d1b2ac1d7818 /src | |
parent | ea71ccfcfab52f74469231cab4e70552333b590a (diff) | |
download | twinkle-38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3.tar twinkle-38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3.tar.gz twinkle-38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3.tar.lz twinkle-38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3.tar.xz twinkle-38bb6b72da1d3f5cfa4c72d8bc9597229423c0e3.zip |
Partial lock rework in t_phone (#17). If the app starts crashing or freezing, this commit is probably to blame.
Diffstat (limited to 'src')
-rw-r--r-- | src/call_history.cpp | 42 | ||||
-rw-r--r-- | src/call_history.h | 10 | ||||
-rw-r--r-- | src/gui/gui.cpp | 20 | ||||
-rw-r--r-- | src/phone.cpp | 326 | ||||
-rw-r--r-- | src/phone.h | 2 | ||||
-rw-r--r-- | src/threads/mutex.cpp | 37 | ||||
-rw-r--r-- | src/threads/mutex.h | 42 |
7 files changed, 309 insertions, 170 deletions
diff --git a/src/call_history.cpp b/src/call_history.cpp index 8d1a02f..cf9ff5c 100644 --- a/src/call_history.cpp +++ b/src/call_history.cpp @@ -55,6 +55,8 @@ t_call_record::t_call_record() { } void t_call_record::renew() { + t_mutex_guard x(mutex); + mtx_class.lock(); id = next_id++; if (next_id == 65535) next_id = 1; @@ -87,6 +89,7 @@ void t_call_record::start_call(const t_request *invite, t_direction dir, { assert(invite->method == INVITE); + t_mutex_guard x(mutex); struct timeval t; gettimeofday(&t, NULL); @@ -128,6 +131,7 @@ void t_call_record::fail_call(const t_response *resp) { assert(resp->get_class() >= 3); assert(resp->hdr_cseq.method == INVITE); + t_mutex_guard x(mutex); struct timeval t; gettimeofday(&t, NULL); @@ -148,6 +152,7 @@ void t_call_record::fail_call(const t_response *resp) { void t_call_record::answer_call(const t_response *resp) { assert(resp->is_success()); + t_mutex_guard x(mutex); struct timeval t; gettimeofday(&t, NULL); @@ -166,6 +171,7 @@ void t_call_record::answer_call(const t_response *resp) { void t_call_record::end_call(t_rel_cause cause) { struct timeval t; + t_mutex_guard x(mutex); gettimeofday(&t, NULL); time_end = t.tv_sec; @@ -285,6 +291,8 @@ bool t_call_record::create_file_record(vector<string> &v) const { } bool t_call_record::populate_from_file_record(const vector<string> &v) { + t_mutex_guard x(mutex); + // Check number of fields if (v.size() != 20) return false; @@ -333,6 +341,40 @@ unsigned short t_call_record::get_id(void) const { return id; } +t_call_record::t_call_record(const t_call_record& that) { + *this = that; +} + +t_call_record& t_call_record::operator=(const t_call_record& that) { + t_mutex_guard x1(that.mutex); + t_mutex_guard x2(this->mutex); + + id = that.id; + + time_start = that.time_start; + time_answer = that.time_answer; + time_end = that.time_end; + direction = that.direction; + from_display = that.from_display; + from_uri = that.from_uri; + from_organization = that.from_organization; + to_display = that.to_display; + to_uri = that.to_uri; + to_organization = that.to_organization; + reply_to_display = that.reply_to_display; + reply_to_uri = that.reply_to_uri; + referred_by_display = that.referred_by_display; + referred_by_uri = that.referred_by_uri; + subject = that.subject; + rel_cause = that.rel_cause; + invite_resp_code = that.invite_resp_code; + invite_resp_reason = that.invite_resp_reason; + far_end_device = that.far_end_device; + user_profile = that.user_profile; + + return *this; +} + //////////////////////// // class t_call_history //////////////////////// diff --git a/src/call_history.h b/src/call_history.h index b7fd3b6..93db6be 100644 --- a/src/call_history.h +++ b/src/call_history.h @@ -82,6 +82,12 @@ public: /** Constructor. */ t_call_record(); + + /** Copy constructor */ + t_call_record(const t_call_record& that); + + /** Assignment operator */ + t_call_record& operator=(const t_call_record& that); /** * Clear current settings and get a new record id. @@ -177,6 +183,10 @@ public: /** Get the record id. */ unsigned short get_id(void) const; +private: + // Guarded by a mutex, because contents of this class are updated from other threads. + // The main thread always creates a copy (snapshot) of current state. + mutable t_mutex mutex; }; /** History of calls. */ diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 97b621e..25b2814 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -758,14 +758,14 @@ t_gui::t_gui(t_phone *_phone) : t_userintf(_phone), timerUpdateMessageSessions(N MEMMAN_NEW(mainWindow); - connect(this, SIGNAL(update_reg_status()), mainWindow, SLOT(updateRegStatus())); - connect(this, SIGNAL(update_mwi()), mainWindow, SLOT(updateMwi())); - connect(this, SIGNAL(update_state()), mainWindow, SLOT(updateState())); - connect(this, SIGNAL(mw_display(const QString&)), mainWindow, SLOT(display(const QString&))); - connect(this, SIGNAL(mw_display_header()), mainWindow, SLOT(displayHeader())); - connect(this, SIGNAL(mw_update_log(bool)), mainWindow, SLOT(updateLog(bool))); - connect(this, SIGNAL(mw_update_call_history()), mainWindow, SLOT(updateCallHistory())); - connect(this, SIGNAL(mw_update_missed_call_status(int)), mainWindow, SLOT(updateMissedCallStatus(int))); + connect(this, SIGNAL(update_reg_status()), mainWindow, SLOT(updateRegStatus()), Qt::QueuedConnection); + connect(this, SIGNAL(update_mwi()), mainWindow, SLOT(updateMwi()), Qt::QueuedConnection); + connect(this, SIGNAL(update_state()), mainWindow, SLOT(updateState()), Qt::QueuedConnection); + connect(this, SIGNAL(mw_display(const QString&)), mainWindow, SLOT(display(const QString&)), Qt::QueuedConnection); + connect(this, SIGNAL(mw_display_header()), mainWindow, SLOT(displayHeader()), Qt::QueuedConnection); + connect(this, SIGNAL(mw_update_log(bool)), mainWindow, SLOT(updateLog(bool)), Qt::QueuedConnection); + connect(this, SIGNAL(mw_update_call_history()), mainWindow, SLOT(updateCallHistory()), Qt::QueuedConnection); + connect(this, SIGNAL(mw_update_missed_call_status(int)), mainWindow, SLOT(updateMissedCallStatus(int)), Qt::QueuedConnection); } t_gui::~t_gui() { @@ -3194,7 +3194,6 @@ void t_gui::open_url_in_browser(const QString &url) { } } #endif - QProcess process; bool process_started = false; QStringList browsers; @@ -3208,8 +3207,7 @@ void t_gui::open_url_in_browser(const QString &url) { for (QStringList::Iterator it = browsers.begin(); it != browsers.end(); ++it) { - process.start(*it, QStringList(url)); - process_started = process.waitForStarted(1000); + process_started = QProcess::startDetached(*it, QStringList(url)); if (process_started) break; } diff --git a/src/phone.cpp b/src/phone.cpp index 96882c6..0022298 100644 --- a/src/phone.cpp +++ b/src/phone.cpp @@ -80,6 +80,8 @@ t_phone_user *t_transfer_data::get_phone_user(void) const { /////////// void t_phone::move_line_to_background(unsigned short lineno) { + // R/W lock is held by callers + // The line will be released in the background. It should // immediately release its RTP ports as these maybe needed // for new calls. @@ -115,6 +117,8 @@ void t_phone::move_line_to_background(unsigned short lineno) { } void t_phone::cleanup_dead_lines(void) { + t_rwmutex_writer x(lines_mtx); + // Only remove idle lines at the end of the dead pool to avoid // moving lines in the vector. while (lines.size() > NUM_CALL_LINES && lines.back()->get_state() == LS_IDLE) @@ -134,6 +138,8 @@ void t_phone::cleanup_dead_lines(void) { } void t_phone::move_releasing_lines_to_background(void) { + t_rwmutex_writer x(lines_mtx); + // NOTE: the line on the REFERRER position is not moved to the // background as a subscription may still be active. for (int i = 0; i < NUM_USER_LINES; i++) { @@ -209,6 +215,8 @@ void t_phone::cleanup_3way(void) { void t_phone::invite(t_phone_user *pu, const t_url &to_uri, const string &to_display, const string &subject, bool no_fork, bool anonymous) { + t_rwmutex_reader x(lines_mtx); + // Ignore if active line is not idle if (lines[active_line]->get_state() != LS_IDLE) { return; @@ -218,6 +226,8 @@ void t_phone::invite(t_phone_user *pu, const t_url &to_uri, const string &to_dis } void t_phone::answer(void) { + t_rwmutex_reader x(lines_mtx); + // Ignore if active line is idle if (lines[active_line]->get_state() == LS_IDLE) return; @@ -225,6 +235,8 @@ void t_phone::answer(void) { } void t_phone::reject(void) { + t_rwmutex_reader x(lines_mtx); + // Ignore if active line is idle if (lines[active_line]->get_state() == LS_IDLE) return; @@ -232,6 +244,8 @@ void t_phone::reject(void) { } void t_phone::reject(unsigned short line) { + t_rwmutex_reader x(lines_mtx); + if (line > NUM_USER_LINES) return; if (lines[line]->get_state() == LS_IDLE) return; @@ -240,6 +254,8 @@ void t_phone::reject(unsigned short line) { void t_phone::redirect(const list<t_display_url> &destinations, int code, string reason) { + t_rwmutex_reader x(lines_mtx); + // Ignore if active line is idle if (lines[active_line]->get_state() == LS_IDLE) return; @@ -247,6 +263,8 @@ void t_phone::redirect(const list<t_display_url> &destinations, int code, string } void t_phone::end_call(void) { + t_rwmutex_writer x(lines_mtx); + // If 3-way is active then end call on both lines if (is_3way && ( active_line == line1_3way->get_line_number() || @@ -263,6 +281,8 @@ void t_phone::end_call(void) { move_line_to_background(lineno1); move_line_to_background(lineno2); } else { + t_rwmutex_reader x(lines_mtx); + // Hangup the active line, and make the next // line active. int l = active_line; @@ -278,6 +298,7 @@ void t_phone::end_call(void) { if (lines.at(active_line)->get_state() == LS_IDLE) return; lines.at(active_line)->end_call(); + move_line_to_background(active_line); } @@ -292,6 +313,8 @@ void t_phone::options(t_phone_user *pu, const t_url &to_uri, const string &to_di } void t_phone::options(void) { + t_rwmutex_reader x(lines_mtx); + lines[active_line]->options(); } @@ -304,19 +327,24 @@ bool t_phone::hold(bool rtponly) { return false; } + t_rwmutex_reader x(lines_mtx); return lines[active_line]->hold(rtponly); } void t_phone::retrieve(void) { + t_rwmutex_reader x(lines_mtx); lines[active_line]->retrieve(); } void t_phone::refer(const t_url &uri, const string &display) { + t_rwmutex_reader x(lines_mtx); lines[active_line]->refer(uri, display); } void t_phone::refer(unsigned short lineno_from, unsigned short lineno_to) { + t_rwmutex_reader x(lines_mtx); + // The nicest transfer is an attended transfer. An attended transfer // is only possible of the transfer target supports the 'replaces' // extension (RFC 3891). @@ -349,6 +377,8 @@ void t_phone::refer(unsigned short lineno_from, unsigned short lineno_to) // See draft-ietf-sipping-cc-transfer-07 7.3 void t_phone::refer_attended(unsigned short lineno_from, unsigned short lineno_to) { + t_rwmutex_reader x(lines_mtx); + t_line *line = lines.at(lineno_to); switch (line->get_substate()) @@ -435,6 +465,7 @@ void t_phone::refer_attended(unsigned short lineno_from, unsigned short lineno_t // See draft-ietf-sipping-cc-transfer-07 7 void t_phone::refer_consultation(unsigned short lineno_from, unsigned short lineno_to) { + t_rwmutex_writer x(lines_mtx); t_line *line = lines.at(lineno_to); if (line->get_substate() != LSSUB_ESTABLISHED) { @@ -447,6 +478,7 @@ void t_phone::refer_consultation(unsigned short lineno_from, unsigned short line // End consultation call line->end_call(); + move_line_to_background(lineno_to); // Transfer call @@ -506,6 +538,7 @@ void t_phone::setup_consultation_call(const t_url &uri, const string &display) { invite(pu, uri, display, subject, no_fork, false); + t_rwmutex_reader x(lines_mtx); lines.at(consult_line)->set_is_transfer_consult(true, xfer_line); lines.at(xfer_line)->set_to_be_transferred(true, consult_line); @@ -562,6 +595,8 @@ void t_phone::activate_line(unsigned short l) { set_active_line(l); + t_rwmutex_reader x(lines_mtx); + // Retrieve the call on the new active line unless that line // is transferring a call and the user profile indicates that // the referrer holds the call during call transfer. @@ -582,6 +617,7 @@ void t_phone::activate_line(unsigned short l) { } void t_phone::send_dtmf(char digit, bool inband, bool info) { + t_rwmutex_reader x(lines_mtx); lines[active_line]->send_dtmf(digit, inband, info); } @@ -686,6 +722,8 @@ void t_phone::handle_response_out_of_dialog(StunMessage *r, t_tuid tuid) { } t_phone_user *t_phone::find_phone_user(const string &profile_name) const { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::const_iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -701,6 +739,8 @@ t_phone_user *t_phone::find_phone_user(const string &profile_name) const { } t_phone_user *t_phone::find_phone_user(const t_url &user_uri) const { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::const_iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -716,6 +756,8 @@ t_phone_user *t_phone::find_phone_user(const t_url &user_uri) const { } t_phone_user *t_phone::match_phone_user(t_response *r, t_tuid tuid, bool active_only) { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -727,6 +769,8 @@ t_phone_user *t_phone::match_phone_user(t_response *r, t_tuid tuid, bool active_ } t_phone_user *t_phone::match_phone_user(t_request *r, bool active_only) { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -738,6 +782,8 @@ t_phone_user *t_phone::match_phone_user(t_request *r, bool active_only) { } t_phone_user *t_phone::match_phone_user(StunMessage *r, t_tuid tuid, bool active_only) { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -749,6 +795,8 @@ t_phone_user *t_phone::match_phone_user(StunMessage *r, t_tuid tuid, bool active } int t_phone::hunt_line(void) { + t_rwmutex_reader x(lines_mtx); + // Send incoming call to active line if it is idle. if (lines.at(active_line)->get_substate() == LSSUB_IDLE) { return active_line; @@ -771,6 +819,8 @@ int t_phone::hunt_line(void) { ////////////// void t_phone::recvd_provisional(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_provisional(r, tuid, tid); @@ -785,6 +835,8 @@ void t_phone::recvd_provisional(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_success(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_success(r, tuid, tid); @@ -797,6 +849,8 @@ void t_phone::recvd_success(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_redirect(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_redirect(r, tuid, tid); @@ -809,6 +863,8 @@ void t_phone::recvd_redirect(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_client_error(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_client_error(r, tuid, tid); @@ -821,6 +877,8 @@ void t_phone::recvd_client_error(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_server_error(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_server_error(r, tuid, tid); @@ -833,6 +891,8 @@ void t_phone::recvd_server_error(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_global_error(t_response *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_global_error(r, tuid, tid); @@ -851,6 +911,8 @@ void t_phone::post_process_response(t_response *r, t_tuid tuid, t_tid tid) { } void t_phone::recvd_invite(t_request *r, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + // Check if this INVITE is a retransmission. // Once the TU sent a 2XX repsonse on an INVITE it has to deal // with retransmissions. @@ -927,6 +989,8 @@ void t_phone::recvd_initial_invite(t_request *r, t_tid tid) { r->hdr_request_disposition.is_populated() && r->hdr_request_disposition.fork_directive == t_hdr_request_disposition::NO_FORK; + t_rwmutex_reader x(lines_mtx); + for (size_t i = 0; i < lines.size(); i++) { if (lines.at(i)->match_replaces(r->hdr_replaces.call_id, r->hdr_replaces.to_tag, @@ -1214,6 +1278,7 @@ void t_phone::recvd_initial_invite(t_request *r, t_tid tid) { log_file->write_report("End call due to Replaces header.", "t_phone::recvd_initial_invite"); + t_rwmutex_writer x(lines_mtx); if (lines.at(replace_line)->get_substate() == LSSUB_INCOMING_PROGRESS) { ui->cb_stop_call_notification(replace_line); lines.at(replace_line)->reject(); @@ -1229,6 +1294,7 @@ void t_phone::recvd_initial_invite(t_request *r, t_tid tid) { if (hunted_line == active_line) { // Auto-answer is only applicable to the active line. + t_rwmutex_reader x(lines_mtx); if (replace_line >= 0 && auto_answer_replace_call) { // RFC 3891 // This call replaces an existing established call, answer immediate. @@ -1243,6 +1309,7 @@ void t_phone::recvd_initial_invite(t_request *r, t_tid tid) { } } + t_rwmutex_reader x(lines_mtx); // Send INVITE to hunted line if (hunted_line >= 0) { lines.at(hunted_line)->recvd_invite(pu, r, tid, @@ -1293,6 +1360,7 @@ void t_phone::recvd_initial_invite(t_request *r, t_tid tid) { void t_phone::recvd_re_invite(t_request *r, t_tid tid) { t_response *resp; list <string> unsupported; + t_rwmutex_reader x(lines_mtx); // RFC 3261 12.2.2 // A To-header with a tag is a mid-dialog request. @@ -1329,6 +1397,7 @@ void t_phone::recvd_re_invite(t_request *r, t_tid tid) { void t_phone::recvd_ack(t_request *r, t_tid tid) { t_response *resp; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { @@ -1347,6 +1416,7 @@ void t_phone::recvd_cancel(t_request *r, t_tid cancel_tid, t_tid target_tid) { t_response *resp; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match_cancel(r, target_tid)) { @@ -1364,6 +1434,7 @@ void t_phone::recvd_cancel(t_request *r, t_tid cancel_tid, void t_phone::recvd_bye(t_request *r, t_tid tid) { t_response *resp; list <string> unsupported; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { @@ -1444,6 +1515,7 @@ t_phone_user *t_phone::find_phone_user_out_dialog_request(t_request *r, t_tid ti t_line *t_phone::find_line_in_dialog_request(t_request *r, t_tid tid) { t_response *resp; list <string> unsupported; + t_rwmutex_reader x(lines_mtx); // RFC 3261 12.2.2 // A To-header with a tag is a mid-dialog request. @@ -1551,6 +1623,7 @@ void t_phone::recvd_register(t_request *r, t_tid tid) { void t_phone::recvd_prack(t_request *r, t_tid tid) { t_response *resp; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { @@ -1578,6 +1651,7 @@ void t_phone::recvd_subscribe(t_request *r, t_tid tid) { return; } + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { lines[i]->recvd_subscribe(r, tid); @@ -1636,6 +1710,7 @@ void t_phone::recvd_notify(t_request *r, t_tid tid) { } // REFER notification + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { lines[i]->recvd_notify(r, tid); @@ -1697,6 +1772,7 @@ void t_phone::recvd_notify(t_request *r, t_tid tid) { void t_phone::recvd_refer(t_request *r, t_tid tid) { t_response *resp; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { @@ -1801,6 +1877,7 @@ void t_phone::recvd_refer_permission(bool permission) { t_phone_user *pu = incoming_refer_data->get_phone_user(); t_user *user_config = pu->get_user_profile(); + t_rwmutex_reader x(lines_mtx); lines[i]->recvd_refer_permission(permission, r); if (!permission) { @@ -1896,6 +1973,7 @@ void t_phone::recvd_refer_permission(bool permission) { void t_phone::recvd_info(t_request *r, t_tid tid) { t_response *resp; list <string> unsupported; + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r)) { @@ -1952,6 +2030,8 @@ void t_phone::failure(t_failure failure, t_tid tid) { } void t_phone::recvd_stun_resp(StunMessage *r, t_tuid tuid, t_tid tid) { + t_rwmutex_reader x(lines_mtx); + for (unsigned short i = 0; i < lines.size(); i++) { if (lines[i]->match(r, tuid)) { lines[i]->recvd_stun_resp(r, tuid, tid); @@ -2031,6 +2111,8 @@ void t_phone::line_timeout_sub(t_object_id id, t_subscribe_timer timer, t_object void t_phone::subscription_timeout(t_subscribe_timer timer, t_object_id id_timer) { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) { @@ -2041,6 +2123,8 @@ void t_phone::subscription_timeout(t_subscribe_timer timer, t_object_id id_timer } void t_phone::publication_timeout(t_publish_timer timer, t_object_id id_timer) { + t_rwmutex_reader x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) { @@ -2051,7 +2135,7 @@ void t_phone::publication_timeout(t_publish_timer timer, t_object_id id_timer) { } void t_phone::timeout(t_phone_timer timer, unsigned short id_timer) { - lock(); + t_rwmutex_reader x(phone_users_mtx); switch (timer) { case PTMR_REGISTRATION: @@ -2084,11 +2168,11 @@ void t_phone::timeout(t_phone_timer timer, unsigned short id_timer) { default: assert(false); } - - unlock(); } void t_phone::handle_broken_connection(t_event_broken_connection *e) { + t_rwmutex_reader x(phone_users_mtx); + // Find the phone user that was associated with the connection. // This phone user has to handle the event. t_phone_user *pu = find_phone_user(e->get_user_uri()); @@ -2151,6 +2235,7 @@ t_phone::~t_phone() { delete lines[i]; } + t_rwmutex_writer x(phone_users_mtx); // Delete all phone users for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) @@ -2164,7 +2249,7 @@ void t_phone::pub_invite(t_user *user, const t_url &to_uri, const string &to_display, const string &subject, bool anonymous) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2175,8 +2260,6 @@ void t_phone::pub_invite(t_user *user, log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_answer(void) { @@ -2214,7 +2297,7 @@ void t_phone::pub_registration(t_user *user, t_register_type register_type, unsigned long expires) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2225,14 +2308,12 @@ void t_phone::pub_registration(t_user *user, log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_options(t_user *user, const t_url &to_uri, const string &to_display) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2243,8 +2324,6 @@ void t_phone::pub_options(t_user *user, log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_options(void) { @@ -2297,6 +2376,7 @@ void t_phone::mute(bool enable) { } else { + t_rwmutex_reader x(lines_mtx); lines[active_line]->mute(enable); } @@ -2317,10 +2397,9 @@ void t_phone::pub_send_dtmf(char digit, bool inband, bool info) { bool t_phone::pub_seize(void) { bool retval; + t_rwmutex_reader x(lines_mtx); - lock(); retval = lines[active_line]->seize(); - unlock(); return retval; } @@ -2328,75 +2407,66 @@ bool t_phone::pub_seize(void) { bool t_phone::pub_seize(unsigned short line) { assert(line < NUM_USER_LINES); bool retval; + t_rwmutex_reader x(lines_mtx); - lock(); retval = lines[line]->seize(); - unlock(); return retval; } void t_phone::pub_unseize(void) { - lock(); + t_rwmutex_reader x(lines_mtx); lines[active_line]->unseize(); - unlock(); } void t_phone::pub_unseize(unsigned short line) { assert(line < NUM_USER_LINES); - lock(); + t_rwmutex_reader x(lines_mtx); lines[line]->unseize(); - unlock(); } void t_phone::pub_confirm_zrtp_sas(unsigned short line) { assert(line < NUM_USER_LINES); - lock(); + + t_rwmutex_reader x(lines_mtx); lines[line]->confirm_zrtp_sas(); - unlock(); } void t_phone::pub_confirm_zrtp_sas(void) { - lock(); + t_rwmutex_reader x(lines_mtx); lines[active_line]->confirm_zrtp_sas(); - unlock(); } void t_phone::pub_reset_zrtp_sas_confirmation(unsigned short line) { assert(line < NUM_USER_LINES); - lock(); + t_rwmutex_reader x(lines_mtx); lines[line]->reset_zrtp_sas_confirmation(); - unlock(); } void t_phone::pub_reset_zrtp_sas_confirmation(void) { - lock(); + t_rwmutex_reader x(lines_mtx); lines[active_line]->reset_zrtp_sas_confirmation(); - unlock(); } void t_phone::pub_enable_zrtp(void) { - lock(); + t_rwmutex_reader x(lines_mtx); lines[active_line]->enable_zrtp(); - unlock(); } void t_phone::pub_zrtp_request_go_clear(void) { - lock(); + t_rwmutex_reader x(lines_mtx); lines[active_line]->zrtp_request_go_clear(); - unlock(); } void t_phone::pub_zrtp_go_clear_ok(unsigned short line) { assert(line < NUM_USER_LINES); - lock(); + t_rwmutex_reader x(lines_mtx); lines[line]->zrtp_go_clear_ok(); - unlock(); } void t_phone::pub_subscribe_mwi(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2407,12 +2477,10 @@ void t_phone::pub_subscribe_mwi(t_user *user) { log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_unsubscribe_mwi(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2423,12 +2491,10 @@ void t_phone::pub_unsubscribe_mwi(t_user *user) { log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_subscribe_presence(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2439,12 +2505,10 @@ void t_phone::pub_subscribe_presence(t_user *user) { log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_unsubscribe_presence(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2455,12 +2519,10 @@ void t_phone::pub_unsubscribe_presence(t_user *user) { log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_publish_presence(t_user *user, t_presence_state::t_basic_state basic_state) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2471,12 +2533,10 @@ void t_phone::pub_publish_presence(t_user *user, t_presence_state::t_basic_state log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } void t_phone::pub_unpublish_presence(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2487,8 +2547,6 @@ void t_phone::pub_unpublish_presence(t_user *user) { log_file->write_raw(user->get_profile_name()); log_file->write_footer(); } - - unlock(); } bool t_phone::pub_send_message(t_user *user, const t_url &to_uri, const string &to_display, @@ -2496,7 +2554,7 @@ bool t_phone::pub_send_message(t_user *user, const t_url &to_uri, const string & { bool retval = true; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2511,8 +2569,6 @@ bool t_phone::pub_send_message(t_user *user, const t_url &to_uri, const string & retval = false; } - unlock(); - return retval; } @@ -2521,7 +2577,7 @@ bool t_phone::pub_send_im_iscomposing(t_user *user, const t_url &to_uri, const s { bool retval = true; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { @@ -2536,13 +2592,11 @@ bool t_phone::pub_send_im_iscomposing(t_user *user, const t_url &to_uri, const s retval = false; } - unlock(); - return retval; } t_phone_state t_phone::get_state(void) const { - lock(); + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < NUM_USER_LINES; i++) { if (lines[i]->get_state() == LS_IDLE) { unlock(); @@ -2551,12 +2605,11 @@ t_phone_state t_phone::get_state(void) const { } // All lines are busy, so the phone is busy. - unlock(); return PS_BUSY; } bool t_phone::all_lines_idle(void) const { - lock(); + t_rwmutex_reader x(lines_mtx); for (unsigned short i = 0; i < NUM_USER_LINES; i++) { if (lines[i]->get_substate() != LSSUB_IDLE) { unlock(); @@ -2565,12 +2618,11 @@ bool t_phone::all_lines_idle(void) const { } // All lines are idle - unlock(); return true; } bool t_phone::get_idle_line(unsigned short &lineno) const { - lock(); + t_rwmutex_reader x(lines_mtx); bool found_idle_line = false; for (unsigned short i = 0; i < NUM_USER_LINES; i++) { @@ -2581,15 +2633,13 @@ bool t_phone::get_idle_line(unsigned short &lineno) const { } } - unlock(); return found_idle_line; } void t_phone::set_active_line(unsigned short l) { - lock(); + t_rwmutex_reader x(lines_mtx); assert (l < NUM_USER_LINES); active_line = l; - unlock(); } unsigned short t_phone::get_active_line(void) const { @@ -2597,6 +2647,7 @@ unsigned short t_phone::get_active_line(void) const { } t_line *t_phone::get_line_by_id(t_object_id id) const { + t_rwmutex_reader x(lines_mtx); for (size_t i = 0; i < lines.size(); i++) { if (lines[i]->get_object_id() == id) { return lines[i]; @@ -2615,28 +2666,25 @@ bool t_phone::authorize(t_user *user, t_request *r, t_response *resp) { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->authorize(r, resp); - unlock(); return result; } void t_phone::remove_cached_credentials(t_user *user, const string &realm) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) pu->remove_cached_credentials(realm); - unlock(); } bool t_phone::get_is_registered(t_user *user) { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->get_is_registered(); - unlock(); return result; } @@ -2644,10 +2692,9 @@ bool t_phone::get_is_registered(t_user *user) { bool t_phone::get_last_reg_failed(t_user *user) { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->get_last_reg_failed(); - unlock(); return result; } @@ -2655,36 +2702,32 @@ bool t_phone::get_last_reg_failed(t_user *user) { t_line_state t_phone::get_line_state(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_line_state s = get_line(lineno)->get_state(); - unlock(); return s; } t_line_substate t_phone::get_line_substate(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_line_substate s = get_line(lineno)->get_substate(); - unlock(); return s; } bool t_phone::is_line_on_hold(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_is_on_hold(); - unlock(); return b; } bool t_phone::is_line_muted(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_is_muted(); - unlock(); return b; } @@ -2693,9 +2736,8 @@ bool t_phone::is_line_transfer_consult(unsigned short lineno, { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_is_transfer_consult(transfer_from_line); - unlock(); return b; } @@ -2704,63 +2746,56 @@ bool t_phone::line_to_be_transferred(unsigned short lineno, { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_to_be_transferred(transfer_to_line); - unlock(); return b; } bool t_phone::is_line_encrypted(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_is_encrypted(); - unlock(); return b; } bool t_phone::is_line_auto_answered(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->get_auto_answer(); - unlock(); return b; } t_refer_state t_phone::get_line_refer_state(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_refer_state s = get_line(lineno)->get_refer_state(); - unlock(); return s; } t_user *t_phone::get_line_user(unsigned short lineno) { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_user *user = get_line(lineno)->get_user(); - unlock(); return user; } bool t_phone::has_line_media(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); bool b = get_line(lineno)->has_media(); - unlock(); return b; } bool t_phone::is_mwi_subscribed(t_user *user) const { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->is_mwi_subscribed(); - unlock(); return result; } @@ -2768,10 +2803,9 @@ bool t_phone::is_mwi_subscribed(t_user *user) const { bool t_phone::is_mwi_terminated(t_user *user) const { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->is_mwi_terminated(); - unlock(); return result; } @@ -2779,10 +2813,9 @@ bool t_phone::is_mwi_terminated(t_user *user) const { t_mwi t_phone::get_mwi(t_user *user) const { t_mwi result; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->mwi; - unlock(); return result; } @@ -2790,10 +2823,9 @@ t_mwi t_phone::get_mwi(t_user *user) const { bool t_phone::is_presence_terminated(t_user *user) const { bool result = false; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) result = pu->is_presence_terminated(); - unlock(); return result; } @@ -2801,18 +2833,16 @@ bool t_phone::is_presence_terminated(t_user *user) const { t_url t_phone::get_remote_uri(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_url uri = get_line(lineno)->get_remote_uri(); - unlock(); return uri; } string t_phone::get_remote_display(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); string display = get_line(lineno)->get_remote_display(); - unlock(); return display; } @@ -2860,6 +2890,7 @@ bool t_phone::join_3way(unsigned short lineno1, unsigned short lineno2) { assert(lineno2 < NUM_USER_LINES); lock(); + t_rwmutex_reader x(lines_mtx); // Check if there isn't a 3-way already if (is_3way) { @@ -2914,6 +2945,8 @@ bool t_phone::join_3way(unsigned short lineno1, unsigned short lineno2) { } void t_phone::notify_refer_progress(t_response *r, unsigned short referee_lineno) { + t_rwmutex_reader x(lines_mtx); + if (lines[LINENO_REFERRER]->get_state() != LS_IDLE) { lines[LINENO_REFERRER]->notify_refer_progress(r); @@ -2976,27 +3009,24 @@ void t_phone::notify_refer_progress(t_response *r, unsigned short referee_lineno t_call_info t_phone::get_call_info(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_call_info call_info = get_line(lineno)->get_call_info(); - unlock(); return call_info; } t_call_record t_phone::get_call_hist(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); t_call_record call_hist = get_line(lineno)->call_hist_record; - unlock(); return call_hist; } string t_phone::get_ringtone(unsigned short lineno) const { assert(lineno < lines.size()); - lock(); + t_rwmutex_reader x(lines_mtx); string ringtone = get_line(lineno)->get_ringtone(); - unlock(); return ringtone; } @@ -3005,16 +3035,17 @@ time_t t_phone::get_startup_time(void) const { } void t_phone::init_rtp_ports(void) { + t_rwmutex_reader x(lines_mtx); for (size_t i = 0; i < lines.size(); i++) { lines[i]->init_rtp_port(); } } bool t_phone::add_phone_user(const t_user &user_config, t_user **dup_user) { - lock(); t_phone_user *existing_phone_user = NULL; - + t_rwmutex_writer x(phone_users_mtx); + for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) { @@ -3036,7 +3067,6 @@ bool t_phone::add_phone_user(const t_user &user_config, t_user **dup_user) { (*i)->is_active()) { *dup_user = user; - unlock(); return false; } @@ -3047,7 +3077,6 @@ bool t_phone::add_phone_user(const t_user &user_config, t_user **dup_user) { (*i)->is_active()) { *dup_user = user; - unlock(); return false; } } @@ -3065,29 +3094,26 @@ bool t_phone::add_phone_user(const t_user &user_config, t_user **dup_user) { t_phone_user *pu = new t_phone_user(user_config); MEMMAN_NEW(pu); phone_users.push_back(pu); - unlock(); return true; } void t_phone::remove_phone_user(const t_user &user_config) { - lock(); + t_rwmutex_writer x(phone_users_mtx); t_phone_user *pu = find_phone_user(user_config.get_profile_name()); if (pu) pu->deactivate(); - unlock(); } list<t_user *> t_phone::ref_users(void) { list<t_user *> l; - lock(); + t_rwmutex_reader x(phone_users_mtx); for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) { if (!(*i)->is_active()) continue; l.push_back((*i)->get_user_profile()); } - unlock(); return l; } @@ -3095,7 +3121,7 @@ list<t_user *> t_phone::ref_users(void) { t_user *t_phone::ref_user_display_uri(const string &display_uri) { t_user *u = NULL; - lock(); + t_rwmutex_reader x(phone_users_mtx); for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); i++) { @@ -3105,7 +3131,6 @@ t_user *t_phone::ref_user_display_uri(const string &display_uri) { break; } } - unlock(); return u; } @@ -3113,10 +3138,9 @@ t_user *t_phone::ref_user_display_uri(const string &display_uri) { t_user *t_phone::ref_user_profile(const string &profile_name) { t_user *u = NULL; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(profile_name); if (pu) u = pu->get_user_profile(); - unlock(); return u; } @@ -3125,10 +3149,9 @@ t_service *t_phone::ref_service(t_user *user) { assert(user); t_service *srv = NULL; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) srv = pu->service; - unlock(); return srv; } @@ -3137,10 +3160,9 @@ t_buddy_list *t_phone::ref_buddy_list(t_user *user) { assert(user); t_buddy_list *l = NULL; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) l = pu->get_buddy_list(); - unlock(); return l; } @@ -3149,10 +3171,9 @@ t_presence_epa *t_phone::ref_presence_epa(t_user *user) { assert(user); t_presence_epa *epa = NULL; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) epa = pu->get_presence_epa(); - unlock(); return epa; } @@ -3160,14 +3181,13 @@ t_presence_epa *t_phone::ref_presence_epa(t_user *user) { string t_phone::get_ip_sip(const t_user *user, const string &auto_ip) const { string result; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { result = pu->get_ip_sip(auto_ip); } else { result = LOCAL_IP; } - unlock(); if (result == AUTO_IP4_ADDRESS) result = auto_ip; @@ -3177,14 +3197,13 @@ string t_phone::get_ip_sip(const t_user *user, const string &auto_ip) const { unsigned short t_phone::get_public_port_sip(const t_user *user) const { unsigned short result; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { result = pu->get_public_port_sip(); } else { result = sys_config->get_sip_port(); } - unlock(); return result; } @@ -3192,14 +3211,13 @@ unsigned short t_phone::get_public_port_sip(const t_user *user) const { bool t_phone::use_stun(t_user *user) { bool result; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { result = pu->use_stun; } else { result = false; } - unlock(); return result; } @@ -3207,36 +3225,33 @@ bool t_phone::use_stun(t_user *user) { bool t_phone::use_nat_keepalive(t_user *user) { bool result; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { result = pu->use_nat_keepalive; } else { result = false; } - unlock(); return result; } void t_phone::disable_stun(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) pu->use_stun = false; - unlock(); } void t_phone::sync_nat_keepalive(t_user *user) { - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) pu->sync_nat_keepalive(); - unlock(); } bool t_phone::stun_discover_nat(list<string> &msg_list) { bool retval = true; - lock(); + t_rwmutex_reader x(phone_users_mtx); for (list<t_phone_user *>::iterator i = phone_users.begin(); i != phone_users.end(); ++i) { @@ -3264,7 +3279,6 @@ bool t_phone::stun_discover_nat(list<string> &msg_list) { } } } - unlock(); return retval; } @@ -3272,7 +3286,7 @@ bool t_phone::stun_discover_nat(list<string> &msg_list) { bool t_phone::stun_discover_nat(t_user *user, string &msg) { bool retval = true; - lock(); + t_rwmutex_reader x(phone_users_mtx); if (user->get_sip_transport() == SIP_TRANS_UDP || user->get_sip_transport() == SIP_TRANS_AUTO) { @@ -3285,7 +3299,6 @@ bool t_phone::stun_discover_nat(t_user *user, string &msg) { if (pu) pu->use_nat_keepalive = user->get_enable_nat_keepalive(); } } - unlock(); return retval; } @@ -3295,20 +3308,18 @@ t_response *t_phone::create_options_response(t_user *user, t_request *r, { t_response *resp; - lock(); + t_rwmutex_reader x(phone_users_mtx); t_phone_user *pu = find_phone_user(user->get_profile_name()); if (pu) { resp = pu->create_options_response(r, in_dialog); } else { resp = r->create_response(R_500_INTERNAL_SERVER_ERROR); } - unlock(); return resp; } void t_phone::init(void) { - lock(); list<t_user *> user_list = ref_users(); @@ -3326,8 +3337,6 @@ void t_phone::init(void) { // This way STUN will have set the correct // IP adres (STUN is done as part of registration.) } - - unlock(); } void t_phone::init_extensions(t_user *user_config) { @@ -3361,8 +3370,8 @@ bool t_phone::set_sighandler(void) const { void t_phone::terminate(void) { string msg; - lock(); + lines_mtx.lockRead(); // Clear all lines log_file->write_report("Clear all lines.", "t_phone::terminate", LOG_NORMAL, LOG_DEBUG); @@ -3387,6 +3396,7 @@ void t_phone::terminate(void) { break; } } + lines_mtx.unlock(); // Deactivate phone is_active = false; @@ -3422,8 +3432,6 @@ void t_phone::terminate(void) { } } - unlock(); - // Wait till phone is deregistered. for (list<t_user *>::iterator i = user_list.begin(); i != user_list.end(); i++) { @@ -3473,7 +3481,7 @@ void t_phone::terminate(void) { // Force lines to idle state if they could not be cleared // gracefully - lock(); + lines_mtx.lockRead(); for (size_t i = 0; i < lines.size(); i++) { if (lines[i]->get_substate() != LSSUB_IDLE) { msg = "Force line %1 to idle state."; @@ -3483,10 +3491,10 @@ void t_phone::terminate(void) { lines[i]->force_idle(); } } + lines_mtx.unlock(); log_file->write_report("Finished phone termination.", "t_phone::terminate", LOG_NORMAL, LOG_DEBUG); - unlock(); } void *phone_uas_main(void *arg) { diff --git a/src/phone.h b/src/phone.h index 2a08936..c85e895 100644 --- a/src/phone.h +++ b/src/phone.h @@ -116,11 +116,13 @@ private: // Phone users list<t_phone_user *> phone_users; + mutable t_rwmutex phone_users_mtx; // Phone lines // The first NUM_CALL_LINES are for making phone calls. // The tail of the vector is for releasing lines in the background. vector<t_line *> lines; + mutable t_rwmutex lines_mtx; // Operations like invite, end_call work on the active line unsigned short active_line; diff --git a/src/threads/mutex.cpp b/src/threads/mutex.cpp index 0ae2a99..159f887 100644 --- a/src/threads/mutex.cpp +++ b/src/threads/mutex.cpp @@ -20,6 +20,7 @@ #include <iostream> #include "mutex.h" #include "thread.h" +#include <stdexcept> using namespace std; @@ -88,3 +89,39 @@ t_mutex_guard::t_mutex_guard(t_mutex &mutex) : mutex_(mutex) { t_mutex_guard::~t_mutex_guard() { mutex_.unlock(); } + + +/////////////////////////// +// t_rwmutex +/////////////////////////// + +t_rwmutex::t_rwmutex() +{ + int ret = pthread_rwlock_init(&_lock, nullptr); + if (ret != 0) throw string( + "t_rwmutex::t_rwmutex failed to create a r/w mutex."); +} + +t_rwmutex::~t_rwmutex() +{ + pthread_rwlock_destroy(&_lock); +} + +void t_rwmutex::lockRead() +{ + int err = pthread_rwlock_rdlock(&_lock); + if (err != 0) + throw std::logic_error("Mutex lock failed"); +} + +void t_rwmutex::lockWrite() +{ + int err = pthread_rwlock_wrlock(&_lock); + if (err != 0) + throw std::logic_error("Mutex lock failed"); +} + +void t_rwmutex::unlock() +{ + pthread_rwlock_unlock(&_lock); +} diff --git a/src/threads/mutex.h b/src/threads/mutex.h index 9970e08..16f314d 100644 --- a/src/threads/mutex.h +++ b/src/threads/mutex.h @@ -21,6 +21,7 @@ #include <errno.h> #include <pthread.h> +// #include <iostream> /** * @file @@ -83,4 +84,45 @@ public: ~t_mutex_guard(); }; +class t_rwmutex { +protected: + pthread_rwlock_t _lock; +public: + t_rwmutex(); + ~t_rwmutex(); + + void lockRead(); + void lockWrite(); + void unlock(); +}; + +class t_rwmutex_reader { +private: + t_rwmutex& _mutex; +public: + t_rwmutex_reader(t_rwmutex& mutex) : _mutex(mutex) { + // std::cout << "mtx rd lock " << (void*)&_mutex << std::endl; + _mutex.lockRead(); + } + ~t_rwmutex_reader() { + // std::cout << "mtx rd unlock " << (void*)&_mutex << std::endl; + _mutex.unlock(); + } +}; + +class t_rwmutex_writer { +private: + t_rwmutex& _mutex; +public: + t_rwmutex_writer(t_rwmutex& mutex) : _mutex(mutex) { + // std::cout << "mtx wr lock " << (void*)&_mutex << std::endl; + _mutex.lockWrite(); + } + ~t_rwmutex_writer() { + // std::cout << "mtx wr unlock " << (void*)&_mutex << std::endl; + _mutex.unlock(); + } +}; + + #endif |