Kernel/LibC: Add basic pipe() syscall and command
You can now create pipes :)
This commit is contained in:
		
							parent
							
								
									22caacd2a9
								
							
						
					
					
						commit
						4eb95c963d
					
				|  | @ -20,6 +20,7 @@ set(KERNEL_SOURCES | |||
| 	kernel/Font.cpp | ||||
| 	kernel/FS/Ext2.cpp | ||||
| 	kernel/FS/Inode.cpp | ||||
| 	kernel/FS/Pipe.cpp | ||||
| 	kernel/FS/VirtualFileSystem.cpp | ||||
| 	kernel/Input/PS2Controller.cpp | ||||
| 	kernel/Input/PS2Keyboard.cpp | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ namespace Kernel | |||
| 		virtual dev_t rdev() const = 0; | ||||
| 
 | ||||
| 		virtual bool is_device() const { return false; } | ||||
| 		virtual bool is_pipe() const { return false; } | ||||
| 
 | ||||
| 		virtual BAN::StringView name() const = 0; | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,54 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/FS/Inode.h> | ||||
| #include <kernel/Semaphore.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class Pipe : public Inode | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<BAN::RefPtr<Inode>> create(const Credentials&); | ||||
| 
 | ||||
| 		virtual bool is_pipe() const override { return true; } | ||||
| 		void clone_writing(); | ||||
| 		void close_writing(); | ||||
| 
 | ||||
| 		virtual ino_t ino() const override { return 0; } // FIXME
 | ||||
| 		virtual Mode mode() const override { return { Mode::IFIFO | Mode::IRUSR | Mode::IWUSR }; } | ||||
| 		virtual nlink_t nlink() const override { return 1; } | ||||
| 		virtual uid_t uid() const override { return m_uid; } | ||||
| 		virtual gid_t gid() const override { return m_gid; } | ||||
| 		virtual off_t size() const override { return 0; } | ||||
| 		virtual timespec atime() const override { return m_atime; } | ||||
| 		virtual timespec mtime() const override { return m_mtime; } | ||||
| 		virtual timespec ctime() const override { return m_ctime; } | ||||
| 		virtual blksize_t blksize() const override { return 4096; } | ||||
| 		virtual blkcnt_t blocks() const override { return 0; } | ||||
| 		virtual dev_t dev() const override { return 0; } // FIXME
 | ||||
| 		virtual dev_t rdev() const override { return 0; } // FIXME
 | ||||
| 
 | ||||
| 		virtual BAN::StringView name() const override { return ""sv; } | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override; | ||||
| 		virtual BAN::ErrorOr<size_t> write(size_t, const void*, size_t) override; | ||||
| 
 | ||||
| 	private: | ||||
| 		Pipe(const Credentials&); | ||||
| 
 | ||||
| 	private: | ||||
| 		const uid_t m_uid; | ||||
| 		const gid_t m_gid; | ||||
| 		timespec m_atime {}; | ||||
| 		timespec m_mtime {}; | ||||
| 		timespec m_ctime {}; | ||||
| 		BAN::Vector<uint8_t> m_buffer; | ||||
| 		SpinLock m_lock; | ||||
| 		Semaphore m_semaphore; | ||||
| 
 | ||||
| 		uint32_t m_writing_count { 1 }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -84,6 +84,8 @@ namespace Kernel | |||
| 		BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count); | ||||
| 		BAN::ErrorOr<long> sys_creat(BAN::StringView name, mode_t); | ||||
| 
 | ||||
| 		BAN::ErrorOr<long> sys_pipe(int fildes[2]); | ||||
| 
 | ||||
| 		BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence); | ||||
| 		BAN::ErrorOr<long> sys_tell(int fd); | ||||
| 
 | ||||
|  | @ -136,6 +138,7 @@ namespace Kernel | |||
| 		BAN::ErrorOr<void> validate_fd(int); | ||||
| 		OpenFileDescription& open_file_description(int); | ||||
| 		BAN::ErrorOr<int> get_free_fd(); | ||||
| 		BAN::ErrorOr<void> get_free_fd_pair(int fds[2]); | ||||
| 
 | ||||
| 
 | ||||
