Context in Ada

Here’s the translated code and explanation in Ada, formatted for Hugo:

Our first example demonstrates how to set up a simple HTTP server in Ada. HTTP servers are useful for demonstrating the usage of task cancellation and timeouts. Ada tasks provide a way to handle concurrent operations and can be used to control cancellation and deadlines across different parts of your program.

with Ada.Text_IO;
with Ada.Calendar;
with GNAT.Sockets;
with Ada.Exceptions;

procedure HTTP_Server is
   use Ada.Text_IO;
   use Ada.Calendar;
   use GNAT.Sockets;

   task type Request_Handler is
      entry Start(Socket : Socket_Type);
   end Request_Handler;

   task body Request_Handler is
      Client_Socket : Socket_Type;
   begin
      accept Start(Socket : Socket_Type) do
         Client_Socket := Socket;
      end Start;

      Put_Line("server: hello handler started");

      declare
         Response : constant String := 
           "HTTP/1.1 200 OK" & ASCII.CR & ASCII.LF &
           "Content-Type: text/plain" & ASCII.CR & ASCII.LF &
           "Content-Length: 7" & ASCII.CR & ASCII.LF &
           ASCII.CR & ASCII.LF &
           "hello" & ASCII.CR & ASCII.LF;
         Deadline : constant Time := Clock + Duration(10.0);
      begin
         select
            delay until Deadline;
            String'Write(Stream(Client_Socket), Response);
         or
            terminate;
         end select;
      exception
         when E : others =>
            Put_Line("server: " & Ada.Exceptions.Exception_Message(E));
      end;

      Close_Socket(Client_Socket);
      Put_Line("server: hello handler ended");
   end Request_Handler;

   Server_Socket : Socket_Type;
   Server_Address : Sock_Addr_Type;
   Client_Address : Sock_Addr_Type;
begin
   Initialize;
   Create_Socket(Server_Socket);
   Server_Address.Addr := Inet_Addr("127.0.0.1");
   Server_Address.Port := 8090;
   Bind_Socket(Server_Socket, Server_Address);
   Listen_Socket(Server_Socket);

   Put_Line("Server listening on port 8090");

   loop
      Accept_Socket(Server_Socket, Client_Address, Client_Socket);
      declare
         Handler : Request_Handler;
      begin
         Handler.Start(Client_Socket);
      end;
   end loop;
exception
   when E : others =>
      Put_Line("Error: " & Ada.Exceptions.Exception_Message(E));
end HTTP_Server;

In this Ada example, we create a simple HTTP server that listens on port 8090. The Request_Handler task is responsible for handling each incoming request. It simulates some work by waiting for 10 seconds before sending a response.

The select statement in the Request_Handler task body is similar to the select statement in the original example. It either waits for the 10-second deadline or terminates if the task is asked to complete early.

To run the server:

$ gnatmake http_server.adb
$ ./http_server
Server listening on port 8090

You can then simulate a client request using curl:

$ curl localhost:8090/hello
server: hello handler started
hello
server: hello handler ended

If you interrupt the curl command before the 10-second timeout, you’ll see the handler end early:

$ curl localhost:8090/hello
^C
server: hello handler ended

This example demonstrates how Ada tasks can be used to handle concurrent operations and implement timeouts, similar to the context functionality in the original example.