mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-02 04:20:28 +00:00
Kernel: Add a writev() syscall for writing multiple buffers in one go.
We then use this immediately in the WindowServer/LibGUI communication in order to send both message + optional "extra data" with a single syscall.
This commit is contained in:
parent
e6443649cb
commit
99aead4857
Notes:
sideshowbarker
2024-07-19 14:11:09 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/99aead4857c
8 changed files with 111 additions and 54 deletions
|
@ -818,6 +818,77 @@ int Process::sys$ptsname_r(int fd, char* buffer, ssize_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
|
||||
{
|
||||
if (iov_count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_read_typed(iov, iov_count))
|
||||
return -EFAULT;
|
||||
|
||||
// FIXME: Return EINVAL if sum of iovecs is greater than INT_MAX
|
||||
|
||||
auto* descriptor = file_descriptor(fd);
|
||||
if (!descriptor)
|
||||
return -EBADF;
|
||||
|
||||
int nwritten = 0;
|
||||
for (int i = 0; i < iov_count; ++i) {
|
||||
int rc = do_write(*descriptor, (const byte*)iov[i].iov_base, iov[i].iov_len);
|
||||
if (rc < 0) {
|
||||
if (nwritten == 0)
|
||||
return rc;
|
||||
return nwritten;
|
||||
}
|
||||
nwritten += rc;
|
||||
}
|
||||
|
||||
if (current->has_unmasked_pending_signals()) {
|
||||
current->block(Thread::State::BlockedSignal);
|
||||
if (nwritten == 0)
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
ssize_t Process::do_write(FileDescriptor& descriptor, const byte* data, int data_size)
|
||||
{
|
||||
ssize_t nwritten = 0;
|
||||
if (!descriptor.is_blocking())
|
||||
return descriptor.write(data, data_size);
|
||||
|
||||
while (nwritten < data_size) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("while %u < %u\n", nwritten, size);
|
||||
#endif
|
||||
if (!descriptor.can_write()) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("block write on %d\n", fd);
|
||||
#endif
|
||||
current->block(Thread::State::BlockedWrite, descriptor);
|
||||
}
|
||||
ssize_t rc = descriptor.write(data + nwritten, data_size - nwritten);
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf(" -> write returned %d\n", rc);
|
||||
#endif
|
||||
if (rc < 0) {
|
||||
// FIXME: Support returning partial nwritten with errno.
|
||||
ASSERT(nwritten == 0);
|
||||
return rc;
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
if (current->has_unmasked_pending_signals()) {
|
||||
current->block(Thread::State::BlockedSignal);
|
||||
if (nwritten == 0)
|
||||
return -EINTR;
|
||||
}
|
||||
nwritten += rc;
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
ssize_t Process::sys$write(int fd, const byte* data, ssize_t size)
|
||||
{
|
||||
if (size < 0)
|
||||
|
@ -832,39 +903,7 @@ ssize_t Process::sys$write(int fd, const byte* data, ssize_t size)
|
|||
auto* descriptor = file_descriptor(fd);
|
||||
if (!descriptor)
|
||||
return -EBADF;
|
||||
ssize_t nwritten = 0;
|
||||
if (descriptor->is_blocking()) {
|
||||
while (nwritten < (ssize_t)size) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("while %u < %u\n", nwritten, size);
|
||||
#endif
|
||||
if (!descriptor->can_write()) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("block write on %d\n", fd);
|
||||
#endif
|
||||
current->block(Thread::State::BlockedWrite, *descriptor);
|
||||
}
|
||||
ssize_t rc = descriptor->write((const byte*)data + nwritten, size - nwritten);
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf(" -> write returned %d\n", rc);
|
||||
#endif
|
||||
if (rc < 0) {
|
||||
// FIXME: Support returning partial nwritten with errno.
|
||||
ASSERT(nwritten == 0);
|
||||
return rc;
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
if (current->has_unmasked_pending_signals()) {
|
||||
current->block(Thread::State::BlockedSignal);
|
||||
if (nwritten == 0)
|
||||
return -EINTR;
|
||||
}
|
||||
nwritten += rc;
|
||||
}
|
||||
} else {
|
||||
nwritten = descriptor->write((const byte*)data, size);
|
||||
}
|
||||
auto nwritten = do_write(*descriptor, data, size);
|
||||
if (current->has_unmasked_pending_signals()) {
|
||||
current->block(Thread::State::BlockedSignal);
|
||||
if (nwritten == 0)
|
||||
|
|
|
@ -110,6 +110,7 @@ public:
|
|||
int sys$close(int fd);
|
||||
ssize_t sys$read(int fd, byte*, ssize_t);
|
||||
ssize_t sys$write(int fd, const byte*, ssize_t);
|
||||
ssize_t sys$writev(int fd, const struct iovec* iov, int iov_count);
|
||||
int sys$fstat(int fd, stat*);
|
||||
int sys$lstat(const char*, stat*);
|
||||
int sys$stat(const char*, stat*);
|
||||
|
@ -255,6 +256,7 @@ private:
|
|||
Process(String&& name, uid_t, gid_t, pid_t ppid, RingLevel, RetainPtr<Inode>&& cwd = nullptr, RetainPtr<Inode>&& executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
||||
|
||||
int do_exec(String path, Vector<String> arguments, Vector<String> environment);
|
||||
ssize_t do_write(FileDescriptor&, const byte*, int data_size);
|
||||
|
||||
int alloc_fd(int first_candidate_fd = 0);
|
||||
void disown_all_shared_buffers();
|
||||
|
|
|
@ -267,6 +267,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->process().sys$systrace((pid_t)arg1);
|
||||
case Syscall::SC_mknod:
|
||||
return current->process().sys$mknod((const char*)arg1, (mode_t)arg2, (dev_t)arg3);
|
||||
case Syscall::SC_writev:
|
||||
return current->process().sys$writev((int)arg1, (const struct iovec*)arg2, (int)arg3);
|
||||
default:
|
||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
__ENUMERATE_SYSCALL(systrace) \
|
||||
__ENUMERATE_SYSCALL(exit_thread) \
|
||||
__ENUMERATE_SYSCALL(mknod) \
|
||||
__ENUMERATE_SYSCALL(writev) \
|
||||
|
||||
|
||||
namespace Syscall {
|
||||
|
|
|
@ -390,3 +390,8 @@ struct [[gnu::packed]] FarPtr {
|
|||
dword offset { 0 };
|
||||
word selector { 0 };
|
||||
};
|
||||
|
||||
struct iovec {
|
||||
void* iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
|
|
@ -41,6 +41,7 @@ LIBC_OBJS = \
|
|||
sys/select.o \
|
||||
sys/socket.o \
|
||||
sys/wait.o \
|
||||
sys/uio.o \
|
||||
poll.o \
|
||||
locale.o \
|
||||
arpa/inet.o \
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <LibC/errno.h>
|
||||
#include <LibC/string.h>
|
||||
#include <LibC/stdlib.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
//#define GEVENTLOOP_DEBUG
|
||||
//#define COALESCING_DEBUG
|
||||
|
@ -359,13 +360,20 @@ bool GEventLoop::post_message_to_server(const WSAPI_ClientMessage& message, cons
|
|||
if (!extra_data.is_empty())
|
||||
const_cast<WSAPI_ClientMessage&>(message).extra_size = extra_data.size();
|
||||
|
||||
int nwritten = write(s_event_fd, &message, sizeof(WSAPI_ClientMessage));
|
||||
ASSERT(nwritten == sizeof(WSAPI_ClientMessage));
|
||||
struct iovec iov[2];
|
||||
int iov_count = 1;
|
||||
iov[0].iov_base = (void*)&message;
|
||||
iov[0].iov_len = sizeof(message);
|
||||
|
||||
if (!extra_data.is_empty()) {
|
||||
nwritten = write(s_event_fd, extra_data.data(), extra_data.size());
|
||||
ASSERT(nwritten == extra_data.size());
|
||||
iov[1].iov_base = (void*)extra_data.data();
|
||||
iov[1].iov_len = extra_data.size();
|
||||
++iov_count;
|
||||
}
|
||||
|
||||
int nwritten = writev(s_event_fd, iov, iov_count);
|
||||
ASSERT(nwritten == sizeof(message) + extra_data.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <WindowServer/WSScreen.h>
|
||||
#include <SharedBuffer.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
@ -76,31 +77,29 @@ void WSClientConnection::post_message(const WSAPI_ServerMessage& message, const
|
|||
if (!extra_data.is_empty())
|
||||
const_cast<WSAPI_ServerMessage&>(message).extra_size = extra_data.size();
|
||||
|
||||
int nwritten = write(m_fd, &message, sizeof(message));
|
||||
struct iovec iov[2];
|
||||
int iov_count = 1;
|
||||
|
||||
iov[0].iov_base = (void*)&message;
|
||||
iov[0].iov_len = sizeof(message);
|
||||
|
||||
if (!extra_data.is_empty()) {
|
||||
iov[1].iov_base = (void*)extra_data.data();
|
||||
iov[1].iov_len = extra_data.size();
|
||||
++iov_count;
|
||||
}
|
||||
|
||||
int nwritten = writev(m_fd, iov, iov_count);
|
||||
if (nwritten < 0) {
|
||||
if (errno == EPIPE) {
|
||||
dbgprintf("WSClientConnection::post_message: Disconnected from peer.\n");
|
||||
return;
|
||||
}
|
||||
perror("WSClientConnection::post_message write");
|
||||
perror("WSClientConnection::post_message writev");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ASSERT(nwritten == sizeof(message));
|
||||
|
||||
if (!extra_data.is_empty()) {
|
||||
nwritten = write(m_fd, extra_data.data(), extra_data.size());
|
||||
if (nwritten < 0) {
|
||||
if (errno == EPIPE) {
|
||||
dbgprintf("WSClientConnection::post_message: Disconnected from peer during extra_data write.\n");
|
||||
return;
|
||||
}
|
||||
perror("WSClientConnection::post_message write (extra_data)");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ASSERT(nwritten == extra_data.size());
|
||||
}
|
||||
ASSERT(nwritten == sizeof(message) + extra_data.size());
|
||||
}
|
||||
|
||||
void WSClientConnection::notify_about_new_screen_rect(const Rect& rect)
|
||||
|
|
Loading…
Reference in a new issue