| 		struct ExitStatus | ||||
|  |  | |||
|  | @ -0,0 +1,88 @@ | |||
| #include <kernel/FS/Pipe.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/RTC.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::create(const Credentials& credentials) | ||||
| 	{ | ||||
| 		Pipe* pipe = new Pipe(credentials); | ||||
| 		if (pipe == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		return BAN::RefPtr<Inode>::adopt(pipe); | ||||
| 	} | ||||
| 	 | ||||
| 	Pipe::Pipe(const Credentials& credentials) | ||||
| 		: m_uid(credentials.euid()) | ||||
| 		, m_gid(credentials.egid()) | ||||
| 	{ | ||||
| 		uint64_t current_time = BAN::to_unix_time(RTC::get_current_time()); | ||||
| 		m_atime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 		m_mtime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 		m_ctime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 	} | ||||
| 
 | ||||
| 	void Pipe::clone_writing() | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		ASSERT(m_writing_count > 0); | ||||
| 		m_writing_count++; | ||||
| 	} | ||||
| 	 | ||||
| 	void Pipe::close_writing() | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		ASSERT(m_writing_count > 0); | ||||
| 		m_writing_count--; | ||||
| 		if (m_writing_count == 0) | ||||
| 			m_semaphore.unblock(); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<size_t> Pipe::read(size_t, void* buffer, size_t count) | ||||
| 	{ | ||||
| 		m_lock.lock(); | ||||
| 		while (m_buffer.empty()) | ||||
| 		{ | ||||
| 			if (m_writing_count == 0) | ||||
| 				return 0; | ||||
| 			m_lock.unlock(); | ||||
| 			m_semaphore.block(); | ||||
| 			m_lock.lock(); | ||||
| 		} | ||||
| 
 | ||||
| 		size_t to_copy = BAN::Math::min<size_t>(count, m_buffer.size()); | ||||
| 		memcpy(buffer, m_buffer.data(), to_copy); | ||||
| 
 | ||||
| 		memmove(m_buffer.data(), m_buffer.data() + to_copy, m_buffer.size() - to_copy); | ||||
| 		MUST(m_buffer.resize(m_buffer.size() - to_copy)); | ||||
| 
 | ||||
| 		uint64_t current_time = BAN::to_unix_time(RTC::get_current_time()); | ||||
| 		m_atime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 
 | ||||
| 		m_semaphore.unblock(); | ||||
| 
 | ||||
| 		m_lock.unlock(); | ||||
| 
 | ||||
| 		return to_copy; | ||||
| 	} | ||||
| 	 | ||||
| 	BAN::ErrorOr<size_t> Pipe::write(size_t, const void* buffer, size_t count) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 
 | ||||
| 		size_t old_size = m_buffer.size(); | ||||
| 
 | ||||
| 		TRY(m_buffer.resize(old_size + count)); | ||||
| 		memcpy(m_buffer.data() + old_size, buffer, count); | ||||
| 
 | ||||
| 		uint64_t current_time = BAN::to_unix_time(RTC::get_current_time()); | ||||
| 		m_mtime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 		m_ctime = { .tv_sec = current_time, .tv_nsec = 0 }; | ||||
| 
 | ||||
| 		m_semaphore.unblock(); | ||||
| 
 | ||||
| 		return count; | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
|  | @ -1,5 +1,6 @@ | |||
| #include <BAN/StringView.h> | ||||
| #include <kernel/CriticalScope.h> | ||||
| #include <kernel/FS/Pipe.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/Memory/Heap.h> | ||||
|  | @ -277,6 +278,14 @@ namespace Kernel | |||
| 		forked->m_working_directory = m_working_directory; | ||||
| 
 | ||||
| 		forked->m_open_files = m_open_files; | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			auto& openfd = open_file_description(fd); | ||||
| 			if (openfd.flags & O_WRONLY && openfd.inode->is_pipe()) | ||||
| 				((Pipe*)openfd.inode.ptr())->clone_writing(); | ||||
| 		} | ||||
| 
 | ||||
| 		forked->m_userspace_info = m_userspace_info; | ||||
| 
 | ||||
|  | @ -325,7 +334,7 @@ namespace Kernel | |||
| 
 | ||||
| 		LockGuard lock_guard(m_lock); | ||||
| 
 | ||||
