Patchwork [Ada] GNAT.Sockets.Null_Selector

login
register
mail settings
Submitter Arnaud Charlet
Date June 18, 2010, 10:08 a.m.
Message ID <20100618100813.GA3965@adacore.com>
Download mbox | patch
Permalink /patch/56158/
State New
Headers show

Comments

Arnaud Charlet - June 18, 2010, 10:08 a.m.
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  <quinot@adacore.com>

	* g-socket.adb, g-socket.ads (Null_Selector): New object.

Patch

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;