PseudoTerminalImpl.mesa
Copyright Ó 1989, 1990, 1991 by Xerox Corporation. All rights reserved.
Brent Welch, September 26, 1990 10:00 am PDT -- extracted from Plumber
Michael Plass, September 24, 1991 2:31 pm PDT
DIRECTORY Ascii, IO, PseudoTerminal, Rope, SymTab, UnixSysCalls, UnixTypes, UXStrings;
PseudoTerminalImpl: CEDAR PROGRAM
IMPORTS IO, Rope, SymTab, UnixSysCalls, UXStrings
EXPORTS PseudoTerminal
~ BEGIN
OPEN PseudoTerminal;
ROPE: TYPE ~ Rope.ROPE;
Error: PUBLIC ERROR [code: ATOM, msg: ROPE] ~ CODE;
Allocate loops through the available names for ptys until it finds an unused one. It opens the master end of the pty and returns the name for the corresponding slave tty device.
inUse: SymTab.Ref ~ SymTab.Create[]; -- Don't try things that are probably in use anyway
Allocate: PUBLIC PROCEDURE [] RETURNS [PseudoTerminal] ~ {
pseudoTerminal: PseudoTerminal ¬ NEW[PseudoTerminalRep ¬ []];
ptyGroupNames: ROPE ~ "pqrs";
ptyLineNames: ROPE ~ "0123456789abcdef";
ptyGroups: NAT ~ ptyGroupNames.Length[];
ptyLines: NAT ~ ptyLineNames.Length[];
ptyCount: NAT ~ ptyGroups * ptyLines;
PTYName: PROCEDURE [nth: NAT, controller: BOOLEAN] RETURNS [ROPE] ~ {
group: NAT ~ nth / ptyLines MOD ptyGroups;
line: NAT ~ nth MOD ptyLines;
name: ROPE ~ IO.PutFR["/dev/%gty%g%g",
[character[IF controller THEN 'p ELSE 't]],
[character[ptyGroupNames.Fetch[group]]],
[character[ptyLineNames.Fetch[line]]]];
RETURN [name];
};
TryOpening: PROCEDURE [name: ROPE] RETURNS [UnixTypes.FileDescriptor] ~ {
IF SymTab.Insert[inUse, name, $TRUE]
THEN {
nameString: UXStrings.CString ~ UXStrings.Create[from: name];
descriptor: UnixTypes.FileDescriptor ~ UnixSysCalls.Open[
path: nameString, flags: [excl: true, access: RDWR], mode: []];
RETURN [descriptor];
}
ELSE RETURN [UnixTypes.FileDescriptor.error]
};
THROUGH [0..2) DO
FOR pty: NAT IN [0 .. ptyCount) DO
pseudoTerminal.controllerName ¬ PTYName[nth: pty, controller: TRUE];
pseudoTerminal.controllerFD ¬ TryOpening[name: pseudoTerminal.controllerName];
IF pseudoTerminal.controllerFD # UnixTypes.FileDescriptor.error THEN {
pseudoTerminal.slaveName ¬ PTYName[nth: pty, controller: FALSE];
EXIT;
}
ENDLOOP;
IF pseudoTerminal.controllerFD = UnixTypes.FileDescriptor.error
THEN SymTab.Erase[inUse] -- Retry - some may have come free
ELSE EXIT;
ENDLOOP;
IF pseudoTerminal.controllerFD = UnixTypes.FileDescriptor.error THEN {
ERROR Error[
code: $CantAllocatePseudoTerminal,
msg: "unable to allocate pseudo-terminal (/dev/pty* all in use)"];
};
RETURN [pseudoTerminal];
};
Close: PUBLIC PROCEDURE [pty: PseudoTerminal] ~ {
IF pty.controllerFD # UnixTypes.FileDescriptor.error THEN {
[] ¬ UnixSysCalls.Close[fd: pty.controllerFD];
pty.controllerFD ¬ UnixTypes.FileDescriptor.error;
[] ¬ SymTab.Delete[inUse, pty.controllerName];
};
};
END.