| 611 | /// Base exception for time measure functions |
| 612 | class TimeMeasureException : public Exception { |
| 613 | public: |
| 614 | /// Constructor |
| 615 | TimeMeasureException() throw() {} |
| 616 | /// Virtual destructor |
| 617 | virtual ~TimeMeasureException() throw() {} |
| 618 | ///A short description of the exception |
| 619 | virtual const char* what() const throw() { |
| 620 | return "lemon::TimeMeasureException"; |
| 621 | } |
| 622 | }; |
| 623 | |
| 624 | /// Exception thrown when time measuring fails |
| 625 | class TimeMeasureError : public TimeMeasureException { |
| 626 | public: |
| 627 | /// Constructor |
| 628 | TimeMeasureError() throw() {} |
| 629 | /// Virtual destructor |
| 630 | virtual ~TimeMeasureError() throw() {} |
| 631 | ///A short description of the exception |
| 632 | virtual const char* what() const throw() { |
| 633 | return "lemon::TimeMeasureError"; |
| 634 | } |
| 635 | }; |
| 636 | |
| 637 | /// Exception thrown when the executed function times out |
| 638 | class TimeoutException : public TimeMeasureException { |
| 639 | public: |
| 640 | /// Constructor |
| 641 | TimeoutException() throw() {} |
| 642 | /// Virtual destructor |
| 643 | virtual ~TimeoutException() throw() {} |
| 644 | ///A short description of the exception |
| 645 | virtual const char* what() const throw() { |
| 646 | return "lemon::TimeoutException"; |
| 647 | } |
| 648 | }; |
| 649 | |
| 650 | /// Exception thrown when the executed function throws an exception |
| 651 | class ExecutionException : public TimeMeasureException { |
| 652 | private: |
| 653 | std::string _message; |
| 654 | mutable std::string _what; |
| 655 | public: |
| 656 | /// Constructor |
| 657 | ExecutionException(const char* message, std::size_t len) throw() { |
| 658 | try { |
| 659 | _message.clear(); |
| 660 | _message.assign(message, len); |
| 661 | } catch (...) {} |
| 662 | } |
| 663 | /// Virtual destructor |
| 664 | virtual ~ExecutionException() throw() {} |
| 665 | ///A short description of the exception |
| 666 | virtual const char* what() const throw() { |
| 667 | try { |
| 668 | _what.clear(); |
| 669 | std::ostringstream oss; |
| 670 | oss << "lemon::ExecutionException: " << _message; |
| 671 | _what = oss.str(); |
| 672 | return _what.c_str(); |
| 673 | } catch (...) {} |
| 674 | return "lemon::ExecutionException"; |
| 675 | } |
| 676 | }; |
| 677 | |
| 678 | namespace _time_measure_bits { |
| 679 | #ifndef LEMON_WIN32 |
| 680 | inline bool write_full(int fd, const void* buffer, std::size_t len) { |
| 681 | std::size_t offset = 0; |
| 682 | while (offset < len) { |
| 683 | ssize_t ret = write(fd, static_cast<const char*>(buffer) + offset, len - offset); |
| 684 | if (ret < 0) { |
| 685 | return false; |
| 686 | } |
| 687 | offset += ret; |
| 688 | } |
| 689 | return true; |
| 690 | } |
| 691 | |
| 692 | inline bool read_full(int fd, void* buffer, std::size_t len) { |
| 693 | std::size_t offset = 0; |
| 694 | while (offset < len) { |
| 695 | ssize_t ret = read(fd, static_cast<char*>(buffer) + offset, len - offset); |
| 696 | if (ret < 0) { |
| 697 | return false; |
| 698 | } |
| 699 | offset += ret; |
| 700 | } |
| 701 | return true; |
| 702 | } |
| 703 | #endif |
| 704 | } |
| 705 | |
| 706 | /// Tool to measure the running time with a time constraint. |
| 707 | |
| 708 | /// This function executes \c f on a forked subprocess, and if the subprocess |
| 709 | /// does not terminate in the given time constraint then it is killed by the |
| 710 | /// master process. Because \c f is executed in a subprocess, the side-effects |
| 711 | /// are not affecting the master process. |
| 712 | /// |
| 713 | /// Because WIN32 API does not have efficient \c fork() implementation, this |
| 714 | /// function is not implemented for Windows. |
| 715 | |
| 716 | /// \param f the function object to be measured. |
| 717 | /// \param max_time the maximum total running time of \c f in seconds. |
| 718 | ///\return The running time of \c f reported by the subprocess. |
| 719 | template<class F> |
| 720 | TimeStamp constrainedRunningTimeTest(F f, double max_time) |
| 721 | { |
| 722 | #ifndef LEMON_WIN32 |
| 723 | int pipefd[2]; |
| 724 | if (pipe(pipefd) == -1) { |
| 725 | throw TimeMeasureError(); |
| 726 | } |
| 727 | |
| 728 | pid_t cpid = fork(); |
| 729 | if (cpid == -1) { |
| 730 | close(pipefd[0]); |
| 731 | close(pipefd[1]); |
| 732 | throw TimeMeasureError(); |
| 733 | } |
| 734 | |
| 735 | if (cpid == 0) { |
| 736 | close(pipefd[0]); |
| 737 | try { |
| 738 | Timer t; |
| 739 | f(); |
| 740 | TimeStamp ts = t; |
| 741 | bool success = true; |
| 742 | _time_measure_bits::write_full(pipefd[1], &success, sizeof(success)); |
| 743 | _time_measure_bits::write_full(pipefd[1], &ts, sizeof(ts)); |
| 744 | } catch (const std::exception& e) { |
| 745 | const char* message = e.what(); |
| 746 | size_t len = strlen(message); |
| 747 | bool success = false; |
| 748 | _time_measure_bits::write_full(pipefd[1], &success, sizeof(success)); |
| 749 | _time_measure_bits::write_full(pipefd[1], &len, sizeof(len)); |
| 750 | _time_measure_bits::write_full(pipefd[1], message, len); |
| 751 | } catch (...) { |
| 752 | static const char* message = "Unknown exception"; |
| 753 | size_t len = strlen(message); |
| 754 | bool success = false; |
| 755 | _time_measure_bits::write_full(pipefd[1], &success, sizeof(bool)); |
| 756 | _time_measure_bits::write_full(pipefd[1], &len, sizeof(len)); |
| 757 | _time_measure_bits::write_full(pipefd[1], message, len); |
| 758 | } |
| 759 | close(pipefd[1]); |
| 760 | _exit(0); |
| 761 | } else { |
| 762 | close(pipefd[1]); |
| 763 | |
| 764 | fd_set rfds; |
| 765 | FD_ZERO(&rfds); |
| 766 | FD_SET(pipefd[0], &rfds); |
| 767 | |
| 768 | double sec_int, sec_frac; |
| 769 | sec_int = modf(max_time, &sec_frac); |
| 770 | struct timeval tv; |
| 771 | tv.tv_sec = sec_int; |
| 772 | tv.tv_usec = sec_frac * 1000000; |
| 773 | |
| 774 | int sel = select(pipefd[0] + 1, &rfds, NULL, NULL, &tv); |
| 775 | |
| 776 | if (sel < -1) { |
| 777 | close(pipefd[0]); |
| 778 | kill(cpid, SIGKILL); |
| 779 | throw TimeMeasureError(); |
| 780 | } |
| 781 | |
| 782 | if (sel == 0) { |
| 783 | close(pipefd[0]); |
| 784 | kill(cpid, SIGKILL); |
| 785 | throw TimeoutException(); |
| 786 | } else { |
| 787 | bool success = false; |
| 788 | _time_measure_bits::read_full(pipefd[0], &success, sizeof(bool)); |
| 789 | if (success) { |
| 790 | TimeStamp ts; |
| 791 | _time_measure_bits::read_full(pipefd[0], &ts, sizeof(ts)); |
| 792 | close(pipefd[0]); |
| 793 | return ts; |
| 794 | } else { |
| 795 | size_t len; |
| 796 | _time_measure_bits::read_full(pipefd[0], &len, sizeof(len)); |
| 797 | std::vector<char> buffer(len); |
| 798 | _time_measure_bits::read_full(pipefd[0], buffer.data(), len); |
| 799 | throw ExecutionException(buffer.data(), len); |
| 800 | } |
| 801 | } |
| 802 | } |
| 803 | #else |
| 804 | throw TimeMeasureError(); |
| 805 | #endif |
| 806 | } |
| 807 | |
| 808 | |