|  | @@ -374,6 +374,79 @@ TEST_P(ClientCallbackEnd2endTest, SimpleRpc) {
 | 
	
		
			
				|  |  |    SendRpcs(1, false);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +TEST_P(ClientCallbackEnd2endTest, SimpleRpcUnderLockNested) {
 | 
	
		
			
				|  |  | +  MAYBE_SKIP_TEST;
 | 
	
		
			
				|  |  | +  ResetStub();
 | 
	
		
			
				|  |  | +  std::mutex mu1, mu2, mu3;
 | 
	
		
			
				|  |  | +  std::condition_variable cv1, cv2, cv3;
 | 
	
		
			
				|  |  | +  bool done1 = false;
 | 
	
		
			
				|  |  | +  EchoRequest request1, request2, request3;
 | 
	
		
			
				|  |  | +  request1.set_message("Hello locked world1.");
 | 
	
		
			
				|  |  | +  EchoResponse response1;
 | 
	
		
			
				|  |  | +  ClientContext cli_ctx1;
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    std::unique_lock<std::mutex> l(mu1);
 | 
	
		
			
				|  |  | +    stub_->experimental_async()->Echo(
 | 
	
		
			
				|  |  | +        &cli_ctx1, &request1, &response1,
 | 
	
		
			
				|  |  | +        [&mu1, this, &cv1, &done1, &request1, &response1](Status s1) {
 | 
	
		
			
				|  |  | +          std::unique_lock<std::mutex> l1(mu1);
 | 
	
		
			
				|  |  | +          EXPECT_TRUE(s1.ok());
 | 
	
		
			
				|  |  | +          EXPECT_EQ(request1.message(), response1.message());
 | 
	
		
			
				|  |  | +          // start the second level of nesting
 | 
	
		
			
				|  |  | +          std::mutex mu2;
 | 
	
		
			
				|  |  | +          bool done2 = false;
 | 
	
		
			
				|  |  | +          std::condition_variable cv2;
 | 
	
		
			
				|  |  | +          EchoRequest request2;
 | 
	
		
			
				|  |  | +          request2.set_message("Hello locked world2.");
 | 
	
		
			
				|  |  | +          EchoResponse response2;
 | 
	
		
			
				|  |  | +          ClientContext cli_ctx2;
 | 
	
		
			
				|  |  | +          std::unique_lock<std::mutex> l2(mu2);
 | 
	
		
			
				|  |  | +          stub_->experimental_async()->Echo(
 | 
	
		
			
				|  |  | +              &cli_ctx2, &request2, &response2,
 | 
	
		
			
				|  |  | +              [&mu2, this, &cv2, &done2, &request2, &response2](Status s2) {
 | 
	
		
			
				|  |  | +                std::unique_lock<std::mutex> l2(mu2);
 | 
	
		
			
				|  |  | +                EXPECT_TRUE(s2.ok());
 | 
	
		
			
				|  |  | +                EXPECT_EQ(request2.message(), response2.message());
 | 
	
		
			
				|  |  | +                // start the third level of nesting
 | 
	
		
			
				|  |  | +                std::mutex mu3;
 | 
	
		
			
				|  |  | +                bool done3 = false;
 | 
	
		
			
				|  |  | +                std::condition_variable cv3;
 | 
	
		
			
				|  |  | +                EchoRequest request3;
 | 
	
		
			
				|  |  | +                request3.set_message("Hello locked world2.");
 | 
	
		
			
				|  |  | +                EchoResponse response3;
 | 
	
		
			
				|  |  | +                ClientContext cli_ctx3;
 | 
	
		
			
				|  |  | +                std::unique_lock<std::mutex> l3(mu3);
 | 
	
		
			
				|  |  | +                stub_->experimental_async()->Echo(
 | 
	
		
			
				|  |  | +                    &cli_ctx3, &request3, &response3,
 | 
	
		
			
				|  |  | +                    [&mu3, &cv3, &done3, &request3, &response3](Status s3) {
 | 
	
		
			
				|  |  | +                      std::lock_guard<std::mutex> l(mu3);
 | 
	
		
			
				|  |  | +                      EXPECT_TRUE(s3.ok());
 | 
	
		
			
				|  |  | +                      EXPECT_EQ(request3.message(), response3.message());
 | 
	
		
			
				|  |  | +                      done3 = true;
 | 
	
		
			
				|  |  | +                      cv3.notify_all();
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                done2 = true;
 | 
	
		
			
				|  |  | +                cv2.notify_all();
 | 
	
		
			
				|  |  | +                // Wait for inner most rpc to return.
 | 
	
		
			
				|  |  | +                while (!done3) {
 | 
	
		
			
				|  |  | +                  cv3.wait(l3);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +              });
 | 
	
		
			
				|  |  | +          // Wait for second rpc to return.
 | 
	
		
			
				|  |  | +          while (!done2) {
 | 
	
		
			
				|  |  | +            cv2.wait(l2);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          done1 = true;
 | 
	
		
			
				|  |  | +          cv1.notify_all();
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  std::unique_lock<std::mutex> l1(mu1);
 | 
	
		
			
				|  |  | +  while (!done1) {
 | 
	
		
			
				|  |  | +    cv1.wait(l1);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  TEST_P(ClientCallbackEnd2endTest, SimpleRpcUnderLock) {
 | 
	
		
			
				|  |  |    MAYBE_SKIP_TEST;
 | 
	
		
			
				|  |  |    ResetStub();
 |