Skip to content

Commit ace2855

Browse files
committed
Unix implementation
1 parent ddc88b6 commit ace2855

File tree

7 files changed

+120
-24
lines changed

7 files changed

+120
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Sys
9+
{
10+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadV", SetLastError = true)]
11+
internal static unsafe partial long ReadV(SafeHandle fd, IOVector* vectors, int vectorCount);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Runtime.InteropServices;
5+
6+
internal static partial class Interop
7+
{
8+
internal static partial class Sys
9+
{
10+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_WriteV", SetLastError = true)]
11+
internal static unsafe partial long WriteV(SafeHandle fd, IOVector* vectors, int vectorCount);
12+
}
13+
}

src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems

+6
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,9 @@
23782378
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.PRead.cs">
23792379
<Link>Common\Interop\Unix\System.Native\Interop.PRead.cs</Link>
23802380
</Compile>
2381+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.ReadV.cs">
2382+
<Link>Common\Interop\Unix\System.Native\Interop.ReadV.cs</Link>
2383+
</Compile>
23812384
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.PReadV.cs">
23822385
<Link>Common\Interop\Unix\System.Native\Interop.PReadV.cs</Link>
23832386
</Compile>
@@ -2390,6 +2393,9 @@
23902393
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Read.cs">
23912394
<Link>Common\Interop\Unix\System.Native\Interop.Read.cs</Link>
23922395
</Compile>
2396+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.WriteV.cs">
2397+
<Link>Common\Interop\Unix\System.Native\Interop.WriteV.cs</Link>
2398+
</Compile>
23932399
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.ReadDir.cs">
23942400
<Link>Common\Interop\Unix\System.Native\Interop.ReadDir.cs</Link>
23952401
</Compile>

src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs

+44-24
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,9 @@ internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span<byte> buffer
3434
{
3535
// Try pread for seekable files.
3636
result = Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset);
37-
if (result == -1)
37+
if (result == -1 && NeedsNonOffsetFallback(handle))
3838
{
39-
// We need to fallback to the non-offset version for certain file types
40-
// e.g: character devices (such as /dev/tty), pipes, and sockets.
41-
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
42-
43-
if (errorInfo.Error == Interop.Error.ENXIO ||
44-
errorInfo.Error == Interop.Error.ESPIPE)
45-
{
46-
handle.SupportsRandomAccess = false;
47-
result = Interop.Sys.Read(handle, bufPtr, buffer.Length);
48-
}
39+
result = Interop.Sys.Read(handle, bufPtr, buffer.Length);
4940
}
5041
}
5142
else
@@ -77,7 +68,18 @@ internal static unsafe long ReadScatterAtOffset(SafeFileHandle handle, IReadOnly
7768

7869
fixed (Interop.Sys.IOVector* pinnedVectors = &MemoryMarshal.GetReference(vectors))
7970
{
80-
result = Interop.Sys.PReadV(handle, pinnedVectors, buffers.Count, fileOffset);
71+
if (handle.SupportsRandomAccess)
72+
{
73+
result = Interop.Sys.PReadV(handle, pinnedVectors, buffers.Count, fileOffset);
74+
if (result == -1 && NeedsNonOffsetFallback(handle))
75+
{
76+
result = Interop.Sys.ReadV(handle, pinnedVectors, buffers.Count);
77+
}
78+
}
79+
else
80+
{
81+
result = Interop.Sys.ReadV(handle, pinnedVectors, buffers.Count);
82+
}
8183
}
8284
}
8385
finally
@@ -111,18 +113,9 @@ internal static unsafe void WriteAtOffset(SafeFileHandle handle, ReadOnlySpan<by
111113
if (handle.SupportsRandomAccess)
112114
{
113115
bytesWritten = Interop.Sys.PWrite(handle, bufPtr, bytesToWrite, fileOffset);
114-
if (bytesWritten == -1)
116+
if (bytesWritten == -1 && NeedsNonOffsetFallback(handle))
115117
{
116-
// We need to fallback to the non-offset version for certain file types
117-
// e.g: character devices (such as /dev/tty), pipes, and sockets.
118-
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
119-
120-
if (errorInfo.Error == Interop.Error.ENXIO ||
121-
errorInfo.Error == Interop.Error.ESPIPE)
122-
{
123-
handle.SupportsRandomAccess = false;
124-
bytesWritten = Interop.Sys.Write(handle, bufPtr, bytesToWrite);
125-
}
118+
bytesWritten = Interop.Sys.Write(handle, bufPtr, bytesToWrite);
126119
}
127120
}
128121
else
@@ -198,7 +191,18 @@ internal static unsafe void WriteGatherAtOffset(SafeFileHandle handle, IReadOnly
198191
long bytesWritten;
199192
fixed (Interop.Sys.IOVector* pinnedVectors = &MemoryMarshal.GetReference(vectors))
200193
{
201-
bytesWritten = Interop.Sys.PWriteV(handle, pinnedVectors, buffersCount, fileOffset);
194+
if (handle.SupportsRandomAccess)
195+
{
196+
bytesWritten = Interop.Sys.PWriteV(handle, pinnedVectors, buffersCount, fileOffset);
197+
if (bytesWritten == -1 && NeedsNonOffsetFallback(handle))
198+
{
199+
bytesWritten = Interop.Sys.WriteV(handle, pinnedVectors, buffersCount);
200+
}
201+
}
202+
else
203+
{
204+
bytesWritten = Interop.Sys.WriteV(handle, pinnedVectors, buffersCount);
205+
}
202206
}
203207

204208
FileStreamHelpers.CheckFileCall(bytesWritten, handle.Path);
@@ -243,5 +247,21 @@ internal static ValueTask WriteAtOffsetAsync(SafeFileHandle handle, ReadOnlyMemo
243247

244248
private static ValueTask WriteGatherAtOffsetAsync(SafeFileHandle handle, IReadOnlyList<ReadOnlyMemory<byte>> buffers, long fileOffset, CancellationToken cancellationToken)
245249
=> handle.GetThreadPoolValueTaskSource().QueueWriteGather(buffers, fileOffset, cancellationToken);
250+
251+
private static bool NeedsNonOffsetFallback(SafeFileHandle handle)
252+
{
253+
// We need to fallback to the non-offset version for certain file types
254+
// e.g: character devices (such as /dev/tty), pipes, and sockets.
255+
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
256+
257+
if (errorInfo.Error == Interop.Error.ENXIO ||
258+
errorInfo.Error == Interop.Error.ESPIPE)
259+
{
260+
handle.SupportsRandomAccess = false;
261+
return true;
262+
}
263+
264+
return false;
265+
}
246266
}
247267
}

src/native/libs/System.Native/entrypoints.c

+2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ static const Entry s_sysNative[] =
265265
DllImportEntry(SystemNative_PWrite)
266266
DllImportEntry(SystemNative_PReadV)
267267
DllImportEntry(SystemNative_PWriteV)
268+
DllImportEntry(SystemNative_ReadV)
269+
DllImportEntry(SystemNative_WriteV)
268270
DllImportEntry(SystemNative_CreateThread)
269271
DllImportEntry(SystemNative_EnablePosixSignalHandling)
270272
DllImportEntry(SystemNative_DisablePosixSignalHandling)

src/native/libs/System.Native/pal_io.c

+28
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,20 @@ int32_t SystemNative_PWrite(intptr_t fd, void* buffer, int32_t bufferSize, int64
18681868
return (int32_t)count;
18691869
}
18701870

1871+
int64_t SystemNative_ReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount)
1872+
{
1873+
assert(vectors != NULL);
1874+
assert(vectorCount >= 0);
1875+
1876+
int64_t count = 0;
1877+
int fileDescriptor = ToFileDescriptor(fd);
1878+
1879+
while ((count = readv(fileDescriptor, (struct iovec*)vectors, (int)vectorCount)) < 0 && errno == EINTR);
1880+
1881+
assert(count >= -1);
1882+
return count;
1883+
}
1884+
18711885
int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset)
18721886
{
18731887
assert(vectors != NULL);
@@ -1908,6 +1922,20 @@ int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount,
19081922
return count;
19091923
}
19101924

