task typeとnewを使うと良いらしい

Taskの開始タイミングはtask typenewを使うと上手くコントロールできるらしい。

要点だけまとめると次のような感じ。

procedure Sock is
   -- Taskを作る
   task type Connection_Send_Task is
      entry Start (Connection : in out Stream_Access);
   end Connection_Send_Task;
   --- Taskの処理内容
   task body Connection_Send_Task is
      ...
   begin
      ...
      accept Start (Connection : in out Stream_Access) do
         Connection_Stream := Connection;
      end Start;
      ...
   end Connection_Send_Task;

   -- TaskをTypeとして定義する
   type Connection_Send_Type is access Connection_Send_Task;
   -- そのタイプの変数を作る
   Connection_Send : Connection_Send_Type;

begin
   ...
   -- Taskの制作
   Connection_Send := new Connection_Send_Task;
   -- 処理開始
   Connection_Send.Start(Connection);
   ...
end Sock;

とりあえず、is accessが謎なので、そこら辺を解明しないと気持ちよく使うことは出来なさそう。TypeとSubTypeも今一理解できてないし。Taskに関してはリファレンスマニュアルの9章あたりを読むと大体理解できそうな雰囲気。

一応コード全体も掲載しておこう。

with Ada.Text_IO;             use Ada.Text_IO;
with GNAT.Sockets;            use GNAT.Sockets;
with Ada.Strings.Unbounded;   use Ada.Strings.Unbounded;
with Ada.Command_Line;        use Ada.Command_Line;

with Ada.Streams;
use type Ada.Streams.Stream_Element_Count;

procedure Sock is

   task type Connection_Send_Task is
      entry Start (Connection : in out Stream_Access);
      entry Stop;
   end Connection_Send_Task;

   task body Connection_Send_Task is
      Connection_Stream : Stream_Access;
      Item              : String(1 .. 512);
      Last              : Natural;
   begin
      accept Start (Connection : in out Stream_Access) do
         Connection_Stream := Connection;
      end Start;
      loop
         select
         Ada.Text_IO.Get_Line (Item => Item, Last => Last);
         String'Write(Connection_Stream, Item(1 .. Last) & ASCII.LF);
      end loop;
   end Connection_Send_Task;

   task type Connection_Recieve_Task is
      entry Start (Connection : in out Stream_Access);
      entry Stop;
   end Connection_Recieve_Task;

   task body Connection_Recieve_Task is
      Connection_Stream : Stream_Access;
      Item              : Character;
   begin
      accept Start (Connection : in out Stream_Access) do
         Connection_Stream := Connection;
      end Start;
      loop
         Character'Read (Connection_Stream, Item);
         Ada.Text_IO.Put (Item);
      end loop;
   end Connection_Recieve_Task;

   Server_Name    : Unbounded_String;
   Server_Port    : Natural := 6667;
   Server_Socket  : Socket_Type;
   Server_Address : Sock_Addr_Type;
   Connection     : Stream_Access;

   type Connection_Send_Type is access Connection_Send_Task;
   type Connection_Recieve_Type is access Connection_Recieve_Task;
   Connection_Send : Connection_Send_Type;
   Connection_Recieve : Connection_Recieve_Type;


begin

   -- Parse arguments
   if Argument_Count < 1 then
      Put_Line ("Usage: " & Command_Name & " [-p port] hostname[:port]");
      return;
   else
      for I in Integer range 1 .. Argument_Count loop
         if Argument (I) = "-p" and I + 1 <= Argument_Count then
            Server_Port := Integer'Value (Argument (I));
         else
            Server_Name := To_Unbounded_String(Argument (I));
         end if;
      end loop;
   end if;

   Server_Address.Addr := Addresses(Get_Host_By_Name(To_String(Server_Name)), 1);
   Server_Address.Port := Port_Type(Server_Port);

   Create_Socket (Server_Socket);
   Ada.Text_IO.Put_Line ("Connecting...");
   Connect_Socket (Server_Socket, Server_Address);
   Connection := Stream (Server_Socket);


   Ada.Text_IO.Put_Line ("Connection Established.");
   Ada.Text_IO.Put_Line ("-----------------------");

   Connection_Recieve := new Connection_Recieve_Task;
   Connection_Send := new Connection_Send_Task;
   Connection_Recieve.Start(Connection);
   Connection_Send.Start(Connection);

end Sock;