From: Jean-Pierre Rosen on
Maciej Sobczak a �crit :
> On 19 Wrz, 15:34, Jean-Pierre Rosen <ro...(a)adalog.fr> wrote:
>
>> Why not simply use a rendezvous?
>
> This is something that I deliberately wanted to avoid.
> I don't like the idea of tasks interacting with each other directly
> and I prefer to have the communication part extracted away (Ravenscar
> got that right for a reason, I think?).
You said "I prefer", so this can be a matter of taste ;-)

Personnally, I view protected types as a great tool for simple,
low-level communications, and rendezvous for higher level
communications. I think rendezvous are closer to real-life, and thus
easier to manage. YMMV of course.

The issue for Ravenscar is different: it is a matter of provability.
There are many examples of things that are simpler for the human being,
but less easy for proofs systems...

--
---------------------------------------------------------
J-P. Rosen (rosen(a)adalog.fr)
Visit Adalog's web site at http://www.adalog.fr
From: Maciej Sobczak on
On 22 Wrz, 04:32, a...(a)anon.org (anon) wrote:

>   Why use "GNAT.Sockets.Check_Selection"?

> [...] basically it has to do with limited
> system resources.

Of course, but as I've said, the intended (fixed) number of pipelines
is relatively small and the system resources do not seem to be any
limitation.

> Note: TCP/IP "Accept" can only monitor one connection port while the
> TCP/IP "Select" allows monitoring up to 32 at one time in one routine.
> which makes the TCP/IP "Select" a better utilization of system resources.

I don't understand this assertion. You cannot *replace* accept with
select, they serve completely different purposes, so you cannot state
that one is better than another.

> Why only 27 servers per TCP/IP "Select" routine  Well, the designers created
> the TCP/IP "Select" to use 3 32-bit word to detect or flag

This is an implementation detail that does not seem to be true any
longer. As I've already explained, on my system the default limit for
select(2) is 1024 descriptors and with a simple compiler option can be
actually unlimited.

The limit of 32 seems to be very impractical today. It is not uncommon
to have hundreds of clients connected at the same time to a single
server. They can be all handled without any partitioning.

> Plus, some system may have 1024 file descriptors, but the OS normally
> limit the number of assigned/open file descriptors to 32 or less.

Again, this is not true on any of the systems that I have access to.

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com

Database Access Library for Ada: www.inspirel.com/soci-ada
From: Maciej Sobczak on
On 22 Wrz, 16:11, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
wrote:

> >> There also exists a third variant with an
> >> exception propagation.
>
> > This assumes rendezvous.
>
> Nope.

> Here is my example with exceptions (a complete program):
[...]

This example uses rendezvous.
I don't like it, because it misuses exceptions for something that is a
perfectly normal control flow.
Yes, this is very subjective - for the record, I also don't like the
End_Error exception.

BTW - the fact that you raise an exception only to shut it up in the
same scope indicates that this is a severe misuse of some language
feature.

> > In the version with protected objects the entity that triggers
> > termination might be different from the one that invents job.
> > In your version these different responsibilities are mixed.
>
> It does not work. You cannot selectively call to multiple entries of a
> protected object anyway.

I don't have to. What I said is that the entities that provide jobs
and that trigger termination can be different, not that the worker can
get them from separate channels.

> Then again, termination should be triggered by
> task finalization

Why? Which task?
The termination of workers can be triggered by the load that is below
some threshold. This is a valid strategy for dynamic task pool and is
not necessarily related to the finalization of the main task.

> > In particular, in my version the task that
> > invents jobs is never blocked on interactions with workers. This is a
> > big advantage, because such a blocking would disturb its own
> > interactions with the environment and reduce its responsiveness.
>
> This is a design fault. Under certain conditions it must either block or
> fail.

Where is the design fault? The immediate failure (as opposed to
blocking) can be a valid overload handling policy.
If I go to some office and cannot be handled because of the clerks
being too busy, I prefer to know it *immediately*, so that I can go to
the pub.

> > In your version with rendezvous the task that invents jobs has to
> > block and during that time it cannot react to the events that drive it
> > (keyboard input, network transmission, etc.).
>
> Wrong, see 9.7.1(16).

Again: keyboard input, network transmission, etc. Select statement is
not flexible enough.
In addition, there is no need to create even more tasks only to fit to
select's limitations.

> Your design is when a multicasting
> publisher "knows" its peers. This is a bad idea, obviously.

Why it is a bad idea? What is bad in the manager having knowledge
about workers in his team?
Is your boss aware of you or do you need to constantly ask him for new
tasks?

BTW - there is no multicasting in my design.

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com

Database Access Library for Ada: www.inspirel.com/soci-ada
From: anon on
--
-- A Server and a Client that shows how to use
-- GNAT.Sockets.Check_Selection as a controller for
-- multiple port server. And can be alter to allow multiple
-- services type of server.
--
-- In C, they call this type of server a Super-Server Class
-- of servers.
--

-- ------------------------------------------------------------ --
-- Multi-Tasking Server that allows Multi-Service to be handled --
-- ------------------------------------------------------------ --

with Ada.Text_IO ;
with GNAT.Sockets ;
with System ;

use Ada.Text_IO ;
use GNAT.Sockets ;

procedure testserver is


-- ------------------- --
-- Server Task Types --
-- ------------------- --

--
-- TCP Task
--

task tcp_hello is
entry Initialize ;
entry Acknowledge ;
end tcp_hello ;


--
-- UDP Task
--

task udp_hello is
entry Initialize ;
entry Acknowledge ;
end udp_hello ;


Server_Error : exception ;

tcp_Socket : Socket_Type ;
udp_Socket : Socket_Type ;


-- ------------------------------------------------------------------------ --
---- TCP/IP Controller Task ----
---- ----
---- dispatches server task to handle tcp/ip services. ----
---- ----
-- ------------------------------------------------------------------------ --

task Controller is
entry Initialize_Controller ;
end Controller ;


task body Controller is

Selector : Selector_Type ;
Server_Status : Selector_Status ;

-- Exception_Fds is not use in Ada 95
-- and is optional Ada 2005 GNAT.Sockets

Read_Fds : Socket_Set_Type ;
Write_Fds : Socket_Set_Type ;


begin -- Controller
--
-- Set up controller variables
--
Create_Selector ( Selector ) ;
Empty ( Read_Fds ) ;
Empty ( Write_Fds ) ;


Accept Initialize_Controller ;

--
-- Set up and active Server
--
Put_Line ( "Controller: Server Dispatching Loop" ) ;
loop
-- Insure Fds value,
Empty ( Read_Fds ) ;
Empty ( Write_Fds ) ;

Set ( Read_Fds, tcp_Socket ) ;
Set ( Read_Fds, udp_Socket ) ;

--
-- Excute the TCP/IP "Select" routine. This routine is blocked
-- until a connecion is made. In this part it is identical to
-- TCP/IP "Accept".
--
-- Also, Exception_Fds is not use in Ada 95 and is optional
-- Ada 2005 GNAT.Sockets
--
Check_Selector ( Selector,
Read_Fds,
Write_Fds,
Server_Status ) ;

-- call a server to handle job using Signalling Fds

if Is_Set ( Read_Fds, tcp_Socket ) then
tcp_hello.Acknowledge ;
elsif Is_Set ( Read_Fds, udp_Socket ) then
udp_hello.Acknowledge ;
else
raise Socket_Error ;
end if ;
end loop ;
exception
when Socket_Error =>
-- need to signal servers to shutdown because
-- dispatcher has stopped
raise ;
end Controller ;




-- ------------------------------------------------------------------------ --
---- TCP/IP Server Tasks ----
---- ----
---- Both tasks are similar. They both send a message to a client ----
---- Differences: ----
---- 1) Transport protocols: One uses TCP, the other uses UDP ----
---- 2) Message and message length ----
---- ----
---- Excution of these two servers will cause the "netstat" program ----
---- to add the following info to the "netstat" socket report ----
---- ----
---- IP Address protocol port ----
---- 127.0.0.1 tcp 54321 ----
---- 127.0.0.1 udp 54321 ----
---- ----
-- ------------------------------------------------------------------------ --



task body tcp_hello is

Port : constant Port_Type := 54321 ;

Address : Sock_Addr_Type ;
Channel : Stream_Access ;
Client : Socket_Type ;

hello_string : String ( 1..25 ) := "TCP Server: Hello, World!" ;

begin -- Tcp_hello

Create_Socket ( tcp_Socket, Family_Inet, Socket_Stream ) ;
--
-- Address.Addr := Any_Inet_Addr ;
Address.Addr := Inet_Addr ( "127.0.0.1" ) ; -- Limited access
Address.Port := Port ;
--
Bind_Socket ( tcp_Socket, Address ) ;

