mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:12:44 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									f60d7e5d1f
								
							
						
					
					
						commit
						b907608e46
					
				
					 12 changed files with 58 additions and 22 deletions
				
			
		|  | @ -2377,28 +2377,19 @@ void Process::disown_all_shared_buffers() | ||||||
|         shared_buffer->disown(m_pid); |         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) |     if (!size || size < 0) | ||||||
|         return -EINVAL; |         return -EINVAL; | ||||||
|     size = PAGE_ROUND_UP(size); |     size = PAGE_ROUND_UP(size); | ||||||
|     if (!peer_pid || peer_pid < 0 || peer_pid == m_pid) |  | ||||||
|         return -EINVAL; |  | ||||||
|     if (!validate_write_typed(buffer)) |     if (!validate_write_typed(buffer)) | ||||||
|         return -EFAULT; |         return -EFAULT; | ||||||
| 
 | 
 | ||||||
|     { |  | ||||||
|         InterruptDisabler disabler; |  | ||||||
|         auto* peer = Process::from_pid(peer_pid); |  | ||||||
|         if (!peer) |  | ||||||
|             return -ESRCH; |  | ||||||
|     } |  | ||||||
|     LOCKER(shared_buffers().lock()); |     LOCKER(shared_buffers().lock()); | ||||||
|     static int s_next_shared_buffer_id; |     static int s_next_shared_buffer_id; | ||||||
|     int shared_buffer_id = ++s_next_shared_buffer_id; |     int shared_buffer_id = ++s_next_shared_buffer_id; | ||||||
|     auto shared_buffer = make<SharedBuffer>(shared_buffer_id, size); |     auto shared_buffer = make<SharedBuffer>(shared_buffer_id, size); | ||||||
|     shared_buffer->share_with(m_pid); |     shared_buffer->share_with(m_pid); | ||||||
|     shared_buffer->share_with(peer_pid); |  | ||||||
|     *buffer = shared_buffer->get_address(*this); |     *buffer = shared_buffer->get_address(*this); | ||||||
|     ASSERT((int)shared_buffer->size() >= size); |     ASSERT((int)shared_buffer->size() >= size); | ||||||
| #ifdef SHARED_BUFFER_DEBUG | #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; |     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) | int Process::sys$release_shared_buffer(int shared_buffer_id) | ||||||
| { | { | ||||||
|     LOCKER(shared_buffers().lock()); |     LOCKER(shared_buffers().lock()); | ||||||
|  |  | ||||||
|  | @ -197,7 +197,8 @@ public: | ||||||
|     int sys$rename(const char* oldpath, const char* newpath); |     int sys$rename(const char* oldpath, const char* newpath); | ||||||
|     int sys$systrace(pid_t); |     int sys$systrace(pid_t); | ||||||
|     int sys$mknod(const char* pathname, mode_t, dev_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); |     void* sys$get_shared_buffer(int shared_buffer_id); | ||||||
|     int sys$release_shared_buffer(int shared_buffer_id); |     int sys$release_shared_buffer(int shared_buffer_id); | ||||||
|     int sys$seal_shared_buffer(int shared_buffer_id); |     int sys$seal_shared_buffer(int shared_buffer_id); | ||||||
|  |  | ||||||
|  | @ -235,7 +235,9 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3 | ||||||
|     case Syscall::SC_connect: |     case Syscall::SC_connect: | ||||||
|         return current->process().sys$connect((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3); |         return current->process().sys$connect((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3); | ||||||
|     case Syscall::SC_create_shared_buffer: |     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: |     case Syscall::SC_get_shared_buffer: | ||||||
|         return (u32)current->process().sys$get_shared_buffer((int)arg1); |         return (u32)current->process().sys$get_shared_buffer((int)arg1); | ||||||
|     case Syscall::SC_release_shared_buffer: |     case Syscall::SC_release_shared_buffer: | ||||||
|  |  | ||||||
|  | @ -83,6 +83,7 @@ struct timeval; | ||||||
|     __ENUMERATE_SYSCALL(listen)                 \ |     __ENUMERATE_SYSCALL(listen)                 \ | ||||||
|     __ENUMERATE_SYSCALL(connect)                \ |     __ENUMERATE_SYSCALL(connect)                \ | ||||||
|     __ENUMERATE_SYSCALL(create_shared_buffer)   \ |     __ENUMERATE_SYSCALL(create_shared_buffer)   \ | ||||||
|  |     __ENUMERATE_SYSCALL(share_buffer_with)      \ | ||||||
|     __ENUMERATE_SYSCALL(get_shared_buffer)      \ |     __ENUMERATE_SYSCALL(get_shared_buffer)      \ | ||||||
|     __ENUMERATE_SYSCALL(release_shared_buffer)  \ |     __ENUMERATE_SYSCALL(release_shared_buffer)  \ | ||||||
|     __ENUMERATE_SYSCALL(link)                   \ |     __ENUMERATE_SYSCALL(link)                   \ | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ void AClientConnection::handshake() | ||||||
| 
 | 
 | ||||||
| void AClientConnection::play(const ABuffer& buffer) | 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) { |     if (!shared_buf) { | ||||||
|         dbg() << "Failed to create a shared buffer!"; |         dbg() << "Failed to create a shared buffer!"; | ||||||
|         return; |         return; | ||||||
|  | @ -27,6 +27,7 @@ void AClientConnection::play(const ABuffer& buffer) | ||||||
| 
 | 
 | ||||||
|     memcpy(shared_buf->data(), buffer.data(), buffer.size_in_bytes()); |     memcpy(shared_buf->data(), buffer.data(), buffer.size_in_bytes()); | ||||||
|     shared_buf->seal(); |     shared_buf->seal(); | ||||||
|  |     shared_buf->share_with(server_pid()); | ||||||
|     ASAPI_ClientMessage request; |     ASAPI_ClientMessage request; | ||||||
|     request.type = ASAPI_ClientMessage::Type::PlayBuffer; |     request.type = ASAPI_ClientMessage::Type::PlayBuffer; | ||||||
|     request.play_buffer.buffer_id = shared_buf->shared_buffer_id(); |     request.play_buffer.buffer_id = shared_buf->shared_buffer_id(); | ||||||
|  |  | ||||||
|  | @ -3,10 +3,10 @@ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| RefPtr<SharedBuffer> SharedBuffer::create(pid_t peer, int size) | RefPtr<SharedBuffer> SharedBuffer::create_with_size(int size) | ||||||
| { | { | ||||||
|     void* data; |     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) { |     if (shared_buffer_id < 0) { | ||||||
|         perror("create_shared_buffer"); |         perror("create_shared_buffer"); | ||||||
|         return nullptr; |         return nullptr; | ||||||
|  | @ -14,6 +14,16 @@ RefPtr<SharedBuffer> SharedBuffer::create(pid_t peer, int size) | ||||||
|     return adopt(*new SharedBuffer(shared_buffer_id, size, data)); |     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) | RefPtr<SharedBuffer> SharedBuffer::create_from_shared_buffer_id(int shared_buffer_id) | ||||||
| { | { | ||||||
|     void* data = get_shared_buffer(shared_buffer_id); |     void* data = get_shared_buffer(shared_buffer_id); | ||||||
|  |  | ||||||
|  | @ -5,10 +5,11 @@ | ||||||
| 
 | 
 | ||||||
| class SharedBuffer : public RefCounted<SharedBuffer> { | class SharedBuffer : public RefCounted<SharedBuffer> { | ||||||
| public: | 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); |     static RefPtr<SharedBuffer> create_from_shared_buffer_id(int); | ||||||
|     ~SharedBuffer(); |     ~SharedBuffer(); | ||||||
| 
 | 
 | ||||||
|  |     bool share_with(pid_t); | ||||||
|     int shared_buffer_id() const { return m_shared_buffer_id; } |     int shared_buffer_id() const { return m_shared_buffer_id; } | ||||||
|     void seal(); |     void seal(); | ||||||
|     int size() const { return m_size; } |     int size() const { return m_size; } | ||||||
|  |  | ||||||
|  | @ -423,9 +423,15 @@ int read_tsc(unsigned* lsw, unsigned* msw) | ||||||
|     __RETURN_WITH_ERRNO(rc, rc, -1); |     __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); |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,8 @@ int gettid(); | ||||||
| int donate(int tid); | int donate(int tid); | ||||||
| int create_thread(int (*)(void*), void*); | int create_thread(int (*)(void*), void*); | ||||||
| void exit_thread(int); | 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); | void* get_shared_buffer(int shared_buffer_id); | ||||||
| int release_shared_buffer(int shared_buffer_id); | int release_shared_buffer(int shared_buffer_id); | ||||||
| int seal_shared_buffer(int shared_buffer_id); | int seal_shared_buffer(int shared_buffer_id); | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ void GClipboard::set_data(const StringView& data) | ||||||
| { | { | ||||||
|     WSAPI_ClientMessage request; |     WSAPI_ClientMessage request; | ||||||
|     request.type = WSAPI_ClientMessage::Type::SetClipboardContents; |     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) { |     if (!shared_buffer) { | ||||||
|         dbgprintf("GClipboard::set_data() failed to create a shared buffer\n"); |         dbgprintf("GClipboard::set_data() failed to create a shared buffer\n"); | ||||||
|         return; |         return; | ||||||
|  | @ -48,6 +48,7 @@ void GClipboard::set_data(const StringView& data) | ||||||
|     else |     else | ||||||
|         ((u8*)shared_buffer->data())[0] = '\0'; |         ((u8*)shared_buffer->data())[0] = '\0'; | ||||||
|     shared_buffer->seal(); |     shared_buffer->seal(); | ||||||
|  |     shared_buffer->share_with(GWindowServerConnection::the().server_pid()); | ||||||
|     request.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); |     request.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); | ||||||
|     request.clipboard.contents_size = data.length(); |     request.clipboard.contents_size = data.length(); | ||||||
|     auto response = GWindowServerConnection::the().sync_request(request, WSAPI_ServerMessage::Type::DidSetClipboardContents); |     auto response = GWindowServerConnection::the().sync_request(request, WSAPI_ServerMessage::Type::DidSetClipboardContents); | ||||||
|  |  | ||||||
|  | @ -600,8 +600,9 @@ NonnullRefPtr<GraphicsBitmap> GWindow::create_backing_bitmap(const Size& size) | ||||||
|     ASSERT(!size.is_empty()); |     ASSERT(!size.is_empty()); | ||||||
|     size_t pitch = round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16); |     size_t pitch = round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16); | ||||||
|     size_t size_in_bytes = size.height() * pitch; |     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); |     ASSERT(shared_buffer); | ||||||
|  |     shared_buffer->share_with(GWindowServerConnection::the().server_pid()); | ||||||
|     auto format = m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32; |     auto format = m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32; | ||||||
|     return GraphicsBitmap::create_with_shared_buffer(format, *shared_buffer, size); |     return GraphicsBitmap::create_with_shared_buffer(format, *shared_buffer, size); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -652,10 +652,11 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&) | ||||||
|         // FIXME: Optimize case where an app is copy/pasting within itself.
 |         // 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.
 |         //        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..
 |         //        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); |         ASSERT(shared_buffer); | ||||||
|         memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size()); |         memcpy(shared_buffer->data(), WSClipboard::the().data(), WSClipboard::the().size()); | ||||||
|         shared_buffer->seal(); |         shared_buffer->seal(); | ||||||
|  |         shared_buffer->share_with(client_pid()); | ||||||
|         response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); |         response.clipboard.shared_buffer_id = shared_buffer->shared_buffer_id(); | ||||||
|         response.clipboard.contents_size = WSClipboard::the().size(); |         response.clipboard.contents_size = WSClipboard::the().size(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robin Burchell
						Robin Burchell