mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:22:43 +00:00 
			
		
		
		
	Kernel: Give each FileDescriptor a chance to co-open sockets.
Track how many fds are open for a socket's Accepted and Connected roles. This allows fork() to clone a socket fd without a subsequent close() walking all over the parent process's fd.
This commit is contained in:
		
							parent
							
								
									b0be3299b5
								
							
						
					
					
						commit
						d5f515cf6c
					
				
					 6 changed files with 51 additions and 27 deletions
				
			
		|  | @ -49,14 +49,14 @@ FileDescriptor::FileDescriptor(RetainPtr<Device>&& device) | |||
| 
 | ||||
| FileDescriptor::FileDescriptor(RetainPtr<Socket>&& socket, SocketRole role) | ||||
|     : m_socket(move(socket)) | ||||
|     , m_socket_role(role) | ||||
| { | ||||
|     set_socket_role(role); | ||||
| } | ||||
| 
 | ||||
| FileDescriptor::~FileDescriptor() | ||||
| { | ||||
|     if (m_socket) { | ||||
|         m_socket->close(m_socket_role); | ||||
|         m_socket->detach_fd(m_socket_role); | ||||
|         m_socket = nullptr; | ||||
|     } | ||||
|     if (m_device) { | ||||
|  | @ -70,6 +70,16 @@ FileDescriptor::~FileDescriptor() | |||
|     m_inode = nullptr; | ||||
| } | ||||
| 
 | ||||
| void FileDescriptor::set_socket_role(SocketRole role) | ||||
| { | ||||
|     if (role == m_socket_role) | ||||
|         return; | ||||
| 
 | ||||
|     ASSERT(m_socket); | ||||
|     m_socket_role = role; | ||||
|     m_socket->attach_fd(role); | ||||
| } | ||||
| 
 | ||||
| RetainPtr<FileDescriptor> FileDescriptor::clone() | ||||
| { | ||||
|     RetainPtr<FileDescriptor> descriptor; | ||||
|  | @ -81,6 +91,9 @@ RetainPtr<FileDescriptor> FileDescriptor::clone() | |||
|         if (m_device) { | ||||
|             descriptor = FileDescriptor::create(m_device.copy_ref()); | ||||
|             descriptor->m_inode = m_inode.copy_ref(); | ||||
|         } else if (m_socket) { | ||||
|             descriptor = FileDescriptor::create(m_socket.copy_ref(), m_socket_role); | ||||
|             descriptor->m_inode = m_inode.copy_ref(); | ||||
|         } else { | ||||
|             descriptor = FileDescriptor::create(m_inode.copy_ref()); | ||||
|         } | ||||
|  |  | |||
|  | @ -86,7 +86,7 @@ public: | |||
| 
 | ||||
|     void set_original_inode(Badge<VFS>, RetainPtr<Inode>&& inode) { m_inode = move(inode); } | ||||
| 
 | ||||
|     void set_socket_role(SocketRole role) { m_socket_role = role; } | ||||
|     void set_socket_role(SocketRole); | ||||
| 
 | ||||
| private: | ||||
|     friend class VFS; | ||||
|  |  | |||
|  | @ -106,23 +106,34 @@ bool LocalSocket::connect(const sockaddr* address, socklen_t address_size, int& | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void LocalSocket::close(SocketRole role) | ||||
| void LocalSocket::attach_fd(SocketRole role) | ||||
| { | ||||
|     if (role == SocketRole::Accepted) | ||||
|         m_server_closed = true; | ||||
|     else if (role == SocketRole::Connected) | ||||
|         m_client_closed = true; | ||||
|     if (role == SocketRole::Accepted) { | ||||
|         ++m_accepted_fds_open; | ||||
|     } else if (role == SocketRole::Connected) { | ||||
|         ++m_connected_fds_open; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LocalSocket::detach_fd(SocketRole role) | ||||
| { | ||||
|     if (role == SocketRole::Accepted) { | ||||
|         ASSERT(m_accepted_fds_open); | ||||
|         --m_accepted_fds_open; | ||||
|     } else if (role == SocketRole::Connected) { | ||||
|         ASSERT(m_connected_fds_open); | ||||
|         --m_connected_fds_open; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool LocalSocket::can_read(SocketRole role) const | ||||
| { | ||||
|     if (m_bound && is_listening()) | ||||
|     if (role == SocketRole::Listener) | ||||
|         return can_accept(); | ||||
| 
 | ||||
|     if (role == SocketRole::Accepted) | ||||
|         return m_client_closed || !m_for_server.is_empty(); | ||||
|     else if (role == SocketRole::Connected) | ||||
|         return m_server_closed || !m_for_client.is_empty(); | ||||
|         return !m_connected_fds_open || !m_for_server.is_empty(); | ||||
|     if (role == SocketRole::Connected) | ||||
|         return !m_accepted_fds_open || !m_for_client.is_empty(); | ||||
|     ASSERT_NOT_REACHED(); | ||||
| } | ||||
| 
 | ||||
|  | @ -130,7 +141,7 @@ ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size) | |||
| { | ||||
|     if (role == SocketRole::Accepted) | ||||
|         return m_for_server.read(buffer, size); | ||||
|     else if (role == SocketRole::Connected) | ||||
|     if (role == SocketRole::Connected) | ||||
|         return m_for_client.read(buffer, size); | ||||
|     ASSERT_NOT_REACHED(); | ||||
| } | ||||
|  | @ -138,11 +149,12 @@ ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size) | |||
| ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size) | ||||
| { | ||||
|     if (role == SocketRole::Accepted) { | ||||
|         if (m_client_closed) | ||||
|         if (!m_accepted_fds_open) | ||||
|             return -EPIPE; | ||||
|         return m_for_client.write(data, size); | ||||
|     } else if (role == SocketRole::Connected) { | ||||
|         if (m_client_closed) | ||||
|     } | ||||
|     if (role == SocketRole::Connected) { | ||||
|         if (!m_connected_fds_open) | ||||
|             return -EPIPE; | ||||
|         return m_for_server.write(data, size); | ||||
|     } | ||||
|  | @ -152,8 +164,8 @@ ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size) | |||
| bool LocalSocket::can_write(SocketRole role) const | ||||
| { | ||||
|     if (role == SocketRole::Accepted) | ||||
|         return m_client_closed || m_for_client.bytes_in_write_buffer() < 4096; | ||||
|     else if (role == SocketRole::Connected) | ||||
|         return m_server_closed || m_for_server.bytes_in_write_buffer() < 4096; | ||||
|         return !m_connected_fds_open || m_for_client.bytes_in_write_buffer() < 4096; | ||||
|     if (role == SocketRole::Connected) | ||||
|         return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096; | ||||
|     ASSERT_NOT_REACHED(); | ||||
| } | ||||
|  |  | |||
|  | @ -13,7 +13,8 @@ public: | |||
|     virtual bool bind(const sockaddr*, socklen_t, int& error) override; | ||||
|     virtual bool connect(const sockaddr*, socklen_t, int& error) override; | ||||
|     virtual bool get_address(sockaddr*, socklen_t*) override; | ||||
|     virtual void close(SocketRole) override; | ||||
|     virtual void attach_fd(SocketRole) override; | ||||
|     virtual void detach_fd(SocketRole) override; | ||||
|     virtual bool can_read(SocketRole) const override; | ||||
|     virtual ssize_t read(SocketRole, byte*, size_t) override; | ||||
|     virtual ssize_t write(SocketRole, const byte*, size_t) override; | ||||
|  | @ -27,8 +28,8 @@ private: | |||
|     RetainPtr<LocalSocket> m_peer; | ||||
| 
 | ||||
|     bool m_bound { false }; | ||||
|     bool m_server_closed { false }; | ||||
|     bool m_client_closed { false }; | ||||
|     int m_accepted_fds_open { 0 }; | ||||
|     int m_connected_fds_open { 0 }; | ||||
|     sockaddr_un m_address; | ||||
| 
 | ||||
|     DoubleBuffer m_for_client; | ||||
|  |  | |||
|  | @ -36,7 +36,6 @@ bool Socket::listen(int backlog, int& error) | |||
|         return false; | ||||
|     } | ||||
|     m_backlog = backlog; | ||||
|     m_listening = true; | ||||
|     kprintf("Socket{%p} listening with backlog=%d\n", this, m_backlog); | ||||
|     return true; | ||||
| } | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ public: | |||
|     static RetainPtr<Socket> create(int domain, int type, int protocol, int& error); | ||||
|     virtual ~Socket(); | ||||
| 
 | ||||
|     bool is_listening() const { return m_listening; } | ||||
|     int domain() const { return m_domain; } | ||||
|     int type() const { return m_type; } | ||||
|     int protocol() const { return m_protocol; } | ||||
|  | @ -28,7 +27,8 @@ public: | |||
|     virtual bool connect(const sockaddr*, socklen_t, int& error) = 0; | ||||
|     virtual bool get_address(sockaddr*, socklen_t*) = 0; | ||||
|     virtual bool is_local() const { return false; } | ||||
|     virtual void close(SocketRole) = 0; | ||||
|     virtual void attach_fd(SocketRole) = 0; | ||||
|     virtual void detach_fd(SocketRole) = 0; | ||||
|     virtual bool can_read(SocketRole) const = 0; | ||||
|     virtual ssize_t read(SocketRole, byte*, size_t) = 0; | ||||
|     virtual ssize_t write(SocketRole, const byte*, size_t) = 0; | ||||
|  | @ -48,7 +48,6 @@ private: | |||
|     int m_type { 0 }; | ||||
|     int m_protocol { 0 }; | ||||
|     int m_backlog { 0 }; | ||||
|     bool m_listening { false }; | ||||
|     bool m_connected { false }; | ||||
| 
 | ||||
|     Vector<RetainPtr<Socket>> m_pending; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling