-- XConnectionImpl.mesa -- Created By Jeff Weinstein on 2-May-87 16:03:25 DIRECTORY Environment, TcpStream, XConnection, XQueue; XConnectionImpl:MONITOR IMPORTS TcpStream, XQueue EXPORTS XConnection = BEGIN MaxClients: CARDINAL = XConnection.MaxClients; ConnectionData:TYPE = RECORD[ q:XQueue.QueuePtr ← NIL, state:XConnection.State ← unused, connection:TcpStream.Handle ]; 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[]; 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; END; ClosingConnection:PUBLIC ENTRY PROCEDURE [client:XConnection.Client] = BEGIN IF Connections[client].state # open THEN RETURN WITH ERROR ConnectionNotOpen; Connections[client].state ← closing; 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; 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]; 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; 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...