Kernel/LibC: Implement flock
This commit is contained in:
parent
0cbc39698c
commit
93e5d09a63
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
|
||||
|
@ -43,6 +44,8 @@ namespace Kernel
|
|||
void close_all();
|
||||
void close_cloexec();
|
||||
|
||||
BAN::ErrorOr<void> flock(int fd, int op);
|
||||
|
||||
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
||||
BAN::ErrorOr<size_t> write(int fd, BAN::ConstByteSpan);
|
||||
|
||||
|
@ -69,6 +72,15 @@ namespace Kernel
|
|||
off_t offset { 0 };
|
||||
int status_flags;
|
||||
|
||||
struct flock_t
|
||||
{
|
||||
bool locked;
|
||||
bool shared;
|
||||
ThreadBlocker thread_blocker;
|
||||
BAN::HashSet<pid_t> lockers;
|
||||
};
|
||||
flock_t flock;
|
||||
|
||||
friend class BAN::RefPtr<OpenFileDescription>;
|
||||
};
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
|
||||
|
||||
BAN::ErrorOr<long> sys_flock(int fd, int op);
|
||||
|
||||
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
|
||||
BAN::ErrorOr<long> sys_pwrite(int fd, const void* buffer, size_t count, off_t offset);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <kernel/OpenFileDescriptorSet.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace Kernel
|
||||
|
@ -310,6 +311,17 @@ namespace Kernel
|
|||
TRY(validate_fd(fd));
|
||||
|
||||
auto& open_file = m_open_files[fd];
|
||||
|
||||
if (auto& flock = open_file.description->flock; Thread::current().has_process() && flock.lockers.contains(Process::current().pid()))
|
||||
{
|
||||
flock.lockers.remove(Process::current().pid());
|
||||
if (flock.lockers.empty())
|
||||
{
|
||||
flock.locked = false;
|
||||
flock.thread_blocker.unblock();
|
||||
}
|
||||
}
|
||||
|
||||
open_file.inode()->on_close(open_file.status_flags());
|
||||
open_file.description.clear();
|
||||
open_file.descriptor_flags = 0;
|
||||
|
@ -336,6 +348,63 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::flock(int fd, int op)
|
||||
{
|
||||
const auto pid = Process::current().pid();
|
||||
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
TRY(validate_fd(fd));
|
||||
|
||||
auto& flock = m_open_files[fd].description->flock;
|
||||
switch (op & ~LOCK_NB)
|
||||
{
|
||||
case LOCK_UN:
|
||||
flock.lockers.remove(pid);
|
||||
if (flock.lockers.empty())
|
||||
{
|
||||
flock.locked = false;
|
||||
flock.thread_blocker.unblock();
|
||||
}
|
||||
return {};
|
||||
case LOCK_SH:
|
||||
if (!flock.locked)
|
||||
{
|
||||
TRY(flock.lockers.insert(pid));
|
||||
flock.locked = true;
|
||||
flock.shared = true;
|
||||
return {};
|
||||
}
|
||||
if (flock.shared)
|
||||
{
|
||||
TRY(flock.lockers.insert(pid));
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
case LOCK_EX:
|
||||
if (!flock.locked)
|
||||
{
|
||||
TRY(flock.lockers.insert(pid));
|
||||
flock.locked = true;
|
||||
flock.shared = false;
|
||||
return {};
|
||||
}
|
||||
if (flock.lockers.contains(pid))
|
||||
return {};
|
||||
break;
|
||||
default:
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (op & LOCK_NB)
|
||||
return BAN::Error::from_errno(EWOULDBLOCK);
|
||||
|
||||
TRY(Thread::current().block_or_eintr_indefinite(flock.thread_blocker, &m_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer)
|
||||
{
|
||||
BAN::RefPtr<Inode> inode;
|
||||
|
|
|
@ -1208,6 +1208,16 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_flock(int fd, int op)
|
||||
{
|
||||
auto maybe_error = m_open_file_descriptors.flock(fd, op);
|
||||
if (maybe_error.is_error() && maybe_error.error().get_error_code() == ENOMEM)
|
||||
return BAN::Error::from_errno(ENOLCK);
|
||||
if (maybe_error.is_error())
|
||||
return maybe_error.error();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
|
||||
{
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
|
|
|
@ -33,6 +33,7 @@ set(LIBC_SOURCES
|
|||
strings.cpp
|
||||
sys/banan-os.cpp
|
||||
sys/epoll.cpp
|
||||
sys/file.cpp
|
||||
sys/ioctl.cpp
|
||||
sys/mman.cpp
|
||||
sys/resource.cpp
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _SYS_FILE_H
|
||||
#define _SYS_FILE_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define LOCK_UN 0
|
||||
#define LOCK_EX 1
|
||||
#define LOCK_SH 2
|
||||
#define LOCK_NB 4
|
||||
|
||||
int flock(int fd, int op);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -107,6 +107,7 @@ __BEGIN_DECLS
|
|||
O(SYS_EPOLL_CREATE1, epoll_create1) \
|
||||
O(SYS_EPOLL_CTL, epoll_ctl) \
|
||||
O(SYS_EPOLL_PWAIT2, epoll_pwait2) \
|
||||
O(SYS_FLOCK, flock) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#include <sys/file.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int flock(int fd, int op)
|
||||
{
|
||||
return syscall(SYS_FLOCK, fd, op);
|
||||
}
|
Loading…
Reference in New Issue