From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,bdf72b2364b0da13 X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII Received: by 10.204.152.89 with SMTP id f25mr1431226bkw.0.1323805907551; Tue, 13 Dec 2011 11:51:47 -0800 (PST) Path: jh9ni8017bkb.0!nntp.google.com!news1.google.com!goblin1!goblin.stu.neva.ru!news.astraweb.com!border3.a.newsrouter.astraweb.com!newsfeed.eweka.nl!eweka.nl!feeder3.eweka.nl!de-l.enfer-du-nord.net!feeder2.enfer-du-nord.net!gegeweb.org!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Interrupts handling in ADA Date: Tue, 13 Dec 2011 20:51:43 +0100 Organization: cbb software GmbH Message-ID: References: <30143086.6.1323549838421.JavaMail.geo-discussion-forums@vbbfq24> <1f0ump3yhi731$.1gh4827ra0a87.dlg@40tude.net> <7a17c1d0-30dd-47b8-a800-3575a8793fbe@d10g2000vbf.googlegroups.com> <70e4b2ba-62c4-41d3-b603-a20e37d3d332@j9g2000vby.googlegroups.com> Reply-To: mailbox@dmitry-kazakov.de NNTP-Posting-Host: QiAlLrcAYONeImYCedImjw.user.speranza.aioe.org Mime-Version: 1.0 X-Complaints-To: abuse@aioe.org User-Agent: 40tude_Dialog/2.0.15.1 X-Notice: Filtered by postfilter v. 0.8.2 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit Date: 2011-12-13T20:51:43+01:00 List-Id: On Tue, 13 Dec 2011 10:51:03 -0800 (PST), Ada BRL wrote: > On 13 Dic, 15:39, "Dmitry A. Kazakov" > wrote: >> On Tue, 13 Dec 2011 06:51:25 -0800 (PST), Ada BRL wrote: >>> On 13 Dic, 14:04, "Dmitry A. Kazakov" >>> wrote: >>>> On Tue, 13 Dec 2011 05:11:14 -0800 (PST), Ada BRL wrote: >>>>> On 11 Dic, 09:23, "Dmitry A. Kazakov" >>>>> wrote: >>>>>> On Sat, 10 Dec 2011 12:43:58 -0800 (PST), Ada @ BRL wrote: >>>>>>> The environment of ADA applcation is: >>>>>>> I have 4 tasks that execute at the same time: >>>>>>> one is the main task, >>>>>>> the other three execute a "read" from network (socket) function inside >>>>>>> their bodies (on the other side there's the C/C++ application with 3 >>>>>>> network sockets). >>>>>>> [I decided to use the sockets instead of dll/lib import because this approach hasn't worked... =( ] >> >>>>>> What dll import has to do with sockets, except that sockets usually are >>>>>> provided by a library? >> >>>>> I would have liked to use dll import to exchange data between C stuff >>>>> and Ada program instead of using two programs (C and Ada) >>>>> communicating through sockets... >> >>>> You can link to an import library from Ada without any problems. Which OS >>>> are you using? >> >>> Windows 7 64 bit, Home Premium SP1 ... >>> I have tried in many ways to import symbols but it was impossible... >>> I had a linker error: couldn't find exported symbols... >>> I've copied the dll into all the possible folder of my project. >> >> No, you link to the import library, that is *.lib, not *.dll. It is also >> possible to load dynamically using LoadLibrary etc. Both works perfectly >> well and simple with GNAT. > > I've tried either with dll and lib but it hasn't worked...I've used > pragma Import(Convention, Entity, External_name) because I've read to > do so to link libraries into the Ada 95 programming book... That is correct: pragma Import (C, Ada-Name, External-Name"); > I prefer to load a static library (lib) instead of a dll (I've read > it's better for efficiency reasons); what I have to do, without pragma > Import(...)? The pragma must stay. You must add instruction to the linker to use your import library. You can describe your library as a project and make your project dependent on it. Or you can add/modify the linker section of your project: package Linker is for Linker_Options use ("-luser32"); -- Link to the Windows' user32 library end Linker; You can also build everything without any project files using raw gnatmake: gnatmake your-file.adb -largs -luser32 >> The simplest way is to create a gpr-file for the external library and >> include it into your Ada project using "with." GNAT knows what to do next. > > How can I create a gpr file for the external library? notepad.exe? (:-)) project My_Library is for Externally_Built use "true"; for Source_Files use (); for Library_Dir use ""; for Library_Name use ""; for Library_Kind use "dynamic"; end My_Library; > What I have to code inside? Nothing, as the library already exists. > I suppose it will be a .ads file that I'll > link to the other ads and adb files. > [Ok, it's clear the use of "with" and "use"] In the gpr file of your Ada program you write: with "my_library"; -- Use my_library defined above project My_Wonderful_Ada_Project is ... >>>> No, OS event objects and entry calls assume that the recipient is inactive >>>> and thus is ready to accept the notification. That is a non-preemptive >>>> model. >> >>> Does this means that the main task has to be in wait for event state >>> (blocked and so NOT running)? >> >> Yes, if the main task is the subscriber. > > If subscriber means the task that has defined inside its declaration > "entry data_available", and inside its body "accept data_available" > it's clear. Subscriber is the recipient of data/messages/notifications. In the rendezvous model it is the task accepting calls, the callee. Publisher is the caller. > The high level strucure roughly is: > > while (!event){ > > do stuff > > } > > exit program > > but in addition with "select" structure I guess you can exit from the > while at any time, just after the event occurs (asynchronous > behaviour). Almost at any time. The language defines so-called "abort-deferred" things, which cannot be jumped out. E.g. assignment, object initialization/finalization. > It's like to check, before executing every atomic action, if the event > is active or not. If it's so exit from the while. Yes, abort-deferred actions are "atomic" to abort. >> There is a queue of calls to each entry, so >> multiple tasks can await there for a rendezvous. At a time only one >> rendezvous is accepted and the corresponding task call is removed from the >> queue. > > Does this means that it can be resumed and continue its execution or > does it must wait until all the calls to the entry are removed? > > Eg: > > Queue of entry calls: > > 123 > > After the "pop" of the first event, can the fist socket continue its > execution or does it have to wait until the queue is empty? It continues once serviced. > In my program I can have for example this situation of the event > queue: > > 1121321 No, you cannot have this, because a task can wait in exactly one queue. So the task 1 cannot queue itself 4 times as above. A call to an entry point is no different from the caller's view as a call to a subprogram. Anything below is executed after return (serviced rendezvous). It is important to understand that rendezvous is a synchronous call. It does not marshal data. The caller itself is queued. This is why rendezvous are so efficient. If you want asynchronous calls, you need a queue for the messages, then the callee could be released as soon it posts the message. This model is far less effective and is exposed to the problems like flooding the queue with too many messages. Which in turn causes publisher blocked when the queue is full, while subscriber keeps on chewing outdated messages. If messages are not so important, e.g. could be dropped when cannot be serviced, you can use a blackboard queue instead. The blackboard is a queue which never blocks publishers at the cost of losing some old messages by lazy subscribers. >> Then both tasks engage the rendezvous. Upon the rendezvous the code >> "do stuff upon rendezvous" is executed. Any exceptions in this code >> propagate into both tasks. When the code completes this or that way the >> rendezvous ends, and both tasks continue their execution independently on >> each other. I.e. concurrently executing "do stuff after." Here is a >> diagram: >> >> � � Main � � � � � � Socket task >> � � � | � � � � � � � � �| >> do stuff before � do stuff before; >> � � � | � � � � � � � � �| >> � � accept � � � � � � call >> � � � �\ � � � � � � � �/ >> � � � do stuff upon rendezvous (synchronously) >> � � � �/ � � � � � � � �\ >> do stuff after; � �do stuff after >> � � � | � � � � � � � � �| >> >> Consider the rendezvous code executed as if both tasks were one. > > OK! So in this phase do they share objects? They share parameters of the entry call. > May you plase make a very simple code example? task Printer is entry Print (Line : String); end Printer; task body Printer is begin loop select accept Print (Line : String) do Put_Line (File, Line); end Print; or terminate; -- accept task completion request end loop; end Printer; -- A caller may pass some string expression to the printer: for Count in 1..3_000 loop My_Printer.Print ("Say" & Integer'Image (Count)); end loop; This is no problem, because calling to Print blocks the caller and thus keeps all temporary objects alive until the rendezvous gets accepted and serviced. After that the objects can be destroyed, exactly like when you call a subprogram. It is a very efficient and safe mechanism comparing to the methods used in the languages having no concurrency support. > I think it's better to explain the environment: > > The socket tasks are not synchronized each other, > they don't have to wait for the completion of another, > they are completely disjoint, > they just have to: > - notify the main task that data is arrived, > - let data be available to the main task in order be elaborated, > - don't be blocked at any time (even when main task is executing) > because they are receiving data from other sockets, so they must be > able to read data from the network at any time. You cannot read data faster than you process them. If this precondition is satisfied, you need not to worry about delayed socket reads. The OS's network stack buffers data, so does the network adapter. There could be issues with reading raw Ethernet frames. But they are solved differently because it is normally impossible to catch such packets however quickly your socket task might take the packet and toss it further. If that is your case, you should use overlapped I/O (under Windows) and keep on multiple read requests (3-5) queued to the driver at any time. The bottom line, don't worry about doing more stuff in a socket task. > The main task has to: > - wait until some data (from any of the sockets) is available, so wait > for the event generated by the sockets, > - don't miss any "incoming new data" event generated by the sockets > (must append all the new data events into a queue...) > - process the data until the queue of events is empty, > - come back to "wait event" state. This does not explain why packet processing should be routed to the main task. Or putting it otherwise, why processing of incoming packets must be serialized? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de