Prev: Using GtkAda in Ubuntu
Next: gnat on opensuse 11.1
From: Jean-Pierre Rosen on 22 Sep 2008 04:23 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 22 Sep 2008 09:05 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 23 Sep 2008 04:07 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 23 Sep 2008 05:25 -- -- 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 23 Sep 2008 05:37
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 |