diff options
author | Robin Burchell <robin+git@viroteck.net> | 2019-07-18 09:52:22 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-07-18 10:06:20 +0200 |
commit | b907608e465cc3b2ff62e01d27f208cb70ac3edf (patch) | |
tree | 4e165a42376e4d99e62c0062c0d5c5b3d79e20e2 | |
parent | f60d7e5d1f5da3ec876a537b3c9079ce258e4cf3 (diff) | |
download | serenity-b907608e465cc3b2ff62e01d27f208cb70ac3edf.zip |
SharedBuffer: Split the creation and share steps
This allows us to seal a buffer *before* anyone else has access to it
(well, ok, the creating process still does, but you can't win them all).
It also means that a SharedBuffer can be shared with multiple clients:
all you need is to have access to it to share it on again.
-rw-r--r-- | Kernel/Process.cpp | 30 | ||||
-rw-r--r-- | Kernel/Process.h | 3 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 4 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 | ||||
-rw-r--r-- | Libraries/LibAudio/AClientConnection.cpp | 3 | ||||
-rw-r--r-- | Libraries/LibC/SharedBuffer.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibC/SharedBuffer.h | 3 | ||||
-rw-r--r-- | Libraries/LibC/unistd.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibC/unistd.h | 3 | ||||
-rw-r--r-- | Libraries/LibGUI/GClipboard.cpp | 3 | ||||
-rw-r--r-- | Libraries/LibGUI/GWindow.cpp | 3 | ||||
-rw-r--r-- | Servers/WindowServer/WSClientConnection.cpp | 3 |
12 files changed, 58 insertions, 22 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 0409299eb7..4c96a794b7 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2377,28 +2377,19 @@ void Process::disown_all_shared_buffers() shared_buffer->disown(m_pid); } -int Process::sys$create_shared_buffer(pid_t peer_pid, int size, void** buffer) +int Process::sys$create_shared_buffer(int size, void** buffer) { if (!size || size < 0) return -EINVAL; size = PAGE_ROUND_UP(size); - if (!peer_pid || peer_pid < 0 || peer_pid == m_pid) - return -EINVAL; if (!validate_write_typed(buffer)) return -EFAULT; - { - InterruptDisabler disabler; - auto* peer = Process::from_pid(peer_pid); - if (!peer) - return -ESRCH; - } LOCKER(shared_buffers().lock()); static int s_next_shared_buffer_id; int shared_buffer_id = ++s_next_shared_buffer_id; auto shared_buffer = make<SharedBuffer>(shared_buffer_id, size); shared_buffer->share_with(m_pid); - shared_buffer->share_with(peer_pid); *buffer = shared_buffer->get_address(*this); ASSERT((int)shared_buffer->size() >= size); #ifdef SHARED_BUFFER_DEBUG @@ -2409,6 +2400,25 @@ int Process::sys$create_shared_buffer(pid_t peer_pid, int size, void** buffer) return shared_buffer_id; } +int Process::sys$share_buffer_with(int shared_buffer_id, pid_t peer_pid) +{ + if (!peer_pid || peer_pid < 0 || peer_pid == m_pid) + return -EINVAL; + LOCKER(shared_buffers().lock()); + auto it = shared_buffers().resource().find(shared_buffer_id); + if (it == shared_buffers().resource().end()) + return -EINVAL; + auto& shared_buffer = *(*it).value; + { + InterruptDisabler disabler; + auto* peer = Process::from_pid(peer_pid); + if (!peer) + return -ESRCH; + } + shared_buffer.share_with(peer_pid); + return 0; +} + int Process::sys$release_shared_buffer(int shared_buffer_id) { LOCKER(shared_buffers().lock()); diff --git a/Kernel/Process.h b/Kernel/Process.h index 3d31f354d8..67ea98672c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -197,7 +197,8 @@ public: int sys$rename(const char* oldpath, const char* newpath); int sys$systrace(pid_t); int sys$mknod(const char* pathname, mode_t, dev_t); - int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer); + int sys$create_shared_buffer(int, void** buffer); + int sys$share_buffer_with(int, pid_t peer_pid); void* sys$get_shared_buffer(int shared_buffer_id); int sys$release_shared_buffer(int shared_buffer_id); int sys$seal_shared_buffer(int shared_buffer_id); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index a8b54e79d2..80f08785de 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -235,7 +235,9 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3 case Syscall::SC_connect: return current->process().sys$connect((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3); case Syscall::SC_create_shared_buffer: - return current->process().sys$create_shared_buffer((pid_t)arg1, (size_t)arg2, (void**)arg3); + return current->process().sys$create_shared_buffer((size_t)arg1, (void**)arg2); + case Syscall::SC_share_buffer_with: + return current->process().sys$share_buffer_with((int)arg1, (pid_t)arg2); case Syscall::SC_get_shared_buffer: return (u32)current->process().sys$get_shared_buffer((int)arg1); case Syscall::SC_release_shared_buffer: diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 58b6e9d44e..2dd38ec449 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -83,6 +83,7 @@ struct timeval; __ENUMERATE_SYSCALL(listen) \ __ENUMERATE_SYSCALL(connect) \ __ENUMERATE_SYSCALL(create_shared_buffer) \ + __ENUMERATE_SYSCALL(share_buffer_with) \ __ENUMERATE_SYSCALL(get_shared_buffer) \ __ENUMERATE_SYSCALL(release_shared_buffer) \ __ENUMERATE_SYSCALL(link) \ diff --git a/Libraries/LibAudio/AClientConnection.cpp b/Libraries/LibAudio/AClientConnection.cpp index 1b52acc63d..5d2abd5935 100644 --- a/Libraries/LibAudio/AClientConnection.cpp +++ b/Libraries/LibAudio/AClientConnection.cpp @@ -19,7 +19,7 @@ void AClientConnection::handshake() void AClientConnection::play(const ABuffer& buffer) { - auto shared_buf = SharedBuffer::create(server_pid(), buffer.size_in_bytes()); + auto shared_buf = SharedBuffer::create_with_size(buffer.size_in_bytes()); if (!shared_buf) { dbg() << "Failed to create a shared buffer!"; return; @@ -27,6 +27,7 @@ void AClientConnection::play(const ABuffer& buffer) memcpy(shared_buf->data(), buffer.data(), buffer.size_in_bytes()); shared_buf->seal(); + shared_buf->share_with(server_pid()); ASAPI_ClientMessage request; request.type = ASAPI_ClientMessage::Type::PlayBuffer; request.play_buffer.buffer_id = shared_buf->shared_buffer_id(); diff --git a/Libraries/LibC/SharedBuffer.cpp b/Libraries/LibC/SharedBuffer.cpp index ef7e31e621..1a0c3a9701 100644 --- a/Libraries/LibC/SharedBuffer.cpp +++ b/Libraries/LibC/SharedBuffer.cpp @@ -3,10 +3,10 @@ #include <stdio.h> #include <unistd.h> -RefPtr<SharedBuffer> SharedBuffer::create(pid_t peer, int size) +RefPtr<SharedBuffer> SharedBuffer::create_with_size(int size) { void* data; - int shared_buffer_id = create_shared_buffer(peer, size, &data); + int shared_buffer_id = create_shared_buffer(size, &data); if (shared_buffer_id < 0) { perror("create_shared_buffer"); return nullptr; @@ -14,6 +14,16 @@ RefPtr<SharedBuffer> SharedBuffer::create(pid_t peer, int size) return adopt(*new SharedBuffer(shared_buffer_id, size, data)); } +bool SharedBuffer::share_with(pid_t peer) +{ + int ret = share_buffer_with(shared_buffer_id(), peer); + if (ret < 0) { + perror("share_buffer_with"); + return false; + } + return true; +} + RefPtr<SharedBuffer> SharedBuffer::create_from_shared_buffer_id(int shared_buffer_id) { void* data = get_shared_buffer(shared_buffer_id); diff --git a/Libraries/LibC/SharedBuffer.h b/Libraries/LibC/SharedBuffer.h index aec7ab3047..2d1cdfc423 100644 --- a/Libraries/LibC/SharedBuffer.h +++ b/Libraries/LibC/SharedBuffer.h @@ -5,10 +5,11 @@ class SharedBuffer : public RefCounted<SharedBuffer> { public: - static RefPtr<SharedBuffer> create(pid_t peer, int); + static RefPtr<SharedBuffer> create_with_size(int); static RefPtr<SharedBuffer> create_from_shared_buffer_id(int); ~SharedBuffer(); + bool share_with(pid_t); int shared_buffer_id() const { return m_shared_buffer_id; } void seal(); int size() const { return m_size; } diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index d4622bba1f..b2307f1f7c 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -423,9 +423,15 @@ int read_tsc(unsigned* lsw, unsigned* msw) __RETURN_WITH_ERRNO(rc, rc, -1); } -int create_shared_buffer(pid_t peer_pid, int size, void** buffer) +int create_shared_buffer(int size, void** buffer) { - int rc = syscall(SC_create_shared_buffer, peer_pid, size, buffer); + int rc = syscall(SC_create_shared_buffer, size, buffer); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int share_buffer_with(int shared_buffer_id, pid_t peer_pid) +{ + int rc = syscall(SC_share_buffer_with, shared_buffer_id, peer_pid); __RETURN_WITH_ERRNO(rc, rc, -1); } diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index 42235b0e63..806efbebe0 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -21,7 +21,8 @@ int gettid(); int donate(int tid); int create_thread(int (*)(void*), void*); void exit_thread(int); -int create_shared_buffer(pid_t peer_pid, int, void** buffer); +int create_shared_buffer(int, void** buffer); +int share_buffer_with(int, pid_t peer_pid); void* get_shared_buffer(int shared_buffer_id); int release_shared_buffer(int shared_buffer_id); int seal_shared_buffer(int shared_buffer_id); diff --git a/Libraries/LibGUI/GClipboard.cpp b/Libraries/LibGUI/GClipboard.cpp index b750f2730a..1c3debce64 100644 --- a/Libraries/LibGUI/GClipboard.cpp +++ b/Libraries/LibGUI/GClipboard.cpp @@ -38,7 +38,7 @@ void GClipboard::set_data(const StringView& data) { WSAPI_ClientMessage request; request.type = WSAPI_ClientMessage::Type::SetClipboardContents; - auto shared_buffer = SharedBuffer::create(GWindowServerConnection::the().server_pid(), data.length() + 1); + auto shared_buffer = SharedBuffer::create_with_size(data.length() + 1); if (!shared_buffer) { dbgprintf("GClipboard::set_data() failed to create a shared buffer\n"); return; @@ -48,6 +48,7 @@ void GClipboard::set_data(const StringView& data) else ((u8*)shared_buffer->data())[0] = '\0'; shared_buffer->seal(); + shared_buffer->share_with(GWindowServerConnection::the().server_pid()); request.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); request.clipboard.contents_size = data.length(); auto response = GWindowServerConnection::the().sync_request(request, WSAPI_ServerMessage::Type::DidSetClipboardContents); diff --git a/Libraries/LibGUI/GWindow.cpp b/Libraries/LibGUI/GWindow.cpp index 87a56ef168..74c582cb52 100644 --- a/Libraries/LibGUI/GWindow.cpp +++ b/Libraries/LibGUI/GWindow.cpp @@ -600,8 +600,9 @@ NonnullRefPtr<GraphicsBitmap> GWindow::create_backing_bitmap(const Size& size) ASSERT(!size.is_empty()); size_t pitch = round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16); size_t size_in_bytes = size.height() * pitch; - auto shared_buffer = SharedBuffer::create(GWindowServerConnection::the().server_pid(), size_in_bytes); + auto shared_buffer = SharedBuffer::create_with_size(size_in_bytes); ASSERT(shared_buffer); + shared_buffer->share_with(GWindowServerConnection::the().server_pid()); auto format = m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32; return GraphicsBitmap::create_with_shared_buffer(format, *shared_buffer, size); } diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index e5343b7fca..6d51cdb42d 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -652,10 +652,11 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&) // FIXME: Optimize case where an app is copy/pasting within itself. // We can just reuse the SharedBuffer then, since it will have the same peer PID. // It would be even nicer if a SharedBuffer could have an arbitrary number of clients.. - RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create(client_pid(), WSClipboard::the().size()); + RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(WSClipboard::the().size()); ASSERT(shared_buffer); memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size()); shared_buffer->seal(); + shared_buffer->share_with(client_pid()); response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); response.clipboard.contents_size = WSClipboard::the().size(); |