The Go internal/poll/fd_unix.go code is here
// Write implements io.Writer. func (fd *FD) Write(p []byte) (int, error) { if err := fd.writeLock(); err != nil { return 0, err } defer fd.writeUnlock() ...... }
the java code java.net.SocketOutputStream#socketWrite is here
private void socketWrite(byte b[], int off, int len) throws IOException { if (len <= 0 || off < 0 || len > b.length - off) { if (len == 0) { return; } throw new ArrayIndexOutOfBoundsException("len == " + len + " off == " + off + " buffer length == " + b.length); } FileDescriptor fd = impl.acquireFD(); try { socketWrite0(fd, b, off, len); } catch (SocketException se) { ......
I don’t know why we need to lock that. Another question is the syscall.Write equivalent to <unistd.h> write in C?
Advertisement
Answer
Well, only answering for the Java part:
As we are already talking about implementation details, why stop at the Java level? The C Source code for OpenJdk implementation of the native method socketWrite0 spans ~70 lines of code and is clearly not atomic. It does things like allocating and deallocating memory using malloc
and free
, among other things, and involves quite a bit of non-trivial logic. Whether or not the NET_Send
function it invokes to actually send data directly translates to a syscall on every supported platform hardly matters anymore, at that point.
The main point is: the implementation invokes this NET_Send
-function in a loop. So whether or not this is threadsafe individually, if it is invoked concurrently by multiple threads, the output will be interleaved (best case).