--
Listen_Socket ( tcp_Socket, 4 ) ;

Accept Initialize ;
--
-- Main Server processing routine
--
Put_Line ( "TCP: Active the Server loop" ) ;
loop
accept Acknowledge ;

-- ------------------------ --
-- Do server services job --
-- ------------------------ --

--
-- Because of Check_Selector, no wait for Accept_Socket
-- used to obtain connected socket ( Client ) address
-- for the tcp protocol.
--
Accept_Socket ( tcp_Socket, Client, Address ) ;

Channel := Stream ( Client ) ;

String'Write ( Channel, hello_string ) ;

Close_Socket ( Client ) ;

end loop ;

--
-- for security, close socket if exception occured
--
exception
when others =>
Put_Line ( "TCP: Exception" ) ;
Close_Socket ( tcp_Socket ) ;
raise ;
end tcp_hello ;



--
-- UDP Task
--

task body udp_hello is

Port : constant Port_Type := 54321 ;

Address : Sock_Addr_Type ;
Channel_Input : Stream_Access ;
Channel_Output : Stream_Access ;

Temp : Character ;
hello_string : String := "UDP Server: Repeat Hello, World!" ;

begin -- udp_hello

Create_Socket ( udp_Socket, Family_Inet, Socket_Datagram ) ;
--
-- Address.Addr := Any_Inet_Addr ;
Address.Addr := Inet_Addr ( "127.0.0.1" ) ;
Address.Port := Port ;
--
Bind_Socket ( udp_Socket, Address ) ;


Accept Initialize ;
--
-- Main Server processing routine
--
Put_Line ( "UDP: Active the Server loop" ) ;
loop
accept Acknowledge ;

-- ------------------------ --
-- Do server services job --
-- ------------------------ --
-- Accept from any Address and Port
Address.Addr := Any_Inet_Addr ;
Address.Port := Any_Port ;

Channel_Input := Stream ( udp_Socket, Address ) ;

Character'Read ( Channel_Input, Temp ) ;

-- Open an output channel
Address := Get_Address ( Channel_Input ) ;
Channel_Output := Stream ( udp_Socket, Address ) ;

String'Write ( Channel_Output, hello_string ) ;
end loop ;

--
-- for security, close socket if exception occured
--
exception
when others =>
Put_Line ( "UDP: Exception" ) ;
Close_Socket ( udp_Socket ) ;
raise ;
end udp_hello ;



-- ------------------------ --
---- Server Initiaizer ----
-- ------------------------ --



begin

-- Initialize each server service task

tcp_hello.Initialize ;
udp_hello.Initialize ;

-- Startup network controller

Controller.Initialize_Controller ;

--
-- Handle all exceptions
--
exception
when Socket_Error =>
raise ;
when others =>
raise ;
end testserver ;





-- ----------------------------------------------------- --
-- Non-Tasking Client that test the Multi-Service Server --
-- ----------------------------------------------------- --

with Ada.Command_Line ;
with Ada.Text_IO ;
with Ada.Unchecked_Conversion ;
with GNAT.Sockets ;

use Ada.Command_Line ;
use Ada.Text_IO ;
use GNAT.Sockets ;

procedure testclient is

localhost : constant Inet_Addr_Type := Inet_Addr ( "127.0.0.1" ) ;
localport : constant Port_Type := 54321 ;
--
Address : Sock_Addr_Type ;
Channel : Stream_Access ;
Socket : Socket_Type ;
--
tcp_Buffer : String ( 1..25 ) ;
udp_Buffer : String ( 1..32 ) ;

begin -- Daytime0

--
Address.Addr := localhost ;
Address.Port := localport ;

--
if Argument ( 1 ) = "-T" then
Put_Line ( "Protocol: TCP" ) ;
--
Create_Socket ( Socket, Family_Inet, Socket_Stream ) ;
Connect_Socket ( Socket, Address ) ;
--
Channel := Stream ( Socket ) ;
String'Read ( Channel, tcp_Buffer ) ;
--
Close_Socket ( Socket ) ;
--
Put ( "Server Data => " ) ;
Put ( tcp_Buffer ) ;
Put ( " <= " ) ;
New_Line ;

