From patchwork Fri Jun 18 10:08:13 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Ada] GNAT.Sockets.Null_Selector Date: Fri, 18 Jun 2010 00:08:13 -0000 From: Arnaud Charlet X-Patchwork-Id: 56158 Message-Id: <20100618100813.GA3965@adacore.com> To: gcc-patches@gcc.gnu.org Cc: Thomas Quinot Developers may want to use the Check_Selector binding to the select(2) system call without needing to abort such calls using Abort_Selector. In this case, using a regular Selector_Type object (which contains a socket pair used for signalling) is unnecessary costly. A new constant Selector_Type object that does not contain signalling sockets is now provided for use in this case. New feature, no behaviour change, no test. Tested on x86_64-pc-linux-gnu, committed on trunk 2010-06-18 Thomas Quinot * g-socket.adb, g-socket.ads (Null_Selector): New object. Index: g-socket.adb =================================================================== --- g-socket.adb (revision 160965) +++ g-socket.adb (working copy) @@ -273,7 +273,8 @@ package body GNAT.Sockets is function Is_Open (S : Selector_Type) return Boolean; -- Return True for an "open" Selector_Type object, i.e. one for which - -- Create_Selector has been called and Close_Selector has not been called. + -- Create_Selector has been called and Close_Selector has not been called, + -- or the null selector. --------- -- "+" -- @@ -294,6 +295,10 @@ package body GNAT.Sockets is begin if not Is_Open (Selector) then raise Program_Error with "closed selector"; + + elsif Selector.Is_Null then + raise Program_Error with "null selector"; + end if; -- Send one byte to unblock select system call @@ -491,7 +496,7 @@ package body GNAT.Sockets is is Res : C.int; Last : C.int; - RSig : constant Socket_Type := Selector.R_Sig_Socket; + RSig : Socket_Type := No_Socket; TVal : aliased Timeval; TPtr : Timeval_Access; @@ -511,9 +516,12 @@ package body GNAT.Sockets is TPtr := TVal'Unchecked_Access; end if; - -- Add read signalling socket + -- Add read signalling socket, if present - Set (R_Socket_Set, RSig); + if not Selector.Is_Null then + RSig := Selector.R_Sig_Socket; + Set (R_Socket_Set, RSig); + end if; Last := C.int'Max (C.int'Max (C.int (R_Socket_Set.Last), C.int (W_Socket_Set.Last)), @@ -540,7 +548,7 @@ package body GNAT.Sockets is -- If Select was resumed because of read signalling socket, read this -- data and remove socket from set. - if Is_Set (R_Socket_Set, RSig) then + if RSig /= No_Socket and then Is_Set (R_Socket_Set, RSig) then Clear (R_Socket_Set, RSig); Res := Signalling_Fds.Read (C.int (RSig)); @@ -585,10 +593,9 @@ package body GNAT.Sockets is procedure Close_Selector (Selector : in out Selector_Type) is begin - if not Is_Open (Selector) then - - -- Selector already in closed state: nothing to do + -- Nothing to do if selector already in closed state + if Selector.Is_Null or else not Is_Open (Selector) then return; end if; @@ -1425,14 +1432,19 @@ package body GNAT.Sockets is function Is_Open (S : Selector_Type) return Boolean is begin - -- Either both controlling socket descriptors are valid (case of an - -- open selector) or neither (case of a closed selector). + if S.Is_Null then + return True; + + else + -- Either both controlling socket descriptors are valid (case of an + -- open selector) or neither (case of a closed selector). - pragma Assert ((S.R_Sig_Socket /= No_Socket) - = - (S.W_Sig_Socket /= No_Socket)); + pragma Assert ((S.R_Sig_Socket /= No_Socket) + = + (S.W_Sig_Socket /= No_Socket)); - return S.R_Sig_Socket /= No_Socket; + return S.R_Sig_Socket /= No_Socket; + end if; end Is_Open; ------------ Index: g-socket.ads =================================================================== --- g-socket.ads (revision 160966) +++ g-socket.ads (working copy) @@ -422,6 +422,11 @@ package GNAT.Sockets is type Selector_Access is access all Selector_Type; -- Selector objects are used to wait for i/o events to occur on sockets + Null_Selector : constant Selector_Type; + -- The Null_Selector can be used in place of a normal selector without + -- having to call Create_Selector if the use of Abort_Selector is not + -- required. + -- Timeval_Duration is a subtype of Standard.Duration because the full -- range of Standard.Duration cannot be represented in the equivalent C -- structure. Moreover, negative values are not allowed to avoid system @@ -1067,7 +1072,7 @@ package GNAT.Sockets is -- the situation where a change to the monitored sockets set must be made. procedure Create_Selector (Selector : out Selector_Type); - -- Create a new selector + -- Initialize (open) a new selector procedure Close_Selector (Selector : in out Selector_Type); -- Close Selector and all internal descriptors associated; deallocate any @@ -1110,7 +1115,8 @@ package GNAT.Sockets is -- different objects. procedure Abort_Selector (Selector : Selector_Type); - -- Send an abort signal to the selector + -- Send an abort signal to the selector. The Selector may not be the + -- Null_Selector. type Fd_Set is private; -- ??? This type must not be used directly, it needs to be visible because @@ -1126,14 +1132,28 @@ private type Socket_Type is new Integer; No_Socket : constant Socket_Type := -1; - type Selector_Type is limited record - R_Sig_Socket : Socket_Type := No_Socket; - W_Sig_Socket : Socket_Type := No_Socket; - -- Signalling sockets used to abort a select operation + -- A selector is either a null selector, which is always "open" and can + -- never be aborted, or a regular selector, which is created "closed", + -- becomes "open" when Create_Selector is called, and "closed" again when + -- Close_Selector is called. + + type Selector_Type (Is_Null : Boolean := False) is limited record + case Is_Null is + when True => + null; + + when False => + R_Sig_Socket : Socket_Type := No_Socket; + W_Sig_Socket : Socket_Type := No_Socket; + -- Signalling sockets used to abort a select operation + + end case; end record; pragma Volatile (Selector_Type); + Null_Selector : constant Selector_Type := (Is_Null => True); + type Fd_Set is new System.Storage_Elements.Storage_Array (1 .. SOSC.SIZEOF_fd_set); for Fd_Set'Alignment use Interfaces.C.long'Alignment;