-- XConnectionEventQImpl.mesa -- Created By Jeff Weinstein on 2-May-87 16:03:25 DIRECTORY Heap, Environment, TcpStream, XConnection, XEventQ, XQueue; XConnectionEventQImpl:MONITOR IMPORTS Heap, TcpStream, XQueue EXPORTS XConnection, XEventQ = BEGIN MaxClients: CARDINAL = XConnection.MaxClients; ConnectionData:TYPE = RECORD[ q:XQueue.QueuePtr ← NIL, state:XConnection.State ← unused, connection:TcpStream.Handle ]; zero: CARDINAL ← 0; Connections:ARRAY [0..MaxClients) OF ConnectionData ← ALL[[NIL,unused,NIL]]; RequestsPending:ARRAY [0..MaxClients) OF BOOLEAN ← ALL[FALSE]; NumPendingRequests:CARDINAL ← 0; connectionQ:XQueue.QueuePtr ← XQueue.NewQueue[]; eventQ:XQueue.QueuePtr ← XQueue.NewQueue[]; zone:UNCOUNTED ZONE ← Heap.systemZone; eventOrClientHint: CONDITION; ConnectionInUse:PUBLIC ERROR = CODE; ConnectionNotOpen:PUBLIC ERROR = CODE; ConnectionNotClosing:PUBLIC ERROR = CODE; QueueEmpty:PUBLIC ERROR = CODE; CreateConnection:PUBLIC ENTRY PROCEDURE [client:XConnection.Client, connection:TcpStream.Handle] = BEGIN IF Connections[client].state # unused THEN RETURN WITH ERROR ConnectionInUse; Connections[client] ← [XQueue.NewQueue[],open, connection]; END; DestroyConnection:PUBLIC ENTRY PROCEDURE [client:XConnection.Client] = BEGIN -- WARNING: DOES NOT FREE STUFF STILL ON QUEUE IF Connections[client].state # closing THEN RETURN WITH ERROR ConnectionNotClosing; NumPendingRequests ← NumPendingRequests - XQueue.QueueCount[Connections[client].q]; XQueue.FreeQueue[@Connections[client].q]; Connections[client].state ← unused; RequestsPending[client] ← FALSE; Connections[client].connection.destroy[Connections[client].connection]; END; ClosingConnection:PUBLIC ENTRY PROCEDURE [client:XConnection.Client] = BEGIN IF Connections[client].state # open THEN RETURN WITH ERROR ConnectionNotOpen; Connections[client].state ← closing; Connections[client].connection.close[]; END; EnQueueRequest:PUBLIC ENTRY PROCEDURE [client:XConnection.Client, request:LONG POINTER TO UNSPECIFIED, size:LONG CARDINAL] = BEGIN IF Connections[client].state # open THEN RETURN WITH ERROR ConnectionNotOpen; XQueue.EnQueue[Connections[client].q, request, size]; NumPendingRequests ← NumPendingRequests + 1; RequestsPending[client] ← TRUE; BROADCAST eventOrClientHint; END; DeQueueRequest:PUBLIC ENTRY PROCEDURE [client:XConnection.Client] RETURNS [request:LONG POINTER TO UNSPECIFIED, size:LONG CARDINAL] = BEGIN IF Connections[client].state = unused THEN RETURN WITH ERROR ConnectionNotOpen; [request, size] ← XQueue.DeQueue[Connections[client].q]; IF request = NIL THEN BEGIN IF Connections[client].state = closing THEN RETURN WITH ERROR ConnectionNotOpen ELSE RETURN WITH ERROR QueueEmpty; END; IF XQueue.QueueCount[Connections[client].q] = 0 THEN RequestsPending[client] ← FALSE; NumPendingRequests ← NumPendingRequests - 1; END; PendingRequests:PUBLIC ENTRY PROCEDURE RETURNS [numRequests:CARDINAL, clients:ARRAY[0..MaxClients) OF BOOLEAN] = BEGIN numRequests ← NumPendingRequests; clients ← RequestsPending; END; PendingConnections:PUBLIC ENTRY PROCEDURE RETURNS[anyPending:BOOLEAN] = BEGIN anyPending ← XQueue.QueueCount[connectionQ] # 0; END; EnQueueConnection: PUBLIC ENTRY PROCEDURE [connection:TcpStream.Handle] = BEGIN XQueue.EnQueue[q:connectionQ, data:connection]; BROADCAST eventOrClientHint; END; DeQueueConnection: PUBLIC ENTRY PROCEDURE RETURNS [connection:TcpStream.Handle] = BEGIN [data:connection] ← XQueue.DeQueue[q:connectionQ]; IF connection = NIL THEN RETURN WITH ERROR QueueEmpty; END; NewEvent:PUBLIC PROCEDURE RETURNS[event:XEventQ.EventPtr] = BEGIN RETURN[zone.NEW[XEventQ.Event]]; END; FreeEvent:PUBLIC PROCEDURE[eventP:LONG POINTER TO XEventQ.EventPtr] = BEGIN zone.FREE[eventP]; END; EnQEvent:PUBLIC ENTRY PROCEDURE[event:XEventQ.EventPtr] = BEGIN XQueue.EnQueue[eventQ,event]; BROADCAST eventOrClientHint; END; DeQEvent:PUBLIC ENTRY PROCEDURE RETURNS[event:XEventQ.EventPtr] = BEGIN [data:event] ← XQueue.DeQueue[eventQ]; -- IF event = NIL THEN -- RETURN WITH ERROR QueueEmpty; END; EventCount:PUBLIC ENTRY PROCEDURE RETURNS[count:CARDINAL] = BEGIN count ← XQueue.QueueCount[eventQ]; END; EventQPointers:PUBLIC PROCEDURE RETURNS[p1, p2:LONG POINTER] = BEGIN p1 ← @eventQ.count; p2 ← @zero; END; WaitForEventOrClient:PUBLIC ENTRY PROCEDURE = BEGIN WHILE ( NumPendingRequests = 0 ) AND ( XQueue.QueueCount[eventQ] = 0 ) AND ( XQueue.QueueCount[connectionQ] = 0 ) DO WAIT eventOrClientHint; ENDLOOP; END; SendToClient:PUBLIC ENTRY PROCEDURE [client:XConnection.Client, data:Environment.Block] = BEGIN IF Connections[client].state # open THEN GOTO noconnect; Connections[client].connection.put[data, TRUE, FALSE! TcpStream.Suspended => GOTO noconnect]; EXITS noconnect => BEGIN Connections[client].state ← closing; RETURN WITH ERROR ConnectionNotOpen; END; END; -- Mainline code -- END...