@@ -33,6 +33,12 @@ type PollFunc = (
33
33
handle : UniffiHandle ,
34
34
) => void ;
35
35
36
+ // Calls setTimeout and then resolves the promise.
37
+ // This may be used as a simple yield.
38
+ export async function delayPromise ( delayMs : number ) : Promise < void > {
39
+ return new Promise ( ( resolve ) => setTimeout ( resolve , delayMs ) ) ;
40
+ }
41
+
36
42
/**
37
43
* This method calls an asynchronous method on the Rust side.
38
44
*
@@ -71,7 +77,7 @@ export async function uniffiRustCallAsync<F, T>(
71
77
pollResult = await pollRust ( ( handle ) => {
72
78
pollFunc ( rustFuture , uniffiFutureContinuationCallback , handle ) ;
73
79
} ) ;
74
- } while ( pollResult != UNIFFI_RUST_FUTURE_POLL_READY ) ;
80
+ } while ( pollResult !== UNIFFI_RUST_FUTURE_POLL_READY ) ;
75
81
76
82
// Now it's ready, all we need to do is pick up the result (and error).
77
83
return liftFunc (
@@ -85,7 +91,7 @@ export async function uniffiRustCallAsync<F, T>(
85
91
// #RUST_TASK_CANCELLATION: the unused `cancelFunc` function should be exposed
86
92
// to client code in order for clients to be able to cancel the running Rust task.
87
93
} finally {
88
- freeFunc ( rustFuture ) ;
94
+ setTimeout ( ( ) => freeFunc ( rustFuture ) , 0 ) ;
89
95
}
90
96
}
91
97
@@ -110,7 +116,24 @@ const uniffiFutureContinuationCallback: UniffiRustFutureContinuationCallback = (
110
116
pollResult : number ,
111
117
) => {
112
118
const resolve = UNIFFI_RUST_FUTURE_RESOLVER_MAP . remove ( handle ) ;
113
- resolve ( pollResult ) ;
119
+ if ( pollResult === UNIFFI_RUST_FUTURE_POLL_READY ) {
120
+ resolve ( pollResult ) ;
121
+ } else {
122
+ // From https://github.com/mozilla/uniffi-rs/pull/1837/files#diff-8a28c9cf1245b4f714d406ea4044d68e1000099928eaca1afb504ccbc008fe9fR35-R37
123
+ //
124
+ // > WARNING: the call to [rust_future_poll] must be scheduled to happen soon after the callback is
125
+ // > called, but not inside the callback itself. If [rust_future_poll] is called inside the
126
+ // > callback, some futures will deadlock and our scheduler code might as well.
127
+ //
128
+ // This delay is to ensure that `uniffiFutureContinuationCallback` returns before the next poll, i.e.
129
+ // so that the next poll is outside of this callback.
130
+ //
131
+ // The length of the delay seems to be significant (at least in tests which hammer a network).
132
+ // I would like to understand this more: I am still seeing deadlocks when this drops below its current
133
+ // delay, but these maybe related to a different issue, as alluded to in
134
+ // https://github.com/mozilla/uniffi-rs/pull/1901
135
+ setTimeout ( ( ) => resolve ( pollResult ) , 20 ) ;
136
+ }
114
137
} ;
115
138
116
139
// For testing only.
0 commit comments