-- 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; RecalcPending[]; XQueue.FreeQueue[@Connections[client].q]; Connections[client].state ¬ unused; RequestsPending[client] ¬ FALSE; Connections[client].connection.destroy[Connections[client].connection]; END; RecalcPending:PRIVATE PROCEDURE = BEGIN NumPendingRequests ¬ 0; FOR i:INTEGER IN [0..MaxClients) DO IF RequestsPending[i] = TRUE THEN NumPendingRequests ¬ NumPendingRequests + XQueue.QueueCount[Connections[i].q]; ENDLOOP; END; ClosingConnection:PUBLIC ENTRY PROCEDURE [client:XConnection.Client] = BEGIN IF Connections[client].state = unused THEN RETURN WITH ERROR ConnectionNotOpen; IF Connections[client].state = open THEN BEGIN Connections[client].state ¬ closing; NumPendingRequests ¬ NumPendingRequests + 1; RequestsPending[client] ¬ TRUE; BROADCAST eventOrClientHint; Connections[client].connection.close[!TcpStream.Closed => CONTINUE; TcpStream.Suspended => CONTINUE]; END; 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 pad:PACKED ARRAY [0..4) OF Environment.Byte ¬ [0,0,0,0]; IF Connections[client].state # open THEN GOTO noconnect; Connections[client].connection.put[data, TRUE, FALSE! TcpStream.Suspended => GOTO noconnect]; IF ( ( data.stopIndexPlusOne - data.startIndex ) MOD 4 ) > 0 THEN Connections[client].connection.put[ [@pad, 0, 4 - ( ( data.stopIndexPlusOne - data.startIndex ) MOD 4 )], TRUE, FALSE!TcpStream.Suspended => GOTO noconnect]; EXITS noconnect => BEGIN ClosingConnection[client]; RETURN WITH ERROR ConnectionNotOpen; END; END; -- Mainline code -- END...