Plugin hangs when calling Invoke

61 views
Skip to first unread message

Gaurav

unread,
Jun 2, 2013, 5:32:05 PM6/2/13
to firebre...@googlegroups.com
I have a MainApplication class which has an Update function. This update function does opengl calls to draw scene. 
So this Update function is being called continuously from the opengl thread. 
User can add new images by calling the insertImage(filename) function from the javascript. This function sets the member 
variable imageToBeLoaded of class MainApplication to the given filename. So when next update call to the main application
is done, it checks for the new image location and makes opengl texture from the given filename. Since this texture is added 
in different thread which happens some time after calling insertImage, I need a callback function in javascript to notify that
my image has been successfully added to the scene. To do so, I added the following code after texture loading -  

std::vector<FB::variant> argsEmpty;
argsEmpty.push_back("Successful");
apiPtr->Invoke("imageAddedCallback", argsEmpty);

But the plugin hangs while making call to invoke. While debugging I found that plugin stops at the boost::recursive_mutex::scoped_lock(m_zoneMutex) 
statement inside Invoke function.

FB::variant FB::JSAPIAuto::Invoke(const std::string& methodName, const std::vector<variant> &args) 
    -> boost::recursive_mutex::scoped_lock lock(m_zoneMutex); 
    ....
}

I'm not able to figure out, what the problem could be.

Gaurav

unread,
Jun 2, 2013, 5:33:37 PM6/2/13
to firebre...@googlegroups.com
I'm working on Windows 7 64-bit, Visual Studio 2010 and Firebreath 1.6.

John Tan

unread,
Jun 2, 2013, 6:28:42 PM6/2/13
to firebre...@googlegroups.com
No idea why it hangs. Perhaps, can you try boost::function and bind method for your callback? I've been using this for my notification event back to javascript and it works fine...

John Tan

unread,
Jun 2, 2013, 6:34:31 PM6/2/13
to firebre...@googlegroups.com
Another thing, this apiPtr, is this object created within your thread or is it from your mainthread? if it is from main thread, you must make sure you are getting the correct instance from the main thread.

Neil Griffiths

unread,
Jun 2, 2013, 6:39:26 PM6/2/13
to firebre...@googlegroups.com
It means that m_zoneMutex is locked by another thread. What is going on in the other threads?


--
 
---
You received this message because you are subscribed to the Google Groups "firebreath-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebreath-de...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Richard Bateman

unread,
Jun 2, 2013, 9:00:56 PM6/2/13
to firebre...@googlegroups.com

Whenever you have a deadlock (a lock that occurs on a mutex) and it's a recursive mutex you know that another thread is locked on that same mutex.  Look at the other threads and see which one it is, that'll give you a better idea of what is going on.  Note that when you call Invoke from another thread it has to marshall across threads to the main thread, which does involve some synchronization

Jun 2, 2013, в 16:39, Neil Griffiths <ne...@muzzylane.com> написал(а):

Gaurav Raj

unread,
Jun 3, 2013, 6:03:17 AM6/3/13
to firebre...@googlegroups.com
Thanks...I'll try checking your suggested methods and let you know what happens.
Gaurav Raj

Gaurav

unread,
Jun 16, 2013, 5:40:19 PM6/16/13
to firebre...@googlegroups.com
Hi, Sorry for the delay, I was busy with the development of Mac version of the plugin so couldnt test this. Finally, facing the same problem with Invoke in a different place.
Let me explain my code properly.

In the onWindowAttched event, I create the opengl thread and my mainApplicationPtr object pointer. mainApplicationPtr is object of MainApplication which is responsible for managing my plugin logic. All opengl calls are done from the mainApplication->update() function. I also pass the FB::JSAPIPtr    apiPtr into my mainApplicationPtr so that it can Invoke JS functions when required. I reset this apiPtr in onWindowDetach event where my mainApplicationPtr pointer is also deleted.

Opengl thread goes something like this -

LPTHREAD_START_ROUTINE SamplePlugin::drawThreaded( LPVOID lpParam )
{
    FBLOG_INFO("drawThreaded", "Initializing OpenGL Thread.");
    EnableOpenGL( pluginWindowWin->getHWND(), &hDC, &hRC );
    SetFocus(pluginWindowWin->getHWND());   
    enableEvents = true;
    pluginRunning = true;

    while(run & !stopThread)
    {
        try
        {
              FB::Rect pos = pluginWindow->getWindowPosition();
             #if FB_WIN
                // HDC hDC;
                // FB::PluginWindowlessWin *wndLess = dynamic_cast<FB::PluginWindowlessWin*>(pluginWindow);
                // FB::PluginWindowWin *wnd = dynamic_cast<FB::PluginWindowWin*>(pluginWindow);

                // The PAINTSTRUCT structure contains information that can be used to paint the client area of a window.
                PAINTSTRUCT ps;
                if(pluginWindowWin)
                {       
                    // The BeginPaint function prepares the specified window for painting and fills a
                    // PAINTSTRUCT structure with information about the painting.
                    hDC = BeginPaint(pluginWindowWin->getHWND(), &ps);
               

                    if(initializeFlag)
                    {
                        {
                            boost::recursive_mutex::scoped_lock lock(openglThreadMutex);
                            mainApplicationPtr->initialize();
                            initializeFlag = false;

                        }
                        std::vector<FB::variant> argsEmpty;
                        argsEmpty.push_back("Successful");
                        apiPtr->Invoke("initializedCallback", argsEmpty);
                }

                {
                    boost::recursive_mutex::scoped_lock lock(openglThreadMutex);
                    mainApplicationPtr->update();
                }               

                SwapBuffers( hDC );
            }
           
            if (pluginWindowWin) 
            {
                // Release the device context
                EndPaint(pluginWindowWin->getHWND(), &ps);
            }
        #endif
        //return true;
        }
        catch(...)
        {
            FBLOG_INFO("ThreadError", "Error occurred in opengl thread");
            return 0;
        }
           
        Sleep(10);
    }

    FBLOG_INFO("drawThreaded", "Breaking out of thread!");
    return 0;
}


I have exposed a JSAPI function named insertImageUsingUrl(url) which is used to load image into the plugin using its url. This JSAPI function internally calls a function with same name(insertImageUsingUrl) from MainApplication class(i.e. mainApplicationPtr->insertImageUsingUrl(std::string url)). This function downloads the image asynchronously and when the download is complete, it sets a bool named insertImageFlag to true. MainApplication's update function checks for this variable, if this is set to true, it creates opengl texture from the downloaded image. After this it Invokes - imageInsertedCallback. It is at this Invoke when the plugin hangs.

On my webpage, in the onload function I check if the plugin is installed or not. If it is installed, I insert the plugin object into the page. I also add the event initializeCallback to the plugin object in javascript. And this callback goes something like this in javascript,

addEvent(plugin(), 'initializeCallback', function(msg)
{
    plugin().insertImageUsingUrl("...");
}

When the plugin is initialized successfully, I insert image into it.

When I try to Invoke imageInsertedCallback, the plugin hangs in this line while locking m_zoneMutex - 
FB::variant FB::JSAPIAuto::Invoke(const std::string& methodName, const std::vector<variant> &args)
{
    boost::recursive_mutex::scoped_lock lock(m_zoneMutex);
...
}

m_zoneMutex shows that I has been locked by the mainThread, and then it hangs but all my Invoke calls are from my opengl thread.

I'm really out of ideas to solve this problem.

@John Tan: Could you please shed more light on how to implement callbacks using boost::bind and boost::function.
To unsubscribe from this group and stop receiving emails from it, send an email to firebreath-dev+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
 
---
You received this message because you are subscribed to the Google Groups "firebreath-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebreath-dev+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
 
---
You received this message because you are subscribed to the Google Groups "firebreath-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebreath-dev+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Gaurav Raj

John Tan

unread,
Jun 16, 2013, 9:15:05 PM6/16/13
to firebre...@googlegroups.com
Hi Gaurav,
 
As I used it to drive the video rendering in windowless mode, I can tell you how I did it for my case.
 
Assuming Player and PlayerAPI class is similar to FB-generated xxx and xxxAPI class.
 
1) Create member variable boost::function<void(void*)> onDrawDelegate; in Player.h
2) In the PlayerAPI init code, getPlugin->onDrawDelegate = boost::bind(&SMPPlayerAPI::RedrawWindowless, this, _1);
3) Create a function RedrawWindowless:
void PlayerAPI::RedrawWindowless(void* ptr)
{
      FB::PluginWindowlessWin* pWin = (FB::PluginWindowlessWin*)ptr;

      HDC hDC = pWin->getHDC();

      //Do whatever drawing here with the retrieved hDC

}

4) In the Player.cpp's onDraw event, call the onDrawDelegate

bool

 Player::onDraw(FB::RefreshEvent *evt, FB::PluginWindow *)

{

FB::PluginWindowlessWin* pWin =

dynamic_cast<FB::PluginWindowlessWin*>(GetWindow());

if (pWin && onDrawDelegate)

{

onDrawDelegate((

void*)pWin);

}

//Should return true or else the core FB event handler will think that RefreshEvent is not handled

//and will in turn always draw a "Firebreath Plugin" text at the center of the screen

return true;

}

5) Call InvalidateWindow from the PlayerAPI code whenever there is an image for me to draw.

6) I used pthread_cond and pthread_mutex mechanism to make sure that The code that prepares the image and call InvalidateWindow(Step 5) is always mutex with the code that does the drawing (Step 4) and also ensure that Step 5 is always executed first then Step 4 comes in.

 

Hope this helps....

Reply all
Reply to author
Forward
0 new messages