|
382 | 382 | FIXTURE_DATA(fixture_name) self; \
|
383 | 383 | pid_t child = 1; \
|
384 | 384 | int status = 0; \
|
385 |
| - bool jmp = false; \ |
| 385 | + /* Makes sure there is only one teardown, even when child forks again. */ \ |
| 386 | + bool *teardown = mmap(NULL, sizeof(*teardown), \ |
| 387 | + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); \ |
| 388 | + *teardown = false; \ |
386 | 389 | memset(&self, 0, sizeof(FIXTURE_DATA(fixture_name))); \
|
387 | 390 | if (setjmp(_metadata->env) == 0) { \
|
388 | 391 | /* Use the same _metadata. */ \
|
|
399 | 402 | _metadata->exit_code = KSFT_FAIL; \
|
400 | 403 | } \
|
401 | 404 | } \
|
402 |
| - else \ |
403 |
| - jmp = true; \ |
404 | 405 | if (child == 0) { \
|
405 |
| - if (_metadata->setup_completed && !_metadata->teardown_parent && !jmp) \ |
| 406 | + if (_metadata->setup_completed && !_metadata->teardown_parent && \ |
| 407 | + __sync_bool_compare_and_swap(teardown, false, true)) \ |
406 | 408 | fixture_name##_teardown(_metadata, &self, variant->data); \
|
407 | 409 | _exit(0); \
|
408 | 410 | } \
|
409 |
| - if (_metadata->setup_completed && _metadata->teardown_parent) \ |
| 411 | + if (_metadata->setup_completed && _metadata->teardown_parent && \ |
| 412 | + __sync_bool_compare_and_swap(teardown, false, true)) \ |
410 | 413 | fixture_name##_teardown(_metadata, &self, variant->data); \
|
| 414 | + munmap(teardown, sizeof(*teardown)); \ |
411 | 415 | if (!WIFEXITED(status) && WIFSIGNALED(status)) \
|
412 | 416 | /* Forward signal to __wait_for_test(). */ \
|
413 | 417 | kill(getpid(), WTERMSIG(status)); \
|
|
0 commit comments