Bug: 28047

Impact:

Product:
GemBuilder for Smalltalk

Versions:
5.4, 5.3.2, 5.3.1, 5.3, 5.2.7, 5.2.6, 5.2.5, 5.2.4, 5.2.3, 5.2.2, 5.2.1, 5.2, 5.1.4, 5.1.3sp1

Platform:
VA

Fixed In:

"Invalid operation during callback" errors from VisualAge

A design limitation in VisualAge causes Semaphore>>wait to fail
with the error:

  'Invalid operation during callback'

if the operation occurs during a UI callback, and the semaphore
must wait.

GBS relies on semaphores for normal operation.  If a UI callback
must unstub objects, or invoke GemStone code, and another thread
is currently accessing that GbsSession, this error may occur.

Workaround:

The simplest way to work around this error is to fork execution
at some point so that by the time GBS has to go through a
semaphore, it is no longer running in the UI process.  Examine
the stack traces of occurrences of this error and determine
an appropriate place to fork.  This can often be achieved
by wrapping the entire contents of such a method with:

  [
    <contents of method>
  ] fork

Often, this can be isolated to a small number of places in the
application.  

There are a couple restriction on this workaround -
the senders of this method cannot be relying on the return
value from this method.  In many cases, the sender is the VisualAge
method CwCallbackRec>>callWith:callData:, which doesn't use the
return value of the application's callback method, so it works
(assuming there aren't other senders in the application that do
rely on the return value).

Another restriction is there can't be any returns (^) at all
from inside the forked block.  So if the method contains a
control flow construct such as:

  x == y ifTrue: [
    <do one thing>
    ^self ].
  <do another thing>

... it needs to be recoded to avoid the return statement, like:

  x == y
    ifTrue: [
      <do one thing> ]
    ifFalse: [
      <do another thing> ]

One potential problem with this workaround of simply forking, though,
is the possibility of introducing multiple threads into the application
where you might not want it.  When the block is forked off, the UI
will immediately become usable again, even though the block may still
be executing.  Ask yourself the following questions:  Is it possible
that another UI request will be issued before that block finishes
executing?  If so, will that be OK?

If that's not OK, then the next part of the workaround is to introduce
a work queue.  Rather than simply saying "[ <work> ] fork", instead
the workaround will be of the form "someQueue submit: [ <work> ]",
and the queue will make sure that blocks submitted to it are executed
one at a time.  


Comments: