Using Microsoft.bcl.async in PCL with Mono Droid? - xamarin.android

I have a Portable Class Library (PCL) targeted at Profile158 (Windows Store, .NET 4.5, Silverlight 5, Windows Phone 8). I can easily work with methods that return a type of Task, and it all works as I would expect. Whenever I access the Result property, it finishes running the asynchronous code and returns the result.
However, if I use the async/await keywords in a method inside the PCL, I get a task back. However, when I attempt to access the Result property, it blocks and never returns.
Looking at the debug output window in Visual Studio in both cases I see the same text:
Thread started:
Thread started:
Loaded assembly: Mono.Security.dll [External]
Thread started:
Thread started:
So it appears as if the code is being run, but it never returns to the UI thread. Has anyone else tried to use a PCL with Microsoft.bcl.async in the PCL?
My Mono Droid project is targeted at Android 2.1.
Thanks,
-- John
Update:
Here is some additional information about the different scenarios. First, here is code that does work on Mono Droid when written in the UI code:
var task = request.GetResponseAsync();
string html = task.Result.GetResponseText();
I then created the following method in the PCL:
public async Task<string> Test()
{
IHttpResponse responce = await GetResponseAsync();
return responce.GetResponseText();
}
And call it with this code from the Mono UI code:
string html = request.Test().Result;
it never returns...

This is a classic deadlock scenario, as I describe on my blog.
By default, await will capture a "context" and use it to resume the async method. This "context" is the current SynchronizationContext unless it is null, in which case it's the current TaskScheduler.
So, you're calling an async method from a UI thread (which provides a SynchronizationContext), then blocking the UI thread by calling Result. The async method cannot finish because it is trying to finish on the UI thread, which is blocked.
To fix this, follow these guidelines:
Use async all the way down. Don't call Result or Wait on Tasks returned from async methods; use await instead.
Use ConfigureAwait(false) whenever possible in your library code.
You may also find my async/await intro helpful.

Related

How to restore runOn Scheduler used in previous operator?

Folks, is it possible to obtain currently used Scheduler within an operator?
The problem that I have is that Mono.fromFuture() is being executed on a native thread (AWS CRT Http Client in my case). As result all subsequent operators are also executed on that thread. And later code wants to obtain class loader context that is obviously null. I realize that I can call .publishOn(originalScheduler) after .fromFuture() but I don't know what scheduler is used to materialize Mono returned by my function.
Is there elegant way to deal with this?
fun myFunction(): Mono<String> {
return Mono.just("example")
.flatMap { value ->
Mono.fromFuture {
// invocation of 3rd party library that executes Future on the thread created in native code.
}
}
.map {
val resource = Thread.currentThread().getContextClassLoader().getResources("META-INF/services/blah_blah");
// NullPointerException because Thread.currentThread().getContextClassLoader() returns NULL
resource.asSequence().first().toString()
}
}
It is not possible, because there's no guarantee that there is a Scheduler at all.
The place where the subscription is made and the data starts flowing could simply be a Thread. There is no mechanism in Java that allows an external actor to submit a task to an arbitrary thread (you have to provide the Runnable at Thread construction).
So no, there's no way of "returning to the previous Scheduler".
Usually, this shouldn't be an issue at all. If your your code is reactive it should also be non-blocking and thus able to "share" whichever thread it currently runs on with other computations.
If your code is blocking, it should off-load the work to a blocking-compatible Scheduler anyway, which you should explicitly chose. Typically: publishOn(Schedulers.boundedElastic()). This is also true for CPU-intensive tasks btw.

How to pass native void pointers to a Dart Isolate - without copying?

