Asynchronous task that have access to XPCOM components: is it possible? - firefox

I need to create asynchronously executing task (pure JS) that is creating and working with XPCOM components (using Components.classes and Components.interfaces).
However, Worker and ChromeWorker do not have access to Components. Also, I cannot pass to them an XPCOM component created in the main thread (postMessage), as XPCOM components are not serializable.
It seems that it can be possible with nsIThread and nsIThreadManager, but documentation states that
In versions of Gecko prior to 2.0, it is possible to create real asynchronous threads.
Although this can often be accomplished without serious adverse effects, it is far from safe
and often leads to unpredictable crashes. For this reason, as of Gecko 2.0, it is no longer
possible to pass JavaScript objects from one thread to another, making the Thread Manager
unuseable from JavaScript.
and I do not want to introduce any incompatibility with Gecko 2.0.
Are there other ways to do that?
P. S. I find (Chrome)Workers hardly usable at all, as they do not have access neither to the DOM nor to Components. Why one would ever want to use them?

No, most XPCOM components are not thread-safe so that working with them from a different thread would only lead to crashes (which is why Thread Manager was rendered inaccessible to scripts). If your task contains lots of computations - use Worker to move it off the main thread and postMessage to tell the main thread access XPCOM whenever necessary. If it is mainly accessing XPCOM then it will be no use of course. You will have to do the work on the main thread and split it into small chunks to make sure that the main thread isn't being blocked. You can use nsIEventTarget.dispatch() to schedule the next processing step, something like this:
var thread = Components.classes["#mozilla.org/thread-manager;1"]
.getService(Components.interfaces.nsIThreadManager)
.currentThread;
var currentStep = -1;
function nextStep()
{
currentStep++;
//
// Execute step currentStep here
//
// Schedule next step
thread.dispatch(nextStep, thread.DISPATCH_NORMAL);
}
nextStep();
Documentation:
nsIThreadManager
nsIThread
nsIEventTarget

Related

When to use Unconfined in Kotlin

When would I choose to use Dispatchers.Unconfined? Is when it doesn't really matter where the coroutine should run? So you let the coroutine to choose the thread pool as it better suits?
And how does it differ from Dispatchers.Default? Is it that when running the Default dispatcher is always within a specific thread pool defined as the default one?
So you let the coroutine to choose the thread pool as it better suits?
That's not really how Unconfined works. The best way to understand it is that it is a "no-op" dispatcher that doesn't actually do any dispatch at all. Wherever you call continuation.resume(), that's where the coroutine resumes execution — within that very call. When the resume() call returns, it means the coroutine has either suspended again or completed.
In normal programming, you usually call continuation.resume() from a callback and it is not your code that runs the callback, so you don't actually have any control over the thread where your coroutine will resume. It is not advisable to use the Unconfined dispatcher when resuming from a callback provided by a library that is not under your control.
Unconfined is really a special-cased tool you can use when building a coroutine execution environment yourself, or in other custom scenarios. Basically, you should use it only when you are actively looking for a way to disable the normal dispatching mechanism.
The unconfined dispatcher is appropriate for coroutines which neither consume CPU time nor update any shared data (like UI) confined to a specific thread.
So, I'd use it in non-IO, UI or computation heavy situations basically :D.
I think the nunmber of use-cases for this is pretty low, but I'd think of an operation which isn't heavy, but still for some reason you'd like it to run on a different thread.
Here's a link for how it actually works.
Dispatchers.Default is really different, and it's mostly used for heavy CPU operations.
This is because, it actually dispatches works to a thread pool with a number of threads equal to the number of CPU cores, and it's at least 2. This way developers can leverage the full capacity of the cpu when doing heavy computational work.

What happens in Xamarin when Forms.Init gets called and the function is already running in another thread?

I'm thinking about how to reduce the cost of loading Forms.Init during the start of my app.
There's some work my app does that I can already do without access to Xamari.Forms. I'm thinking about loading Forms.Init in parallel in another thread.
In case that thread isn't yet finished and I already need Xamari.Forms, I'm not sure what my option are at handling the event.
What happens in Xamarin when Forms.Init gets called and the function is already running in another thread? Or are there otherwise best practices of dealing with loading Forms.Init in parallel to other work?
Forms.Init() calls the private SetupInit() which runs platform dependent code ranging from getting an Android Context, registering renderers, adding log listeners, etc...
Assembly callingAssembly = Assembly.GetCallingAssembly ();
SetupInit (activity, callingAssembly);
There are no callbacks or events tried to the competition of Init other then its synchronous completion, but there is a boolean flag that can be checked:
global::Xamarin.Forms.Forms.IsInitialized
But, depending upon platform, this flag can be set at the beginning of the method or at the end and also note there is no lock on setting this flag (which would cause a performance hit).
So, if the other code you need to run can be done completely without Forms, yes, you could do run this in parallel.
Your Application subclass and its LoadApplication step, of course, should not be done until Init() is finished.
re: https://github.com/xamarin/Xamarin.Forms

Run async function in specific thread

