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) | FileDescriptor::FileDescriptor(RetainPtr<Socket>&& socket, SocketRole role) | ||||||
|     : m_socket(move(socket)) |     : m_socket(move(socket)) | ||||||
|     , m_socket_role(role) |  | ||||||
| { | { | ||||||
|  |     set_socket_role(role); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FileDescriptor::~FileDescriptor() | FileDescriptor::~FileDescriptor() | ||||||
| { | { | ||||||
|     if (m_socket) { |     if (m_socket) { | ||||||
|         m_socket->close(m_socket_role); |         m_socket->detach_fd(m_socket_role); | ||||||
|         m_socket = nullptr; |         m_socket = nullptr; | ||||||
|     } |     } | ||||||
|     if (m_device) { |     if (m_device) { | ||||||
|  | @ -70,6 +70,16 @@ FileDescriptor::~FileDescriptor() | ||||||
|     m_inode = nullptr; |     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> FileDescriptor::clone() | ||||||
| { | { | ||||||
|     RetainPtr<FileDescriptor> descriptor; |     RetainPtr<FileDescriptor> descriptor; | ||||||
|  | @ -81,6 +91,9 @@ RetainPtr<FileDescriptor> FileDescriptor::clone() | ||||||
|         if (m_device) { |         if (m_device) { | ||||||
|             descriptor = FileDescriptor::create(m_device.copy_ref()); |             descriptor = FileDescriptor::create(m_device.copy_ref()); | ||||||
|             descriptor->m_inode = m_inode.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 { |         } else { | ||||||
|             descriptor = FileDescriptor::create(m_inode.copy_ref()); |             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_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: | private: | ||||||
|     friend class VFS; |     friend class VFS; | ||||||
|  |  | ||||||
|  | @ -106,23 +106,34 @@ bool LocalSocket::connect(const sockaddr* address, socklen_t address_size, int& | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LocalSocket::close(SocketRole role) | void LocalSocket::attach_fd(SocketRole role) | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) { | ||||||
|         m_server_closed = true; |         ++m_accepted_fds_open; | ||||||
|     else if (role == SocketRole::Connected) |     } else if (role == SocketRole::Connected) { | ||||||
|         m_client_closed = true; |         ++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 | bool LocalSocket::can_read(SocketRole role) const | ||||||
| { | { | ||||||
|     if (m_bound && is_listening()) |     if (role == SocketRole::Listener) | ||||||
|         return can_accept(); |         return can_accept(); | ||||||
| 
 |  | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return m_client_closed || !m_for_server.is_empty(); |         return !m_connected_fds_open || !m_for_server.is_empty(); | ||||||
|     else if (role == SocketRole::Connected) |     if (role == SocketRole::Connected) | ||||||
|         return m_server_closed || !m_for_client.is_empty(); |         return !m_accepted_fds_open || !m_for_client.is_empty(); | ||||||
|     ASSERT_NOT_REACHED(); |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -130,7 +141,7 @@ ssize_t LocalSocket::read(SocketRole role, byte* buffer, size_t size) | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return m_for_server.read(buffer, size); |         return m_for_server.read(buffer, size); | ||||||
|     else if (role == SocketRole::Connected) |     if (role == SocketRole::Connected) | ||||||
|         return m_for_client.read(buffer, size); |         return m_for_client.read(buffer, size); | ||||||
|     ASSERT_NOT_REACHED(); |     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) | ssize_t LocalSocket::write(SocketRole role, const byte* data, size_t size) | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) { |     if (role == SocketRole::Accepted) { | ||||||
|         if (m_client_closed) |         if (!m_accepted_fds_open) | ||||||
|             return -EPIPE; |             return -EPIPE; | ||||||
|         return m_for_client.write(data, size); |         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 -EPIPE; | ||||||
|         return m_for_server.write(data, size); |         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 | bool LocalSocket::can_write(SocketRole role) const | ||||||
| { | { | ||||||
|     if (role == SocketRole::Accepted) |     if (role == SocketRole::Accepted) | ||||||
|         return m_client_closed || m_for_client.bytes_in_write_buffer() < 4096; |         return !m_connected_fds_open || m_for_client.bytes_in_write_buffer() < 4096; | ||||||
|     else if (role == SocketRole::Connected) |     if (role == SocketRole::Connected) | ||||||
|         return m_server_closed || m_for_server.bytes_in_write_buffer() < 4096; |         return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096; | ||||||
|     ASSERT_NOT_REACHED(); |     ASSERT_NOT_REACHED(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,7 +13,8 @@ public: | ||||||
|     virtual bool bind(const sockaddr*, socklen_t, int& error) override; |     virtual bool bind(const sockaddr*, socklen_t, int& error) override; | ||||||
|     virtual bool connect(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 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 bool can_read(SocketRole) const override; | ||||||
|     virtual ssize_t read(SocketRole, byte*, size_t) override; |     virtual ssize_t read(SocketRole, byte*, size_t) override; | ||||||
|     virtual ssize_t write(SocketRole, const byte*, size_t) override; |     virtual ssize_t write(SocketRole, const byte*, size_t) override; | ||||||
|  | @ -27,8 +28,8 @@ private: | ||||||
|     RetainPtr<LocalSocket> m_peer; |     RetainPtr<LocalSocket> m_peer; | ||||||
| 
 | 
 | ||||||
|     bool m_bound { false }; |     bool m_bound { false }; | ||||||
|     bool m_server_closed { false }; |     int m_accepted_fds_open { 0 }; | ||||||
|     bool m_client_closed { false }; |     int m_connected_fds_open { 0 }; | ||||||
|     sockaddr_un m_address; |     sockaddr_un m_address; | ||||||
| 
 | 
 | ||||||
|     DoubleBuffer m_for_client; |     DoubleBuffer m_for_client; | ||||||
|  |  | ||||||
|  | @ -36,7 +36,6 @@ bool Socket::listen(int backlog, int& error) | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     m_backlog = backlog; |     m_backlog = backlog; | ||||||
|     m_listening = true; |  | ||||||
|     kprintf("Socket{%p} listening with backlog=%d\n", this, m_backlog); |     kprintf("Socket{%p} listening with backlog=%d\n", this, m_backlog); | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,7 +14,6 @@ public: | ||||||
|     static RetainPtr<Socket> create(int domain, int type, int protocol, int& error); |     static RetainPtr<Socket> create(int domain, int type, int protocol, int& error); | ||||||
|     virtual ~Socket(); |     virtual ~Socket(); | ||||||
| 
 | 
 | ||||||
|     bool is_listening() const { return m_listening; } |  | ||||||
|     int domain() const { return m_domain; } |     int domain() const { return m_domain; } | ||||||
|     int type() const { return m_type; } |     int type() const { return m_type; } | ||||||
|     int protocol() const { return m_protocol; } |     int protocol() const { return m_protocol; } | ||||||
|  | @ -28,7 +27,8 @@ public: | ||||||
|     virtual bool connect(const sockaddr*, socklen_t, int& error) = 0; |     virtual bool connect(const sockaddr*, socklen_t, int& error) = 0; | ||||||
|     virtual bool get_address(sockaddr*, socklen_t*) = 0; |     virtual bool get_address(sockaddr*, socklen_t*) = 0; | ||||||
|     virtual bool is_local() const { return false; } |     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 bool can_read(SocketRole) const = 0; | ||||||
|     virtual ssize_t read(SocketRole, byte*, size_t) = 0; |     virtual ssize_t read(SocketRole, byte*, size_t) = 0; | ||||||
|     virtual ssize_t write(SocketRole, const 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_type { 0 }; | ||||||
|     int m_protocol { 0 }; |     int m_protocol { 0 }; | ||||||
|     int m_backlog { 0 }; |     int m_backlog { 0 }; | ||||||
|     bool m_listening { false }; |  | ||||||
|     bool m_connected { false }; |     bool m_connected { false }; | ||||||
| 
 | 
 | ||||||
|     Vector<RetainPtr<Socket>> m_pending; |     Vector<RetainPtr<Socket>> m_pending; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling