--- old/src/java.naming/share/classes/com/sun/jndi/ldap/BerDecoder.java	Fri Aug  5 14:26:41 2016
+++ new/src/java.naming/share/classes/com/sun/jndi/ldap/BerDecoder.java	Fri Aug  5 14:26:41 2016
@@ -186,12 +186,16 @@
       *</pre></blockquote>
       */
     private int parseIntWithTag(int tag) throws DecodeException {
-
-
         if (parseByte() != tag) {
+            // Ber could have been reset;
+            String s;
+            if (offset > 0) {
+                s = Integer.toString(buf[offset - 1] & 0xff);
+            } else {
+                s = "Empty tag";
+            }
             throw new DecodeException("Encountered ASN.1 tag " +
-                Integer.toString(buf[offset - 1] & 0xff) +
-                " (expected tag " + Integer.toString(tag) + ")");
+                s + " (expected tag " + Integer.toString(tag) + ")");
         }
 
         int len = parseLength();
--- old/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java	Fri Aug  5 14:26:43 2016
+++ new/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java	Fri Aug  5 14:26:42 2016
@@ -389,58 +389,23 @@
     /**
      * Reads a reply; waits until one is ready.
      */
-    BerDecoder readReply(LdapRequest ldr)
-            throws IOException, NamingException {
+    BerDecoder readReply(LdapRequest ldr) throws IOException, NamingException {
         BerDecoder rber;
 
-        // Track down elapsed time to workaround spurious wakeups
-        long elapsedMilli = 0;
-        long elapsedNano = 0;
-
-        while (((rber = ldr.getReplyBer()) == null) &&
-                (readTimeout <= 0 || elapsedMilli < readTimeout))
-        {
             try {
-                // If socket closed, don't even try
-                synchronized (this) {
-                    if (sock == null) {
-                        throw new ServiceUnavailableException(host + ":" + port +
-                            "; socket closed");
-                    }
-                }
-                synchronized (ldr) {
-                    // check if condition has changed since our last check
-                    rber = ldr.getReplyBer();
-                    if (rber == null) {
-                        if (readTimeout > 0) {  // Socket read timeout is specified
-                            long beginNano = System.nanoTime();
-
-                            // will be woken up before readTimeout if reply is
-                            // available
-                            ldr.wait(readTimeout - elapsedMilli);
-                            elapsedNano += (System.nanoTime() - beginNano);
-                            elapsedMilli += elapsedNano / 1000_000;
-                            elapsedNano %= 1000_000;
-
-                        } else {
-                            // no timeout is set so we wait infinitely until
-                            // a response is received
-                            // http://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html#PROP
-                            ldr.wait();
-                        }
-                    } else {
-                        break;
-                    }
-                }
+                // if no timeout is set so we wait infinitely until
+                // a response is received
+                // http://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html#PROP
+                rber = ldr.getReplyBer(readTimeout);
             } catch (InterruptedException ex) {
                 throw new InterruptedNamingException(
                     "Interrupted during LDAP operation");
             }
-        }
 
-        if ((rber == null) && (elapsedMilli >= readTimeout)) {
+        if (rber == null) {
             abandonRequest(ldr, null);
-            throw new NamingException("LDAP response read timed out, timeout used:"
+            throw new NamingException(
+                    "LDAP response read timed out, timeout used:"
                             + readTimeout + "ms." );
 
         }
@@ -447,7 +412,6 @@
         return rber;
     }
 
-
     ////////////////////////////////////////////////////////////////////////////
     //
     // Methods to add, find, delete, and abandon requests made to server
@@ -641,14 +605,11 @@
             if (nparent) {
                 LdapRequest ldr = pendingRequests;
                 while (ldr != null) {
-
-                    synchronized (ldr) {
-                        ldr.notify();
+                    ldr.close();
                         ldr = ldr.next;
                     }
                 }
             }
-        }
         if (nparent) {
             parent.processConnectionClosure();
         }
@@ -736,7 +697,7 @@
      * the safest thing to do is to shut it down.
      */
 
-    private Object pauseLock = new Object();  // lock for reader to wait on while paused
+    private final Object pauseLock = new Object();  // lock for reader to wait on while paused
     private boolean paused = false;           // paused state of reader
 
     /*
--- old/src/java.naming/share/classes/com/sun/jndi/ldap/LdapRequest.java	Fri Aug  5 14:26:44 2016
+++ new/src/java.naming/share/classes/com/sun/jndi/ldap/LdapRequest.java	Fri Aug  5 14:26:43 2016
@@ -29,41 +29,41 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import javax.naming.CommunicationException;
+import java.util.concurrent.TimeUnit;
 
 final class LdapRequest {
 
+    private final static BerDecoder EOF = new BerDecoder(new byte[]{}, -1, 0);
+
     LdapRequest next;   // Set/read in synchronized Connection methods
-    int msgId;          // read-only
+    final int msgId;          // read-only
 
-    private int gotten = 0;
-    private BlockingQueue<BerDecoder> replies;
-    private int highWatermark = -1;
-    private boolean cancelled = false;
-    private boolean pauseAfterReceipt = false;
-    private boolean completed = false;
+    private final BlockingQueue<BerDecoder> replies;
+    private volatile boolean cancelled;
+    private boolean completed;
+    private final boolean pauseAfterReceipt;
 
-    LdapRequest(int msgId, boolean pause) {
-        this(msgId, pause, -1);
-    }
-
     LdapRequest(int msgId, boolean pause, int replyQueueCapacity) {
         this.msgId = msgId;
         this.pauseAfterReceipt = pause;
         if (replyQueueCapacity == -1) {
-            this.replies = new LinkedBlockingQueue<BerDecoder>();
+            this.replies = new LinkedBlockingQueue<>();
         } else {
-            this.replies =
-                new LinkedBlockingQueue<BerDecoder>(replyQueueCapacity);
-            highWatermark = (replyQueueCapacity * 80) / 100; // 80% capacity
+            this.replies = new LinkedBlockingQueue<>(8 * replyQueueCapacity / 10);
         }
     }
 
-    synchronized void cancel() {
+    void cancel() {
         cancelled = true;
+        replies.offer(EOF);
+    }
 
-        // Unblock reader of pending request
-        // Should only ever have at most one waiter
-        notify();
+    synchronized void close() {
+        try {
+            replies.put(EOF);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
     }
 
     synchronized boolean addReplyBer(BerDecoder ber) {
@@ -87,34 +87,32 @@
             // ignore
         }
         ber.reset();
-
-        notify(); // notify anyone waiting for reply
-        /*
-         * If a queue capacity has been set then trigger a pause when the
-         * queue has filled to 80% capacity. Later, when the queue has drained
-         * then the reader gets unpaused.
-         */
-        if (highWatermark != -1 && replies.size() >= highWatermark) {
-            return true; // trigger the pause
-        }
         return pauseAfterReceipt;
     }
 
-    synchronized BerDecoder getReplyBer() throws CommunicationException {
+    BerDecoder getReplyBer(long millis) throws CommunicationException,
+                                               InterruptedException {
         if (cancelled) {
             throw new CommunicationException("Request: " + msgId +
                 " cancelled");
         }
 
-        /*
-         * Remove a reply if the queue is not empty.
-         * poll returns null if queue is empty.
-         */
-        BerDecoder reply = replies.poll();
-        return reply;
+        BerDecoder result = millis > 0 ?
+                replies.poll(millis, TimeUnit.MILLISECONDS) : replies.take();
+
+        if (cancelled) {
+            throw new CommunicationException("Request: " + msgId +
+                " cancelled");
     }
 
-    synchronized boolean hasSearchCompleted() {
+        if (result == LdapRequest.EOF) {
+            return null; 
+        }
+
+        return result;
+    }
+
+    boolean hasSearchCompleted() {
         return completed;
     }
 }
