Skip to content

Commit 2cd54b7

Browse files
authored
refactor: Make ConnectivityStore use a non-async lock (#7129)
Follow-up to #7125: We now have a mix of non-async (parking_lot) and async (tokio) Mutexes used for the connectivity. We can just use non-async Mutexes, because we don't attempt to hold them over an await point. I also tested that we get a compiler error if we do try to hold one over an await point (rather than just deadlocking/blocking the executor on runtime). Not 100% sure about using the parking_lot rather than std Mutex, because since rust-lang/rust#93740, parking_lot doesn't have a lot of advantages anymore. But as long as iroh depends on it, we might as well use it ourselves.
1 parent c34ccaf commit 2cd54b7

File tree

6 files changed

+47
-49
lines changed

6 files changed

+47
-49
lines changed

deltachat-ffi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ pub unsafe extern "C" fn dc_get_connectivity(context: *const dc_context_t) -> li
375375
return 0;
376376
}
377377
let ctx = &*context;
378-
block_on(ctx.get_connectivity()) as u32 as libc::c_int
378+
ctx.get_connectivity() as u32 as libc::c_int
379379
}
380380

381381
#[no_mangle]

deltachat-jsonrpc/src/api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1908,7 +1908,7 @@ impl CommandApi {
19081908
/// If the connectivity changes, a #DC_EVENT_CONNECTIVITY_CHANGED will be emitted.
19091909
async fn get_connectivity(&self, account_id: u32) -> Result<u32> {
19101910
let ctx = self.get_context(account_id).await?;
1911-
Ok(ctx.get_connectivity().await as u32)
1911+
Ok(ctx.get_connectivity() as u32)
19121912
}
19131913

19141914
/// Get an overview of the current connectivity, and possibly more statistics.

src/imap.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ impl Imap {
325325
}
326326

327327
info!(context, "Connecting to IMAP server.");
328-
self.connectivity.set_connecting(context).await;
328+
self.connectivity.set_connecting(context);
329329

330330
self.conn_last_try = tools::Time::now();
331331
const BACKOFF_MIN_MS: u64 = 2000;
@@ -408,7 +408,7 @@ impl Imap {
408408
"IMAP-LOGIN as {}",
409409
lp.user
410410
)));
411-
self.connectivity.set_preparing(context).await;
411+
self.connectivity.set_preparing(context);
412412
info!(context, "Successfully logged into IMAP server.");
413413
return Ok(session);
414414
}
@@ -466,7 +466,7 @@ impl Imap {
466466
let mut session = match self.connect(context, configuring).await {
467467
Ok(session) => session,
468468
Err(err) => {
469-
self.connectivity.set_err(context, &err).await;
469+
self.connectivity.set_err(context, &err);
470470
return Err(err);
471471
}
472472
};
@@ -692,7 +692,7 @@ impl Imap {
692692
}
693693

694694
if !uids_fetch.is_empty() {
695-
self.connectivity.set_working(context).await;
695+
self.connectivity.set_working(context);
696696
}
697697

698698
let (sender, receiver) = async_channel::unbounded();

src/scheduler.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl SchedulerState {
227227
_ => return,
228228
};
229229
drop(inner);
230-
connectivity::idle_interrupted(inbox, oboxes).await;
230+
connectivity::idle_interrupted(inbox, oboxes);
231231
}
232232

233233
/// Indicate that the network likely is lost.
@@ -244,7 +244,7 @@ impl SchedulerState {
244244
_ => return,
245245
};
246246
drop(inner);
247-
connectivity::maybe_network_lost(context, stores).await;
247+
connectivity::maybe_network_lost(context, stores);
248248
}
249249