| 		for (int fd = 0; fd < m_open_files.size(); fd++) | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
|  | @ -538,6 +547,8 @@ namespace Kernel | |||
| 		LockGuard _(m_lock); | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		auto& open_file_description = this->open_file_description(fd); | ||||
| 		if (open_file_description.flags & O_WRONLY && open_file_description.inode->is_pipe()) | ||||
| 			((Pipe*)open_file_description.inode.ptr())->close_writing(); | ||||
| 		open_file_description.inode = nullptr; | ||||
| 		return 0; | ||||
| 	} | ||||
|  | @ -590,6 +601,29 @@ namespace Kernel | |||
| 		return nwrite; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_pipe(int fildes[2]) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 
 | ||||
| 		auto pipe = TRY(Pipe::create(m_credentials)); | ||||
| 
 | ||||
| 		TRY(get_free_fd_pair(fildes)); | ||||
| 
 | ||||
| 		auto& openfd_read = m_open_files[fildes[0]]; | ||||
| 		openfd_read.inode = pipe; | ||||
| 		openfd_read.flags = O_RDONLY; | ||||
| 		openfd_read.offset = 0; | ||||
| 		openfd_read.path.clear(); | ||||
| 
 | ||||
| 		auto& openfd_write = m_open_files[fildes[1]]; | ||||
| 		openfd_write.inode = pipe; | ||||
| 		openfd_write.flags = O_WRONLY; | ||||
| 		openfd_write.offset = 0; | ||||
| 		openfd_write.path.clear(); | ||||
| 
 | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
|  | @ -1089,4 +1123,27 @@ namespace Kernel | |||
| 		return m_open_files.size() - 1; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> Process::get_free_fd_pair(int fds[2]) | ||||
| 	{ | ||||
| 		ASSERT(m_lock.is_locked()); | ||||
| 		int found = 0; | ||||
| 		for (size_t fd = 0; fd < m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (!m_open_files[fd].inode) | ||||
| 			{ | ||||
| 				fds[found++] = fd; | ||||
| 				if (found >= 2) | ||||
| 					return {}; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		while (found < 2) | ||||
| 		{ | ||||
| 			TRY(m_open_files.push_back({})); | ||||
| 			fds[found++] = m_open_files.size() - 1; | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -132,6 +132,9 @@ namespace Kernel | |||
| 		case SYS_CLOCK_GETTIME: | ||||
| 			ret = Process::current().sys_clock_gettime((clockid_t)arg1, (timespec*)arg2); | ||||
| 			break; | ||||
| 		case SYS_PIPE: | ||||
| 			ret = Process::current().sys_pipe((int*)arg1); | ||||
| 			break; | ||||
| 		default: | ||||
| 			dwarnln("Unknown syscall {}", syscall); | ||||
| 			break; | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ __BEGIN_DECLS | |||
| #define SYS_GET_PWD 32 | ||||
| #define SYS_SET_PWD 33 | ||||
| #define SYS_CLOCK_GETTIME 34 | ||||
| #define SYS_PIPE 35 | ||||
| 
 | ||||
| __END_DECLS | ||||
| 
 | ||||
|  |  | |||
|  | @ -251,6 +251,12 @@ long syscall(long syscall, ...) | |||
| 			ret = Kernel::syscall(SYS_CLOCK_GETTIME, clock_id, (uintptr_t)tp); | ||||
| 			break; | ||||
| 		} | ||||
| 		case SYS_PIPE: | ||||
| 		{ | ||||
| 			int* fildes = va_arg(args, int*); | ||||
| 			ret = Kernel::syscall(SYS_PIPE, (uintptr_t)fildes); | ||||
| 			break; | ||||
| 		} | ||||
| 		default: | ||||
| 			puts("LibC: Unhandeled syscall"); | ||||
| 			ret = -ENOSYS; | ||||
|  | @ -365,6 +371,11 @@ pid_t fork(void) | |||
| 	return syscall(SYS_FORK); | ||||
| } | ||||
| 
 | ||||
| int pipe(int fildes[2]) | ||||
| { | ||||
| 	return syscall(SYS_PIPE, fildes); | ||||
| } | ||||
| 
 | ||||
| unsigned int sleep(unsigned int seconds) | ||||
| { | ||||
| 	return syscall(SYS_SLEEP, seconds); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue