mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:32:46 +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); | ||||
| } | ||||
| 
 | ||||
| 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()); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
|  | @ -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)                   \ | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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; } | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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); | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Robin Burchell
						Robin Burchell