250250
pub(crate) async fn interrupt_inbox(&self) {
@@ -569,7 +569,7 @@ async fn fetch_idle(
569569
// The folder is not configured.
570570
// For example, this happens if the server does not have Sent folder
571571
// but watching Sent folder is enabled.
572-
connection.connectivity.set_not_configured(ctx).await;
572+
connection.connectivity.set_not_configured(ctx);
573573
connection.idle_interrupt_receiver.recv().await.ok();
574574
bail!("Cannot fetch folder {folder_meaning} because it is not configured");
575575
};
@@ -659,7 +659,7 @@ async fn fetch_idle(
659659
.log_err(ctx)
660660
.ok();
661661

662-
connection.connectivity.set_idle(ctx).await;
662+
connection.connectivity.set_idle(ctx);
663663

664664
ctx.emit_event(EventType::ImapInboxIdle);
665665

@@ -810,8 +810,8 @@ async fn smtp_loop(
810810
// Fake Idle
811811
info!(ctx, "SMTP fake idle started.");
812812
match &connection.last_send_error {
813-
None => connection.connectivity.set_idle(&ctx).await,
814-
Some(err) => connection.connectivity.set_err(&ctx, err).await,
813+
None => connection.connectivity.set_idle(&ctx),
814+
Some(err) => connection.connectivity.set_err(&ctx, err),
815815
}
816816

817817
// If send_smtp_messages() failed, we set a timeout for the fake-idle so that

src/scheduler/connectivity.rs

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::{iter::once, ops::Deref, sync::Arc};
44

55
use anyhow::Result;
66
use humansize::{BINARY, format_size};
7-
use tokio::sync::Mutex;
87

98
use crate::events::EventType;
109
use crate::imap::{FolderMeaning, scan_folders::get_watched_folder_configs};
@@ -160,52 +159,51 @@ impl DetailedConnectivity {
160159
}
161160

162161
#[derive(Clone, Default)]
163-
pub(crate) struct ConnectivityStore(Arc<Mutex<DetailedConnectivity>>);
162+
pub(crate) struct ConnectivityStore(Arc<parking_lot::Mutex<DetailedConnectivity>>);
164163

165164
impl ConnectivityStore {
166-
async fn set(&self, context: &Context, v: DetailedConnectivity) {
165+
fn set(&self, context: &Context, v: DetailedConnectivity) {
167166
{
168-
*self.0.lock().await = v;
167+
*self.0.lock() = v;
169168
}
170169
context.emit_event(EventType::ConnectivityChanged);
171170
}
172171

173-
pub(crate) async fn set_err(&self, context: &Context, e: impl ToString) {
174-
self.set(context, DetailedConnectivity::Error(e.to_string()))
175-
.await;
172+
pub(crate) fn set_err(&self, context: &Context, e: impl ToString) {
173+
self.set(context, DetailedConnectivity::Error(e.to_string()));
176174
}
177-
pub(crate) async fn set_connecting(&self, context: &Context) {
178-
self.set(context, DetailedConnectivity::Connecting).await;
175+
pub(crate) fn set_connecting(&self, context: &Context) {
176+
self.set(context, DetailedConnectivity::Connecting);
179177
}
180-
pub(crate) async fn set_working(&self, context: &Context) {
181-
self.set(context, DetailedConnectivity::Working).await;
178+
pub(crate) fn set_working(&self, context: &Context) {
179+
self.set(context, DetailedConnectivity::Working);
182180
}
183-
pub(crate) async fn set_preparing(&self, context: &Context) {
184-
self.set(context, DetailedConnectivity::Preparing).await;
181+
pub(crate) fn set_preparing(&self, context: &Context) {
182+
self.set(context, DetailedConnectivity::Preparing);
185183
}
186-
pub(crate) async fn set_not_configured(&self, context: &Context) {
187-
self.set(context, DetailedConnectivity::NotConfigured).await;
184+
pub(crate) fn set_not_configured(&self, context: &Context) {
185+
self.set(context, DetailedConnectivity::NotConfigured);
188186
}
189-
pub(crate) async fn set_idle(&self, context: &Context) {
190-
self.set(context, DetailedConnectivity::Idle).await;
187+
pub(crate) fn set_idle(&self, context: &Context) {
188+
self.set(context, DetailedConnectivity::Idle);
191189
}
192190

193-
async fn get_detailed(&self) -> DetailedConnectivity {
194-
self.0.lock().await.deref().clone()
191+
fn get_detailed(&self) -> DetailedConnectivity {
192+
self.0.lock().deref().clone()
195193
}
196-
async fn get_basic(&self) -> Option<Connectivity> {
197-
self.0.lock().await.to_basic()
194+
fn get_basic(&self) -> Option<Connectivity> {
195+
self.0.lock().to_basic()
198196
}
199-
async fn get_all_work_done(&self) -> bool {
200-
self.0.lock().await.all_work_done()
197+
fn get_all_work_done(&self) -> bool {
198+
self.0.lock().all_work_done()
201199
}
202200
}
203201

204202
/// Set all folder states to InterruptingIdle in case they were `Idle` before.
205203
/// Called during `dc_maybe_network()` to make sure that `all_work_done()`
206204
/// returns false immediately after `dc_maybe_network()`.
207-
pub(crate) async fn idle_interrupted(inbox: ConnectivityStore, oboxes: Vec<ConnectivityStore>) {
208-
let mut connectivity_lock = inbox.0.lock().await;
205+
pub(crate) fn idle_interrupted(inbox: ConnectivityStore, oboxes: Vec<ConnectivityStore>) {
206+
let mut connectivity_lock = inbox.0.lock();
209207
// For the inbox, we also have to set the connectivity to InterruptingIdle if it was
210208
// NotConfigured before: If all folders are NotConfigured, dc_get_connectivity()
211209
// returns Connected. But after dc_maybe_network(), dc_get_connectivity() must not
@@ -219,7 +217,7 @@ pub(crate) async fn idle_interrupted(inbox: ConnectivityStore, oboxes: Vec<Conne
219217
drop(connectivity_lock);
220218

221219
for state in oboxes {
222-
let mut connectivity_lock = state.0.lock().await;
220+
let mut connectivity_lock = state.0.lock();
223221
if *connectivity_lock == DetailedConnectivity::Idle {
224222
*connectivity_lock = DetailedConnectivity::InterruptingIdle;
225223
}
@@ -231,9 +229,9 @@ pub(crate) async fn idle_interrupted(inbox: ConnectivityStore, oboxes: Vec<Conne
231229
/// Set the connectivity to "Not connected" after a call to dc_maybe_network_lost().
232230
/// If we did not do this, the connectivity would stay "Connected" for quite a long time
233231
/// after `maybe_network_lost()` was called.
234-
pub(crate) async fn maybe_network_lost(context: &Context, stores: Vec<ConnectivityStore>) {
232+
pub(crate) fn maybe_network_lost(context: &Context, stores: Vec<ConnectivityStore>) {
235233
for store in &stores {
236-
let mut connectivity_lock = store.0.lock().await;
234+
let mut connectivity_lock = store.0.lock();
237235
if !matches!(
238236
*connectivity_lock,
239237
DetailedConnectivity::Uninitialized
@@ -248,7 +246,7 @@ pub(crate) async fn maybe_network_lost(context: &Context, stores: Vec<Connectivi
248246

249247
impl fmt::Debug for ConnectivityStore {
250248
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251-
if let Ok(guard) = self.0.try_lock() {
249+
if let Some(guard) = self.0.try_lock() {
252250
write!(f, "ConnectivityStore {:?}", &*guard)
253251
} else {
254252
write!(f, "ConnectivityStore [LOCKED]")
@@ -271,11 +269,11 @@ impl Context {
271269
/// e.g. in the title of the main screen.
272270
///
273271
/// If the connectivity changes, a DC_EVENT_CONNECTIVITY_CHANGED will be emitted.
274-
pub async fn get_connectivity(&self) -> Connectivity {
272+
pub fn get_connectivity(&self) -> Connectivity {
275273
let stores = self.connectivities.lock().clone();
276274
let mut connectivities = Vec::new();
277275
for s in stores {
278-
if let Some(connectivity) = s.get_basic().await {
276+
if let Some(connectivity) = s.get_basic() {
279277
connectivities.push(connectivity);
280278
}
281279
}
@@ -393,7 +391,7 @@ impl Context {
393391
let f = self.get_config(config).await.log_err(self).ok().flatten();
394392

395393
if let Some(foldername) = f {
396-
let detailed = &state.get_detailed().await;
394+
let detailed = &state.get_detailed();
397395
ret += "<li>";
398396
ret += &*detailed.to_icon();
399397
ret += " <b>";
@@ -407,7 +405,7 @@ impl Context {
407405
}
408406

409407
if !folder_added && folder == &FolderMeaning::Inbox {
410-
let detailed = &state.get_detailed().await;
408+
let detailed = &state.get_detailed();
411409
if let DetailedConnectivity::Error(_) = detailed {
412410
// On the inbox thread, we also do some other things like scan_folders and run jobs
413411
// so, maybe, the inbox is not watched, but something else went wrong
@@ -429,7 +427,7 @@ impl Context {
429427

430428
let outgoing_messages = stock_str::outgoing_messages(self).await;
431429
ret += &format!("<h3>{outgoing_messages}</h3><ul><li>");
432-
let detailed = smtp.get_detailed().await;
430+
let detailed = smtp.get_detailed();
433431
ret += &*detailed.to_icon();
434432
ret += " ";
435433
ret += &*escaper::encode_minimal(&detailed.to_string_smtp(self).await);
@@ -553,7 +551,7 @@ impl Context {
553551
drop(lock);
554552

555553
for s in &stores {
556-
if !s.get_all_work_done().await {
554+
if !s.get_all_work_done() {
557555
return false;
558556
}
559557
}

src/smtp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl Smtp {
8787
return Ok(());
8888
}
8989

90-
self.connectivity.set_connecting(context).await;
90+
self.connectivity.set_connecting(context);
9191
let lp = ConfiguredLoginParam::load(context)
9292
.await?
9393
.context("Not configured")?;
@@ -187,7 +187,7 @@ pub(crate) async fn smtp_send(
187187
info!(context, "SMTP-sending out mime message:\n{message}");
188188
}
189189

190-
smtp.connectivity.set_working(context).await;
190+
smtp.connectivity.set_working(context);
191191

192192
if let Err(err) = smtp
193193
.connect_configured(context)

0 commit comments

Comments
 (0)