1925+
int64_t SystemNative_WriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount)
1926+
{
1927+
assert(vectors != NULL);
1928+
assert(vectorCount >= 0);
1929+
1930+
int64_t count = 0;
1931+
int fileDescriptor = ToFileDescriptor(fd);
1932+
1933+
while ((count = writev(fileDescriptor, (struct iovec*)vectors, (int)vectorCount)) < 0 && errno == EINTR);
1934+
1935+
assert(count >= -1);
1936+
return count;
1937+
}
1938+
19111939
int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset)
19121940
{
19131941
assert(vectors != NULL);

src/native/libs/System.Native/pal_io.h

+14
Original file line numberDiff line numberDiff line change
@@ -829,3 +829,17 @@ PALEXPORT int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t ve
829829
* Returns the number of bytes written on success; otherwise, -1 is returned an errno is set.
830830
*/
831831
PALEXPORT int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset);
832+
833+
/**
834+
* Reads the number of bytes specified into the provided buffers from the specified, opened file descriptor.
835+
*
836+
* Returns the number of bytes read on success; otherwise, -1 is returned an errno is set.
837+
*/
838+
PALEXPORT int64_t SystemNative_ReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount);
839+
840+
/**
841+
* Writes the number of bytes specified in the buffers into the specified, opened file descriptor
842+
*
843+
* Returns the number of bytes written on success; otherwise, -1 is returned an errno is set.
844+
*/
845+
PALEXPORT int64_t SystemNative_WriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount);

0 commit comments

Comments
 (0)