I am working on exposing an audio library (C library) for Dart. To trigger the audio engine, it requires a few initializations steps (non blocking for UI), then audio processing is triggered with a perform function, which is blocking (audio processing is a heavy task). That is why I came to read about Dart isolates.
My first thought was that I only needed to call the performance method in the isolate, but it doesn't seem possible, since the perform function takes the engine state as first argument - this engine state is an opaque pointer ( Pointer in dart:ffi ). When trying to pass engine state to a new isolate with compute function, Dart VM returns an error - it cannot pass C pointers to an isolate.
I could not find a way to pass this data to the isolate, I assume this is due to the separate memory of main isolate and the one I'm creating.
So, I should probably manage the entire engine state in the isolate which means :
Create the engine state
Initialize it with some options (strings)
trigger the perform function
control audio at runtime
I couldn't find any example on how to perform this actions in the isolate, but triggered from main thread/isolate. Neither on how to manage isolate memory (keep the engine state, and use it). Of course I could do
Here is a non-isolated example of what I want to do :
Pointer<Void> engineState = createEngineState();
initEngine(engineState, parametersString);
startEngine(engineState);
perform(engineState);
And at runtime, triggered by UI actions (like slider value changed, or button clicked) :
setEngineControl(engineState, valueToSet);
double controleValue = getEngineControl(engineState);
The engine state could be encapsulated in a class, I don't think it really matters here.
Whether it is a class or an opaque datatype, I can't find how to manage and keep this state, and perform triggers from main thread (processed in isolate). Any idea ?
In advance, thanks.
PS: I notice, while writing, that my question/explaination may not be precise, I have to say I'm a bit lost here, since I never used Dart Isolates. Please tell me if some information is missing.
EDIT April 24th :
It seems to be working with creating and managing object state inside the Isolate. But the main problem isn't solved. Because the perform method is actually blocking while it is not completed, there is no way to still receive messages in the isolate.
An option I thought first was to use the performBlock method, which only performs a block of audio samples. Like this :
while(performBlock(engineState)) {
// listen messages, and do something
}
But this doesn't seem to work, process is still blocked until audio performance finishes. Even if this loop is called in an async method in the isolate, it blocks, and no message are read.
I now think about the possibility to pass the Pointer<Void> managed in main isolate to another, that would then be the worker (for perform method only), and then be able to trigger some control methods from main isolate.
The isolate Dart package provides a registry sub library to manage some shared memory. But it is still impossible to pass void pointer between isolates.
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Invalid argument(s): Native objects (from dart:ffi) such as Pointers and Structs cannot be passed between isolates.
Has anyone already met this kind of situation ?
It is possible to get an address which this Pointer points to as a number and construct a new Pointer from this address (see Pointer.address and Pointer.fromAddress()). Since numbers can freely be passed between isolates, this can be used to pass native pointers between them.
In your case that could be done, for example, like this (I used Flutter's compute to make the example a bit simpler but that would apparently work with explicitly using Send/ReceivePorts as well)
// Callback to be used in a backround isolate.
// Returns address of the new engine.
int initEngine(String parameters) {
Pointer<Void> engineState = createEngineState();
initEngine(engineState, parameters);
startEngine(engineState);
return engineState.address;
}
// Callback to be used in a backround isolate.
// Does whichever processing is needed using the given engine.
void processWithEngine(int engineStateAddress) {
final engineState = Pointer<Void>.fromAddress(engineStateAddress);
process(engineState);
}
void main() {
// Initialize the engine in a background isolate.
final address = compute(initEngine, "parameters");
final engineState = Pointer<Void>.fromAddress(address);
// Do some heavy computation in a background isolate using the engine.
compute(processWithEngine, engineState.address);
}
I ended up doing the processing of callbacks inside the audio loop itself.
while(performAudio())
{
tasks.forEach((String key, List<int> value) {
double val = getCallback(key);
value.forEach((int element) {
callbackPort.send([element, val]);
});
});
}
Where the 'val' is the thing you want to send to callback. The list of int 'value' is a list of callback index.
Let's say you audio loop performs with vector size of 512 samples, you will be able to pass your callbacks after every 512 audio samples are processed, which means 48000 / 512 times per second (assuming you sample rate is 48000). This method is not the best one but it works, I still have to see if it works in very intensive processing context though. Here, it has been thought for realtime audio, but it could work the same for audio rendering.
You can see the full code here : https://framagit.org/johannphilippe/csounddart/-/blob/master/lib/csoundnative.dart

how to use suspendCoroutine to turn java 7 future into kotlin suspending function

What is the best approach to wrap java 7 futures inside a kotlin suspend function?
Is there a way to convert a method returning Java 7 futures into a suspending function?
The process is pretty straightforward for arbitrary callbacks or java 8 completablefutures, as illustrated for example here:
* https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#suspending-functions
In these cases, there is a hook that is triggered when the future is done, so it can be used to resume the continuation as soon as the value of the future is ready (or an exception is triggered).
Java 7 futures however don't expose a method that is invoked when the computation is over.
Converting a Java 7 future to a Java 8 completable future is not an option in my codebase.
Of course, i can create a suspend function that calls future.get() but this would be blocking, which breaks the overall purpose of using coroutine suspension.
Another option would be to submit a runnable to a new thread executor, and inside the runnable call future.get() and invoke a callback. This wrapper will make the code looks like "non-blocking" from the consumer point of view, the coroutine can suspend, but under the hood we are still writing blocking code and we are creating a new thread just for the sake of blocking it
Java 7 future is blocking. It is not designed for asynchronous APIs and does not provide any way to install a callback that is invoked when the future is complete. It means that there is no direct way to use suspendCoroutine with it, because suspendCoroutine is designed for use with asynchronous callback-using APIs.
However, if your code is, in fact, running under JDK 8 or a newer version, there are high chances that the actual Future instance that you have in your code happens to implement CompletionStage interface at run-time. You can try to cast it to CompletionStage and use ready-to-use CompletionStage.await extension from kotlinx-coroutines-jdk8 module of kotlinx.coroutines library.
Of course Roman is right that a Java Future does not let you provide a callback for when the work is done.
However, it does give you a way to check if the work is done, and if it is, then calling .get() won't block.
Luckily for us, we also have a cheap way to divert a thread to quickly do a poll check via coroutines.
Let's write that polling logic and also vend it as an extension method:
suspend fun <T> Future<T>.wait(): T {
while(!isDone)
delay(1) // or whatever you want your polling frequency to be
return get()
}
Then to use:
fun someBlockingWork(): Future<String> { ... }
suspend fun useWork() {
val result = someBlockingWork().wait()
println("Result: $result")
}
So we have millisecond-response time to our Futures completing without using any extra threads.
And of course you'll want to add some upper bound to use as a timeout so you don't end up waiting forever. In that case, we can update the code just a little:
suspend fun <T> Future<T>.wait(timeoutMs: Int = 60000): T? {
val start = System.currentTimeMillis()
while (!isDone) {
if (System.currentTimeMillis() - start > timeoutMs)
return null
delay(1)
}
return get()
}
You should be now be able to do this by creating another coroutine in the same scope that cancels the Future when the coroutine is cancelled.
withContext(Dispatchers.IO) {
val future = getSomeFuture()
coroutineScope {
val cancelJob = launch {
suspendCancellableCoroutine<Unit> { cont ->
cont.invokeOnCancellation {
future.cancel(true)
}
}
}
future.get().also {
cancelJob.cancel()
}
}
}

Redemption RDOFolderSynchronizer Not working on BackgroundWorker Thread

I am a long time Redemption coder, with several apps using Redemption on the background thread (but not using RDOFolderSynchronizer up to now).
I have a new rSession object created on the backgroundworker thread, to which I pass the MAPI Object.
RedemptionCode rCodeBW = new RedemptionCode();
rCodeBW.InitialiseRedemption(Globals.MapiObject, true);
On the background thread I am trying to use the RDOFolderSynchronizer but when I run it, I get an error when I try to retrieve the syncitems. The error is:
IMAPIFolder.OpenProperty(PR_CONTENTS_SYNCHRONIZER) returned MAPI_E_INTERFACE_NOT_SUPPORTED
Synchronization is only supported for the Exchange folders in the online mode.
If I run the same code in the main thread it works fine, so I 'think' the 'online mode' issue is not the direct reason it is failing.
The code I am using is:
var MAPI_NO_CACHE = 0x200;
var MAPI_BEST_ACCESS = 0x10;
RDOFolder2 rFolder2 = rSession.GetFolderFromID(entryID, storeID, MAPI_NO_CACHE ^ MAPI_BEST_ACCESS) as RDOFolder2;
RDOFolderSynchronizer synchronizer = rFolder2.ExchangeSynchronizer;
RDOSyncMessagesCollection syncItems = synchronizer.SyncItems(Globals.UserSettings.LastSyncDataEmailInbox);
Any suggestions gratefully received.
Yes, that interface has to be used on the same thread where the parent MAPI session (IMAPISession) is created. It is an ICS API limitation in Extended MAPI.

Syncronous waiting for a Future or a Stream to complete in Dart

I'm playing with a tiny web server and I'm implementing one version using the async package, and one synchronous version executing each request in a separate isolate. I would like to simply pipe a file stream to the HttpResponse, but I can't do that synchronously. And I can't find a way to wait for neither the Stream nor a Future synchronously. I'm now using a RandomAccessFile instead which works, but it becomes messier.
One solution would be to execute a periodical timer to check if the future is completed (by setting a boolean or similar), but that is most definitely not something I want to use.
Is there a way to wait synchronously for a Future and a Stream? If not, why?
For future visitors coming here simply wanting to perform some task after a Future or Stream completes, use await and await for inside an async method.
Future
final myInt = await getFutureInt();
Stream
int mySum = 0;
await for (int someInt in myIntStream) {
mySum += someInt;
}
Note
This may be technically different than performing a synchronous task, but it achieves the goal of completing one task before doing another one.
AFAIK there isn't a way to wait synchronously for a Future or a Stream. Why? Because these are asynchronous pretty much definitionally, and as you are discovering, the APIs are designed with asynchronous behavior in mind.
There are a couple of Future constructors, Future.value() and Future.sync(), that execute immediately, but I don't think these are probably what you have in mind.

Resources