Share file offset across processes

This change ensures that if a file descriptor for an open disk file gets
shared by multiple processes within a process tree, then lseek() changes
will be visible across processes, and read() / write() are synchronized.
Note this only applies to Windows, because UNIX kernels already do this.
This commit is contained in:
Justine Tunney 2024-08-03 01:24:46 -07:00
parent a80ab3f8fe
commit 761c6ad615
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
15 changed files with 256 additions and 63 deletions

View file

@ -62,9 +62,10 @@ static dontinline textwindows ssize_t sys_sendfile_nt(
int outfd, int infd, int64_t *opt_in_out_inoffset, uint32_t uptobytes) {
ssize_t rc;
uint32_t flags = 0;
bool locked = false;
int64_t ih, oh, eof, offset;
struct NtByHandleFileInformation wst;
if (!__isfdkind(infd, kFdFile))
if (!__isfdkind(infd, kFdFile) || !g_fds.p[infd].shared)
return ebadf();
if (!__isfdkind(outfd, kFdSocket))
return ebadf();
@ -73,7 +74,9 @@ static dontinline textwindows ssize_t sys_sendfile_nt(
if (opt_in_out_inoffset) {
offset = *opt_in_out_inoffset;
} else {
offset = g_fds.p[infd].pointer;
locked = true;
__fd_lock(&g_fds.p[infd]);
offset = g_fds.p[infd].shared->pointer;
}
if (GetFileInformationByHandle(ih, &wst)) {
// TransmitFile() returns EINVAL if `uptobytes` goes past EOF.
@ -82,9 +85,10 @@ static dontinline textwindows ssize_t sys_sendfile_nt(
uptobytes = eof - offset;
}
} else {
if (locked)
__fd_unlock(&g_fds.p[infd]);
return ebadf();
}
BLOCK_SIGNALS;
struct NtOverlapped ov = {.hEvent = WSACreateEvent(), .Pointer = offset};
cosmo_once(&g_transmitfile.once, transmitfile_init);
if (g_transmitfile.lpTransmitFile(oh, ih, uptobytes, 0, &ov, 0, 0) ||
@ -95,7 +99,7 @@ static dontinline textwindows ssize_t sys_sendfile_nt(
if (opt_in_out_inoffset) {
*opt_in_out_inoffset = offset + rc;
} else {
g_fds.p[infd].pointer = offset + rc;
g_fds.p[infd].shared->pointer = offset + rc;
}
} else {
rc = __winsockerr();
@ -103,8 +107,9 @@ static dontinline textwindows ssize_t sys_sendfile_nt(
} else {
rc = __winsockerr();
}
if (locked)
__fd_unlock(&g_fds.p[infd]);
WSACloseEvent(ov.hEvent);
ALLOW_SIGNALS;
return rc;
}
@ -186,7 +191,9 @@ ssize_t sendfile(int outfd, int infd, int64_t *opt_in_out_inoffset,
} else if (IsFreebsd() || IsXnu()) {
rc = sys_sendfile_bsd(outfd, infd, opt_in_out_inoffset, uptobytes);
} else if (IsWindows()) {
BLOCK_SIGNALS;
rc = sys_sendfile_nt(outfd, infd, opt_in_out_inoffset, uptobytes);
ALLOW_SIGNALS;
} else {
rc = enosys();
}