1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:17:35 +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:
Andreas Kling 2019-05-10 03:19:25 +02:00
parent e6443649cb
commit 99aead4857
8 changed files with 111 additions and 54 deletions

View file

@ -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)

View file

@ -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();

View file

@ -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;

View file

@ -102,6 +102,7 @@
__ENUMERATE_SYSCALL(systrace) \
__ENUMERATE_SYSCALL(exit_thread) \
__ENUMERATE_SYSCALL(mknod) \
__ENUMERATE_SYSCALL(writev) \
namespace Syscall {

View file

@ -390,3 +390,8 @@ struct [[gnu::packed]] FarPtr {
dword offset { 0 };
word selector { 0 };
};
struct iovec {
void* iov_base;
size_t iov_len;
};