INT-3453 Fix NIO Connection Race Condition

JIRA: https://jira.spring.io/browse/INT-3453

A race condition in the TcpNioConnection can leave
an assembler thread blocked when there is no data coming.

This can happen because `writingToPipe` might not be reset
before the assembler consumed the IO data.

Change it to a semaphore so that the assembler will wait
until the data is actually written to the pipe
and will not block again in `convert()` unless the message is not
fully assembled. As soon as the write completes the semaphore is
released so that an assembler won't block once the write for the
current IO has completed.

SSL can be call `write` multiple times for each IO so only one
permit is released on each write to keep the assembler processing
until `doRead()` completes.

The finally block in `doRead()` makes the semaphore wide open.
However, during normal processing, the permits are not acquired
(only if the assembler detects there are no permits) so this
is not strictly necessary, but for safety only.

INT-3453 Test Case

Exposes the race condition when `writingToPipe` is not reset in time
and we end up tying up an assembler thread on a socket with no data.

Examines the assembler thread's stack trace to ensure it does not
contain `ChannelInputStream.getNextBuffer()`.

__cherry-pick to 4.0.x, 3.0.x__