elsif Argument ( 1 ) = "-U" then
Put_Line ( "Protocol: UDP" ) ;
--
Create_Socket ( Socket, Family_Inet, Socket_Datagram ) ;
Channel := Stream ( Socket, Address ) ;

-- Allows server to obtain client address by send a dummy character

Character'Write ( Channel, Ascii.nul ) ;
--
Channel := Stream ( Socket, Address ) ;
String'Read ( Channel, udp_Buffer ) ;
--
Close_Socket ( Socket ) ;
--
Put ( "Server Data => " ) ;
Put ( udp_Buffer ) ;
Put ( " <= " ) ;
New_Line ;

else
Put_Line ( Standard_Error, "usage: testclient [-DT]" ) ;
Put_Line ( Standard_Error, "-T: tcp" ) ;
Put_Line ( Standard_Error, "-U: udp" ) ;
New_Line ;
end if ;
end testclient ;
From: Dmitry A. Kazakov on
On Tue, 23 Sep 2008 01:07:38 -0700 (PDT), Maciej Sobczak wrote:

> I don't like it, because it misuses exceptions for something that is a
> perfectly normal control flow.

I don't know how a control flow can be abnormal. If "normality" is
attributed to the meaning of program's artefacts, then that is at the
programmer's discretion. Is it normal not to have a job? For a worker that
might look abnormal, for a welfare receiver it maybe not...

> Yes, this is very subjective - for the record, I also don't like the
> End_Error exception.

But you certainly enjoy Constraint_Error... It is not subjective, it is
unrealistic.

> BTW - the fact that you raise an exception only to shut it up in the
> same scope indicates that this is a severe misuse of some language
> feature.

I use this language feature in order to express "not a value" in a
type-safe way. The same feature is used when an integer overflows.

You didn't want "no job" become a job, so I used exceptions instead. (A
return flag with a rubbish value is not an Ada way.)

>>> In the version with protected objects the entity that triggers
>>> termination might be different from the one that invents job.
>>> In your version these different responsibilities are mixed.
>>
>> It does not work. You cannot selectively call to multiple entries of a
>> protected object anyway.
>
> I don't have to. What I said is that the entities that provide jobs
> and that trigger termination can be different, not that the worker can
> get them from separate channels.

If entries are different then the worker cannot selectively call to them.
If they are never called by it, then how is this related to the worker? In
your code there was only one entry called by the worker.

>> Then again, termination should be triggered by
>> task finalization
>
> Why? Which task?

The worker task.

>>> In particular, in my version the task that
>>> invents jobs is never blocked on interactions with workers. This is a
>>> big advantage, because such a blocking would disturb its own
>>> interactions with the environment and reduce its responsiveness.
>>
>> This is a design fault. Under certain conditions it must either block or
>> fail.
>
> Where is the design fault? The immediate failure (as opposed to
> blocking) can be a valid overload handling policy.

First you said that it neither blocks nor fail. Now you consider it to fail
immediately. Fine, let's take this. Why then to queue jobs, which are known
to fail later? (It is difficult to pursue a moving target...)

>>> In your version with rendezvous the task that invents jobs has to
>>> block and during that time it cannot react to the events that drive it
>>> (keyboard input, network transmission, etc.).
>>
>> Wrong, see 9.7.1(16).
>
> Again: keyboard input, network transmission, etc. Select statement is
> not flexible enough.

1. The selective accept statement is flexible enough. And in any case it is
far more flexible than entry call statements. This is one of the reasons
why rendezvous might be better in one to many relationships.

The problem with the things you mentioned is that their interfaces are not
conform to Ada tasking. There are many reasons for this, unrelated to the
discussion.

2. Not all interfaces are like those.

3. In this particular case the server can block on job reception, because
this is the only event to react to.

>> Your design is when a multicasting
>> publisher "knows" its peers. This is a bad idea, obviously.
>
> Why it is a bad idea? What is bad in the manager having knowledge
> about workers in his team?

Yes, obviously. This requires a team and maintenance of. Such managers are
expensive and exposed to various risks. It might appear the only way of
design when you deal with humans, but fortunately, with bits and bytes
there are much better options.

> Is your boss aware of you or do you need to constantly ask him for new
> tasks?

This is a model widely used when you don't want to employ staff
permanently. If you have plenty of free workers, you just sit and wait them
to come. Fee is paid per work made. See freelances, etc.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4
Prev: Using GtkAda in Ubuntu
Next: gnat on opensuse 11.1