In XULRunner version belowe 12.0 it's works, but when i'm trying port it to version 12.0 or higher it crash application. Main reason is that in sdk v12 or newer developers remove proxy objects to xpcom components and recommend replace it by wrapping objects with nsRunnable/nsIRunnable and route invocation to main thread by function NS_DispatchToMainThread (click here)
I created db connector which is async and comunicate with main thread by callbacks. Using: XULRunner v6, porting to XULRunner v17 or above
//nsIDBCallback.idl
[scriptable, function, uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)]
interface nsIDBCallback : nsISupports {
void onInfo(in long phase, in long status, in string info);
}
//nsDBService.h, it is XPCOM component
class nsDBService : public nsIDBService, nsIRunnable
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSIDBSERVICE
private:
std::vector<nsIThread*> threads;
std::vector<nsIDBCallback*> callbacks;
std::vector<const char*> sqls;
nsIThread* makeNewThread();
void runOperationIfNotBussy();
public:
NS_IMETHODIMP Query(const char *sql, nsIDBCallback *callback);
}
//nsDBService.cpp
// adding query and other data to buffers,
// it's thread safe, there are used mutex's
NS_IMETHODIMP nsDBService::Query(const char *sql, nsIDBCallback *callback)
{
callbacks.push_back(callback);
sqls .push_back(sql);
threads .push_back( makeNewThread() );
//run added operation if db driver is free,
//if driver is bussy then invocation is in buffer and need to wait
runOperationIfNotBussy();
return NS_OK;
}
void nsDBService::runOperationIfNotBussy()
{
//some conditions, test's etc.
//run first operation on list
// RUNNING A THREAD, still ok
if(...) threads.front()->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
}
//if this method is used by another thread+db query,
//then other operations can't run and need to wait
//operations are stored and supported like fifo
NS_IMETHODIMP nsDBService::Run(void)
{
//some other operations
//real db operations in background
int32_t phase = 3; //endphase
int32_t code = 0; //ok
const char *msg = "OK";
nsIDBCallback *callback = callbacks.pop();
//wrapping callback function with runnable interface
nsIRunnable *runCallback = new nsResultCallback(callback,
phase,
code,
msg);
//routing event to main thread
NS_DispatchToMainThread(runCallback, NS_DISPATCH_NORMAL);
runOperationIfNotBussy();
}
//nsResultCallback.h
class nsResultCallback: public nsRunnable
{
public:
NS_DECL_ISUPPORTS
public:
NS_DECL_NSIRUNNABLE
private:
nsIDBCallback* callback;
int32_t resPhase;
int32_t resStatus;
const char* resMessage;
public:
nsResultCallback(nsIDBCallback* callback,
int32_t phase,
int32_t status,
const std::string &message)
: callback(callback),
resPhase(phase),
resStatus(status),
resMessage(c_str_clone(message.c_str())) {};
~nsResultCallback();
};
//nsResultCallback.cpp
NS_IMETHODIMP nsResultCallback::Run(void)
{
nsresult rv = NS_ERROR_FAILURE;
try
{
// APP HANDS AND CRUSH !
if(this->callback) this->callback->OnInfo(resPhase, resStatus, resMessage);
}
catch(...)
{
rv = NS_ERROR_UNEXPECTED;
ERRF("nsBackpack::Run call method OnInfo from callback failed");
}
return rv;
}
// *.js
nsDBService.query("SELECT * FROM t", function(phase, code, mes) {
//some UI actions or others db queries
});
Application freeze and crash when code execution look like this:
nsDBService::Query //main thread ok
nsDBService::runOperationIfNotBussy //main thread
nsDBService::threads.front()->Dispatch //run bg thread
nsDBService:Run //bg thread
NS_DispatchToMainThread //main thread
nsResultCallback::Run //main thread
nsIDBCallback::OnInfo //main thread, crash
If code execution look like this, everything is ok:
nsDBService::Query //main thread ok
NS_DispatchToMainThread //main thread
nsResultCallback::Run //main thread
nsIDBCallback::OnInfo //main thread ok
When nsIDBCallback is invoked from NS_DispatchToMainThread and NS_DispatchToMainThread is invoked from other thread then main app thread, then execution fails, what i'm missing, don't understand? Or what is another approach for background tasks?
Cannot reproduce, as you didn't provide a self-contained, complete example, so some remarks instead:
The first thing I noticed is the cross-thread access of std::vector
. You wrote something about mutexes in the comments, so this might be OK.
What is certainly wrong, is storing raw pointers to nsIDBCallback
. XPCOM objects are ref-counted. So as soon your Query
method returns, the underlying object might be delete
d if there are no other references to it, leaving behind a dangling pointer in your vector. I think this is what is happening here!
You need to keep the object alive until the thread is done with it, preferably by putting it into a nsCOMPtr<nsIDBCallback>
somewhere, e.g. in an nsCOMPArray<nsIDBCallback>
.
PS: Turns out this is a somewhat old question, which I missed... So sorry for the delay answering it :p
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With