diff --git a/tests/abortutil.hpp b/tests/abortutil.hpp new file mode 100644 index 000000000..c6f9c0b4d --- /dev/null +++ b/tests/abortutil.hpp @@ -0,0 +1,95 @@ +#pragma once +#ifdef __linux__ +#include +#include +#include +#include +#include +#include +#include +// copied from cppreference as possible implementation +namespace detail { +template inline auto INVOKE(F &&f, Args &&... args) -> decltype(std::forward(f)(std::forward(args)...)) +{ + return std::forward(f)(std::forward(args)...); +} + +template inline auto INVOKE(T Base::*pmd, Derived &&ref) -> decltype(std::forward(ref).*pmd) +{ + return std::forward(ref).*pmd; +} + +template inline auto INVOKE(PMD pmd, Pointer &&ptr) -> decltype((*std::forward(ptr)).*pmd) +{ + return (*std::forward(ptr)).*pmd; +} + +template +inline auto INVOKE(T Base::*pmf, Derived &&ref, Args &&... args) -> decltype((std::forward(ref).*pmf)(std::forward(args)...)) +{ + return (std::forward(ref).*pmf)(std::forward(args)...); +} + +template +inline auto INVOKE(PMF pmf, Pointer &&ptr, Args &&... args) -> decltype(((*std::forward(ptr)).*pmf)(std::forward(args)...)) +{ + return ((*std::forward(ptr)).*pmf)(std::forward(args)...); +} +} // namespace detail + +namespace util { +template decltype(auto) invoke(F &&f, ArgTypes &&... args) +{ + return detail::INVOKE(std::forward(f), std::forward(args)...); +} +} // namespace util + +void Disable_Console_Output() +{ + // close C file descriptors + fclose(stdout); + fclose(stderr); +} + +template bool ABORTS(F &&f, Args &&... args) +{ + // pipe + int fd[2]; + pipe(fd); + + // spawn a new process + auto child_pid = fork(); + bool aborted = false; + + // if the fork succeeded + if (child_pid >= 0) { + + // if we are in the child process + if (child_pid == 0) { + close(fd[0]); + + // call the function that we expect to abort + Disable_Console_Output(); + util::invoke(std::forward(f), std::forward(args)...); + + char succ[] = "1"; + write(fd[1], succ, 2); + + // if the function didn't abort, we'll exit cleanly + std::exit(EXIT_SUCCESS); + } else { + close(fd[1]); + char buff[128]; + int n = read(fd[0], buff, 127); + aborted = n == 0; + } + } + + return true; +} +#else +template bool ABORTS(F &&, Args &&...) +{ + return true; +} +#endif