-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added failing test that illustrates critical bug where a reaction is …
…invoked twice at the same logical time.
- Loading branch information
1 parent
0a0af59
commit 88c2dc0
Showing
1 changed file
with
99 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// This test checks that the downstream reaction is not invoked more | ||
// than once at a logical time. | ||
target C { | ||
logging: LOG, | ||
timeout: 1 sec | ||
} | ||
reactor Source { | ||
output out:int; | ||
state count:int(1); | ||
timer t(0, 100 msec); | ||
reaction(t) -> out {= | ||
SET(out, self->count++); | ||
=} | ||
} | ||
reactor Sieve { | ||
input in:int; | ||
output out:bool; | ||
state primes:int*({= NULL =}); | ||
state last_prime:int(0); | ||
reaction(startup) {= | ||
// There are 1229 primes between 1 and 10,000. | ||
self->primes = calloc(1229, sizeof(int)); | ||
// Primes 1 and 2 are not on the list. | ||
self->primes[0] = 3; | ||
=} | ||
reaction(in) -> out {= | ||
// Reject inputs that are out of bounds. | ||
if (in->value <= 0 || in->value > 10000) { | ||
warning_print("Sieve: Input value out of range: %d.", in->value); | ||
} | ||
// Primes 1 and 2 are not on the list. | ||
if (in->value == 1 || in->value == 2) { | ||
SET(out, true); | ||
return; | ||
} | ||
// If the input is greater than the last found prime, then | ||
// we have to expand the list of primes before checking to | ||
// see whether this is prime. | ||
int candidate = self->primes[self->last_prime]; | ||
while (in->value > self->primes[self->last_prime]) { | ||
// The next prime is always odd, so we can increment by two. | ||
candidate += 2; | ||
bool prime = true; | ||
for (int i = 0; i < self->last_prime; i++) { | ||
if (candidate % self->primes[i] == 0) { | ||
// Candidate is not prime. Break and add 2 | ||
prime = false; | ||
break; | ||
} | ||
} | ||
// If the candidate is not divisible by any prime in the list, it is prime. | ||
if (prime) { | ||
self->last_prime++; | ||
self->primes[self->last_prime] = candidate; | ||
info_print("Sieve: Found prime: %d.", candidate); | ||
} | ||
} | ||
// We are now assured that the input is less than or | ||
// equal to the last prime on the list. | ||
// See whether the input is an already found prime. | ||
for (int i = self->last_prime; i >= 0; i--) { | ||
// Search the primes from the end, where they are sparser. | ||
if (self->primes[i] == in->value) { | ||
SET(out, true); | ||
return; | ||
} | ||
} | ||
=} | ||
} | ||
|
||
reactor Destination { | ||
input ok:bool; | ||
input in:int; | ||
state last_invoked:tag_t({= NEVER_TAG =}); | ||
reaction(ok, in) {= | ||
if (ok->is_present && in->is_present) { | ||
info_print("Destination: Input %d is prime at tag (%lld, %d).", | ||
in->value, | ||
current_tag.time - start_time, current_tag.microstep | ||
); | ||
} | ||
if (compare_tags(current_tag, self->last_invoked) <= 0) { | ||
error_print_and_exit("Invoked at tag (%lld, %d), " | ||
"but previously invoked at tag (%lld, %d).", | ||
current_tag.time - start_time, current_tag.microstep, | ||
self->last_invoked.time - start_time, self->last_invoked.microstep | ||
); | ||
} | ||
self->last_invoked = current_tag; | ||
=} | ||
} | ||
main reactor { | ||
source = new Source(); | ||
sieve = new Sieve(); | ||
destination = new Destination(); | ||
source.out -> sieve.in; | ||
sieve.out -> destination.ok; | ||
source.out -> destination.in; | ||
} |