/src/lib/sequencer/events_set.e
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.