PageRenderTime 46ms CodeModel.GetById 28ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/src/lib/sequencer/events_set.e

http://github.com/tybor/Liberty
Specman e | 495 lines | 357 code | 58 blank | 80 comment | 6 complexity | 6a80df57414558d7f4accc1d46b8d460 MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class EVENTS_SET
  5   --
  6   -- A set of events to be waited for. Expected events are set via the `expect' feature when the EVENTS_SET
  7   -- is not `queryable'. After having been waited for (see `wait'), the EVENTS_SET becomes `queryable' and
  8   -- events may be checked by using the `event_occurred' feature. To reuse the EVENTS_SET (make it not
  9   -- `queryable' again) one may call `reset'.
 10   --
 11   --    -----------------------------                  ------------------------
 12   --   |                             | <-- `wait' --- |                        |
 13   --   | State: `queryable'          |                | State: not `queryable' |
 14   --   | (may call `event_occurred') |                | (may call `expect')    |
 15   --   |                             | -- `reset' --> |                        |
 16   --    -----------------------------                  ------------------------
 17   --
 18   -- May be useful for:
 19   -- * time/date waiting (see TIME_EVENTS and PERIODIC_JOB).
 20   -- * checking if data are available in files without locking (see INPUT_STREAM.event_can_read
 21   -- and OUTPUT_STREAM.event_can_write).
 22   --
 23   -- See also JOB
 24   --
 25
 26insert
 27   ANY
 28   PLATFORM
 29
 30create {ANY}
 31   make
 32
 33feature {}
 34   make
 35      require
 36         create_events
 37      do
 38         read_set := sequencer_create_set
 39         write_set := sequencer_create_set
 40         exception_set := sequencer_create_set
 41         reset
 42      ensure
 43         queryable = False
 44      end
 45
 46feature {ANY}
 47   queryable: BOOLEAN
 48         -- At creation this object is not `queryable'. You have to configure the conditions you want to wait
 49         -- for (data on file, timeout...) using `expect'. When the configuration is done, you start waiting
 50         -- using `wait'. Then this object is `queryable', that means that you can query the state of the
 51         -- events, using `event_occurred'.
 52
 53   reset
 54         -- Reset the event descriptors.
 55         --
 56         -- See also:
 57         -- * `expect'
 58         -- * `wait'
 59         -- * `exception'
 60      require
 61         reset_events
 62      do
 63         timeout := Maximum_integer
 64         expiration_valid := False
 65         current_time_valid := False
 66         sequencer_reset(read_set)
 67         sequencer_reset(write_set)
 68         sequencer_reset(exception_set)
 69         highest := -1
 70         read_size := 0
 71         write_size := 0
 72         exception_size := 0
 73         queryable := False
 74      ensure
 75         queryable = False
 76      end
 77
 78   wait
 79         -- Blocks until requested condition (max time and/or data).
 80         --
 81         -- See also:
 82         -- * `expect'
 83         -- * `event_occurred'
 84         -- * `reset'
 85      require
 86         not queryable
 87      local
 88         now: MICROSECOND_TIME; s, us: INTEGER; remaining: REAL
 89      do
 90         if expiration_valid then
 91            now.update
 92            if now < expiration then
 93               remaining := now.elapsed_seconds(expiration)
 94            end
 95            if timeout / 1000 < remaining then
 96               remaining := timeout / 1000
 97            end
 98         else
 99            remaining := timeout / 1000
100         end
101         from
102            s := remaining.floor.force_to_integer_32
103            us := ((remaining - s) * 1000000).floor.force_to_integer_32
104         until
105            sequencer_wait(highest + 1,
106                           read_set, read_size, read_more,
107                           write_set, write_size, write_more,
108                           exception_set, exception_size, exception_more,
109                           s, us) /= -1
110         loop
111         end
112         queryable := True
113         current_time_valid := False
114      ensure
115         queryable
116      end
117
118   expect (event: EVENT_DESCRIPTOR)
119         -- `wait' will return if that `event' happens.
120      require
121         not event_expected(event)
122         not queryable
123         action: mark_event_as_expected(event)
124      do
125         event.expect(Current)
126      ensure
127         event_expected(event)
128      end
129
130   event_occurred (event: EVENT_DESCRIPTOR): BOOLEAN
131         -- True if `wait' returned because that `event' happened.
132      require
133         event_expected(event)
134         queryable
135      do
136         Result := event.occurred(Current)
137      end
138
139feature {EVENTS_SET_HANDLER} -- low level features
140   expect_readable (descriptor: INTEGER)
141      do
142         sequencer_watch(read_set, descriptor)
143         read_size := read_size + 1
144         highest := highest.max(descriptor)
145      end
146
147   can_read (descriptor: INTEGER): BOOLEAN
148      do
149         Result := sequencer_is_ready(read_set, descriptor)
150      end
151
152   expect_writeable (descriptor: INTEGER)
153      do
154         sequencer_watch(write_set, descriptor)
155         write_size := write_size + 1
156         highest := highest.max(descriptor)
157      end
158
159   can_write (descriptor: INTEGER): BOOLEAN
160      do
161         Result := sequencer_is_ready(write_set, descriptor)
162      end
163
164   expect_exception (descriptor: INTEGER)
165      do
166          sequencer_watch(exception_set, descriptor)
167          exception_size := exception_size + 1
168          highest := highest.max(descriptor)
169      end
170
171   has_exception (descriptor: INTEGER): BOOLEAN
172      do
173         Result := sequencer_is_ready(exception_set, descriptor)
174      end
175
176   set_read_size (rs: like read_size)
177      require
178         rs > read_size
179      do
180         read_size := rs
181      end
182
183   set_write_size (ws: like write_size)
184      require
185         ws > write_size
186      do
187         write_size := ws
188      end
189
190   set_exception_size (es: like exception_size)
191      require
192         es > exception_size
193      do
194         exception_size := es
195      end
196
197   set_highest (h: like highest)
198      require
199         h > highest
200      do
201         highest := h
202      end
203
204feature {EVENT_DESCRIPTOR}
205   after (timeout_ms: INTEGER)
206         -- `timeout_ms' is the max time in milliseconds to wait when
207         -- wait begins.
208      require
209         timeout_ms >= 0
210         not queryable
211      do
212         timeout := timeout.min(timeout_ms)
213      end
214
215   at (date: MICROSECOND_TIME)
216         -- `date' is the last moment that`wait' can wait.
217      require
218         not queryable
219      do
220         if expiration_valid then
221            expiration := date.min(expiration)
222         else
223            expiration := date
224            expiration_valid := True
225         end
226      end
227
228   when_data (file: INPUT_STREAM)
229      require
230         file /= Void
231         file.is_connected
232         file.has_descriptor
233         not queryable
234      do
235         expect_readable(file.descriptor)
236      end
237
238   is_data (file: INPUT_STREAM): BOOLEAN
239      require
240         file /= Void
241         file.is_connected
242         file.has_descriptor
243         queryable
244      do
245         Result := can_read(file.descriptor)
246      end
247
248   when_connection (server: SOCKET_SERVER)
249      require
250         server /= Void
251         not queryable
252      do
253         expect_readable(server.fd)
254      end
255
256   is_connection (server: SOCKET_SERVER): BOOLEAN
257      require
258         server /= Void
259         queryable
260      do
261         Result := can_read(server.fd)
262      end
263
264   when_free (file: OUTPUT_STREAM)
265      require
266         file /= Void
267         file.is_connected
268         file.has_descriptor
269         not queryable
270      do
271         expect_writeable(file.descriptor)
272      end
273
274   is_free (file: OUTPUT_STREAM): BOOLEAN
275      require
276         file /= Void
277         file.is_connected
278         file.has_descriptor
279         queryable
280      do
281         Result := can_write(file.descriptor)
282      end
283
284    when_exception (file: STREAM)
285       require
286          file /= Void
287          file.is_connected
288          file.has_descriptor
289          not queryable
290       do
291         expect_exception(file.descriptor)
292       end
293
294    is_exception (file: STREAM): BOOLEAN
295       require
296          file /= Void
297          file.is_connected
298          file.has_descriptor
299          queryable
300       do
301          Result := has_exception(file.descriptor)
302       end
303
304   when_expecter (expecter: EVENTS_EXPECTER)
305      require
306         expecter /= Void
307         not queryable
308      do
309         expecter.expect(read_set, write_set, exception_set)
310         read_more := expecter.expected_read
311         write_more := expecter.expected_write
312         exception_more := expecter.expected_exception
313         highest := highest.max(expecter.expected_highest)
314      end
315
316   has_expecter (expecter: EVENTS_EXPECTER): BOOLEAN
317      require
318         expecter /= Void
319         queryable
320      do
321         Result := expecter.happened(read_set, write_set, exception_set)
322      end
323
324feature {JOB, TIME_EVENT}
325   current_time: MICROSECOND_TIME
326      do
327         if not current_time_valid then
328            current_time_valid := True
329            current_time_memory.update
330         end
331         Result := current_time_memory
332      end
333
334feature {ANY} -- Expected events
335   event_expected (a_event: EVENT_DESCRIPTOR): BOOLEAN
336         -- True in check modes if the event is expected. Always False in boost mode. Exported to {ANY} only
337         -- because the language requires it.
338         --
339         -- CAVEAT: '''Use only in require/ensure clauses.''' It's very important. In boost mode, it will
340         -- always be False. It's meant to catch programming mistakes, not as a guard. If you feel the need to
341         -- call that feature, please check your algorithm. Twice. And don't use it.
342         --
343         -- Tip: only call `event_occurred' on events that passed to `expect' (I mean, the ''same'' object,
344         -- ''not'' a twin!)
345      do
346         Result := events /= Void and then events.fast_has(a_event)
347      ensure
348         definition: Result = events.fast_has(a_event)
349         equivalence: Result = a_event.expected(Current)
350      end
351
352feature {} -- Expected events
353   --| Clever use of assertions to be sure not to create arrays in boost mode
354
355   events: FAST_ARRAY[EVENT_DESCRIPTOR]
356         -- This array is created only if the assertion level is at least require_check. That's why all the
357         -- functions below are used only in contracts.
358
359   mark_event_as_expected (a_event: EVENT_DESCRIPTOR): BOOLEAN
360         -- Mark the event as expected and return True. Use only in require clauses.
361      do
362         events.add_last(a_event)
363         Result := True
364      ensure
365         Result
366      end
367
368   create_events: BOOLEAN
369         -- Create the events array. Use only in require clauses.
370      do
371         if events = Void then
372            create events.make(0)
373            Result := True
374         end
375      end
376
377   reset_events: BOOLEAN
378         -- Empties the events array. Use only in require clauses.
379      local
380         i: INTEGER
381      do
382         from
383            i := events.lower
384         until
385            i > events.upper
386         loop
387            events.item(i).reset(Current)
388            i := i + 1
389         end
390         events.clear_count
391         Result := True
392      end
393
394feature {}
395   timeout: INTEGER
396
397   expiration: MICROSECOND_TIME
398
399   expiration_valid: BOOLEAN
400
401   current_time_memory: MICROSECOND_TIME
402
403   current_time_valid: BOOLEAN
404
405   read_set: POINTER
406
407   read_size: INTEGER
408
409   read_more: BOOLEAN
410
411   write_set: POINTER
412
413   write_size: INTEGER
414
415   write_more: BOOLEAN
416
417   exception_set: POINTER
418
419   exception_size: INTEGER
420
421   exception_more: BOOLEAN
422
423   highest: INTEGER
424
425   sequencer_create_set: POINTER
426      external "plug_in"
427      alias "{
428         location: "${sys}/plugins"
429         module_name: "sequencer"
430         feature_name: "sequencer_create_set"
431         }"
432      end
433
434   sequencer_reset (set: POINTER)
435      external "plug_in"
436      alias "{
437         location: "${sys}/plugins"
438         module_name: "sequencer"
439         feature_name: "sequencer_reset"
440         }"
441      end
442
443   sequencer_watch (set: POINTER; file: INTEGER)
444      external "plug_in"
445      alias "{
446         location: "${sys}/plugins"
447         module_name: "sequencer"
448         feature_name: "sequencer_watch"
449         }"
450      end
451
452   sequencer_is_ready (set: POINTER; file: INTEGER): BOOLEAN
453      external "plug_in"
454      alias "{
455         location: "${sys}/plugins"
456         module_name: "sequencer"
457         feature_name: "sequencer_is_ready"
458         }"
459      end
460
461   sequencer_wait (n: INTEGER;
462                   rset: POINTER; rsize: INTEGER; rmote: BOOLEAN;
463                   wset: POINTER; wsize: INTEGER; wmore: BOOLEAN;
464                   eset:POINTER; esize: INTEGER; emore: BOOLEAN;
465                   s, us: INTEGER): INTEGER
466         --return -1 if signal interrupt occurred
467      external "plug_in"
468      alias "{
469         location: "${sys}/plugins"
470         module_name: "sequencer"
471         feature_name: "sequencer_wait"
472         }"
473      end
474
475end -- class EVENTS_SET
476--
477-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
478--
479-- Permission is hereby granted, free of charge, to any person obtaining a copy
480-- of this software and associated documentation files (the "Software"), to deal
481-- in the Software without restriction, including without limitation the rights
482-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
483-- copies of the Software, and to permit persons to whom the Software is
484-- furnished to do so, subject to the following conditions:
485--
486-- The above copyright notice and this permission notice shall be included in
487-- all copies or substantial portions of the Software.
488--
489-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
490-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
491-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
492-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
493-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
494-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
495-- THE SOFTWARE.