We are in the process of implementing support for multiple, concurrent clients in Sneezy. There are a number of issues that must be addressed: how should we arbitrate when multiple clients have registered an interest in the same event? To what extent should a client be allowed to change the state of the computation? How should we balance the need for clients to be protected from one another's manipulations and with the need for some clients to co-operate? How can we insure that simple clients with simple needs (a visualizer, for example) can be implemented without being required to support complex inter-client protocols?
Initially, we addressed the issues of arbitration and co-operation by allowing only one of the clients to be the ``master'' of the program at any time, with other clients being slaves. Signaled events were reported only to the master who could choose to forward them on to the slaves. This approach was determined to be too coarse-grained and we refined it to allow master/slave designations on a thread-by-thread basis. While this was sufficient for most situations, the resulting design forced even simple clients to use the full multi-client protocol. After looking more carefully at the behaviors of our tools, we have now concluded that a multi-level mechanism that allows simple clients to ignore others and lets complex tools manipulate the event delivery mechanism in the agent would best serve our needs.
A Sneezy client can be classified along two dimensions: what it does to the program state, and what its intentions are when it issues the CONTINUE command. The full classification is beyond the scope of this paper, but in general, ``nice'' clients don't modify the state and don't care what happens after a CONTINUE command. Consider, for example, the situation where a visualizer, an event-based debugger, and a state-based debugger are all running together. The visualizer is a ``nice'' tool which does not need to know about the others; it can receive events as they occur, retain control briefly, and then pass the event and the control on to the next client (perhaps the event-based debugger) by issuing a CONTINUE command. The event-and state-based debuggers, however, may not be as ``nice'' in the sense that they interact in complex ways. Thus, for example, the event-based debugger may modify or filter events, passing them to the state-based debugger only as it sees fit. The state-based debugger, in turn, may actually modify program state variables and execution but may allow its command stream to be monitored and intercepted by the event-based debugger. The tools set up the priorities and the event and command filtering by manipulating data structures within the agent. The agent does not provide high-level mechanisms for computing the priority/filtering structure, but one can implement a Sneezy client which does, allowing other clients to communicate with this client to set up arbitration.