Bug 27368

Summary: XCB deadlocks in multi-threaded use
Product: XCB Reporter: Nicholas Allen <nick.allen>
Component: ProtocolAssignee: xcb mailing list dummy <xcb>
Status: RESOLVED FIXED QA Contact: xcb mailing list dummy <xcb>
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: GDB session dump
protocol dump obtained from xtrace.

Description Nicholas Allen 2010-03-29 22:41:47 UTC
Every now and then our application deadlocks and xcb_wait_for_reply does not return. I am doing an xcb_flush prior to every xcb_wait_for_event call.

I have attached the protocol trace obtained with xtrace and also a stack trace from gdb using "thread apply all bt full". It seems that GDB did not pick up the debugging symbols installed. Unfortunately, I could not run it with the debug libraries explicitly by setting the LD_LIBRARY_PATH as the JVM then crashed in Sun's native code trying to load the library.

The hang happens mostly when I call xcb_property_changed from the property utils library (I have 0.3.6-1 package installed on Ubuntu 9.10). Very rarely it also happens inside xcb_wait_for_event. In this trace it was inside xcb_property_changed again and I will try to get a trace of it inside xcb_wait_for_event as well.

Our event loop looks like this:

int finished = 0;
   xcb_generic_event_t* event;

   while (!finished)
   {
      xcb_flush(connection);
      event = xcb_wait_for_event(connection);

      if (event == NULL)
      {
         printf("Connection broken\n");
         break;
      }

      switch (event->response_type & 0x7f)
      {
      case XCB_EXPOSE:
      {
         xcb_expose_event_t* exposeEvent = (xcb_expose_event_t*)event;
         handleExposedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, exposeEvent->window),
               exposeEvent->x,
               exposeEvent->y,
               exposeEvent->width,
               exposeEvent->height);
      }
         break;

      case XCB_BUTTON_PRESS:
      {
         xcb_button_press_event_t* buttonPressEvent = (xcb_button_press_event_t*)event;
         handleMouseButtonPressedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, buttonPressEvent->event),
               buttonPressEvent->state,
               buttonPressEvent->detail,
               buttonPressEvent->event_x,
               buttonPressEvent->event_y);
      }
         break;

      case XCB_BUTTON_RELEASE:
      {
         xcb_button_release_event_t* buttonReleaseEvent = (xcb_button_release_event_t*)event;
         handleMouseButtonReleasedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, buttonReleaseEvent->event),
               buttonReleaseEvent->state,
               buttonReleaseEvent->detail,
               buttonReleaseEvent->event_x,
               buttonReleaseEvent->event_y);
      }
         break;

      case XCB_MOTION_NOTIFY:
      {
         xcb_motion_notify_event_t* mouseMoveEvent = (xcb_motion_notify_event_t*)event;
         handleMouseMovedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, mouseMoveEvent->event),
               mouseMoveEvent->state,
               mouseMoveEvent->event_x,
               mouseMoveEvent->event_y);
      }
         break;

      case XCB_KEY_PRESS:
      {
         xcb_key_press_event_t* keyPressEvent = (xcb_key_press_event_t*)event;
         xcb_keysym_t keySymbol = xcb_key_press_lookup_keysym(keySymbols, keyPressEvent, 0);

         handleKeyPressedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, keyPressEvent->event),
               connection,
               keyPressEvent->state,
               keySymbol,
               0);
      }
      break;

      case XCB_KEY_RELEASE:
      {
         xcb_key_release_event_t* keyReleaseEvent = (xcb_key_release_event_t*)event;
         xcb_keysym_t keySymbol = xcb_key_release_lookup_keysym(keySymbols, keyReleaseEvent, 0);

         handleKeyReleasedEvent(
            env,
            getTopLevelWindowHandle(env, javaDisplay, keyReleaseEvent->event),
            connection,
            keyReleaseEvent->state,
            keySymbol);
     }
     break;

      case XCB_CONFIGURE_NOTIFY:
      {
         xcb_configure_notify_event_t* configureEvent = (xcb_configure_notify_event_t*)event;
         handleWindowResizedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, configureEvent->window),
               configureEvent->width,
               configureEvent->height);

         handleWindowMovedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, configureEvent->window),
               configureEvent->x,
               configureEvent->y);
      }
      break;

      case XCB_CLIENT_MESSAGE:
      {
         xcb_client_message_event_t* clientEvent = (xcb_client_message_event_t*)event;

         if (clientEvent->type == displayData->WM_PROTOCOLS_ATOM)
         {
            if (clientEvent->data.data32[0] == displayData->WM_DELETE_WINDOW_ATOM)
            {
               handleCloseWindowRequestEvent(
                     env,
                     getTopLevelWindowHandle(env, javaDisplay, clientEvent->window));
            }
            else if (clientEvent->data.data32[0] == displayData->NET_WM_PING_ATOM)
            {
               respondToPing(connection, screen->root, clientEvent);
            }
         }
         else if (clientEvent->type == displayData->SHUTDOWN_EVENT_ATOM)
         {
            finished = 1;
         }
      }
      break;

      case XCB_PROPERTY_NOTIFY:
      {
         xcb_property_notify_event_t* propertyEvent = (xcb_property_notify_event_t*)event;

         xcb_property_changed(&propertyHandlers, propertyEvent->state, propertyEvent->window, propertyEvent->atom);
      }
      break;

      case XCB_MAP_NOTIFY:
      {
         xcb_map_notify_event_t* mapEvent = (xcb_map_notify_event_t*)event;

         handleWindowShownEvent(env, getTopLevelWindowHandle(env, javaDisplay, mapEvent->event));
      }
      break;

      case XCB_FOCUS_IN:
      {
         xcb_focus_in_event_t* focusEvent = (xcb_focus_in_event_t*)event;
         handleWindowActivatedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, focusEvent->event));
      }
      break;

      case XCB_FOCUS_OUT:
      {
         xcb_focus_out_event_t* focusEvent = (xcb_focus_out_event_t*)event;
         handleWindowDeactivatedEvent(
               env,
               getTopLevelWindowHandle(env, javaDisplay, focusEvent->event));
      }
      break;

      default: /* unknown event type - ignore it. */
         printf("Unknown event type %d\n", (int)event->response_type);
      break;
      }

      if (env->ExceptionOccurred())
      {
         env->ExceptionDescribe();
         env->ExceptionClear();
      }
   }
Comment 1 Nicholas Allen 2010-03-29 22:52:04 UTC
Created attachment 34539 [details]
GDB session dump
Comment 2 Nicholas Allen 2010-03-29 22:54:56 UTC
Created attachment 34540 [details]
protocol dump obtained from xtrace.
Comment 3 Jamey Sharp 2010-04-17 18:25:45 UTC
I bet I just fixed your bug. Could you retest with libxcb git master? Thanks!
Comment 4 Uli Schlachter 2012-01-30 08:56:19 UTC
Reporter vanished, so let's assume that Jamey's "I bet I just fixed your bug" is correct. (Reopen if not)

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.