mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			Report early wakeup of condition_variable::wait_until as no_timeout
As currently implemented, condition_variable always ultimately waits against std::chrono::system_clock. This clock can be changed in arbitrary ways by the user which may result in us waking up too early or too late when measured against the caller-supplied clock. We can't (yet) do much about waking up too late (PR 41861), but if we wake up too early we must return cv_status::no_timeout to indicate a spurious wakeup rather than incorrectly returning cv_status::timeout. 2018-08-01 Mike Crowe <mac@mcrowe.com> * include/std/condition_variable (wait_until): Only report timeout if we really have timed out when measured against the caller-supplied clock. * testsuite/30_threads/condition_variable/members/2.cc: Add test case to confirm above behaviour. From-SVN: r263224
This commit is contained in:
		
							parent
							
								
									5534096c09
								
							
						
					
					
						commit
						2f59343265
					
				|  | @ -1,3 +1,11 @@ | |||
| 2018-08-01  Mike Crowe  <mac@mcrowe.com> | ||||
| 
 | ||||
| 	* include/std/condition_variable (wait_until): Only report timeout | ||||
| 	if we really have timed out when measured against the | ||||
| 	caller-supplied clock. | ||||
| 	* testsuite/30_threads/condition_variable/members/2.cc: Add test | ||||
| 	case to confirm above behaviour. | ||||
| 
 | ||||
| 2018-08-01  Jonathan Wakely  <jwakely@redhat.com> | ||||
| 
 | ||||
| 	PR libstdc++/60555 | ||||
|  |  | |||
|  | @ -117,7 +117,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION | |||
| 	const auto __delta = __atime - __c_entry; | ||||
| 	const auto __s_atime = __s_entry + __delta; | ||||
| 
 | ||||
| 	return __wait_until_impl(__lock, __s_atime); | ||||
| 	if (__wait_until_impl(__lock, __s_atime) == cv_status::no_timeout) | ||||
| 	  return cv_status::no_timeout; | ||||
| 	// We got a timeout when measured against __clock_t but | ||||
| 	// we need to check against the caller-supplied clock | ||||
| 	// to tell whether we should return a timeout. | ||||
| 	if (_Clock::now() < __atime) | ||||
| 	  return cv_status::no_timeout; | ||||
| 	return cv_status::timeout; | ||||
|       } | ||||
| 
 | ||||
|     template<typename _Clock, typename _Duration, typename _Predicate> | ||||
|  |  | |||
|  | @ -51,8 +51,60 @@ void test01() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| struct slow_clock | ||||
| { | ||||
|   using rep = std::chrono::system_clock::rep; | ||||
|   using period = std::chrono::system_clock::period; | ||||
|   using duration = std::chrono::system_clock::duration; | ||||
|   using time_point = std::chrono::time_point<slow_clock, duration>; | ||||
|   static constexpr bool is_steady = false; | ||||
| 
 | ||||
|   static time_point now() | ||||
|   { | ||||
|     auto real = std::chrono::system_clock::now(); | ||||
|     return time_point{real.time_since_epoch() / 3}; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void test01_alternate_clock() | ||||
| { | ||||
|   try | ||||
|     { | ||||
|       std::condition_variable c1; | ||||
|       std::mutex m; | ||||
|       std::unique_lock<std::mutex> l(m); | ||||
|       auto const expire = slow_clock::now() + std::chrono::seconds(1); | ||||
| 
 | ||||
|       while (slow_clock::now() < expire) | ||||
|        { | ||||
|          auto const result = c1.wait_until(l, expire); | ||||
| 
 | ||||
|          // If wait_until returns before the timeout has expired when
 | ||||
|          // measured against the supplied clock, then wait_until must
 | ||||
|          // return no_timeout.
 | ||||
|          if (slow_clock::now() < expire) | ||||
|            VERIFY(result == std::cv_status::no_timeout); | ||||
| 
 | ||||
|          // If wait_until returns timeout then the timeout must have
 | ||||
|          // expired.
 | ||||
|          if (result == std::cv_status::timeout) | ||||
|            VERIFY(slow_clock::now() >= expire); | ||||
|        } | ||||
|     } | ||||
|   catch (const std::system_error& e) | ||||
|     { | ||||
|       VERIFY( false ); | ||||
|     } | ||||
|   catch (...) | ||||
|     { | ||||
|       VERIFY( false ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|   test01(); | ||||
|   test01_alternate_clock(); | ||||
|   return 0; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Mike Crowe
						Mike Crowe