I would like to run specific long-running functions (which execute database queries) on a separate thread. However, let's assume that the underlying database engine only allows one connection at a time and the connection struct isn't Sync (I think at least the latter is true for diesel).
My solution would be to have a single separate thread (as opposed to a thread pool) where all the database-work happens and which runs as long as the main thread is alive.
I think I know how I would have to do this with passing messages over channels, but that requires quite some boilerplate code (e.g. explicitly sending the function arguments over the channel etc.).
Is there a more direct way of achieving something like this with rust (and possibly tokio and the new async/await notation that is in nightly)?
I'm hoping to do something along the lines of:
let handle = spawn_thread_with_runtime(...);
let future = run_on_thread!(handle, query_function, argument1, argument2);
where query_function would be a function that immediately returns a future and does the work on the other thread.
Rust nightly and external crates / macros would be ok.
If external crates are an option, I'd consider taking a look at actix, an Actor Framework for Rust.
This will let you spawn an Actor in a separate thread that effectively owns the connection to the DB. It can then listen for messages, execute work/queries based on those messages, and return either sync results or futures.
It takes care of most of the boilerplate for message passing, spawning, etc. at a higher level.
There's also a Diesel example in the actix documentation, which sounds quite close to the use case you had in mind.

NSUrlConnection synchronous request without accepting redirects

I am currently implementing code that uses macOS API for HTTP/HTTPs requests in a Delphi/Lazarus program.
The code runs in its own thread (i.e. not main/ui thread) and is part of a larger threading based crawler across Windows/Mac and Delphi/Lazarus. I try to implement the actual HTTP/S request part using the OS API - but handle e.g. processing and taking action upon HTTP headers myself.
This means I would like to keep using synchronous mode if possible.
I want the request to simply return to me what the server returns.
I do not want it to follow redirects.
I currently use sendSynchroniousRequest_returningResponse_error
I have tried searching Google, but it seems there is no way when using synchronous requests? That just seems a bit odd.
No, NSURLConnection's synchronous functionality is very limited, and was never expanded because it is so strongly discouraged. That said, it is technically possible to implement what you're trying to do.
My recollection, from having replaced that method with an NSURLSession equivalent once (to swizzle in a less leaky replacement for that method in a binary-only library), is that you need to basically write a method that uses a shared dictionary to store a semaphore for each NSURLSessionDataTask (using the data task as a key). Then, you set the semaphore's count to zero so that it will block immediately when you wait on it, asynchronously start an asynchronous request on the main thread, and then wait on the semaphore (in the current thread). In the asynchronous data task's completion handler block, you increment the semaphore, thus unblocking the calling thread.
The trick is to ensure that the session runs its callbacks on a thread OTHER than the current one (which is blocked waiting for the semaphore). So you'll need to dispatch_async into the main thread when you actually start the data task.
Ostensibly, if you supported converting the task into a download task or stream task in the relevant delegate method, you would also need to take appropriate action to update the shared dictionary as well, but I'm assuming you won't use that feature. :-)

Outlook Addin: Working with threads

I'm working on an Outlook Addin, and I have to process a large amount of items. This takes quite a lot of time, and I therefore tried to have the processing running in a different thread (using Task.Factory.StartNew). However, that results in Outlook randomly crashing.
I'm using Redemption to work with MAPITable, in order to reduce workload and load only relevant data.
I've tried initializing my RDOSession from both my main thread, and my worker thread.
I've tried getting the MAPIFolders on the main thread, and working with only the MAPITable on the worker thread
Currently, the only thing that works for me is running all my logic on the main thread (in the button click event), however that locks Outlook's user interface for a long period of time, which is unacceptable from a user's point of view.
Does anyone have some pointer on how to work with background threads from within an Outlook Addin?
Having similar code in my project I would suggest the following:
Create new thread using the Thread class and set it apartment to STA.
Loggin to session using "session.Logon("profileName", NoMail: true, NewSession: false);" and not using MAPIOBJECT. I found it has better performance than using MAPIOBJECT, my guess is it still marshal some calls back to the main thread as MAPIOBJECT was created on the main thread.
Use "Marshal.ReleaseComObject" on each and every COM object you use as soon as you are done with them. This is probably what causing the instability as Outlook really doesn't like when it's object are left too long. For example this line of code "var table = rdoFolder.Items.MAPITable;" create two COM objects: RDOItems and MAPITable, both of them must be released so you need to split this line to hold reference to RDOItems object.
Call GC.Collect and Application.DoEvents because if you don't call Marshal.ReleaseComObject on all COM object the finalizer will try to release them and will hang because the COM objects were created on thread that don't pump message loop and it's finalizer method must run on the thread that created them.
If you can, fire a secondary process and do this loop in the separate process. This will make maximum separation between the UI and your background work.
What was the problem using RDO objects in a secondary thread? As long as RDOSession is created on the secondary thread, MAPI should be properly initialized.
Also, TaskFactory uses a thread pool, you'd be better off using an explicit Thread class, o at least make sure that RDOSession is not shared between different threads - MAPI must be initialized on each thread.

Resources