Case Closed (was Re: Help with fixing x2x...)

Harold L Hunt II huntharo@msu.edu
Thu Jul 25 13:45:00 GMT 2002


Thomas,

Excellent.

In xwinclip I calculate the maximum socket number just like you are doing:
   /* Find max of our file descriptors */
   iMaxDescriptor = max (fdMessageQueue, iConnectionNumber) + 1;

At least it is fixed now.

Harold


Thomas Chadwick wrote:
> Well, I figured it out.  The buggy behavior was indeed due to a bogus 
> value of nfds.  After poking around in the xfree86 source, I came across 
> xc/lib/Xt/Display.c, which manipulates its own nfds variable in much the 
> same way as x2x.
> 
> In short, changing this:
> 
>  /* set up for select */
>  nfds = getdtablesize();
>  fdset = (fd_set *)malloc(sizeof(fd_set));
>  fromConn = XConnectionNumber(fromDpy);
>  toConn   = XConnectionNumber(toDpy);
> 
> To this:
> 
>  /* set up for select */
>  fdset = (fd_set *)malloc(sizeof(fd_set));
>  fromConn = XConnectionNumber(fromDpy);
>  toConn   = XConnectionNumber(toDpy);
>  nfds = MAX(fromConn, toConn) + 1;
> 
> Does the trick.  However, before I repackage it for Cygwin Setup, I'll 
> probably apply many (if not all) of Harold's suggestions as well.
> 
> Thanks, everyone!
> 
>> From: Harold L Hunt II <huntharo@msu.edu>
>> Reply-To: cygwin-xfree@cygwin.com
>> To: cygwin-xfree@cygwin.com
>> Subject: Re: Help with fixing x2x...
>> Date: Wed, 24 Jul 2002 15:17:52 -0400
>>
>> Thomas Chadwick wrote:
>>
>>> Hmmm.   I tried your suggestion and the behavior has not changed.  It's
>>> still gobbling up 99% of the CPU.  Suspecting that select() is not
>>> blocking like it should, I inserted "printf("Hello\n");" just before the
>>> select() function call.  Now when I run x2x I get a continuous stream of
>>> "Hello"s on STDOUT whether or not I'm moving the mouse or typing.
>>>
>>> By comparison, I compiled x2x on my AIX workstation, including the
>>> "Hello" addition.  When I run x2x there, I observe that it only prints
>>> "Hello" when I move the mouse or hit a key.  This seems to me to be the
>>> appropriate behavior.
>>>
>>> This little experiment implicates the select() function call itself as
>>> being the source of the trouble.  Now the question is, is it a problem
>>> with how select() is being used (and if so, is the problem at the
>>> Xserver or the Xclient end), or is there a problem with the Cygwin
>>> implementation of it?
>>>
>>> Are you aware of any Xclients which use select() and yet do not exhibit
>>> the non-blocking behavior I'm seeing?  Perhaps there is a minor tweak
>>> required in how it is being called.
>>>
>>
>> Yup, xwinclip uses select () just like x2x does:
>>
>> http://xfree86.cygwin.com/devel/xwinclip/changelog.html
>>
>> Just download the tarball for Test06 and look in xwinclip.c/main ()/Line
>> 390.
>>
>> I think the problem may be with the value that getdtablesize () is
>> returning.  To find out, you need to printf the value of nfds, fromConn,
>>  and toConn.  If nfds isn't at least one larger than the maximum of
>> fromConn and toConn, then you have a problem.  You can alternatively
>> replace nfds in the call to select with FD_SETSIZE.
>>
>> Probably the main problem here, other than if nfds is incorrect, is that
>> the event loop fails to flush all X events before its first call to
>> select (), which is necessary because there may be events stored in
>> local structures already.  Also, the manner in which the program
>> determines whether or not events are pending is non-standard and easy to
>> break.
>>
>> One other thing: the original programmer is malloc'ing fdset and freeing
>> it later.  This is entirely unnecessary, fdset should be an automatic
>> variable instead.
>>
>> I recommend completely replaceing the DoX2X function with the one below.
>>  I promise that it will work this time :)
>>
>> Harold
>>
>>
>> static void DoX2X(fromDpy, toDpy)
>> Display *fromDpy;
>> Display *toDpy;
>> {
>>   DPYINFO   dpyInfo;
>>   fd_set    fdset;
>>   int       fromConn, toConn;
>>   int       iReturn;
>>   Bool      fReturn;
>>
>>   /* set up displays */
>>   dpyInfo.fromDpy = fromDpy;
>>   dpyInfo.toDpy = toDpy;
>>   InitDpyInfo (&dpyInfo);
>>   RegisterEventHandlers (&dpyInfo);
>>
>>   /* get file handles for display event pipes */
>>   fromConn = XConnectionNumber(fromDpy);
>>   toConn   = XConnectionNumber(toDpy);
>>
>>   /*
>>    * We have to clear any pending events before our
>>    * first call to select, because there may be events
>>    * stored in local structures.  Failing to clear these
>>    * events will lead to select failing to operate
>>    * properly.  We just set the event flags here so
>>    * that both event loops are entered on the first time
>>    * through the main loop below.
>>    */
>>   FD_ZERO (&fdset);
>>   FD_SET (fromConn, &fdset);
>>   FD_SET (toConn, &fdSet);
>>
>>   /* Loop forever */
>>   while (True)
>>     {
>>       /* Check for events for From display */
>>       if (FD_ISSET (fromConn, &fdset))
>>         {
>>       /* Process any pending events for From display */
>>           while (XPending (fromDpy))
>>             fReturn = ProcessEvent (fromDpy, &dpyInfo);
>>
>>       /* Check for failure */
>>           if (fReturn) break;
>>         }
>>
>>       /* Check for events for To display */
>>       if (FD_ISSET (toConn, &fdset))
>>         {
>>       /* Process any pending events for To display */
>>           while (XPending (toDpy))
>>             fReturn = ProcessEvent (toDpy, &dpyInfo);
>>
>>       /* Check for failure */
>>           if (fReturn) break;
>>         }
>>
>>       /* Setup the structures for select () */
>>       FD_ZERO(&fdset);
>>       FD_SET(fromConn, &fdSet);
>>       FD_SET(toConn, &fdSet);
>>
>>       /* Wait for events from either screen before looping again */
>>       iReturn = select (FD_SETSIZE, &fdset, NULL, NULL, NULL);
>>       if (iReturn <= 0)
>>         {
>>           printf ("Call to select () failed.  Bailing.\n");
>>           break;
>>         }
>>     }
>> }
>>
>>
>>>> From: Harold L Hunt II <huntharo@msu.edu>
>>>> To: Thomas Chadwick <j_tetazoo@hotmail.com>
>>>> CC: cygwin-xfree@cygwin.com
>>>> Subject: Re: Help with fixing x2x...
>>>> Date: Tue, 23 Jul 2002 18:58:15 -0400
>>>>
>>>> Thomas,
>>>>
>>>> In x2x, the return value from ProcessEvent which indicates that
>>>> everything went normally is False, not True.  The real intentions for
>>>> the return value of ProcessEvent can be described by the boolean
>>>> variable called ``bAbortedDisconnect'' that is returned from
>>>> ProcessMotionNotify.  Much more on that below but for now,
>>>>
>>>> Ohmygodthatisfunny!!!
>>>>
>>>> In the loop, the code does this:
>>>>
>>>> 1) Check for an event on fromDpy.  XPending returns immediately.
>>>>
>>>> 2) Process the event for fromDpy if an event was pending.  If we
>>>> processed an event successfully, continue looping.  Else, the
>>>> ProcessEvent function returned True and we are supposed to shutdown,
>>>> thus the ``break''.
>>>>
>>>> 3) Check for an event on toDpy.  XPending returns immediately.
>>>>
>>>> 4) Process the event for toDpy if an event was pending.  If we
>>>> processed an event successfully, continue looping.  Else, the
>>>> ProcessEvent function returned True and we are supposed to shutdown,
>>>> thus the ``break''.
>>>>
>>>> 5) Else, if we did not process an event from either screen, wait until
>>>> one or both o fthe file handles that represent the display event
>>>> queues becomes ready for reading.
>>>>
>>>> I think that your infinite loop has to do with the fact that XPending
>>>> returns a count of events ready for reading in fromPending, rather
>>>> than a boolean value.  I think that (!fromPending) had the desired
>>>> effect on the developer's platform of determining that (fromPending ==
>>>> 0), but that is a highly compiler-dependent assumption on behalf of
>>>> the original developer.
>>>>
>>>> For clarity, I would rewrite the section as follows (notice the
>>>> correction in the ``else if''):
>>>>
>>>> ====================================================================
>>>> while (True) /* FOREVER */
>>>>   {
>>>>     /* Save the number of event ready for fromDpy */
>>>>     fromPending = XPending(fromDpy);
>>>>
>>>>     /* Process any events ready for fromDpy */
>>>>     if (fromPending != 0)
>>>>       if (ProcessEvent(fromDpy, &dpyInfo)) /* shutdown if True! */
>>>>         break;
>>>>
>>>>     /* Process any events ready for toDpy */
>>>>     if (XPending(toDpy))
>>>>       {
>>>>         if (ProcessEvent(toDpy, &dpyInfo)) /* shutdown if True! */
>>>>           break;
>>>>       }
>>>>     else if (fromPending == 0)
>>>>       {
>>>>         /* No events ready for either display.  Wait for an event. */
>>>>         FD_ZERO(fdset);
>>>>         FD_SET(fromConn, fdset);
>>>>         FD_SET(toConn, fdset);
>>>>         select(nfds, fdset, NULL, NULL, NULL);
>>>>       }
>>>>   } /* END FOREVER */
>>>> ====================================================================
>>>>
>>>> Now, for the excitement about the bAbortedDisconnect variable from
>>>> ProcessMotionNotify:
>>>>
>>>> It looks like the original programmer is using some sort of
>>>> consistency checking on MotionNotify events to determine that the X
>>>> server is shutting down.  I will have to look into this further, but
>>>> it looks promising from my initial inspection.  This is the final step
>>>> that I need for xwinclip to function properly on server resets and
>>>> shutdowns. Needless to say, hopefully I am seeing what I want to see :)
>>>>
>>>> Harold
>>>>
>>>>
>>>>
>>>> Thomas Chadwick wrote:
>>>>
>>>>> I recently discovered that when I run x2x, the Win2k Task Manager
>>>>> reports that it's using 90-99% of the CPU.
>>>>>
>>>>> While I have not noticed a slow down in performance when it's
>>>>> running, I'd like to fix it if I can.  I've poked around in the
>>>>> source and I don't like the looks of the main loop:
>>>>>
>>>>>  while (True) { /* FOREVER */
>>>>>    if (fromPending = XPending(fromDpy))
>>>>>      if (ProcessEvent(fromDpy, &dpyInfo)) /* done! */
>>>>>     break;
>>>>>
>>>>>    if (XPending(toDpy)) {
>>>>>      if (ProcessEvent(toDpy, &dpyInfo)) /* done! */
>>>>>     break;
>>>>>    } else if (!fromPending) {
>>>>>      FD_ZERO(fdset);
>>>>>      FD_SET(fromConn, fdset);
>>>>>      FD_SET(toConn, fdset);
>>>>>      select(nfds, fdset, NULL, NULL, NULL);
>>>>>    }
>>>>>
>>>>> It would appear to me that this constant polling for an event to
>>>>> process is what's eating up the CPU cycles.
>>>>>
>>>>> Not being an X programmer, I'm hoping someone monitoring the list can
>>>>> suggest a way to modify this loop to be less of a CPU hog.
>>>>>
>>>>> Thanks.
>>>>>
>>>>>
>>>>> _________________________________________________________________
>>>>> MSN Photos is the easiest way to share and print your photos:
>>>>> http://photos.msn.com/support/worldwide.aspx
>>>>>
>>>
>>>
>>>
>>>
>>> _________________________________________________________________
>>> Send and receive Hotmail on your mobile device: http://mobile.msn.com
>>>
>>
>>
> 
> 
> 
> 
> _________________________________________________________________
> Chat with friends online, try MSN Messenger: http://messenger.msn.com
> 




More information about the Cygwin-xfree mailing list