Compare commits

...

22 Commits

Author SHA1 Message Date
Bananymous 2b48933f29 LibC: Implement all functions from complex.h 2025-06-01 13:48:03 +03:00
Bananymous 4ac6cbe70e LibC: Add some missing wchar.h functions
isw* functions are just wrappers to is*
tow* functions are just wrappers to to*
2025-06-01 13:48:03 +03:00
Bananymous cc07c3df94 LibC: Add basic strxfrm{,_l} 2025-06-01 13:48:03 +03:00
Bananymous 31bcad2535 LibC: Implement truncate 2025-06-01 13:48:03 +03:00
Bananymous b75970958e Kernel/LibC: Implement unlinkat 2025-06-01 13:48:03 +03:00
Bananymous 91756c057e LibC: Add all of the missing POSIX definitions in unistd.h and limits.h 2025-06-01 13:48:03 +03:00
Bananymous df7f245cf8 LibC: Implement pthread_atfork
Again this code is not tested but *feels* right :D
2025-06-01 13:48:03 +03:00
Bananymous dbdefa0f4a LibC: Implement pthread cancelation
This code is not tested at all but it looks correct xD
2025-06-01 13:48:03 +03:00
Bananymous 56fdf6002c Kernel/LibC: Implement pthread_kill 2025-06-01 13:48:03 +03:00
Bananymous c957f1ddca LibC: Cleanup pthread code and add some pthread_attr functions
errno, pthread cleanup and pthread id are now stored in uthread. This
allows using these without TLS
2025-06-01 13:48:03 +03:00
Bananymous 423386a052 LibC: Add memory.h that just includes string.h
There are a lot of ports trying to include memory.h. This is not posix
but glibc just includes string.h. I think this is just to privide mem*
functionss...?
2025-06-01 13:48:03 +03:00
Bananymous 1c882ea361 DynamicLoader: Don't print TODOs on PT_GNU_ headers
These should be either handled by kernel or just used as optimizations.
There is no requirement to handle them in dynamic loader
2025-06-01 13:48:03 +03:00
Bananymous b1065fa01d Kernel/LibC: Add ppoll syscall and fix poll
poll is now using its own syscall instead of wrapping aroung pselect.
This adds less overhead on top of poll and adds support for POLLHUP
2025-06-01 13:48:03 +03:00
Bananymous 8ff9c030bf Kernel: Add better termios support
I'm not sure if this is correct but at least it's better than before :)
2025-06-01 13:48:03 +03:00
Bananymous 9b875fb930 Kernel: Make epoll work with different fds pointing to same inode 2025-06-01 13:48:03 +03:00
Bananymous 857bac4b78 Kernel: Disable unused interrupt methods in PCI devices 2025-06-01 13:48:03 +03:00
Bananymous 30074c290d Kernel: Add more descriptive names to sockets types 2025-06-01 13:48:03 +03:00
Bananymous 60d1c26114 Kernel: Fix race condition in FileBackedRegion creation 2025-06-01 13:48:03 +03:00
Bananymous 692ba43182 Kernel: Fix spinlock bugs found by the new spinlock security 2025-06-01 13:48:03 +03:00
Bananymous 6542a037df Kernel: Make spinlocks more safe
Kernel now makes sure thread is not holding any spinlocks when it tries
to lock a mutex or yield. Spinlocks are supposed to be only used for
short times without the possibility of yielding
2025-06-01 13:48:03 +03:00
Bananymous 9f4b451501 Kernel: Fix epoll deadlock
If epoll_wait and epoll_notify were called at the same time, there was a
possible deadlock when epoll was confirming the event from the inode
2025-06-01 13:48:03 +03:00
Bananymous 1bd454b8fd Kernel/LibC: Implement utime* family functions
This patch adds *working*
 - utime
 - utimes
 - utimensat
 - futimens
2025-06-01 13:48:03 +03:00
71 changed files with 2576 additions and 493 deletions

View File

@ -14,7 +14,7 @@
#define dprintln(...) \
do { \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar,"\r\n"); \
BAN::Formatter::print(__debug_putchar,"\n"); \
fflush(stddbg); \
} while (false)
@ -22,7 +22,7 @@
do { \
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
fflush(stddbg); \
} while(false)
@ -30,7 +30,7 @@
do { \
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
fflush(stddbg); \
} while(false)

View File

@ -43,6 +43,7 @@ set(KERNEL_SOURCES
kernel/Interruptable.cpp
kernel/InterruptController.cpp
kernel/kernel.cpp
kernel/Lock/SpinLock.cpp
kernel/Memory/DMARegion.cpp
kernel/Memory/FileBackedRegion.cpp
kernel/Memory/Heap.cpp

View File

@ -1,10 +1,12 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/CircularQueue.h>
#include <BAN/HashMap.h>
#include <BAN/HashSet.h>
#include <kernel/FS/Inode.h>
#include <limits.h>
#include <sys/epoll.h>
namespace Kernel
@ -16,7 +18,7 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<Epoll>> create();
~Epoll();
BAN::ErrorOr<void> ctl(int op, BAN::RefPtr<Inode> inode, epoll_event event);
BAN::ErrorOr<void> ctl(int op, int fd, BAN::RefPtr<Inode> inode, epoll_event event);
BAN::ErrorOr<size_t> wait(BAN::Span<epoll_event> events, uint64_t waketime_ns);
void notify(BAN::RefPtr<Inode> inode, uint32_t event);
@ -59,10 +61,45 @@ namespace Kernel
}
};
struct ListenEventList
{
BAN::Array<epoll_event, OPEN_MAX> events;
uint32_t bitmap[(OPEN_MAX + 31) / 32] {};
bool has_fd(int fd) const
{
if (fd < 0 || static_cast<size_t>(fd) >= events.size())
return false;
return bitmap[fd / 32] & (1u << (fd % 32));
}
bool empty() const
{
for (auto val : bitmap)
if (val != 0)
return false;
return true;
}
void add_fd(int fd, epoll_event event)
{
ASSERT(!has_fd(fd));
bitmap[fd / 32] |= (1u << (fd % 32));
events[fd] = event;
}
void remove_fd(int fd)
{
ASSERT(has_fd(fd));
bitmap[fd / 32] &= ~(1u << (fd % 32));
events[fd] = {};
}
};
private:
ThreadBlocker m_thread_blocker;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events;
BAN::HashMap<BAN::RefPtr<Inode>, epoll_event, InodeRefPtrHash> m_listening_events;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events;
BAN::HashMap<BAN::RefPtr<Inode>, ListenEventList, InodeRefPtrHash> m_listening_events;
};
}

View File

@ -46,6 +46,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
virtual BAN::ErrorOr<void> fsync_impl() override;
virtual bool can_read_impl() const override { return true; }

View File

@ -44,6 +44,7 @@ namespace Kernel
//virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
//virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
//virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
//virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
virtual bool can_read_impl() const override { return true; }

View File

@ -119,6 +119,7 @@ namespace Kernel
BAN::ErrorOr<void> truncate(size_t);
BAN::ErrorOr<void> chmod(mode_t);
BAN::ErrorOr<void> chown(uid_t, gid_t);
BAN::ErrorOr<void> utimens(const timespec[2]);
BAN::ErrorOr<void> fsync();
// Select/Non blocking API
@ -165,6 +166,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> chown_impl(uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> fsync_impl() = 0;
// Select/Non blocking API
@ -182,6 +184,7 @@ namespace Kernel
BAN::WeakPtr<SharedFileData> m_shared_region;
Mutex m_epoll_mutex;
BAN::LinkedList<class Epoll*> m_epolls;
friend class Epoll;
friend class FileBackedRegion;
friend class OpenFileDescriptorSet;
friend class SharedFileData;

View File

@ -47,6 +47,8 @@ namespace Kernel
protected:
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
void sync();
@ -75,7 +77,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; }
@ -98,7 +99,6 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override { return BAN::Error::from_errno(ENODEV); }
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(ENODEV); }
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(ENODEV); }
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }

View File

@ -88,6 +88,8 @@ namespace Kernel
void lock()
{
const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock());
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
else
@ -111,6 +113,8 @@ namespace Kernel
bool try_lock()
{
const auto tid = Thread::current_tid();
ASSERT(!tid || !Thread::current().has_spinlock());
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
else

View File

@ -18,42 +18,11 @@ namespace Kernel
public:
SpinLock() = default;
InterruptState lock()
{
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
InterruptState lock();
auto id = Processor::current_id().as_u32();
ASSERT(m_locker.load(BAN::MemoryOrder::memory_order_relaxed) != id);
bool try_lock_interrupts_disabled();
auto expected = PROCESSOR_NONE.as_u32();
while (!m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire))
{
Processor::pause();
expected = PROCESSOR_NONE.as_u32();
}
return state;
}
bool try_lock_interrupts_disabled()
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
auto id = Processor::current_id().as_u32();
ASSERT(m_locker.load(BAN::MemoryOrder::memory_order_relaxed) != id);
auto expected = PROCESSOR_NONE.as_u32();
return m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire);
}
void unlock(InterruptState state)
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
ASSERT(current_processor_has_lock());
m_locker.store(PROCESSOR_NONE.as_u32(), BAN::MemoryOrder::memory_order_release);
Processor::set_interrupt_state(state);
}
void unlock(InterruptState state);
bool current_processor_has_lock() const
{

View File

@ -12,6 +12,7 @@
#error
#endif
#undef PAGE_SIZE
#define PAGE_SIZE ((uintptr_t)4096)
#define PAGE_SIZE_SHIFT 12
#define PAGE_ADDR_MASK (~(uintptr_t)0xFFF)

View File

@ -16,6 +16,7 @@
#include <kernel/Terminal/TTY.h>
#include <kernel/Thread.h>
#include <poll.h>
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/select.h>
@ -106,7 +107,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag);
BAN::ErrorOr<long> sys_unlink(const char*);
BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
@ -116,6 +117,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
BAN::ErrorOr<long> sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag);
BAN::ErrorOr<long> sys_utimensat(int fd, const char* path, const struct timespec times[2], int flag);
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
BAN::ErrorOr<long> sys_socketpair(int domain, int type, int protocol, int socket_vector[2]);
@ -134,6 +136,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
BAN::ErrorOr<long> sys_pselect(sys_pselect_t* arguments);
BAN::ErrorOr<long> sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* tmp_p, const sigset_t* sigmask);
BAN::ErrorOr<long> sys_epoll_create1(int flags);
BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
@ -147,7 +150,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence);
BAN::ErrorOr<long> sys_tell(int fd);
BAN::ErrorOr<long> sys_truncate(int fd, off_t length);
BAN::ErrorOr<long> sys_ftruncate(int fd, off_t length);
BAN::ErrorOr<long> sys_fsync(int fd);
@ -191,6 +194,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_pthread_exit(void* value);
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
BAN::ErrorOr<long> sys_pthread_self();
BAN::ErrorOr<long> sys_pthread_kill(pthread_t thread, int signal);
BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);

View File

@ -57,7 +57,7 @@ namespace Kernel
virtual bool has_hungup_impl() const override { return false; }
protected:
TTY(mode_t mode, uid_t uid, gid_t gid);
TTY(termios termios, mode_t mode, uid_t uid, gid_t gid);
virtual bool putchar_impl(uint8_t ch) = 0;
virtual void update_cursor() {}

View File

@ -101,6 +101,10 @@ namespace Kernel
void save_sse();
void load_sse();
void add_spinlock() { m_spinlock_count++; }
void remove_spinlock() { m_spinlock_count--; }
bool has_spinlock() const { return !!m_spinlock_count; }
void add_mutex() { m_mutex_count++; }
void remove_mutex() { m_mutex_count--; }
@ -137,6 +141,7 @@ namespace Kernel
SpinLock m_signal_lock;
static_assert(_SIGMAX < 64);
BAN::Atomic<uint32_t> m_spinlock_count { 0 };
BAN::Atomic<uint32_t> m_mutex_count { 0 };
alignas(16) uint8_t m_sse_storage[512] {};

View File

@ -19,7 +19,7 @@ namespace Kernel
inode->del_epoll(this);
}
BAN::ErrorOr<void> Epoll::ctl(int op, BAN::RefPtr<Inode> inode, epoll_event event)
BAN::ErrorOr<void> Epoll::ctl(int op, int fd, BAN::RefPtr<Inode> inode, epoll_event event)
{
LockGuard _(m_mutex);
@ -28,27 +28,51 @@ namespace Kernel
switch (op)
{
case EPOLL_CTL_ADD:
if (it != m_listening_events.end())
{
if (it == m_listening_events.end())
it = TRY(m_listening_events.emplace(inode));
if (it->value.has_fd(fd))
return BAN::Error::from_errno(EEXIST);
TRY(m_listening_events.reserve(m_listening_events.size() + 1));
TRY(m_ready_events.reserve(m_listening_events.size() + 1));
TRY(m_ready_events.reserve(m_listening_events.size()));
TRY(inode->add_epoll(this));
MUST(m_listening_events.insert(inode, event));
MUST(m_ready_events.insert(inode, event.events));
it->value.add_fd(fd, event);
auto ready_it = m_ready_events.find(inode);
if (ready_it == m_ready_events.end())
ready_it = MUST(m_ready_events.insert(inode, 0));
ready_it->value |= event.events;
return {};
}
case EPOLL_CTL_MOD:
{
if (it == m_listening_events.end())
return BAN::Error::from_errno(ENOENT);
MUST(m_ready_events.emplace_or_assign(inode, event.events));
it->value = event;
if (!it->value.has_fd(fd))
return BAN::Error::from_errno(ENOENT);
it->value.events[fd] = event;
auto ready_it = m_ready_events.find(inode);
if (ready_it == m_ready_events.end())
ready_it = MUST(m_ready_events.insert(inode, 0));
ready_it->value |= event.events;
return {};
}
case EPOLL_CTL_DEL:
{
if (it == m_listening_events.end())
return BAN::Error::from_errno(ENOENT);
m_listening_events.remove(it);
m_ready_events.remove(inode);
inode->del_epoll(this);
if (!it->value.has_fd(fd))
return BAN::Error::from_errno(ENOENT);
it->value.remove_fd(fd);
if (it->value.empty())
{
m_listening_events.remove(it);
m_ready_events.remove(inode);
}
return {};
}
}
return BAN::Error::from_errno(EINVAL);
@ -56,20 +80,37 @@ namespace Kernel
BAN::ErrorOr<size_t> Epoll::wait(BAN::Span<epoll_event> event_span, uint64_t waketime_ns)
{
if (event_span.empty())
return BAN::Error::from_errno(EINVAL);
size_t count = 0;
for (;;)
{
bool failed_lock = false;
{
LockGuard _(m_mutex);
for (auto it = m_ready_events.begin(); it != m_ready_events.end() && count < event_span.size();)
{
auto& [inode, events] = *it;
auto& listen = m_listening_events[inode];
const uint32_t listen_mask = (listen.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
uint32_t listen_mask = EPOLLERR | EPOLLHUP;
for (int fd = 0; fd < OPEN_MAX; fd++)
if (listen.has_fd(fd))
listen_mask |= listen.events[fd].events;
events &= listen_mask;
// This prevents a possible deadlock
if (!inode->m_mutex.try_lock())
{
failed_lock = true;
continue;
}
#define CHECK_EVENT_BIT(mask, func) \
if ((events & mask) && !inode->func()) \
events &= ~mask;
@ -79,6 +120,8 @@ namespace Kernel
CHECK_EVENT_BIT(EPOLLHUP, has_hungup);
#undef CHECK_EVENT_BIT
inode->m_mutex.unlock();
if (events == 0)
{
m_ready_events.remove(it);
@ -86,16 +129,27 @@ namespace Kernel
continue;
}
event_span[count++] = {
.events = events,
.data = listen.data,
};
for (int fd = 0; fd < OPEN_MAX && count < event_span.size(); fd++)
{
if (!listen.has_fd(fd))
continue;
auto& listen_event = listen.events[fd];
if (listen.events & EPOLLONESHOT)
listen.events = 0;
const auto new_events = listen_event.events & events;
if (new_events == 0)
continue;
if (listen.events & EPOLLET)
events &= ~listen_mask;
event_span[count++] = {
.events = new_events,
.data = listen_event.data,
};
if (listen_event.events & EPOLLONESHOT)
listen_event.events = 0;
// this doesn't work with multiple of the same inode
if (listen_event.events & EPOLLET)
events &= ~new_events;
}
it++;
}
@ -107,6 +161,8 @@ namespace Kernel
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
if (current_ns >= waketime_ns)
break;
if (failed_lock)
continue;
const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns);
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false));
}
@ -118,18 +174,13 @@ namespace Kernel
{
LockGuard _(m_mutex);
auto listen_it = m_listening_events.find(inode);
if (listen_it == m_listening_events.end())
if (!m_listening_events.contains(inode))
return;
event &= (listen_it->value.events & (EPOLLIN | EPOLLOUT)) | EPOLLERR | EPOLLHUP;
if (event == 0)
return;
if (auto ready_it = m_ready_events.find(inode); ready_it != m_ready_events.end())
ready_it->value |= event;
else
MUST(m_ready_events.insert(inode, event));
auto ready_it = m_ready_events.find(inode);
if (ready_it == m_ready_events.end())
ready_it = MUST(m_ready_events.insert(inode, 0));
ready_it->value |= event;
m_thread_blocker.unblock();
}

View File

@ -4,6 +4,8 @@
#include <kernel/FS/Ext2/Inode.h>
#include <kernel/Timer/Timer.h>
#include <sys/stat.h>
namespace Kernel
{
@ -287,6 +289,28 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2])
{
const uint32_t old_times[2] {
m_inode.atime,
m_inode.mtime,
};
if (times[0].tv_nsec != UTIME_OMIT)
m_inode.atime = times[0].tv_sec;
if (times[1].tv_nsec != UTIME_OMIT)
m_inode.mtime = times[1].tv_sec;
if (auto ret = sync(); ret.is_error())
{
m_inode.atime = old_times[0];
m_inode.mtime = old_times[1];
return ret.release_error();
}
return {};
}
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
{
for (size_t i = 0; i < max_used_data_block_count(); i++)

View File

@ -231,6 +231,12 @@ namespace Kernel
return chown_impl(uid, gid);
}
BAN::ErrorOr<void> Inode::utimens(const timespec times[2])
{
LockGuard _(m_mutex);
return utimens_impl(times);
}
BAN::ErrorOr<void> Inode::fsync()
{
LockGuard _(m_mutex);

View File

@ -2,6 +2,8 @@
#include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Timer/Timer.h>
#include <sys/stat.h>
namespace Kernel
{
@ -90,6 +92,23 @@ namespace Kernel
m_fs.delete_inode(ino());
}
BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode)
{
ASSERT(!(new_mode & Mode::TYPE_MASK));
m_inode_info.mode &= ~Mode::TYPE_MASK;
m_inode_info.mode |= new_mode;
return {};
}
BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2])
{
if (times[0].tv_nsec != UTIME_OMIT)
m_inode_info.atime = times[0];
if (times[1].tv_nsec != UTIME_OMIT)
m_inode_info.atime = times[1];
return {};
}
void TmpInode::sync()
{
m_fs.write_inode(m_ino, m_inode_info);
@ -219,12 +238,6 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> TmpFileInode::chmod_impl(mode_t new_mode)
{
m_inode_info.mode = new_mode;
return {};
}
/* SOCKET INODE */
BAN::ErrorOr<BAN::RefPtr<TmpSocketInode>> TmpSocketInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
{
@ -248,12 +261,6 @@ namespace Kernel
{
}
BAN::ErrorOr<void> TmpSocketInode::chmod_impl(mode_t new_mode)
{
m_inode_info.mode = new_mode;
return {};
}
/* SYMLINK INODE */
BAN::ErrorOr<BAN::RefPtr<TmpSymlinkInode>> TmpSymlinkInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid, BAN::StringView target)

View File

@ -0,0 +1,55 @@
#include <kernel/Lock/SpinLock.h>
#include <kernel/Thread.h>
namespace Kernel
{
InterruptState SpinLock::lock()
{
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
auto id = Processor::current_id().as_u32();
ASSERT(m_locker.load(BAN::MemoryOrder::memory_order_relaxed) != id);
auto expected = PROCESSOR_NONE.as_u32();
while (!m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire))
{
Processor::pause();
expected = PROCESSOR_NONE.as_u32();
}
if (Thread::current_tid())
Thread::current().add_spinlock();
return state;
}
bool SpinLock::try_lock_interrupts_disabled()
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
auto id = Processor::current_id().as_u32();
ASSERT(m_locker.load(BAN::MemoryOrder::memory_order_relaxed) != id);
auto expected = PROCESSOR_NONE.as_u32();
if (!m_locker.compare_exchange(expected, id, BAN::MemoryOrder::memory_order_acquire))
return false;
if (Thread::current_tid())
Thread::current().add_spinlock();
return true;
}
void SpinLock::unlock(InterruptState state)
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
ASSERT(current_processor_has_lock());
m_locker.store(PROCESSOR_NONE.as_u32(), BAN::MemoryOrder::memory_order_release);
if (Thread::current_tid())
Thread::current().remove_spinlock();
Processor::set_interrupt_state(state);
}
}

View File

@ -27,9 +27,7 @@ namespace Kernel
TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE)));
LockGuard _(inode->m_mutex);
if (inode->m_shared_region.valid())
region->m_shared_data = inode->m_shared_region.lock();
else
if (!(region->m_shared_data = inode->m_shared_region.lock()))
{
auto shared_data = TRY(BAN::RefPtr<SharedFileData>::create());
TRY(shared_data->pages.resize(BAN::Math::div_round_up<size_t>(inode->size(), PAGE_SIZE)));

View File

@ -281,10 +281,11 @@ namespace Kernel
if (!is_streaming())
m_packet_sizes.push(packet.size());
epoll_notify(EPOLLIN);
m_packet_thread_blocker.unblock();
m_packet_lock.unlock(state);
epoll_notify(EPOLLIN);
return {};
}

View File

@ -146,9 +146,17 @@ namespace Kernel
auto sock_info = TRY(parse_socket_info(domain, type, protocol));
auto socket = TRY(NetworkManager::get().create_socket(sock_info.domain, sock_info.type, 0777, m_credentials.euid(), m_credentials.egid()));
auto socket_sv = "<socket>"_sv;
if (sock_info.domain == Socket::Domain::UNIX)
socket_sv = "<unix socket>"_sv;
else if (sock_info.type == Socket::Type::STREAM)
socket_sv = "<tcp socket>";
else if (sock_info.type == Socket::Type::DGRAM)
socket_sv = "<udp socket>";
LockGuard _(m_mutex);
int fd = TRY(get_free_fd());
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, "<socket>"_sv), 0, O_RDWR | sock_info.status_flags));
m_open_files[fd].description = TRY(BAN::RefPtr<OpenFileDescription>::create(VirtualFileSystem::File(socket, socket_sv), 0, O_RDWR | sock_info.status_flags));
m_open_files[fd].descriptor_flags = sock_info.descriptor_flags;
return fd;
}

View File

@ -415,12 +415,35 @@ namespace Kernel::PCI
const uint8_t irq = get_interrupt(index);
interruptable.set_irq(irq);
const auto disable_msi =
[this]()
{
if (!m_offset_msi.has_value())
return;
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(1u << 0);
write_word(*m_offset_msi + 0x02, msg_ctrl);
};
const auto disable_msi_x =
[this]()
{
if (!m_offset_msi_x.has_value())
return;
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
msg_ctrl &= ~(1u << 15); // Disable
write_word(*m_offset_msi_x + 0x02, msg_ctrl);
};
switch (m_interrupt_mechanism)
{
case InterruptMechanism::NONE:
ASSERT_NOT_REACHED();
case InterruptMechanism::PIN:
enable_pin_interrupts();
disable_msi();
disable_msi_x();
if (!InterruptController::get().is_using_apic())
write_byte(PCI_REG_IRQ_LINE, irq);
InterruptController::get().enable_irq(irq);
@ -428,6 +451,7 @@ namespace Kernel::PCI
case InterruptMechanism::MSI:
{
disable_pin_interrupts();
disable_msi_x();
uint16_t msg_ctrl = read_word(*m_offset_msi + 0x02);
msg_ctrl &= ~(0x07 << 4); // Only one interrupt
@ -454,6 +478,7 @@ namespace Kernel::PCI
case InterruptMechanism::MSIX:
{
disable_pin_interrupts();
disable_msi();
uint16_t msg_ctrl = read_word(*m_offset_msi_x + 0x02);
msg_ctrl |= 1 << 15; // Enable

View File

@ -350,6 +350,12 @@ namespace Kernel
.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size),
.master_tls_addr = reinterpret_cast<void*>(master_addr),
.master_tls_size = master_size,
.cleanup_stack = nullptr,
.id = 0,
.errno_ = 0,
.cancel_type = 0,
.cancel_state = 0,
.canceled = 0,
};
const uintptr_t dtv[2] { 1, region->vaddr() };
@ -1152,12 +1158,19 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_unlink(const char* path)
BAN::ErrorOr<long> Process::sys_unlinkat(int fd, const char* path, int flag)
{
if (flag && flag != AT_REMOVEDIR)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto [parent, file_name] = TRY(find_parent_file(AT_FDCWD, path, O_WRONLY));
auto [parent, file_name] = TRY(find_parent_file(fd, path, O_WRONLY));
if (TRY(parent.inode->find_inode(file_name))->mode().ifdir() != (flag == AT_REMOVEDIR))
return BAN::Error::from_errno(flag ? EPERM : ENOTDIR);
TRY(parent.inode->unlink(file_name));
return 0;
@ -1262,6 +1275,56 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_utimensat(int fd, const char* path, const struct timespec _times[2], int flag)
{
if (flag & ~AT_SYMLINK_NOFOLLOW)
return BAN::Error::from_errno(EINVAL);
if (flag == AT_SYMLINK_NOFOLLOW)
flag = O_NOFOLLOW;
timespec times[2];
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
times[0] = times[1] = timespec {
.tv_sec = static_cast<time_t>(current_ns / 1'000'000),
.tv_nsec = static_cast<long>(current_ns % 1'000'000),
};
if (_times)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(_times, sizeof(timespec) * 2, false));
if (_times[0].tv_nsec != UTIME_NOW)
{
times[0] = _times[0];
if (auto ns = times[0].tv_nsec; ns != UTIME_OMIT && (ns < 0 || ns >= 1'000'000'000))
return BAN::Error::from_errno(EINVAL);
}
if (_times[1].tv_nsec != UTIME_NOW)
{
times[1] = _times[1];
if (auto ns = times[1].tv_nsec; ns != UTIME_OMIT && (ns < 0 || ns >= 1'000'000'000))
return BAN::Error::from_errno(EINVAL);
}
}
if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
return 0;
LockGuard _(m_process_lock);
auto inode = TRY(find_file(fd, path, flag)).inode;
if (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid())
{
dwarnln("cannot chmod uid {} vs {}", inode->uid(), m_credentials.euid());
return BAN::Error::from_errno(EPERM);
}
TRY(inode->utimens(times));
return 0;
}
BAN::ErrorOr<long> Process::sys_socket(int domain, int type, int protocol)
{
LockGuard _(m_process_lock);
@ -1533,7 +1596,7 @@ namespace Kernel
}
auto epoll = TRY(Epoll::create());
for (int fd = 0; fd < user_arguments->nfds; fd++)
for (int fd = 0; fd < arguments.nfds; fd++)
{
uint32_t events = 0;
if (arguments.readfds && FD_ISSET(fd, arguments.readfds))
@ -1549,11 +1612,11 @@ namespace Kernel
if (inode_or_error.is_error())
continue;
TRY(epoll->ctl(EPOLL_CTL_ADD, inode_or_error.release_value(), { .events = events, .data = { .fd = fd }}));
TRY(epoll->ctl(EPOLL_CTL_ADD, fd, inode_or_error.release_value(), { .events = events, .data = { .fd = fd }}));
}
BAN::Vector<epoll_event> event_buffer;
TRY(event_buffer.resize(user_arguments->nfds));
TRY(event_buffer.resize(arguments.nfds));
const size_t waited_events = TRY(epoll->wait(event_buffer.span(), waketime_ns));
@ -1578,6 +1641,113 @@ namespace Kernel
return waited_events;
}
BAN::ErrorOr<long> Process::sys_ppoll(pollfd* fds, nfds_t nfds, const timespec* timeout, const sigset_t* sigmask)
{
auto* fds_region = TRY(validate_and_pin_pointer_access(fds, nfds * sizeof(pollfd), true));
BAN::ScopeGuard _([fds_region] { if (fds_region) fds_region->unpin(); });
const auto old_sigmask = Thread::current().m_signal_block_mask;
if (sigmask)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(sigmask, sizeof(sigset_t), false));
Thread::current().m_signal_block_mask = *sigmask;
}
BAN::ScopeGuard sigmask_restore([old_sigmask] { Thread::current().m_signal_block_mask = old_sigmask; });
uint64_t waketime_ns = BAN::numeric_limits<uint64_t>::max();
if (timeout)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(timeout, sizeof(timespec), false));
waketime_ns =
SystemTimer::get().ns_since_boot() +
(timeout->tv_sec * 1'000'000'000) +
timeout->tv_nsec;
}
uint32_t events_per_fd[OPEN_MAX] {};
for (nfds_t i = 0; i < nfds; i++)
{
if (fds[i].fd < 0 || fds[i].fd >= OPEN_MAX)
continue;
events_per_fd[fds[i].fd] |= fds[i].events;
}
size_t fd_count = 0;
auto epoll = TRY(Epoll::create());
for (int fd = 0; fd < OPEN_MAX; fd++)
{
if (events_per_fd[fd] == 0)
continue;
auto inode_or_error = m_open_file_descriptors.inode_of(fd);
if (inode_or_error.is_error())
continue;
uint32_t events = 0;
if (events_per_fd[fd] & (POLLIN | POLLRDNORM))
events |= EPOLLIN;
if (events_per_fd[fd] & (POLLOUT | POLLWRNORM))
events |= EPOLLOUT;
if (events_per_fd[fd] & POLLPRI)
events |= EPOLLPRI;
// POLLRDBAND
// POLLWRBAND
TRY(epoll->ctl(EPOLL_CTL_ADD, fd, inode_or_error.release_value(), { .events = events, .data = { .fd = fd }}));
fd_count++;
}
BAN::Vector<epoll_event> event_buffer;
TRY(event_buffer.resize(fd_count));
const size_t waited_events = TRY(epoll->wait(event_buffer.span(), waketime_ns));
size_t return_value = 0;
for (size_t i = 0; i < nfds; i++)
{
fds[i].revents = 0;
if (fds[i].fd < 0)
continue;
if (m_open_file_descriptors.inode_of(fds[i].fd).is_error())
{
fds[i].revents = POLLNVAL;
return_value++;
continue;
}
for (size_t j = 0; j < waited_events; j++)
{
if (fds[i].fd != event_buffer[j].data.fd)
continue;
const uint32_t wanted = fds[i].events;
const uint32_t got = event_buffer[j].events;
if (got & EPOLLIN)
fds[i].revents |= wanted & (POLLIN | POLLRDNORM);
if (got & EPOLLOUT)
fds[i].revents |= wanted & (POLLOUT | POLLWRNORM);
if (got & EPOLLPRI)
fds[i].revents |= wanted & POLLPRI;
if (got & EPOLLERR)
fds[i].revents |= POLLERR;
if (got & EPOLLHUP)
fds[i].revents |= POLLHUP;
// POLLRDBAND
// POLLWRBAND
if (fds[i].revents)
return_value++;
break;
}
}
return return_value;
}
BAN::ErrorOr<long> Process::sys_epoll_create1(int flags)
{
if (flags && (flags & ~EPOLL_CLOEXEC))
@ -1613,7 +1783,7 @@ namespace Kernel
event = *user_event;
}
TRY(static_cast<Epoll*>(epoll_inode.ptr())->ctl(op, inode, event));
TRY(static_cast<Epoll*>(epoll_inode.ptr())->ctl(op, fd, inode, event));
return 0;
}
@ -1686,7 +1856,7 @@ namespace Kernel
return TRY(m_open_file_descriptors.tell(fd));
}
BAN::ErrorOr<long> Process::sys_truncate(int fd, off_t length)
BAN::ErrorOr<long> Process::sys_ftruncate(int fd, off_t length)
{
TRY(m_open_file_descriptors.truncate(fd, length));
return 0;
@ -2311,11 +2481,7 @@ namespace Kernel
if (attr)
{
TRY(validate_pointer_access(attr, sizeof(*attr), false));
if (*attr)
{
dwarnln("pthread attr not supported");
return BAN::Error::from_errno(ENOTSUP);
}
dwarnln("TODO: ignoring thread attr");
}
LockGuard _(m_process_lock);
@ -2401,6 +2567,25 @@ namespace Kernel
return Thread::current().tid();
}
BAN::ErrorOr<long> Process::sys_pthread_kill(pthread_t tid, int signal)
{
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock);
for (auto* thread : m_threads)
{
if (thread->tid() != tid)
continue;
if (signal != 0)
thread->add_signal(signal);
return 0;
}
return BAN::Error::from_errno(ESRCH);
}
BAN::ErrorOr<long> Process::sys_tcgetpgrp(int fd)
{
LockGuard _(m_process_lock);

View File

@ -337,6 +337,8 @@ namespace Kernel
auto state = get_interrupt_state();
set_interrupt_state(InterruptState::Disabled);
ASSERT(!Thread::current().has_spinlock());
auto& processor_info = s_processors[current_id().as_u32()];
{

View File

@ -88,18 +88,20 @@ namespace Kernel
bool PseudoTerminalMaster::putchar(uint8_t ch)
{
SpinLockGuard _(m_buffer_lock);
{
SpinLockGuard _(m_buffer_lock);
if (m_buffer_size >= m_buffer->size())
return false;
if (m_buffer_size >= m_buffer->size())
return false;
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
m_buffer_size++;
reinterpret_cast<uint8_t*>(m_buffer->vaddr())[(m_buffer_tail + m_buffer_size) % m_buffer->size()] = ch;
m_buffer_size++;
m_buffer_blocker.unblock();
}
epoll_notify(EPOLLIN);
m_buffer_blocker.unblock();
return true;
}
@ -130,10 +132,10 @@ namespace Kernel
m_buffer_size -= to_copy;
m_buffer_tail = (m_buffer_tail + to_copy) % m_buffer->size();
epoll_notify(EPOLLOUT);
m_buffer_lock.unlock(state);
epoll_notify(EPOLLOUT);
return to_copy;
}
@ -156,7 +158,15 @@ namespace Kernel
}
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
: TTY(mode, uid, gid)
: TTY({
.c_iflag = 0,
.c_oflag = 0,
.c_cflag = CS8,
.c_lflag = ECHO | ICANON,
.c_cc = {},
.c_ospeed = B38400,
.c_ispeed = B38400,
}, mode, uid, gid)
, m_name(BAN::move(name))
, m_number(number)
{}

View File

@ -170,7 +170,15 @@ namespace Kernel
}
SerialTTY::SerialTTY(Serial serial)
: TTY(0600, 0, 0)
: TTY({
.c_iflag = ICRNL,
.c_oflag = OPOST | ONLCR,
.c_cflag = CS8,
.c_lflag = ECHO | ICANON,
.c_cc = {},
.c_ospeed = B38400,
.c_ispeed = B38400,
}, 0600, 0, 0)
, m_name(MUST(BAN::String::formatted("ttyS{}", s_next_tty_number++)))
, m_serial(serial)
{}
@ -235,8 +243,6 @@ namespace Kernel
while (!m_input.empty())
{
*ptr = m_input.front();
if (*ptr == '\r')
*ptr = '\n';
m_input.pop();
ptr++;
}

View File

@ -66,18 +66,11 @@ namespace Kernel
return makedev(DeviceNumber::TTY, s_minor++);
}
TTY::TTY(mode_t mode, uid_t uid, gid_t gid)
TTY::TTY(termios termios, mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid)
, m_termios(termios)
, m_rdev(next_tty_rdev())
{
// FIXME: add correct baud and flags
m_termios.c_iflag = 0;
m_termios.c_oflag = 0;
m_termios.c_cflag = CS8;
m_termios.c_lflag = ECHO | ICANON;
m_termios.c_ospeed = B38400;
m_termios.c_ispeed = B38400;
}
{ }
BAN::RefPtr<TTY> TTY::current()
{
@ -228,6 +221,17 @@ namespace Kernel
LockGuard _(m_mutex);
if ((m_termios.c_iflag & ISTRIP))
ch &= 0x7F;
if ((m_termios.c_iflag & IGNCR) && ch == '\r')
return;
uint8_t conv = ch;
if ((m_termios.c_iflag & ICRNL) && ch == '\r')
conv = '\n';
if ((m_termios.c_iflag & INLCR) && ch == '\n')
conv = '\r';
ch = conv;
// ^C
if (ch == '\x03')
{
@ -252,6 +256,10 @@ namespace Kernel
return;
}
// FIXME: don't ignore these bytes
if (m_output.bytes >= m_output.buffer.size())
return;
m_output.buffer[m_output.bytes++] = ch;
if (m_termios.c_lflag & ECHO)
@ -280,7 +288,7 @@ namespace Kernel
}
}
if (ch == '\n' || !(m_termios.c_lflag & ICANON))
if (ch == '\n' || !(m_termios.c_lflag & ICANON) || m_output.bytes == m_output.buffer.size())
{
m_output.flush = true;
epoll_notify(EPOLLIN);
@ -334,9 +342,16 @@ namespace Kernel
bool TTY::putchar(uint8_t ch)
{
SpinLockGuard _(m_write_lock);
if (m_tty_ctrl.draw_graphics)
return putchar_impl(ch);
return true;
if (!m_tty_ctrl.draw_graphics)
return true;
if (m_termios.c_oflag & OPOST)
{
if ((m_termios.c_oflag & ONLCR) && ch == '\n')
return putchar_impl('\r') && putchar_impl('\n');
if ((m_termios.c_oflag & OCRNL) && ch == '\r')
return putchar_impl('\n');
}
return putchar_impl(ch);
}
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
@ -353,7 +368,13 @@ namespace Kernel
return 0;
}
size_t to_copy = BAN::Math::min<size_t>(buffer.size(), m_output.bytes);
const size_t max_to_copy = BAN::Math::min<size_t>(buffer.size(), m_output.bytes);
size_t to_copy = max_to_copy;
if (m_termios.c_lflag & ICANON)
for (to_copy = 1; to_copy < max_to_copy; to_copy++)
if (m_output.buffer[to_copy - 1] == '\n')
break;
memcpy(buffer.data(), m_output.buffer.data(), to_copy);
memmove(m_output.buffer.data(), m_output.buffer.data() + to_copy, m_output.bytes - to_copy);

View File

@ -36,7 +36,15 @@ namespace Kernel
}
VirtualTTY::VirtualTTY(BAN::RefPtr<TerminalDriver> driver)
: TTY(0600, 0, 0)
: TTY({
.c_iflag = 0,
.c_oflag = 0,
.c_cflag = CS8,
.c_lflag = ECHO | ICANON,
.c_cc = {},
.c_ospeed = B38400,
.c_ispeed = B38400,
}, 0600, 0, 0)
, m_name(MUST(BAN::String::formatted("tty{}", s_next_tty_number++)))
, m_terminal_driver(driver)
, m_palette(driver->palette())

View File

@ -140,6 +140,8 @@ namespace Kernel
pid_t Thread::current_tid()
{
if (Processor::count() == 0)
return 0;
return Processor::scheduler().current_tid();
}
@ -523,6 +525,8 @@ namespace Kernel
// Ignore the signal
case SIGCHLD:
case SIGURG:
case SIGWINCH:
case SIGCANCEL:
break;
// Stop the process:

View File

@ -1,6 +1,7 @@
set(LIBC_SOURCES
arpa/inet.cpp
assert.cpp
complex.cpp
ctype.cpp
dirent.cpp
dlfcn.cpp
@ -47,6 +48,7 @@ set(LIBC_SOURCES
time.cpp
unistd.cpp
utime.cpp
wchar-stdio.cpp
wchar.cpp
icxxabi.cpp

View File

@ -0,0 +1,192 @@
#include <BAN/Math.h>
#include <BAN/Traits.h>
#include <complex.h>
#include <math.h>
template<BAN::floating_point T> struct _complex_t;
template<> struct _complex_t<float> { using type = __complex__ float; };
template<> struct _complex_t<double> { using type = __complex__ double; };
template<> struct _complex_t<long double> { using type = __complex__ long double; };
template<BAN::floating_point T>
using _complex = _complex_t<T>::type;
template<BAN::floating_point T>
static constexpr T _cabs(_complex<T> z)
{
return BAN::Math::sqrt(creal(z) * creal(z) + cimag(z) * cimag(z));
}
template<BAN::floating_point T>
static constexpr T _carg(_complex<T> z)
{
return BAN::Math::atan2(cimag(z), creal(z));
}
template<BAN::floating_point T>
static constexpr _complex<T> _cproj(_complex<T> z)
{
if (!isfinite(creal(z)) || !isfinite(cimag(z)))
return INFINITY + I * copysign(0.0, cimag(z));
return z;
}
template<BAN::floating_point T>
static constexpr _complex<T> _conj(_complex<T> z)
{
cimag(z) = -cimag(z);
return z;
}
template<BAN::floating_point T>
static constexpr _complex<T> _cexp(_complex<T> z)
{
T sin, cos;
BAN::Math::sincos(cimag(z), sin, cos);
return BAN::Math::exp(creal(z)) * (cos + sin * I);
}
template<BAN::floating_point T>
static constexpr _complex<T> _clog(_complex<T> z)
{
return BAN::Math::log(_cabs<T>(z)) + I * _carg<T>(z);
}
template<BAN::floating_point T>
static constexpr _complex<T> _csqrt(_complex<T> z)
{
return BAN::Math::sqrt(_cabs<T>(z)) * _cexp<T>(I * _carg<T>(z) / 2);
}
template<BAN::floating_point T>
static constexpr _complex<T> _csin(_complex<T> z)
{
return (_cexp<T>(z * I) - _cexp<T>(-z * I)) / 2i;
}
template<BAN::floating_point T>
static constexpr _complex<T> _ccos(_complex<T> z)
{
return (_cexp<T>(z * I) + _cexp<T>(-z * I)) / 2i;
}
template<BAN::floating_point T>
static constexpr _complex<T> _ctan(_complex<T> z)
{
const _complex<T> exp_pos = _cexp<T>(+I * z);
const _complex<T> exp_neg = _cexp<T>(-I * z);
return -I * (exp_pos - exp_neg) / (exp_pos + exp_neg);
}
template<BAN::floating_point T>
static constexpr _complex<T> _cpow(_complex<T> x, _complex<T> y)
{
const T ln_r = BAN::Math::log(_cabs<T>(x));
const T theta = _carg<T>(x);
const T a = creal(y);
const T b = cimag(y);
return BAN::Math::exp(a * ln_r - b * theta) * _cexp<T>(I * (a * theta + b * ln_r));
}
template<BAN::floating_point T>
static constexpr _complex<T> _casin(_complex<T> z)
{
return -I * _clog<T>(_csqrt<T>(1 - z * z) + I * z);
}
template<BAN::floating_point T>
static constexpr _complex<T> _cacos(_complex<T> z)
{
return -I * _clog<T>(I * _csqrt<T>(1 - z * z) + z);
}
template<BAN::floating_point T>
static constexpr _complex<T> _catan(_complex<T> z)
{
return -I / 2 * _clog<T>((I - z) / (I + z));
}
template<BAN::floating_point T>
static constexpr _complex<T> _csinh(_complex<T> z)
{
return (_cexp<T>(z) - _cexp<T>(-z)) / 2;
}
template<BAN::floating_point T>
static constexpr _complex<T> _ccosh(_complex<T> z)
{
return (_cexp<T>(z) + _cexp<T>(-z)) / 2;
}
template<BAN::floating_point T>
static constexpr _complex<T> _ctanh(_complex<T> z)
{
const _complex<T> exp2x = _cexp<T>(2 * z);
return (exp2x - 1) / (exp2x + 1);
}
template<BAN::floating_point T>
static constexpr _complex<T> _casinh(_complex<T> z)
{
return _clog<T>(z + _csqrt<T>(z * z + 1));
}
template<BAN::floating_point T>
static constexpr _complex<T> _cacosh(_complex<T> z)
{
return _clog<T>(z + _csqrt<T>(z * z - 1));
}
template<BAN::floating_point T>
static constexpr _complex<T> _catanh(_complex<T> z)
{
return _clog<T>((1 + z) / (1 - z)) / 2;
}
#define COMPLEX_FUNCS(func) \
float func##f(float complex a) { return _##func<float>(a); } \
double func(double complex a) { return _##func<double>(a); } \
long double func##l(long double complex a) { return _##func<long double>(a); }
COMPLEX_FUNCS(cabs)
COMPLEX_FUNCS(carg)
#undef COMPLEX_FUNCS
#define COMPLEX_FUNCS(func) \
float complex func##f(float complex a) { return _##func<float>(a); } \
double complex func(double complex a) { return _##func<double>(a); } \
long double complex func##l(long double complex a) { return _##func<long double>(a); }
COMPLEX_FUNCS(cproj)
COMPLEX_FUNCS(conj)
COMPLEX_FUNCS(cexp)
COMPLEX_FUNCS(ctan)
COMPLEX_FUNCS(clog)
COMPLEX_FUNCS(csin)
COMPLEX_FUNCS(ccos)
COMPLEX_FUNCS(csqrt)
COMPLEX_FUNCS(csinh)
COMPLEX_FUNCS(ccosh)
COMPLEX_FUNCS(ctanh)
COMPLEX_FUNCS(cacos)
COMPLEX_FUNCS(casin)
COMPLEX_FUNCS(catan)
COMPLEX_FUNCS(cacosh)
COMPLEX_FUNCS(casinh)
COMPLEX_FUNCS(catanh)
#undef COMPLEX_FUNCS
#define COMPLEX_FUNCS(func) \
float complex func##f(float complex a, float complex b) { return _##func<float>(a, b); } \
double complex func(double complex a, double complex b) { return _##func<double>(a, b); } \
long double complex func##l(long double complex a, long double complex b) { return _##func<long double>(a, b); }
COMPLEX_FUNCS(cpow)
#undef COMPLEX_FUNCS

View File

@ -1,12 +1,9 @@
#include <errno.h>
#include <pthread.h>
#if __disable_thread_local_storage
static int s_errno = 0;
#else
static thread_local int s_errno = 0;
#endif
extern uthread* _get_uthread();
int* __errno_location()
{
return &s_errno;
return &_get_uthread()->errno_;
}

View File

@ -1,15 +1,19 @@
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/syscall.h>
#include <unistd.h>
int creat(const char* path, mode_t mode)
{
pthread_testcancel();
return open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
int open(const char* path, int oflag, ...)
{
pthread_testcancel();
va_list args;
va_start(args, oflag);
mode_t mode = va_arg(args, mode_t);
@ -20,6 +24,8 @@ int open(const char* path, int oflag, ...)
int openat(int fd, const char* path, int oflag, ...)
{
pthread_testcancel();
va_list args;
va_start(args, oflag);
mode_t mode = va_arg(args, mode_t);
@ -30,6 +36,8 @@ int openat(int fd, const char* path, int oflag, ...)
int fcntl(int fildes, int cmd, ...)
{
pthread_testcancel();
va_list args;
va_start(args, cmd);
int extra = va_arg(args, int);

View File

@ -12,11 +12,12 @@ __BEGIN_DECLS
#include <signal.h>
#define __need_off_t
#define __need_pthread_attr_t
#define __need_size_t
#define __need_ssize_t
#include <sys/types.h>
#include <bits/types/pthread_attr_t.h>
struct aiocb
{
int aio_fildes; /* File descriptor. */

View File

@ -1,44 +0,0 @@
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#if !defined(__pthread_attr_t_defined) && (defined(__need_all_types) || defined(__need_pthread_attr_t) || defined(__need_pthread_types))
#define __pthread_attr_t_defined 1
typedef int pthread_attr_t;
#endif
#undef __need_pthread_attr_t
#if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t) || defined(__need_pthread_types))
#define __pthread_t_defined 1
typedef pid_t pthread_t;
#endif
#undef __need_pthread_t
#if !defined(__pthread_types_defined) && (defined(__need_all_types) || defined(__need_pthread_types))
#define __pthread_types_defined 1
typedef int pthread_once_t;
typedef unsigned pthread_key_t;
typedef pthread_t pthread_spinlock_t;
typedef struct { int type; int shared; } pthread_mutexattr_t;
typedef struct { pthread_mutexattr_t attr; pthread_t locker; unsigned lock_depth; } pthread_mutex_t;
typedef struct { int shared; } pthread_barrierattr_t;
typedef struct { pthread_barrierattr_t attr; unsigned target; unsigned waiting; } pthread_barrier_t;
typedef struct { int clock; int shared; } pthread_condattr_t;
struct _pthread_cond_block { struct _pthread_cond_block* next; int signaled; };
typedef struct { pthread_condattr_t attr; pthread_spinlock_t lock; struct _pthread_cond_block* block_list; } pthread_cond_t;
typedef struct { int shared; } pthread_rwlockattr_t;
typedef struct { pthread_rwlockattr_t attr; unsigned lockers; unsigned writers; } pthread_rwlock_t;
#endif
#undef __need_pthread_types
__END_DECLS

View File

@ -1,5 +1,5 @@
#ifndef _BITS_LOCALE_T_H
#define _BITS_LOCALE_T_H 1
#ifndef _BITS_TYPES_LOCALE_T_H
#define _BITS_TYPES_LOCALE_T_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html

View File

@ -0,0 +1,25 @@
#ifndef _BITS_TYPES_PTHREAD_ATTR_T_H
#define _BITS_TYPES_PTHREAD_ATTR_T_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <bits/types/sched_param.h>
typedef struct
{
int inheritsched;
struct sched_param schedparam;
int schedpolicy;
int detachstate;
int scope;
size_t stacksize;
size_t guardsize;
} pthread_attr_t;
__END_DECLS
#endif

View File

@ -0,0 +1,17 @@
#ifndef _BITS_TYPES_PTHREAD_T_H
#define _BITS_TYPES_PTHREAD_T_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#define __need_pid_t
#include <sys/types.h>
typedef pid_t pthread_t;
__END_DECLS
#endif

View File

@ -0,0 +1,72 @@
#ifndef _BITS_TYPES_PTHREAD_TYPES_H
#define _BITS_TYPES_PTHREAD_TYPES_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <bits/types/pthread_attr_t.h>
#include <bits/types/pthread_t.h>
typedef int pthread_once_t;
typedef unsigned pthread_key_t;
typedef pthread_t pthread_spinlock_t;
typedef struct
{
int type;
int shared;
} pthread_mutexattr_t;
typedef struct
{
pthread_mutexattr_t attr;
pthread_t locker;
unsigned lock_depth;
} pthread_mutex_t;
typedef struct
{
int shared;
} pthread_barrierattr_t;
typedef struct
{
pthread_barrierattr_t attr;
unsigned target;
unsigned waiting;
} pthread_barrier_t;
typedef struct
{
int clock;
int shared;
} pthread_condattr_t;
struct _pthread_cond_block
{
struct _pthread_cond_block* next;
int signaled;
};
typedef struct
{
pthread_condattr_t attr;
pthread_spinlock_t lock;
struct _pthread_cond_block* block_list;
} pthread_cond_t;
typedef struct
{
int shared;
} pthread_rwlockattr_t;
typedef struct
{
pthread_rwlockattr_t attr;
unsigned lockers;
unsigned writers;
} pthread_rwlock_t;
__END_DECLS
#endif

View File

@ -0,0 +1,23 @@
#ifndef _BITS_TYPES_SCHED_PARAM_H
#define _BITS_TYPES_SCHED_PARAM_H 1
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <time.h>
struct sched_param
{
int sched_priority; /* Process or thread execution scheduling priority. */
int sched_ss_low_priority; /* Low scheduling priority for sporadic server. */
struct timespec sched_ss_repl_period; /* Replenishment period for sporadic server. */
struct timespec sched_ss_init_budget; /* Initial budget for sporadic server. */
int sched_ss_max_repl; /* Maximum pending replenishments for sporadic server. */
};
__END_DECLS
#endif

View File

@ -1,5 +1,5 @@
#ifndef _BITS_TIMEVAL_H
#define _BITS_TIMEVAL_H 1
#ifndef _BITS_TYPES_TIMEVAL_H
#define _BITS_TYPES_TIMEVAL_H 1
#include <sys/cdefs.h>

View File

@ -13,6 +13,14 @@
__BEGIN_DECLS
#define creal(complex) (__real__ (complex))
#define crealf(complex) (__real__ (complex))
#define creall(complex) (__real__ (complex))
#define cimag(complex) (__imag__ (complex))
#define cimagf(complex) (__imag__ (complex))
#define cimagl(complex) (__imag__ (complex))
double cabs(double complex);
float cabsf(float complex);
long double cabsl(long double complex);
@ -46,9 +54,6 @@ long double complex ccosl(long double complex);
double complex cexp(double complex);
float complex cexpf(float complex);
long double complex cexpl(long double complex);
double cimag(double complex);
float cimagf(float complex);
long double cimagl(long double complex);
double complex clog(double complex);
float complex clogf(float complex);
long double complex clogl(long double complex);
@ -61,9 +66,6 @@ long double complex cpowl(long double complex, long double complex);
double complex cproj(double complex);
float complex cprojf(float complex);
long double complex cprojl(long double complex);
double creal(double complex);
float crealf(float complex);
long double creall(long double complex);
double complex csin(double complex);
float complex csinf(float complex);
double complex csinh(double complex);

View File

@ -7,67 +7,140 @@
__BEGIN_DECLS
#define _POSIX_AIO_LISTIO_MAX 2
#define _POSIX_AIO_MAX 1
#define _POSIX_ARG_MAX 4096
#define _POSIX_CHILD_MAX 25
#define _POSIX_DELAYTIMER_MAX 32
#define _POSIX_HOST_NAME_MAX 255
#define _POSIX_LINK_MAX 8
#define _POSIX_LOGIN_NAME_MAX 9
#define _POSIX_MAX_CANON 255
#define _POSIX_MAX_INPUT 255
#define _POSIX_MQ_OPEN_MAX 8
#define _POSIX_MQ_PRIO_MAX 32
#define _POSIX_NAME_MAX 14
#define _POSIX_NGROUPS_MAX 8
#define _POSIX_OPEN_MAX 20
#define _POSIX_PATH_MAX 256
#define _POSIX_PIPE_BUF 512
#define _POSIX_RE_DUP_MAX 255
#define _POSIX_RTSIG_MAX 8
#define _POSIX_SEM_NSEMS_MAX 256
#define _POSIX_SEM_VALUE_MAX 32767
#define _POSIX_SIGQUEUE_MAX 32
#define _POSIX_SSIZE_MAX 32767
#define _POSIX_SS_REPL_MAX 4
#define _POSIX_STREAM_MAX 8
#define _POSIX_SYMLINK_MAX 255
#define _POSIX_SYMLOOP_MAX 8
// Maximum Values
#define _POSIX_CLOCKRES_MIN 20000000
// Minimum Values
#define _POSIX_AIO_LISTIO_MAX 2
#define _POSIX_AIO_MAX 1
#define _POSIX_ARG_MAX 4096
#define _POSIX_CHILD_MAX 25
#define _POSIX_DELAYTIMER_MAX 32
#define _POSIX_HOST_NAME_MAX 255
#define _POSIX_LINK_MAX 8
#define _POSIX_LOGIN_NAME_MAX 9
#define _POSIX_MAX_CANON 255
#define _POSIX_MAX_INPUT 255
#define _POSIX_MQ_OPEN_MAX 8
#define _POSIX_MQ_PRIO_MAX 32
#define _POSIX_NAME_MAX 14
#define _POSIX_NGROUPS_MAX 8
#define _POSIX_OPEN_MAX 20
#define _POSIX_PATH_MAX 256
#define _POSIX_PIPE_BUF 512
#define _POSIX_RE_DUP_MAX 255
#define _POSIX_RTSIG_MAX 8
#define _POSIX_SEM_NSEMS_MAX 256
#define _POSIX_SEM_VALUE_MAX 32767
#define _POSIX_SIGQUEUE_MAX 32
#define _POSIX_SSIZE_MAX 32767
#define _POSIX_SS_REPL_MAX 4
#define _POSIX_STREAM_MAX 8
#define _POSIX_SYMLINK_MAX 255
#define _POSIX_SYMLOOP_MAX 8
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
#define _POSIX_THREAD_KEYS_MAX 128
#define _POSIX_THREAD_THREADS_MAX 64
#define _POSIX_TIMER_MAX 32
#define _POSIX_TRACE_EVENT_NAME_MAX 30
#define _POSIX_TRACE_NAME_MAX 8
#define _POSIX_TRACE_SYS_MAX 8
#define _POSIX_TRACE_USER_EVENT_MAX 32
#define _POSIX_TTY_NAME_MAX 9
#define _POSIX_TZNAME_MAX 6
#define _POSIX2_BC_BASE_MAX 99
#define _POSIX2_BC_DIM_MAX 2048
#define _POSIX2_BC_SCALE_MAX 99
#define _POSIX2_BC_STRING_MAX 1000
#define _POSIX2_CHARCLASS_NAME_MAX 14
#define _POSIX2_COLL_WEIGHTS_MAX 2
#define _POSIX2_EXPR_NEST_MAX 32
#define _POSIX2_LINE_MAX 2048
#define _POSIX2_RE_DUP_MAX 255
#define _XOPEN_IOV_MAX 16
#define _XOPEN_NAME_MAX 255
#define _XOPEN_PATH_MAX 1024
#define _POSIX_THREAD_KEYS_MAX 128
#define _POSIX_THREAD_THREADS_MAX 64
#define _POSIX_TIMER_MAX 32
#define _POSIX_TRACE_EVENT_NAME_MAX 30
#define _POSIX_TRACE_NAME_MAX 8
#define _POSIX_TRACE_SYS_MAX 8
#define _POSIX_TRACE_USER_EVENT_MAX 32
#define _POSIX_TTY_NAME_MAX 9
#define _POSIX_TZNAME_MAX 6
#define _POSIX2_BC_BASE_MAX 99
#define _POSIX2_BC_DIM_MAX 2048
#define _POSIX2_BC_SCALE_MAX 99
#define _POSIX2_BC_STRING_MAX 1000
#define _POSIX2_CHARCLASS_NAME_MAX 14
#define _POSIX2_COLL_WEIGHTS_MAX 2
#define _POSIX2_EXPR_NEST_MAX 32
#define _POSIX2_LINE_MAX 2048
#define _POSIX2_RE_DUP_MAX 255
#define _XOPEN_IOV_MAX 16
#define _XOPEN_NAME_MAX 255
#define _XOPEN_PATH_MAX 1024
#define ARG_MAX _POSIX_ARG_MAX
#define OPEN_MAX 64
#define NAME_MAX 255
#define PATH_MAX 256
#define PASS_MAX 256
#define LOGIN_NAME_MAX 256
#define HOST_NAME_MAX 255
#define TTY_NAME_MAX PATH_MAX
#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
// Runtime Invariant Values (Possibly Indeterminate)
#define AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX
#define AIO_MAX _POSIX_AIO_MAX
#define AIO_PRIO_DELTA_MAX 0
#define ARG_MAX _POSIX_ARG_MAX
#define ATEXIT_MAX 128
#define CHILD_MAX _POSIX_CHILD_MAX
#define DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX
#define HOST_NAME_MAX 255
#define IOV_MAX _XOPEN_IOV_MAX
#define LOGIN_NAME_MAX 256
#define MQ_OPEN_MAX _POSIX_MQ_OPEN_MAX
#define MQ_PRIO_MAX _POSIX_MQ_PRIO_MAX
#define OPEN_MAX 64
#define PAGESIZE PAGE_SIZE
#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
#define PTHREAD_STACK_MIN PAGE_SIZE
#define PTHREAD_THREADS_MAX _POSIX_THREAD_THREADS_MAX
#define RTSIG_MAX _POSIX_RTSIG_MAX
#define SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX
#define SEM_VALUE_MAX _POSIX_SEM_VALUE_MAX
#define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX
#define SS_REPL_MAX _POSIX_SS_REPL_MAX
#define STREAM_MAX _POSIX_STREAM_MAX
#define SYMLOOP_MAX _POSIX_SYMLOOP_MAX
#define TIMER_MAX _POSIX_TIMER_MAX
#define TRACE_EVENT_NAME_MAX _POSIX_TRACE_EVENT_NAME_MAX
#define TRACE_NAME_MAX _POSIX_TRACE_NAME_MAX
#define TRACE_SYS_MAX _POSIX_TRACE_SYS_MAX
#define TRACE_USER_EVENT_MAX _POSIX_TRACE_USER_EVENT_MAX
#define TTY_NAME_MAX PATH_MAX
#define TZNAME_MAX _POSIX_TZNAME_MAX
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
// Pathname Variable Values
#define FILESIZEBITS 32
#define LINK_MAX _POSIX_LINK_MAX
#define MAX_CANON _POSIX_MAX_CANON
#define MAX_INPUT _POSIX_MAX_INPUT
#define NAME_MAX 255
#define PATH_MAX _POSIX_PATH_MAX
#define PIPE_BUF PAGE_SIZE
//#define POSIX_ALLOC_SIZE_MIN
//#define POSIX_REC_INCR_XFER_SIZE
//#define POSIX_REC_MAX_XFER_SIZE
//#define POSIX_REC_MIN_XFER_SIZE
//#define POSIX_REC_XFER_ALIGN
#define SYMLINK_MAX _POSIX_SYMLINK_MAX
// Runtime Increasable Values
#define BC_BASE_MAX _POSIX2_BC_BASE_MAX
#define BC_DIM_MAX _POSIX2_BC_DIM_MAX
#define BC_SCALE_MAX _POSIX2_BC_SCALE_MAX
#define BC_STRING_MAX _POSIX2_BC_STRING_MAX
#define CHARCLASS_NAME_MAX _POSIX2_CHARCLASS_NAME_MAX
#define COLL_WEIGHTS_MAX _POSIX2_COLL_WEIGHTS_MAX
#define EXPR_NEST_MAX _POSIX2_EXPR_NEST_MAX
#define LINE_MAX _POSIX2_LINE_MAX
#define NGROUPS_MAX _POSIX_NGROUPS_MAX
#define RE_DUP_MAX _POSIX_RE_DUP_MAX
// Legacy things
#define PASS_MAX 256
// Numerical Limits
#define CHAR_MAX SCHAR_MAX
#define CHAR_MIN SCHAR_MIN

View File

@ -0,0 +1,6 @@
#ifndef _MEMORY_H
#define _MEMORY_H 1
#include <string.h>
#endif

View File

@ -10,11 +10,12 @@ __BEGIN_DECLS
#include <time.h>
#include <signal.h>
#define __need_pthread_attr_t
#define __need_size_t
#define __need_ssize_t
#include <sys/types.h>
#include <bits/types/pthread_attr_t.h>
typedef int mqd_t;
struct mq_attr

View File

@ -7,6 +7,8 @@
__BEGIN_DECLS
#include <signal.h>
struct pollfd
{
int fd; /* The following descriptor being polled. */
@ -28,6 +30,7 @@ typedef unsigned long nfds_t;
#define POLLNVAL 0x200
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
int ppoll(struct pollfd fds[], nfds_t nfds, const struct timespec* timeout, const sigset_t* sigmask);
__END_DECLS

View File

@ -13,29 +13,51 @@ __BEGIN_DECLS
#define __need_size_t
#define __need_clockid_t
#define __need_pthread_types
#include <sys/types.h>
#include <bits/types/pthread_types.h>
struct _pthread_cleanup_t
{
void (*routine)(void*);
void* arg;
struct _pthread_cleanup_t* next;
};
struct uthread
{
struct uthread* self;
void* master_tls_addr;
size_t master_tls_size;
struct _pthread_cleanup_t* cleanup_stack;
pthread_t id;
int errno_;
int cancel_type;
int cancel_state;
int canceled;
uintptr_t dtv[];
};
#define PTHREAD_CANCEL_ASYNCHRONOUS 2
#define PTHREAD_CANCEL_ENABLE 3
#define PTHREAD_CANCEL_DEFERRED 4
#define PTHREAD_CANCEL_DISABLE 5
#define PTHREAD_CANCELED 6
#define PTHREAD_EXPLICIT_SCHED 9
#define PTHREAD_INHERIT_SCHED 10
#define PTHREAD_PRIO_INHERIT 18
#define PTHREAD_PRIO_NONE 19
#define PTHREAD_PRIO_PROTECT 20
#define PTHREAD_SCOPE_PROCESS 23
#define PTHREAD_SCOPE_SYSTEM 24
#define PTHREAD_CANCELED (void*)1
#define PTHREAD_CANCEL_ASYNCHRONOUS 1
#define PTHREAD_CANCEL_DEFERRED 0
#define PTHREAD_CANCEL_DISABLE 0
#define PTHREAD_CANCEL_ENABLE 1
// cancellation points
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_09_05_02
#define PTHREAD_PRIO_INHERIT 1
#define PTHREAD_PRIO_NONE 0
#define PTHREAD_PRIO_PROTECT 2
#define PTHREAD_EXPLICIT_SCHED 1
#define PTHREAD_INHERIT_SCHED 0
#define PTHREAD_SCOPE_PROCESS 1
#define PTHREAD_SCOPE_SYSTEM 0
#define PTHREAD_CREATE_DETACHED 1
#define PTHREAD_CREATE_JOINABLE 0
@ -60,6 +82,11 @@ struct uthread
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, 0 }, 0, 0 }
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { 0 }, 0, 0 }
#define _PTHREAD_ATFORK_PREPARE 0
#define _PTHREAD_ATFORK_PARENT 1
#define _PTHREAD_ATFORK_CHILD 2
void _pthread_call_atfork(int state);
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
int pthread_attr_destroy(pthread_attr_t* attr);
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate);

View File

@ -12,14 +12,7 @@ __BEGIN_DECLS
#define __need_pid_t
#include <sys/types.h>
struct sched_param
{
int sched_priority; /* Process or thread execution scheduling priority. */
int sched_ss_low_priority; /* Low scheduling priority for sporadic server. */
struct timespec sched_ss_repl_period; /* Replenishment period for sporadic server. */
struct timespec sched_ss_init_budget; /* Initial budget for sporadic server. */
int sched_ss_max_repl; /* Maximum pending replenishments for sporadic server. */
};
#include <bits/types/sched_param.h>
#define SCHED_FIFO 1
#define SCHED_RR 2

View File

@ -14,13 +14,14 @@ __BEGIN_DECLS
#define SIG_HOLD ((void (*)(int))2)
#define SIG_IGN ((void (*)(int))3)
#define __need_pthread_t
#define __need_size_t
#define __need_uid_t
#define __need_pid_t
#define __need_pthread_attr_t
#include <sys/types.h>
#include <bits/types/pthread_attr_t.h>
#include <bits/types/pthread_t.h>
typedef int sig_atomic_t;
typedef unsigned long long sigset_t;
@ -105,7 +106,8 @@ struct sigevent
#define SIGXCPU 27
#define SIGXFSZ 28
#define SIGWINCH 29
#define SIGRTMIN 30
#define SIGCANCEL 30
#define SIGRTMIN 31
#define SIGRTMAX (SIGRTMIN+32)
#define NSIG SIGRTMAX

View File

@ -56,7 +56,7 @@ __BEGIN_DECLS
O(SYS_POWEROFF, poweroff) \
O(SYS_FCHMODAT, fchmodat) \
O(SYS_CREATE_DIR, create_dir) \
O(SYS_UNLINK, unlink) \
O(SYS_UNLINKAT, unlinkat) \
O(SYS_READLINKAT, readlinkat) \
O(SYS_MSYNC, msync) \
O(SYS_PREAD, pread) \
@ -73,7 +73,8 @@ __BEGIN_DECLS
O(SYS_CONNECT, connect) \
O(SYS_LISTEN, listen) \
O(SYS_PSELECT, pselect) \
O(SYS_TRUNCATE, truncate) \
O(SYS_PPOLL, ppoll) \
O(SYS_FTRUNCATE, ftruncate) \
O(SYS_SMO_CREATE, smo_create) \
O(SYS_SMO_DELETE, smo_delete) \
O(SYS_SMO_MAP, smo_map) \
@ -94,6 +95,7 @@ __BEGIN_DECLS
O(SYS_FSYNC, fsync) \
O(SYS_SYMLINKAT, symlinkat) \
O(SYS_HARDLINKAT, hardlinkat) \
O(SYS_UTIMENSAT, utimensat) \
O(SYS_YIELD, yield) \
O(SYS_SET_TLS, set_tls) \
O(SYS_GET_TLS, get_tls) \
@ -101,6 +103,7 @@ __BEGIN_DECLS
O(SYS_PTHREAD_EXIT, pthread_exit) \
O(SYS_PTHREAD_JOIN, pthread_join) \
O(SYS_PTHREAD_SELF, pthread_self) \
O(SYS_PTHREAD_KILL, pthread_kill) \
O(SYS_EPOLL_CREATE1, epoll_create1) \
O(SYS_EPOLL_CTL, epoll_ctl) \
O(SYS_EPOLL_PWAIT2, epoll_pwait2) \

View File

@ -21,9 +21,6 @@ __BEGIN_DECLS
&& !defined(__need_nlink_t) \
&& !defined(__need_off_t) \
&& !defined(__need_pid_t) \
&& !defined(__need_pthread_attr_t) \
&& !defined(__need_pthread_t) \
&& !defined(__need_pthread_types) \
&& !defined(__need_size_t) \
&& !defined(__need_ssize_t) \
&& !defined(__need_suseconds_t) \
@ -122,18 +119,12 @@ __BEGIN_DECLS
#endif
#undef __need_off_t
#ifdef __need_pthread_t
#define __need_pid_t
#endif
#if !defined(__pid_t_defined) && (defined(__need_all_types) || defined(__need_pid_t))
#define __pid_t_defined 1
typedef int pid_t;
#endif
#undef __need_pid_t
#include <bits/pthread_types.h>
#if !defined(__size_t_defined) && (defined(__need_all_types) || defined(__need_size_t))
#define __size_t_defined 1
#define __need_size_t

View File

@ -7,89 +7,109 @@
__BEGIN_DECLS
#define _POSIX_VERSION 200809L
#define _POSIX_VERSION 200809L
#define _POSIX2_VERSION -1
#define _XOPEN_VERSION 700
#define _XOPEN_VERSION 700
#define _POSIX_ADVISORY_INFO -1
#define _POSIX_ASYNCHRONOUS_IO -1
#define _POSIX_BARRIERS -1
#define _POSIX_CHOWN_RESTRICTED -1
#define _POSIX_CLOCK_SELECTION -1
#define _POSIX_CPUTIME -1
#define _POSIX_FSYNC -1
#define _POSIX_IPV6 -1
#define _POSIX_JOB_CONTROL -1
#define _POSIX_MAPPED_FILES -1
#define _POSIX_MEMLOCK -1
#define _POSIX_MEMLOCK_RANGE -1
#define _POSIX_MEMORY_PROTECTION -1
#define _POSIX_MESSAGE_PASSING -1
#define _POSIX_MONOTONIC_CLOCK -1
#define _POSIX_NO_TRUNC -1
#define _POSIX_PRIORITIZED_IO -1
#define _POSIX_PRIORITY_SCHEDULING -1
#define _POSIX_RAW_SOCKETS -1
#define _POSIX_READER_WRITER_LOCKS -1
#define _POSIX_REALTIME_SIGNALS -1
#define _POSIX_REGEXP -1
#define _POSIX_SAVED_IDS -1
#define _POSIX_SEMAPHORES -1
#define _POSIX_SHARED_MEMORY_OBJECTS -1
#define _POSIX_SHELL -1
#define _POSIX_SPAWN -1
#define _POSIX_SPIN_LOCKS -1
#define _POSIX_SPORADIC_SERVER -1
#define _POSIX_SYNCHRONIZED_IO xx
#define _POSIX_THREAD_ATTR_STACKADDR -1
#define _POSIX_THREAD_ATTR_STACKSIZE -1
#define _POSIX_THREAD_CPUTIME -1
#define _POSIX_THREAD_PRIO_INHERIT -1
#define _POSIX_THREAD_PRIO_PROTECT -1
#define _POSIX_THREAD_PRIORITY_SCHEDULING -1
#define _POSIX_THREAD_PROCESS_SHARED -1
#define _POSIX_THREAD_ROBUST_PRIO_INHERIT -1
#define _POSIX_THREAD_ROBUST_PRIO_PROTECT -1
#define _POSIX_THREAD_SAFE_FUNCTIONS -1
#define _POSIX_THREAD_SPORADIC_SERVER -1
#define _POSIX_THREADS -1
#define _POSIX_TIMEOUTS -1
#define _POSIX_TIMERS -1
#define _POSIX_TRACE -1
#define _POSIX_TRACE_EVENT_FILTER -1
#define _POSIX_TRACE_INHERIT -1
#define _POSIX_TRACE_LOG -1
#define _POSIX_TYPED_MEMORY_OBJECTS -1
#define _POSIX_V6_ILP32_OFF32 -1
#define _POSIX_V6_ILP32_OFFBIG -1
#define _POSIX_V6_LP64_OFF64 -1
#define _POSIX_V6_LPBIG_OFFBIG -1
#define _POSIX_V7_ILP32_OFF32 -1
#define _POSIX_V7_ILP32_OFFBIG -1
#define _POSIX_V7_LP64_OFF64 -1
#define _POSIX_V7_LPBIG_OFFBIG -1
#define _POSIX2_C_BIND -1
#define _POSIX2_C_DEV -1
#define _POSIX2_CHAR_TERM -1
#define _POSIX2_FORT_DEV -1
#define _POSIX2_FORT_RUN -1
#define _POSIX2_LOCALEDEF -1
#define _POSIX2_PBS -1
#define _POSIX2_PBS_ACCOUNTING -1
#define _POSIX2_PBS_CHECKPOINT -1
#define _POSIX2_PBS_LOCATE -1
#define _POSIX2_PBS_MESSAGE -1
#define _POSIX2_PBS_TRACK -1
#define _POSIX2_SW_DEV -1
#define _POSIX2_UPE -1
#define _XOPEN_CRYPT -1
#define _XOPEN_ENH_I18N -1
#define _XOPEN_REALTIME -1
// -1 not supported for compilation
// 0 might or might not be supported during runtime
// >0 always supported
// MISSING / UNSUPPORTED
#define _POSIX_ADVISORY_INFO -1 /* posix_{fadvice,fallocate,memalign,madvice} */
#define _POSIX_ASYNCHRONOUS_IO -1 /* aio_{cancel,error,fsync,read,return,suspend,write,listio} */
#define _POSIX_BARRIERS 200809L
#define _POSIX_CHOWN_RESTRICTED 200809L
#define _POSIX_CLOCK_SELECTION 0 /* pthread_condattr_{getclock,setclock}, clock_nanosleep */
#define _POSIX_CPUTIME 0 /* working CLOCK_CPUTIME */
#define _POSIX_FSYNC 200809L
#define _POSIX_IPV6 0 /* IPv6 :D */
#define _POSIX_JOB_CONTROL 200809L /* tcdrain, tcsendbreak */
#define _POSIX_MAPPED_FILES 200809L
#define _POSIX_MEMLOCK -1 /* mlockall, munlockall */
#define _POSIX_MEMLOCK_RANGE -1 /* mlock, munlock */
#define _POSIX_MEMORY_PROTECTION -1 /* mprotect */
#define _POSIX_MESSAGE_PASSING -1 /* mq_{close,getattr,notify,open,receive,send,sendattr,unlink} */
#define _POSIX_MONOTONIC_CLOCK 200809L
#define _POSIX_NO_TRUNC 200809L
#define _POSIX_PRIORITIZED_IO -1 /* aio_{read,write} */
#define _POSIX_PRIORITY_SCHEDULING -1 /* sched_{get_priority_min,get_priority_max,getparam,getscheduler,rr_get_interval,setparam,setscheduler} */
#define _POSIX_RAW_SOCKETS 0 /* raw sockets :D */
#define _POSIX_READER_WRITER_LOCKS 200809L
#define _POSIX_REALTIME_SIGNALS -1 /* siq{queue,timedwait,waitinfo} */
#define _POSIX_REGEXP -1 /* reg{comp,error,exec,free} */
#define _POSIX_SAVED_IDS 200809L
#define _POSIX_SEMAPHORES -1 /* sem_{close,destroy,getvalue,init,open,post,trywait,unlink,wait} */
#define _POSIX_SHARED_MEMORY_OBJECTS -1 /* shm_{open,unlink} */
#define _POSIX_SHELL 200809L
#define _POSIX_SPAWN -1 /* posix_spawn* */
#define _POSIX_SPIN_LOCKS 200809L
#define _POSIX_SPORADIC_SERVER -1 /* sched_{setparam,setscheduler} with SCHED_SPORADIC */
#define _POSIX_SYNCHRONIZED_IO 200809L
#define _POSIX_THREAD_ATTR_STACKADDR 0 /* pthread_attr_{get,set}stack{,addr} */
#define _POSIX_THREAD_ATTR_STACKSIZE 0 /* pthread_attr_{get,set}stack{,size} */
#define _POSIX_THREAD_CPUTIME -1 /* pthread_getcpuclockid, clock_{getres,gettime,settime,create} for thread CPU time */
#define _POSIX_THREAD_PRIO_INHERIT -1 /* pthread_mutexattr_{get,set}protocol */
#define _POSIX_THREAD_PRIO_PROTECT -1 /* pthread_mutex{,attr}_{get,set}prioceiling, pthread_mutexattr_{get,set}protocol */
#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 /* pthread_attr_{get,set}{inheritsched,schedpolicy,scope}, pthread_{get,set}schedparam, pthread_setschedprio */
#define _POSIX_THREAD_PROCESS_SHARED 200809L
#define _POSIX_THREAD_ROBUST_PRIO_INHERIT 0 /* robust mutexes */
#define _POSIX_THREAD_ROBUST_PRIO_PROTECT 0 /* robust mutexes */
#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L /* some *_r functions */
#define _POSIX_THREAD_SPORADIC_SERVER -1
#define _POSIX_THREADS 200809L
#define _POSIX_TIMEOUTS -1 /* mq_timed{receive,send}, sem_timedwait, posix_trace_timedgetnext_event */
#define _POSIX_TIMERS -1 /* timer_{create,delete,gettime,getoverrun,settime} */
#define _POSIX_TRACE -1 /* posix_trace_* */
#define _POSIX_TRACE_EVENT_FILTER -1 /* posix_trace_* */
#define _POSIX_TRACE_INHERIT -1 /* posix_trace_* */
#define _POSIX_TRACE_LOG -1 /* posix_trace_* */
#define _POSIX_TYPED_MEMORY_OBJECTS -1 /* posix_mem_offset, posix_typed_mem_{get_info,open} */
#define _POSIX2_C_BIND 200809L
#define _POSIX2_C_DEV -1 /* c99, lex, yacc */
#define _POSIX2_CHAR_TERM 200809L
#define _POSIX2_FORT_DEV -1 /* fortran stuff */
#define _POSIX2_FORT_RUN -1 /* fortran stuff */
#define _POSIX2_LOCALEDEF -1 /* localedef */
#define _POSIX2_PBS -1 /* batch stuff */
#define _POSIX2_PBS_ACCOUNTING -1 /* batch stuff */
#define _POSIX2_PBS_CHECKPOINT -1 /* batch stuff */
#define _POSIX2_PBS_LOCATE -1 /* batch stuff */
#define _POSIX2_PBS_MESSAGE -1 /* batch stuff */
#define _POSIX2_PBS_TRACK -1 /* batch stuff */
#define _POSIX2_SW_DEV -1 /* ar, make, nm, strip */
#define _POSIX2_UPE -1 /* bg, ex, fc, fg, jobs, more, talk, vi */
#define _XOPEN_CRYPT -1 /* crypt, encrypt, setkey */
#define _XOPEN_ENH_I18N -1
#define _XOPEN_REALTIME -1
#define _XOPEN_REALTIME_THREADS -1
#define _XOPEN_SHM -1
#define _XOPEN_STREAMS -1
#define _XOPEN_UNIX -1
#define _XOPEN_UUCP -1
#define _XOPEN_SHM -1
#define _XOPEN_STREAMS -1
#define _XOPEN_UNIX 200809L
#define _XOPEN_UUCP -1
#if defined(__x86_64__)
# define _POSIX_V6_ILP32_OFF32 -1
# define _POSIX_V6_ILP32_OFFBIG -1
# define _POSIX_V6_LP64_OFF64 1
# define _POSIX_V6_LPBIG_OFFBIG 1
# define _POSIX_V7_ILP32_OFF32 -1
# define _POSIX_V7_ILP32_OFFBIG -1
# define _POSIX_V7_LP64_OFF64 1
# define _POSIX_V7_LPBIG_OFFBIG 1
#elif defined(__i686__)
# define _POSIX_V6_ILP32_OFF32 1
# define _POSIX_V6_ILP32_OFFBIG -1
# define _POSIX_V6_LP64_OFF64 -1
# define _POSIX_V6_LPBIG_OFFBIG -1
# define _POSIX_V7_ILP32_OFF32 1
# define _POSIX_V7_ILP32_OFFBIG -1
# define _POSIX_V7_LP64_OFF64 -1
# define _POSIX_V7_LPBIG_OFFBIG -1
#else
#error "TODO: _POSIX_ compilation environment"
#endif
#include <stddef.h>
#include <stdint.h>
@ -104,31 +124,370 @@ __BEGIN_DECLS
#define __need_useconds_t
#include <sys/types.h>
// FIXME: _CS prefixed definitions
enum
{
_CS_PATH = 1,
#define _CS_PATH _CS_PATH
_CS_POSIX_V6_ILP32_OFF32_CFLAGS,
#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS _CS_POSIX_V6_ILP32_OFF32_CFLAGS
_CS_POSIX_V6_ILP32_OFF32_LDFLAGS,
#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
_CS_POSIX_V6_ILP32_OFF32_LIBS,
#define _CS_POSIX_V6_ILP32_OFF32_LIBS _CS_POSIX_V6_ILP32_OFF32_LIBS
_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS,
#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS,
#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
_CS_POSIX_V6_ILP32_OFFBIG_LIBS,
#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS _CS_POSIX_V6_ILP32_OFFBIG_LIBS
_CS_POSIX_V6_LP64_OFF64_CFLAGS,
#define _CS_POSIX_V6_LP64_OFF64_CFLAGS _CS_POSIX_V6_LP64_OFF64_CFLAGS
_CS_POSIX_V6_LP64_OFF64_LDFLAGS,
#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS _CS_POSIX_V6_LP64_OFF64_LDFLAGS
_CS_POSIX_V6_LP64_OFF64_LIBS,
#define _CS_POSIX_V6_LP64_OFF64_LIBS _CS_POSIX_V6_LP64_OFF64_LIBS
_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS,
#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS,
#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
_CS_POSIX_V6_LPBIG_OFFBIG_LIBS,
#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS,
#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
_CS_V6_ENV,
#define _CS_V6_ENV _CS_V6_ENV
_CS_POSIX_V7_ILP32_OFF32_CFLAGS,
#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS _CS_POSIX_V7_ILP32_OFF32_CFLAGS
_CS_POSIX_V7_ILP32_OFF32_LDFLAGS,
#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS _CS_POSIX_V7_ILP32_OFF32_LDFLAGS
_CS_POSIX_V7_ILP32_OFF32_LIBS,
#define _CS_POSIX_V7_ILP32_OFF32_LIBS _CS_POSIX_V7_ILP32_OFF32_LIBS
_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS,
#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS,
#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
_CS_POSIX_V7_ILP32_OFFBIG_LIBS,
#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS _CS_POSIX_V7_ILP32_OFFBIG_LIBS
_CS_POSIX_V7_LP64_OFF64_CFLAGS,
#define _CS_POSIX_V7_LP64_OFF64_CFLAGS _CS_POSIX_V7_LP64_OFF64_CFLAGS
_CS_POSIX_V7_LP64_OFF64_LDFLAGS,
#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS _CS_POSIX_V7_LP64_OFF64_LDFLAGS
_CS_POSIX_V7_LP64_OFF64_LIBS,
#define _CS_POSIX_V7_LP64_OFF64_LIBS _CS_POSIX_V7_LP64_OFF64_LIBS
_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS,
#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS,
#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
_CS_POSIX_V7_LPBIG_OFFBIG_LIBS,
#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS _CS_POSIX_V7_LPBIG_OFFBIG_LIBS
_CS_POSIX_V7_THREADS_CFLAGS,
#define _CS_POSIX_V7_THREADS_CFLAGS _CS_POSIX_V7_THREADS_CFLAGS
_CS_POSIX_V7_THREADS_LDFLAGS,
#define _CS_POSIX_V7_THREADS_LDFLAGS _CS_POSIX_V7_THREADS_LDFLAGS
_CS_POSIX_V7_WIDTH_RESTRICTED_ENVS,
#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
_CS_V7_ENV,
#define _CS_V7_ENV _CS_V7_ENV
};
enum
{
_PC_2_SYMLINKS,
_PC_2_SYMLINKS = 1,
#define _PC_2_SYMLINKS _PC_2_SYMLINKS
_PC_ALLOC_SIZE_MIN,
#define _PC_ALLOC_SIZE_MIN _PC_ALLOC_SIZE_MIN
_PC_ASYNC_IO,
#define _PC_ASYNC_IO _PC_ASYNC_IO
_PC_CHOWN_RESTRICTED,
#define _PC_CHOWN_RESTRICTED _PC_CHOWN_RESTRICTED
_PC_FILESIZEBITS,
#define _PC_FILESIZEBITS _PC_FILESIZEBITS
_PC_LINK_MAX,
#define _PC_LINK_MAX _PC_LINK_MAX
_PC_MAX_CANON,
#define _PC_MAX_CANON _PC_MAX_CANON
_PC_MAX_INPUT,
#define _PC_MAX_INPUT _PC_MAX_INPUT
_PC_NAME_MAX,
#define _PC_NAME_MAX _PC_NAME_MAX
_PC_NO_TRUNC,
#define _PC_NO_TRUNC _PC_NO_TRUNC
_PC_PATH_MAX,
#define _PC_PATH_MAX _PC_PATH_MAX
_PC_PIPE_BUF,
#define _PC_PIPE_BUF _PC_PIPE_BUF
_PC_PRIO_IO,
#define _PC_PRIO_IO _PC_PRIO_IO
_PC_REC_INCR_XFER_SIZE,
#define _PC_REC_INCR_XFER_SIZE _PC_REC_INCR_XFER_SIZE
_PC_REC_MAX_XFER_SIZE,
#define _PC_REC_MAX_XFER_SIZE _PC_REC_MAX_XFER_SIZE
_PC_REC_MIN_XFER_SIZE,
#define _PC_REC_MIN_XFER_SIZE _PC_REC_MIN_XFER_SIZE
_PC_REC_XFER_ALIGN,
#define _PC_REC_XFER_ALIGN _PC_REC_XFER_ALIGN
_PC_SYMLINK_MAX,
#define _PC_SYMLINK_MAX _PC_SYMLINK_MAX
_PC_SYNC_IO,
#define _PC_SYNC_IO _PC_SYNC_IO
_PC_TIMESTAMP_RESOLUTION,
#define _PC_TIMESTAMP_RESOLUTION _PC_TIMESTAMP_RESOLUTION
_PC_VDISABLE,
#define _PC_VDISABLE _PC_VDISABLE
};
enum
{
_SC_2_C_BIND = 1,
#define _SC_2_C_BIND _SC_2_C_BIND
_SC_2_C_DEV,
#define _SC_2_C_DEV _SC_2_C_DEV
_SC_2_CHAR_TERM,
#define _SC_2_CHAR_TERM _SC_2_CHAR_TERM
_SC_2_FORT_DEV,
#define _SC_2_FORT_DEV _SC_2_FORT_DEV
_SC_2_FORT_RUN,
#define _SC_2_FORT_RUN _SC_2_FORT_RUN
_SC_2_LOCALEDEF,
#define _SC_2_LOCALEDEF _SC_2_LOCALEDEF
_SC_2_PBS,
#define _SC_2_PBS _SC_2_PBS
_SC_2_PBS_ACCOUNTING,
#define _SC_2_PBS_ACCOUNTING _SC_2_PBS_ACCOUNTING
_SC_2_PBS_CHECKPOINT,
#define _SC_2_PBS_CHECKPOINT _SC_2_PBS_CHECKPOINT
_SC_2_PBS_LOCATE,
#define _SC_2_PBS_LOCATE _SC_2_PBS_LOCATE
_SC_2_PBS_MESSAGE,
#define _SC_2_PBS_MESSAGE _SC_2_PBS_MESSAGE
_SC_2_PBS_TRACK,
#define _SC_2_PBS_TRACK _SC_2_PBS_TRACK
_SC_2_SW_DEV,
#define _SC_2_SW_DEV _SC_2_SW_DEV
_SC_2_UPE,
#define _SC_2_UPE _SC_2_UPE
_SC_2_VERSION,
#define _SC_2_VERSION _SC_2_VERSION
_SC_ADVISORY_INFO,
#define _SC_ADVISORY_INFO _SC_ADVISORY_INFO
_SC_AIO_LISTIO_MAX,
#define _SC_AIO_LISTIO_MAX _SC_AIO_LISTIO_MAX
_SC_AIO_MAX,
#define _SC_AIO_MAX _SC_AIO_MAX
_SC_AIO_PRIO_DELTA_MAX,
#define _SC_AIO_PRIO_DELTA_MAX _SC_AIO_PRIO_DELTA_MAX
_SC_ARG_MAX,
#define _SC_ARG_MAX _SC_ARG_MAX
_SC_ASYNCHRONOUS_IO,
#define _SC_ASYNCHRONOUS_IO _SC_ASYNCHRONOUS_IO
_SC_ATEXIT_MAX,
#define _SC_ATEXIT_MAX _SC_ATEXIT_MAX
_SC_BARRIERS,
#define _SC_BARRIERS _SC_BARRIERS
_SC_BC_BASE_MAX,
#define _SC_BC_BASE_MAX _SC_BC_BASE_MAX
_SC_BC_DIM_MAX,
#define _SC_BC_DIM_MAX _SC_BC_DIM_MAX
_SC_BC_SCALE_MAX,
#define _SC_BC_SCALE_MAX _SC_BC_SCALE_MAX
_SC_BC_STRING_MAX,
#define _SC_BC_STRING_MAX _SC_BC_STRING_MAX
_SC_CHILD_MAX,
#define _SC_CHILD_MAX _SC_CHILD_MAX
_SC_CLK_TCK,
#define _SC_CLK_TCK _SC_CLK_TCK
_SC_CLOCK_SELECTION,
#define _SC_CLOCK_SELECTION _SC_CLOCK_SELECTION
_SC_COLL_WEIGHTS_MAX,
#define _SC_COLL_WEIGHTS_MAX _SC_COLL_WEIGHTS_MAX
_SC_CPUTIME,
#define _SC_CPUTIME _SC_CPUTIME
_SC_DELAYTIMER_MAX,
#define _SC_DELAYTIMER_MAX _SC_DELAYTIMER_MAX
_SC_EXPR_NEST_MAX,
#define _SC_EXPR_NEST_MAX _SC_EXPR_NEST_MAX
_SC_FSYNC,
#define _SC_FSYNC _SC_FSYNC
_SC_GETGR_R_SIZE_MAX,
#define _SC_GETGR_R_SIZE_MAX _SC_GETGR_R_SIZE_MAX
_SC_GETPW_R_SIZE_MAX,
#define _SC_GETPW_R_SIZE_MAX _SC_GETPW_R_SIZE_MAX
_SC_HOST_NAME_MAX,
#define _SC_HOST_NAME_MAX _SC_HOST_NAME_MAX
_SC_IOV_MAX,
#define _SC_IOV_MAX _SC_IOV_MAX
_SC_IPV6,
#define _SC_IPV6 _SC_IPV6
_SC_JOB_CONTROL,
#define _SC_JOB_CONTROL _SC_JOB_CONTROL
_SC_LINE_MAX,
#define _SC_LINE_MAX _SC_LINE_MAX
_SC_LOGIN_NAME_MAX,
#define _SC_LOGIN_NAME_MAX _SC_LOGIN_NAME_MAX
_SC_MAPPED_FILES,
#define _SC_MAPPED_FILES _SC_MAPPED_FILES
_SC_MEMLOCK,
#define _SC_MEMLOCK _SC_MEMLOCK
_SC_MEMLOCK_RANGE,
#define _SC_MEMLOCK_RANGE _SC_MEMLOCK_RANGE
_SC_MEMORY_PROTECTION,
#define _SC_MEMORY_PROTECTION _SC_MEMORY_PROTECTION
_SC_MESSAGE_PASSING,
#define _SC_MESSAGE_PASSING _SC_MESSAGE_PASSING
_SC_MONOTONIC_CLOCK,
#define _SC_MONOTONIC_CLOCK _SC_MONOTONIC_CLOCK
_SC_MQ_OPEN_MAX,
#define _SC_MQ_OPEN_MAX _SC_MQ_OPEN_MAX
_SC_MQ_PRIO_MAX,
#define _SC_MQ_PRIO_MAX _SC_MQ_PRIO_MAX
_SC_NGROUPS_MAX,
#define _SC_NGROUPS_MAX _SC_NGROUPS_MAX
_SC_OPEN_MAX,
#define _SC_OPEN_MAX _SC_OPEN_MAX
_SC_PAGE_SIZE,
#define _SC_PAGE_SIZE _SC_PAGE_SIZE
_SC_PAGESIZE,
#define _SC_PAGESIZE _SC_PAGESIZE
_SC_PRIORITIZED_IO,
#define _SC_PRIORITIZED_IO _SC_PRIORITIZED_IO
_SC_PRIORITY_SCHEDULING,
#define _SC_PRIORITY_SCHEDULING _SC_PRIORITY_SCHEDULING
_SC_RAW_SOCKETS,
#define _SC_RAW_SOCKETS _SC_RAW_SOCKETS
_SC_RE_DUP_MAX,
#define _SC_RE_DUP_MAX _SC_RE_DUP_MAX
_SC_READER_WRITER_LOCKS,
#define _SC_READER_WRITER_LOCKS _SC_READER_WRITER_LOCKS
_SC_REALTIME_SIGNALS,
#define _SC_REALTIME_SIGNALS _SC_REALTIME_SIGNALS
_SC_REGEXP,
#define _SC_REGEXP _SC_REGEXP
_SC_RTSIG_MAX,
#define _SC_RTSIG_MAX _SC_RTSIG_MAX
_SC_SAVED_IDS,
#define _SC_SAVED_IDS _SC_SAVED_IDS
_SC_SEM_NSEMS_MAX,
#define _SC_SEM_NSEMS_MAX _SC_SEM_NSEMS_MAX
_SC_SEM_VALUE_MAX,
#define _SC_SEM_VALUE_MAX _SC_SEM_VALUE_MAX
_SC_SEMAPHORES,
#define _SC_SEMAPHORES _SC_SEMAPHORES
_SC_SHARED_MEMORY_OBJECTS,
#define _SC_SHARED_MEMORY_OBJECTS _SC_SHARED_MEMORY_OBJECTS
_SC_SHELL,
#define _SC_SHELL _SC_SHELL
_SC_SIGQUEUE_MAX,
#define _SC_SIGQUEUE_MAX _SC_SIGQUEUE_MAX
_SC_SPAWN,
#define _SC_SPAWN _SC_SPAWN
_SC_SPIN_LOCKS,
#define _SC_SPIN_LOCKS _SC_SPIN_LOCKS
_SC_SPORADIC_SERVER,
#define _SC_SPORADIC_SERVER _SC_SPORADIC_SERVER
_SC_SS_REPL_MAX,
#define _SC_SS_REPL_MAX _SC_SS_REPL_MAX
_SC_STREAM_MAX,
#define _SC_STREAM_MAX _SC_STREAM_MAX
_SC_SYMLOOP_MAX,
#define _SC_SYMLOOP_MAX _SC_SYMLOOP_MAX
_SC_SYNCHRONIZED_IO,
#define _SC_SYNCHRONIZED_IO _SC_SYNCHRONIZED_IO
_SC_THREAD_ATTR_STACKADDR,
#define _SC_THREAD_ATTR_STACKADDR _SC_THREAD_ATTR_STACKADDR
_SC_THREAD_ATTR_STACKSIZE,
#define _SC_THREAD_ATTR_STACKSIZE _SC_THREAD_ATTR_STACKSIZE
_SC_THREAD_CPUTIME,
#define _SC_THREAD_CPUTIME _SC_THREAD_CPUTIME
_SC_THREAD_DESTRUCTOR_ITERATIONS,
#define _SC_THREAD_DESTRUCTOR_ITERATIONS _SC_THREAD_DESTRUCTOR_ITERATIONS
_SC_THREAD_KEYS_MAX,
#define _SC_THREAD_KEYS_MAX _SC_THREAD_KEYS_MAX
_SC_THREAD_PRIO_INHERIT,
#define _SC_THREAD_PRIO_INHERIT _SC_THREAD_PRIO_INHERIT
_SC_THREAD_PRIO_PROTECT,
#define _SC_THREAD_PRIO_PROTECT _SC_THREAD_PRIO_PROTECT
_SC_THREAD_PRIORITY_SCHEDULING,
#define _SC_THREAD_PRIORITY_SCHEDULING _SC_THREAD_PRIORITY_SCHEDULING
_SC_THREAD_PROCESS_SHARED,
#define _SC_THREAD_PROCESS_SHARED _SC_THREAD_PROCESS_SHARED
_SC_THREAD_ROBUST_PRIO_INHERIT,
#define _SC_THREAD_ROBUST_PRIO_INHERIT _SC_THREAD_ROBUST_PRIO_INHERIT
_SC_THREAD_ROBUST_PRIO_PROTECT,
#define _SC_THREAD_ROBUST_PRIO_PROTECT _SC_THREAD_ROBUST_PRIO_PROTECT
_SC_THREAD_SAFE_FUNCTIONS,
#define _SC_THREAD_SAFE_FUNCTIONS _SC_THREAD_SAFE_FUNCTIONS
_SC_THREAD_SPORADIC_SERVER,
#define _SC_THREAD_SPORADIC_SERVER _SC_THREAD_SPORADIC_SERVER
_SC_THREAD_STACK_MIN,
#define _SC_THREAD_STACK_MIN _SC_THREAD_STACK_MIN
_SC_THREAD_THREADS_MAX,
#define _SC_THREAD_THREADS_MAX _SC_THREAD_THREADS_MAX
_SC_THREADS,
#define _SC_THREADS _SC_THREADS
_SC_TIMEOUTS,
#define _SC_TIMEOUTS _SC_TIMEOUTS
_SC_TIMER_MAX,
#define _SC_TIMER_MAX _SC_TIMER_MAX
_SC_TIMERS,
#define _SC_TIMERS _SC_TIMERS
_SC_TRACE,
#define _SC_TRACE _SC_TRACE
_SC_TRACE_EVENT_FILTER,
#define _SC_TRACE_EVENT_FILTER _SC_TRACE_EVENT_FILTER
_SC_TRACE_EVENT_NAME_MAX,
#define _SC_TRACE_EVENT_NAME_MAX _SC_TRACE_EVENT_NAME_MAX
_SC_TRACE_INHERIT,
#define _SC_TRACE_INHERIT _SC_TRACE_INHERIT
_SC_TRACE_LOG,
#define _SC_TRACE_LOG _SC_TRACE_LOG
_SC_TRACE_NAME_MAX,
#define _SC_TRACE_NAME_MAX _SC_TRACE_NAME_MAX
_SC_TRACE_SYS_MAX,
#define _SC_TRACE_SYS_MAX _SC_TRACE_SYS_MAX
_SC_TRACE_USER_EVENT_MAX,
#define _SC_TRACE_USER_EVENT_MAX _SC_TRACE_USER_EVENT_MAX
_SC_TTY_NAME_MAX,
#define _SC_TTY_NAME_MAX _SC_TTY_NAME_MAX
_SC_TYPED_MEMORY_OBJECTS,
#define _SC_TYPED_MEMORY_OBJECTS _SC_TYPED_MEMORY_OBJECTS
_SC_TZNAME_MAX,
#define _SC_TZNAME_MAX _SC_TZNAME_MAX
_SC_V7_ILP32_OFF32,
#define _SC_V7_ILP32_OFF32 _SC_V7_ILP32_OFF32
_SC_V7_ILP32_OFFBIG,
#define _SC_V7_ILP32_OFFBIG _SC_V7_ILP32_OFFBIG
_SC_V7_LP64_OFF64,
#define _SC_V7_LP64_OFF64 _SC_V7_LP64_OFF64
_SC_V7_LPBIG_OFFBIG,
#define _SC_V7_LPBIG_OFFBIG _SC_V7_LPBIG_OFFBIG
_SC_V6_ILP32_OFF32,
#define _SC_V6_ILP32_OFF32 _SC_V6_ILP32_OFF32
_SC_V6_ILP32_OFFBIG,
#define _SC_V6_ILP32_OFFBIG _SC_V6_ILP32_OFFBIG
_SC_V6_LP64_OFF64,
#define _SC_V6_LP64_OFF64 _SC_V6_LP64_OFF64
_SC_V6_LPBIG_OFFBIG,
#define _SC_V6_LPBIG_OFFBIG _SC_V6_LPBIG_OFFBIG
_SC_VERSION,
#define _SC_VERSION _SC_VERSION
_SC_XOPEN_CRYPT,
#define _SC_XOPEN_CRYPT _SC_XOPEN_CRYPT
_SC_XOPEN_ENH_I18N,
#define _SC_XOPEN_ENH_I18N _SC_XOPEN_ENH_I18N
_SC_XOPEN_REALTIME,
#define _SC_XOPEN_REALTIME _SC_XOPEN_REALTIME
_SC_XOPEN_REALTIME_THREADS,
#define _SC_XOPEN_REALTIME_THREADS _SC_XOPEN_REALTIME_THREADS
_SC_XOPEN_SHM,
#define _SC_XOPEN_SHM _SC_XOPEN_SHM
_SC_XOPEN_STREAMS,
#define _SC_XOPEN_STREAMS _SC_XOPEN_STREAMS
_SC_XOPEN_UNIX,
#define _SC_XOPEN_UNIX _SC_XOPEN_UNIX
_SC_XOPEN_UUCP,
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
_SC_XOPEN_VERSION,
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
};
#define F_OK 0x01

View File

@ -30,7 +30,7 @@ typedef __WINT_TYPE__ wint_t;
wint_t btowc(int c);
wint_t fgetwc(FILE* stream);
wchar_t* fgetws(wchar_t* __restrict ws, int n, FILE* __restrict stream);
wint_t fputwc(wchar_t c, FILE* stream);
wint_t fputwc(wchar_t wc, FILE* stream);
int fputws(const wchar_t* __restrict ws, FILE* __restrict stream);
int fwide(FILE* stream, int mode);
int fwprintf(FILE* __restrict stream, const wchar_t* __restrict format, ...);

View File

@ -1,56 +1,22 @@
#include <poll.h>
#include <sys/select.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
fd_set rfds, wfds, efds;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
for (nfds_t i = 0; i < nfds; i++)
fds[i].revents = 0;
constexpr short rmask = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLHUP;
constexpr short wmask = POLLOUT | POLLWRNORM | POLLWRBAND;
constexpr short emask = POLLERR;
int max_fd = 0;
for (nfds_t i = 0; i < nfds; i++)
{
if (fds[i].fd < 0)
continue;
if (fds[i].events & rmask)
FD_SET(fds[i].fd, &rfds);
if (fds[i].events & wmask)
FD_SET(fds[i].fd, &wfds);
if (fds[i].events & emask)
FD_SET(fds[i].fd, &efds);
if (fds[i].fd > max_fd)
max_fd = fds[i].fd;
}
timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = timeout % 1000 * 1000;
int nselect = select(max_fd + 1, &rfds, &wfds, &efds, &tv);
if (nselect == -1)
return -1;
for (nfds_t i = 0; i < nfds; i++)
{
if (fds[i].fd < 0)
continue;
if (FD_ISSET(fds[i].fd, &rfds))
fds[i].revents |= fds[i].events & rmask;
if (FD_ISSET(fds[i].fd, &wfds))
fds[i].revents |= fds[i].events & wmask;
if (FD_ISSET(fds[i].fd, &efds))
fds[i].revents |= fds[i].events & emask;
}
return nselect;
pthread_testcancel();
if (timeout < 0)
return ppoll(fds, nfds, nullptr, nullptr);
const timespec timeout_ts {
.tv_sec = static_cast<time_t>(timeout / 1000),
.tv_nsec = static_cast<long>(timeout % 1000),
};
return ppoll(fds, nfds, &timeout_ts, nullptr);
}
int ppoll(struct pollfd fds[], nfds_t nfds, const struct timespec* timeout, const sigset_t* sigmask)
{
pthread_testcancel();
return syscall(SYS_PPOLL, fds, nfds, timeout, sigmask);
}

View File

@ -4,6 +4,7 @@
#include <BAN/PlacementNew.h>
#include <kernel/Arch.h>
#include <kernel/Thread.h>
#include <errno.h>
#include <pthread.h>
@ -46,13 +47,14 @@ asm(
extern "C" void _pthread_trampoline_cpp(void* arg)
{
auto info = *reinterpret_cast<pthread_trampoline_info_t*>(arg);
info.uthread->id = syscall(SYS_PTHREAD_SELF);
syscall(SYS_SET_TLS, info.uthread);
free(arg);
pthread_exit(info.start_routine(info.arg));
ASSERT_NOT_REACHED();
}
static uthread* get_uthread()
uthread* _get_uthread()
{
uthread* result;
#if ARCH(x86_64)
@ -75,22 +77,13 @@ static void free_uthread(uthread* uthread)
munmap(tls_addr, tls_size);
}
#if not __disable_thread_local_storage
struct pthread_cleanup_t
{
void (*routine)(void*);
void* arg;
pthread_cleanup_t* next;
};
static thread_local pthread_cleanup_t* s_cleanup_stack = nullptr;
void pthread_cleanup_pop(int execute)
{
ASSERT(s_cleanup_stack);
uthread* uthread = _get_uthread();
ASSERT(uthread->cleanup_stack);
auto* cleanup = s_cleanup_stack;
s_cleanup_stack = cleanup->next;
auto* cleanup = uthread->cleanup_stack;
uthread->cleanup_stack = cleanup->next;
if (execute)
cleanup->routine(cleanup->arg);
@ -100,16 +93,17 @@ void pthread_cleanup_pop(int execute)
void pthread_cleanup_push(void (*routine)(void*), void* arg)
{
auto* cleanup = static_cast<pthread_cleanup_t*>(malloc(sizeof(pthread_cleanup_t)));
auto* cleanup = static_cast<_pthread_cleanup_t*>(malloc(sizeof(_pthread_cleanup_t)));
ASSERT(cleanup);
uthread* uthread = _get_uthread();
cleanup->routine = routine;
cleanup->arg = arg;
cleanup->next = s_cleanup_stack;
cleanup->next = uthread->cleanup_stack;
s_cleanup_stack = cleanup;
uthread->cleanup_stack = cleanup;
}
#endif
#if not __disable_thread_local_storage
static thread_local struct {
@ -175,38 +169,148 @@ int pthread_attr_destroy(pthread_attr_t* attr)
int pthread_attr_init(pthread_attr_t* attr)
{
*attr = 0;
return 0;
}
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize)
{
(void)attr;
(void)stacksize;
dwarnln("TODO: ignoring pthread_attr_setstacksize");
*attr = {
.inheritsched = PTHREAD_INHERIT_SCHED,
.schedparam = {},
.schedpolicy = SCHED_RR,
.detachstate = PTHREAD_CREATE_JOINABLE,
.scope = PTHREAD_SCOPE_SYSTEM,
.stacksize = Kernel::Thread::userspace_stack_size,
.guardsize = static_cast<size_t>(getpagesize()),
};
return 0;
}
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate)
{
(void)attr;
*detachstate = PTHREAD_CREATE_JOINABLE;
*detachstate = attr->detachstate;
return 0;
}
int pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate)
{
(void)attr;
switch (detachstate)
{
case PTHREAD_CREATE_DETACHED:
dwarnln("TODO: pthread_attr_setdetachstate");
return ENOTSUP;
case PTHREAD_CREATE_JOINABLE:
attr->detachstate = detachstate;
return 0;
default:
return EINVAL;
}
return EINVAL;
}
int pthread_attr_getguardsize(const pthread_attr_t* __restrict attr, size_t* __restrict guardsize)
{
*guardsize = attr->guardsize;
return 0;
}
int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guardsize)
{
attr->guardsize = guardsize;
return 0;
}
int pthread_attr_getinheritsched(const pthread_attr_t* __restrict attr, int* __restrict inheritsched)
{
*inheritsched = attr->inheritsched;
return 0;
}
int pthread_attr_setinheritsched(pthread_attr_t* attr, int inheritsched)
{
switch (inheritsched)
{
case PTHREAD_INHERIT_SCHED:
case PTHREAD_EXPLICIT_SCHED:
attr->inheritsched = inheritsched;
return 0;
}
return EINVAL;
}
int pthread_attr_getschedparam(const pthread_attr_t* __restrict attr, struct sched_param* __restrict param)
{
*param = attr->schedparam;
return 0;
}
int pthread_attr_setschedparam(pthread_attr_t* __restrict attr, const struct sched_param* __restrict param)
{
attr->schedparam = *param;
return 0;
}
int pthread_attr_getschedpolicy(const pthread_attr_t* __restrict attr, int* __restrict policy)
{
*policy = attr->schedpolicy;
return 0;
}
int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)
{
switch (policy)
{
case SCHED_FIFO:
case SCHED_SPORADIC:
case SCHED_OTHER:
return ENOTSUP;
case SCHED_RR:
attr->schedpolicy = policy;
return 0;
}
return EINVAL;
}
int pthread_attr_getscope(const pthread_attr_t* __restrict attr, int* __restrict contentionscope)
{
*contentionscope = attr->scope;
return 0;
}
int pthread_attr_setscope(pthread_attr_t* attr, int contentionscope)
{
switch (contentionscope)
{
case PTHREAD_SCOPE_PROCESS:
return ENOTSUP;
case PTHREAD_SCOPE_SYSTEM:
attr->scope = contentionscope;
return 0;
}
return EINVAL;
}
int pthread_attr_getstack(const pthread_attr_t* __restrict attr, void** __restrict stackaddr, size_t* __restrict stacksize)
{
(void)attr;
(void)stackaddr;
(void)stacksize;
dwarnln("TODO: pthread_attr_getstack");
return ENOTSUP;
}
int pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize)
{
(void)attr;
(void)stackaddr;
(void)stacksize;
dwarnln("TODO: pthread_attr_setstack");
return ENOTSUP;
}
int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __restrict stacksize)
{
*stacksize = attr->stacksize;
return 0;
}
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize)
{
attr->stacksize = stacksize;
return 0;
}
int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
@ -223,14 +327,23 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest
long syscall_ret = 0;
if (uthread* self = get_uthread(); self->master_tls_addr == nullptr)
if (uthread* self = _get_uthread(); self->master_tls_addr == nullptr)
{
uthread* uthread = static_cast<struct uthread*>(malloc(sizeof(struct uthread) + sizeof(uintptr_t)));
if (uthread == nullptr)
goto pthread_create_error;
uthread->self = uthread;
uthread->master_tls_addr = nullptr;
uthread->master_tls_size = 0;
*uthread = {
.self = uthread,
.master_tls_addr = nullptr,
.master_tls_size = 0,
.cleanup_stack = nullptr,
.id = -1,
.errno_ = 0,
.cancel_type = PTHREAD_CANCEL_DEFERRED,
.cancel_state = PTHREAD_CANCEL_ENABLE,
.canceled = false,
};
uthread->dtv[0] = 0;
info->uthread = uthread;
@ -249,9 +362,17 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest
memcpy(tls_addr, self->master_tls_addr, self->master_tls_size);
uthread* uthread = reinterpret_cast<struct uthread*>(tls_addr + self->master_tls_size);
uthread->self = uthread;
uthread->master_tls_addr = self->master_tls_addr;
uthread->master_tls_size = self->master_tls_size;
*uthread = {
.self = uthread,
.master_tls_addr = self->master_tls_addr,
.master_tls_size = self->master_tls_size,
.cleanup_stack = nullptr,
.id = -1,
.errno_ = 0,
.cancel_type = PTHREAD_CANCEL_DEFERRED,
.cancel_state = PTHREAD_CANCEL_ENABLE,
.canceled = 0,
};
const uintptr_t self_addr = reinterpret_cast<uintptr_t>(self);
const uintptr_t uthread_addr = reinterpret_cast<uintptr_t>(uthread);
@ -288,9 +409,11 @@ int pthread_detach(pthread_t thread)
void pthread_exit(void* value_ptr)
{
#if not __disable_thread_local_storage
while (s_cleanup_stack)
uthread* uthread = _get_uthread();
while (uthread->cleanup_stack)
pthread_cleanup_pop(1);
#if not __disable_thread_local_storage
for (size_t iteration = 0; iteration < PTHREAD_DESTRUCTOR_ITERATIONS; iteration++)
{
bool called = false;
@ -309,7 +432,8 @@ void pthread_exit(void* value_ptr)
break;
}
#endif
free_uthread(get_uthread());
free_uthread(uthread);
syscall(SYS_PTHREAD_EXIT, value_ptr);
ASSERT_NOT_REACHED();
}
@ -321,19 +445,13 @@ int pthread_equal(pthread_t t1, pthread_t t2)
int pthread_join(pthread_t thread, void** value_ptr)
{
pthread_testcancel();
return syscall(SYS_PTHREAD_JOIN, thread, value_ptr);
}
pthread_t pthread_self(void)
{
#if __disable_thread_local_storage
return syscall(SYS_PTHREAD_SELF);
#else
static thread_local pthread_t s_pthread_self { -1 };
if (s_pthread_self == -1) [[unlikely]]
s_pthread_self = syscall(SYS_PTHREAD_SELF);
return s_pthread_self;
#endif
return _get_uthread()->id;
}
int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
@ -352,6 +470,168 @@ int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
return 0;
}
struct pthread_atfork_t
{
void (*function)();
pthread_atfork_t* next;
};
static pthread_atfork_t* s_atfork_prepare = nullptr;
static pthread_atfork_t* s_atfork_parent = nullptr;
static pthread_atfork_t* s_atfork_child = nullptr;
static pthread_mutex_t s_atfork_mutex = PTHREAD_MUTEX_INITIALIZER;
void _pthread_call_atfork(int state)
{
pthread_mutex_lock(&s_atfork_mutex);
pthread_atfork_t* list = nullptr;
switch (state)
{
case _PTHREAD_ATFORK_PREPARE: list = s_atfork_prepare; break;
case _PTHREAD_ATFORK_PARENT: list = s_atfork_parent; break;
case _PTHREAD_ATFORK_CHILD: list = s_atfork_child; break;
default:
ASSERT_NOT_REACHED();
}
for (; list; list = list->next)
list->function();
pthread_mutex_unlock(&s_atfork_mutex);
}
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void))
{
pthread_atfork_t* prepare_entry = nullptr;
if (prepare != nullptr)
prepare_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
pthread_atfork_t* parent_entry = nullptr;
if (parent != nullptr)
parent_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
pthread_atfork_t* child_entry = nullptr;
if (child != nullptr)
child_entry = static_cast<pthread_atfork_t*>(malloc(sizeof(pthread_attr_t)));
if ((prepare && !prepare_entry) || (parent && !parent_entry) || (child && !child_entry))
{
if (prepare_entry)
free(prepare_entry);
if (parent_entry)
free(parent_entry);
if (child_entry)
free(child_entry);
return ENOMEM;
}
const auto prepend_atfork =
[](pthread_atfork_t*& list, pthread_atfork_t* entry)
{
entry->next = list;
list = entry;
};
const auto append_atfork =
[](pthread_atfork_t*& list, pthread_atfork_t* entry)
{
while (list)
list = list->next;
entry->next = nullptr;
list = entry;
};
pthread_mutex_lock(&s_atfork_mutex);
if (prepare_entry)
{
prepare_entry->function = prepare;
prepend_atfork(s_atfork_prepare, prepare_entry);
}
if (parent_entry)
{
parent_entry->function = parent;
append_atfork(s_atfork_parent, parent_entry);
}
if (child_entry)
{
child_entry->function = parent;
append_atfork(s_atfork_child, child_entry);
}
pthread_mutex_unlock(&s_atfork_mutex);
return 0;
}
static void pthread_cancel_handler(int)
{
uthread* uthread = _get_uthread();
BAN::atomic_store(uthread->canceled, true);
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
return;
switch (BAN::atomic_load(uthread->cancel_type))
{
case PTHREAD_CANCEL_ASYNCHRONOUS:
pthread_exit(PTHREAD_CANCELED);
case PTHREAD_CANCEL_DEFERRED:
return;
}
ASSERT_NOT_REACHED();
}
int pthread_cancel(pthread_t thread)
{
signal(SIGCANCEL, &pthread_cancel_handler);
return pthread_kill(thread, SIGCANCEL);
}
int pthread_setcancelstate(int state, int* oldstate)
{
switch (state)
{
case PTHREAD_CANCEL_ENABLE:
case PTHREAD_CANCEL_DISABLE:
break;
default:
return EINVAL;
}
BAN::atomic_exchange(_get_uthread()->cancel_state, state);
if (oldstate)
*oldstate = state;
return 0;
}
int pthread_setcanceltype(int type, int* oldtype)
{
switch (type)
{
case PTHREAD_CANCEL_DEFERRED:
case PTHREAD_CANCEL_ASYNCHRONOUS:
break;
default:
return EINVAL;
}
BAN::atomic_exchange(_get_uthread()->cancel_type, type);
if (oldtype)
*oldtype = type;
return 0;
}
void pthread_testcancel(void)
{
uthread* uthread = _get_uthread();
if (BAN::atomic_load(uthread->cancel_state) != PTHREAD_CANCEL_ENABLE)
return;
if (!BAN::atomic_load(uthread->canceled))
return;
pthread_exit(PTHREAD_CANCELED);
}
int pthread_spin_destroy(pthread_spinlock_t* lock)
{
(void)lock;
@ -732,7 +1012,7 @@ int pthread_condattr_getpshared(const pthread_condattr_t* __restrict attr, int*
return 0;
}
int pthread_condattr_setpshared(pthread_barrierattr_t* attr, int pshared)
int pthread_condattr_setpshared(pthread_condattr_t* attr, int pshared)
{
switch (pshared)
{
@ -788,11 +1068,14 @@ int pthread_cond_signal(pthread_cond_t* cond)
int pthread_cond_wait(pthread_cond_t* __restrict cond, pthread_mutex_t* __restrict mutex)
{
// pthread_testcancel in pthread_cond_timedwait
return pthread_cond_timedwait(cond, mutex, nullptr);
}
int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __restrict mutex, const struct timespec* __restrict abstime)
{
pthread_testcancel();
constexpr auto has_timed_out =
[](const struct timespec* abstime, clockid_t clock_id) -> bool
{
@ -925,7 +1208,7 @@ struct tls_index
extern "C" void* __tls_get_addr(tls_index* ti)
{
return reinterpret_cast<void*>(get_uthread()->dtv[ti->ti_module] + ti->ti_offset);
return reinterpret_cast<void*>(_get_uthread()->dtv[ti->ti_module] + ti->ti_offset);
}
#if ARCH(i686)

View File

@ -38,9 +38,18 @@ void psignal(int signum, const char* message)
fprintf(stderr, "%s\n", strsignal(signum));
}
int pthread_kill(pthread_t thread, int sig)
{
if (syscall(SYS_PTHREAD_KILL, thread, sig) == -1)
return errno;
return 0;
}
int pthread_sigmask(int how, const sigset_t* __restrict set, sigset_t* __restrict oset)
{
return syscall(SYS_SIGPROCMASK, how, set, oset);
if (syscall(SYS_SIGPROCMASK, how, set, oset) == -1)
return errno;
return 0;
}
int raise(int sig)
@ -138,7 +147,12 @@ int sigpending(sigset_t* set)
int sigprocmask(int how, const sigset_t* __restrict set, sigset_t* __restrict oset)
{
return pthread_sigmask(how, set, oset);
if (int error = pthread_sigmask(how, set, oset))
{
errno = error;
return -1;
}
return 0;
}
int sigrelse(int sig)

View File

@ -190,6 +190,8 @@ int strcoll_l(const char *s1, const char *s2, locale_t locale)
u1 += BAN::UTF8::byte_length(*u1);
u2 += BAN::UTF8::byte_length(*u2);
}
// TODO: this isn't really correct :D
return wc1 - wc2;
}
}
@ -364,6 +366,19 @@ char* strtok_r(char* __restrict str, const char* __restrict sep, char** __restri
#undef CHAR_BITMASK
#undef CHAR_BITMASK_TEST
size_t strxfrm(char* __restrict s1, const char* __restrict s2, size_t n)
{
return strxfrm_l(s1, s2, n, __getlocale(LC_COLLATE));
}
size_t strxfrm_l(char* __restrict s1, const char* __restrict s2, size_t n, locale_t locale)
{
(void)locale;
// TODO: this isn't really correct :D
strncpy(s1, s2, n);
return strlen(s2);
}
char* strsignal(int signum)
{
static char buffer[128];

View File

@ -1,3 +1,4 @@
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
@ -25,6 +26,7 @@ int munmap(void* addr, size_t len)
int msync(void* addr, size_t len, int flags)
{
pthread_testcancel();
return syscall(SYS_MSYNC, addr, len, flags);
}

View File

@ -1,9 +1,11 @@
#include <pthread.h>
#include <sys/select.h>
#include <sys/syscall.h>
#include <unistd.h>
int pselect(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, const struct timespec* __restrict timeout, const sigset_t* __restrict sigmask)
{
pthread_testcancel();
sys_pselect_t arguments {
.nfds = nfds,
.readfds = readfds,
@ -17,6 +19,7 @@ int pselect(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, f
int select(int nfds, fd_set* __restrict readfds, fd_set* __restrict writefds, fd_set* __restrict errorfds, struct timeval* __restrict timeout)
{
pthread_testcancel();
timespec* pts = nullptr;
timespec ts;
if (timeout)

View File

@ -1,14 +1,17 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <unistd.h>
int accept(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
{
pthread_testcancel();
return accept4(socket, address, address_len, 0);
}
int accept4(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len, int flags)
{
pthread_testcancel();
return syscall(SYS_ACCEPT, socket, address, address_len, flags);
}
@ -19,6 +22,7 @@ int bind(int socket, const struct sockaddr* address, socklen_t address_len)
int connect(int socket, const struct sockaddr* address, socklen_t address_len)
{
pthread_testcancel();
return syscall(SYS_CONNECT, socket, address, address_len);
}
@ -29,11 +33,13 @@ int listen(int socket, int backlog)
ssize_t recv(int socket, void* __restrict buffer, size_t length, int flags)
{
pthread_testcancel();
return recvfrom(socket, buffer, length, flags, nullptr, nullptr);
}
ssize_t recvfrom(int socket, void* __restrict buffer, size_t length, int flags, struct sockaddr* __restrict address, socklen_t* __restrict address_len)
{
pthread_testcancel();
sys_recvfrom_t arguments {
.socket = socket,
.buffer = buffer,
@ -47,11 +53,13 @@ ssize_t recvfrom(int socket, void* __restrict buffer, size_t length, int flags,
ssize_t send(int socket, const void* message, size_t length, int flags)
{
pthread_testcancel();
return sendto(socket, message, length, flags, nullptr, 0);
}
ssize_t sendto(int socket, const void* message, size_t length, int flags, const struct sockaddr* dest_addr, socklen_t dest_len)
{
pthread_testcancel();
sys_sendto_t arguments {
.socket = socket,
.message = message,

View File

@ -53,3 +53,13 @@ int mkdir(const char* path, mode_t mode)
{
return syscall(SYS_CREATE_DIR, path, __UMASKED_MODE(mode));
}
int futimens(int fd, const struct timespec times[2])
{
return utimensat(fd, nullptr, times, 0);
}
int utimensat(int fd, const char* path, const struct timespec times[2], int flag)
{
return syscall(SYS_UTIMENSAT, fd, path, times, flag);
}

View File

@ -1,3 +1,4 @@
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <time.h>
@ -26,3 +27,20 @@ int setitimer(int which, const struct itimerval* __restrict value, struct itimer
{
return syscall(SYS_SETITIMER, which, value, ovalue);
}
int utimes(const char* path, const struct timeval times[2])
{
if (times == nullptr)
return utimensat(AT_FDCWD, path, nullptr, 0);
const timespec times_ts[2] {
timespec {
.tv_sec = times[0].tv_sec,
.tv_nsec = times[0].tv_usec * 1000,
},
timespec {
.tv_sec = times[1].tv_sec,
.tv_nsec = times[1].tv_usec * 1000,
},
};
return utimensat(AT_FDCWD, path, times_ts, 0);
}

View File

@ -1,8 +1,11 @@
#include <pthread.h>
#include <sys/uio.h>
#include <unistd.h>
ssize_t readv(int fildes, const struct iovec* iov, int iovcnt)
{
pthread_testcancel();
size_t result = 0;
for (int i = 0; i < iovcnt; i++)
{
@ -25,6 +28,8 @@ ssize_t readv(int fildes, const struct iovec* iov, int iovcnt)
ssize_t writev(int fildes, const struct iovec* iov, int iovcnt)
{
pthread_testcancel();
size_t result = 0;
for (int i = 0; i < iovcnt; i++)
{

View File

@ -1,13 +1,16 @@
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t wait(int* stat_loc)
{
pthread_testcancel();
return waitpid(-1, stat_loc, 0);
}
pid_t waitpid(pid_t pid, int* stat_loc, int options)
{
pthread_testcancel();
return (pid_t)syscall(SYS_WAIT, pid, stat_loc, options);
}

View File

@ -2,6 +2,7 @@
#include <BAN/Debug.h>
#include <errno.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <termios.h>
#include <unistd.h>
@ -64,9 +65,19 @@ int cfsetospeed(struct termios* termios, speed_t speed)
return 0;
}
int tcdrain(int);
int tcdrain(int fd)
{
pthread_testcancel();
int tcflow(int, int);
dwarnln("TODO: tcdrain({})", fd);
return 0;
}
int tcflow(int fd, int action)
{
dwarnln("TODO: tcflow({}, {})", fd, action);
return -1;
}
int tcflush(int fd, int queue_selector)
{
@ -81,7 +92,11 @@ int tcgetattr(int fildes, struct termios* termios)
pid_t tcgetsid(int);
int tcsendbreak(int, int);
int tcsendbreak(int fd, int duration)
{
dwarnln("FIXME: tcsendbreak({}, {})", fd, duration);
return -1;
}
int tcsetattr(int fildes, int optional_actions, const struct termios* termios)
{

View File

@ -4,6 +4,7 @@
#include <ctype.h>
#include <errno.h>
#include <langinfo.h>
#include <pthread.h>
#include <string.h>
#include <sys/syscall.h>
#include <time.h>
@ -20,6 +21,7 @@ int clock_gettime(clockid_t clock_id, struct timespec* tp)
int nanosleep(const struct timespec* rqtp, struct timespec* rmtp)
{
pthread_testcancel();
return syscall(SYS_NANOSLEEP, rqtp, rmtp);
}

View File

@ -34,7 +34,16 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
if (::environ == nullptr)
::environ = environ;
if (syscall(SYS_GET_TLS) == 0)
if (uthread* self = reinterpret_cast<uthread*>(syscall(SYS_GET_TLS)))
{
self->cleanup_stack = nullptr;
self->id = syscall(SYS_PTHREAD_SELF);
self->errno_ = 0;
self->cancel_type = PTHREAD_CANCEL_DEFERRED;
self->cancel_state = PTHREAD_CANCEL_ENABLE;
self->canceled = false;
}
else
{
alignas(uthread) static uint8_t storage[sizeof(uthread) + sizeof(uintptr_t)];
@ -43,6 +52,12 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
.self = &uthread,
.master_tls_addr = nullptr,
.master_tls_size = 0,
.cleanup_stack = nullptr,
.id = static_cast<pthread_t>(syscall(SYS_PTHREAD_SELF)),
.errno_ = 0,
.cancel_type = PTHREAD_CANCEL_DEFERRED,
.cancel_state = PTHREAD_CANCEL_ENABLE,
.canceled = false,
};
uthread.dtv[0] = 0;
@ -99,16 +114,19 @@ long syscall(long syscall, ...)
int close(int fd)
{
pthread_testcancel();
return syscall(SYS_CLOSE, fd);
}
ssize_t read(int fildes, void* buf, size_t nbyte)
{
pthread_testcancel();
return syscall(SYS_READ, fildes, buf, nbyte);
}
ssize_t write(int fildes, const void* buf, size_t nbyte)
{
pthread_testcancel();
return syscall(SYS_WRITE, fildes, buf, nbyte);
}
@ -124,11 +142,13 @@ ssize_t readlinkat(int fd, const char* __restrict path, char* __restrict buf, si
ssize_t pread(int fildes, void* buf, size_t nbyte, off_t offset)
{
pthread_testcancel();
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
}
ssize_t pwrite(int fildes, const void* buf, size_t nbyte, off_t offset)
{
pthread_testcancel();
return syscall(SYS_PWRITE, fildes, buf, nbyte, offset);
}
@ -137,13 +157,24 @@ off_t lseek(int fildes, off_t offset, int whence)
return syscall(SYS_SEEK, fildes, offset, whence);
}
int truncate(const char* path, off_t length)
{
const int fd = open(path, O_WRONLY);
if (fd == -1)
return -1;
int ret = ftruncate(fd, length);
close(fd);
return ret;
}
int ftruncate(int fildes, off_t length)
{
return syscall(SYS_TRUNCATE, fildes, length);
return syscall(SYS_FTRUNCATE, fildes, length);
}
int fsync(int fildes)
{
pthread_testcancel();
return syscall(SYS_FSYNC, fildes);
}
@ -402,7 +433,12 @@ int execvp(const char* pathname, char* const argv[])
pid_t fork(void)
{
return syscall(SYS_FORK);
_pthread_call_atfork(_PTHREAD_ATFORK_PREPARE);
const pid_t pid = syscall(SYS_FORK);
if (pid == -1)
return -1;
_pthread_call_atfork(pid ? _PTHREAD_ATFORK_PARENT : _PTHREAD_ATFORK_CHILD);
return pid;
}
int pipe(int fildes[2])
@ -412,6 +448,7 @@ int pipe(int fildes[2])
unsigned int sleep(unsigned int seconds)
{
pthread_testcancel();
unsigned int ret = syscall(SYS_SLEEP, seconds);
if (ret > 0)
errno = EINTR;
@ -480,14 +517,28 @@ void syncsync(int should_block)
syscall(SYS_SYNC, should_block);
}
int fdatasync(int fildes)
{
pthread_testcancel();
(void)fildes;
dprintln("TODO: fdatasync");
return syscall(SYS_SYNC, true);
}
int unlink(const char* path)
{
return syscall(SYS_UNLINK, path);
return unlinkat(AT_FDCWD, path, 0);
}
int unlinkat(int fd, const char* path, int flag)
{
return syscall(SYS_UNLINKAT, fd, path, flag);
}
int rmdir(const char* path)
{
return syscall(SYS_UNLINK, path);
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
}
char* optarg = nullptr;
@ -771,3 +822,199 @@ int linkat(int fd1, const char *path1, int fd2, const char *path2, int flag)
{
return syscall(SYS_HARDLINKAT, fd1, path1, fd2, path2, flag);
}
size_t confstr(int name, char* buf, size_t len)
{
(void)buf;
(void)len;
switch (name)
{
#define CONFSTR_CASE(name) case name: return 0;
CONFSTR_CASE(_CS_PATH)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFF32_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFF32_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFF32_LIBS)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_ILP32_OFFBIG_LIBS)
CONFSTR_CASE(_CS_POSIX_V6_LP64_OFF64_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_LP64_OFF64_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_LP64_OFF64_LIBS)
CONFSTR_CASE(_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V6_LPBIG_OFFBIG_LIBS)
CONFSTR_CASE(_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS)
CONFSTR_CASE(_CS_V6_ENV)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFF32_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFF32_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFF32_LIBS)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_ILP32_OFFBIG_LIBS)
CONFSTR_CASE(_CS_POSIX_V7_LP64_OFF64_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_LP64_OFF64_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_LP64_OFF64_LIBS)
CONFSTR_CASE(_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_LPBIG_OFFBIG_LIBS)
CONFSTR_CASE(_CS_POSIX_V7_THREADS_CFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_THREADS_LDFLAGS)
CONFSTR_CASE(_CS_POSIX_V7_WIDTH_RESTRICTED_ENVS)
CONFSTR_CASE(_CS_V7_ENV)
#undef CONFSTR_CASE
}
errno = EINVAL;
return 0;
}
long pathconf(const char* path, int name);
long sysconf(int name)
{
switch (name)
{
#define POSIX2_CASE(name) case _SC_2_##name: return _POSIX2_##name;
POSIX2_CASE(C_BIND)
POSIX2_CASE(C_DEV)
POSIX2_CASE(CHAR_TERM)
POSIX2_CASE(FORT_DEV)
POSIX2_CASE(FORT_RUN)
POSIX2_CASE(LOCALEDEF)
POSIX2_CASE(PBS)
POSIX2_CASE(PBS_ACCOUNTING)
POSIX2_CASE(PBS_CHECKPOINT)
POSIX2_CASE(PBS_LOCATE)
POSIX2_CASE(PBS_MESSAGE)
POSIX2_CASE(PBS_TRACK)
POSIX2_CASE(SW_DEV)
POSIX2_CASE(UPE)
POSIX2_CASE(VERSION)
#undef POSIX2_CASE
#define POSIX_CASE(name) case _SC_##name: return _POSIX_##name;
POSIX_CASE(ADVISORY_INFO)
POSIX_CASE(AIO_LISTIO_MAX)
POSIX_CASE(AIO_MAX)
POSIX_CASE(ARG_MAX)
POSIX_CASE(ASYNCHRONOUS_IO)
POSIX_CASE(BARRIERS)
POSIX_CASE(CHILD_MAX)
POSIX_CASE(CLOCK_SELECTION)
POSIX_CASE(CPUTIME)
POSIX_CASE(DELAYTIMER_MAX)
POSIX_CASE(FSYNC)
POSIX_CASE(HOST_NAME_MAX)
POSIX_CASE(IPV6)
POSIX_CASE(JOB_CONTROL)
POSIX_CASE(LOGIN_NAME_MAX)
POSIX_CASE(MAPPED_FILES)
POSIX_CASE(MEMLOCK)
POSIX_CASE(MEMLOCK_RANGE)
POSIX_CASE(MEMORY_PROTECTION)
POSIX_CASE(MESSAGE_PASSING)
POSIX_CASE(MONOTONIC_CLOCK)
POSIX_CASE(MQ_OPEN_MAX)
POSIX_CASE(MQ_PRIO_MAX)
POSIX_CASE(NGROUPS_MAX)
POSIX_CASE(OPEN_MAX)
POSIX_CASE(PRIORITIZED_IO)
POSIX_CASE(PRIORITY_SCHEDULING)
POSIX_CASE(RAW_SOCKETS)
POSIX_CASE(RE_DUP_MAX)
POSIX_CASE(READER_WRITER_LOCKS)
POSIX_CASE(REALTIME_SIGNALS)
POSIX_CASE(REGEXP)
POSIX_CASE(RTSIG_MAX)
POSIX_CASE(SAVED_IDS)
POSIX_CASE(SEM_NSEMS_MAX)
POSIX_CASE(SEM_VALUE_MAX)
POSIX_CASE(SEMAPHORES)
POSIX_CASE(SHARED_MEMORY_OBJECTS)
POSIX_CASE(SHELL)
POSIX_CASE(SIGQUEUE_MAX)
POSIX_CASE(SPAWN)
POSIX_CASE(SPIN_LOCKS)
POSIX_CASE(SPORADIC_SERVER)
POSIX_CASE(SS_REPL_MAX)
POSIX_CASE(STREAM_MAX)
POSIX_CASE(SYMLOOP_MAX)
POSIX_CASE(SYNCHRONIZED_IO)
POSIX_CASE(THREAD_ATTR_STACKADDR)
POSIX_CASE(THREAD_ATTR_STACKSIZE)
POSIX_CASE(THREAD_CPUTIME)
POSIX_CASE(THREAD_DESTRUCTOR_ITERATIONS)
POSIX_CASE(THREAD_KEYS_MAX)
POSIX_CASE(THREAD_PRIO_INHERIT)
POSIX_CASE(THREAD_PRIO_PROTECT)
POSIX_CASE(THREAD_PRIORITY_SCHEDULING)
POSIX_CASE(THREAD_PROCESS_SHARED)
POSIX_CASE(THREAD_ROBUST_PRIO_INHERIT)
POSIX_CASE(THREAD_ROBUST_PRIO_PROTECT)
POSIX_CASE(THREAD_SAFE_FUNCTIONS)
POSIX_CASE(THREAD_SPORADIC_SERVER)
POSIX_CASE(THREAD_THREADS_MAX)
POSIX_CASE(THREADS)
POSIX_CASE(TIMEOUTS)
POSIX_CASE(TIMER_MAX)
POSIX_CASE(TIMERS)
POSIX_CASE(TRACE)
POSIX_CASE(TRACE_EVENT_FILTER)
POSIX_CASE(TRACE_EVENT_NAME_MAX)
POSIX_CASE(TRACE_INHERIT)
POSIX_CASE(TRACE_LOG)
POSIX_CASE(TRACE_NAME_MAX)
POSIX_CASE(TRACE_SYS_MAX)
POSIX_CASE(TRACE_USER_EVENT_MAX)
POSIX_CASE(TTY_NAME_MAX)
POSIX_CASE(TYPED_MEMORY_OBJECTS)
POSIX_CASE(TZNAME_MAX)
POSIX_CASE(V7_ILP32_OFF32)
POSIX_CASE(V7_ILP32_OFFBIG)
POSIX_CASE(V7_LP64_OFF64)
POSIX_CASE(V7_LPBIG_OFFBIG)
POSIX_CASE(V6_ILP32_OFF32)
POSIX_CASE(V6_ILP32_OFFBIG)
POSIX_CASE(V6_LP64_OFF64)
POSIX_CASE(V6_LPBIG_OFFBIG)
POSIX_CASE(VERSION)
#undef POSIX_CASE
#define LIMITS_CASE(name) case _SC_##name: return name;
LIMITS_CASE(AIO_PRIO_DELTA_MAX)
LIMITS_CASE(ATEXIT_MAX)
LIMITS_CASE(BC_BASE_MAX)
LIMITS_CASE(BC_DIM_MAX)
LIMITS_CASE(BC_SCALE_MAX)
LIMITS_CASE(BC_STRING_MAX)
LIMITS_CASE(COLL_WEIGHTS_MAX)
LIMITS_CASE(EXPR_NEST_MAX)
LIMITS_CASE(IOV_MAX)
LIMITS_CASE(LINE_MAX)
#undef LIMITS_CASE
#define XOPEN_CASE(name) case _SC_XOPEN_##name: return _XOPEN_##name;
XOPEN_CASE(CRYPT)
XOPEN_CASE(ENH_I18N)
XOPEN_CASE(REALTIME)
XOPEN_CASE(REALTIME_THREADS)
XOPEN_CASE(SHM)
XOPEN_CASE(STREAMS)
XOPEN_CASE(UNIX)
XOPEN_CASE(UUCP)
XOPEN_CASE(VERSION)
#undef XOPEN_CASE
case _SC_PAGE_SIZE:
case _SC_PAGESIZE: return getpagesize();
case _SC_CLK_TCK: return 100;
case _SC_GETGR_R_SIZE_MAX: return 1024;
case _SC_GETPW_R_SIZE_MAX: return 1024;
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
}
errno = EINVAL;
return -1;
}

View File

@ -1,11 +1,20 @@
#include <utime.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <utime.h>
int utime(const char* filename, const struct utimbuf* times)
{
fprintf(stddbg, "TODO: utime(\"%s\", %p)\n", filename, times);
struct stat st;
return stat(filename, &st);
if (times == nullptr)
return utimensat(AT_FDCWD, filename, nullptr, 0);
const timespec times_ts[2] {
timespec {
.tv_sec = times->actime,
.tv_nsec = 0,
},
timespec {
.tv_sec = times->modtime,
.tv_nsec = 0,
},
};
return utimensat(AT_FDCWD, filename, times_ts, 0);
}

View File

@ -0,0 +1,102 @@
#include <BAN/UTF8.h>
#include <errno.h>
#include <wchar.h>
struct FILEScopeLock
{
FILEScopeLock(FILE* stream)
: m_stream(stream)
{
flockfile(m_stream);
}
~FILEScopeLock()
{
funlockfile(m_stream);
}
FILE* m_stream;
};
wint_t getwc(FILE* stream)
{
return fgetwc(stream);
}
wint_t fgetwc(FILE* stream)
{
FILEScopeLock _(stream);
char buffer[4];
buffer[0] = getc_unlocked(stream);
if (buffer[0] == EOF)
return WEOF;
const auto length = BAN::UTF8::byte_length(buffer[0]);
if (length == BAN::UTF8::invalid)
{
errno = EILSEQ;
return WEOF;
}
for (uint32_t i = 1; i < length; i++)
if ((buffer[i] = getc_unlocked(stream)) == EOF)
return WEOF;
const auto ret = BAN::UTF8::to_codepoint(buffer);
if (ret == BAN::UTF8::invalid)
{
errno = EILSEQ;
return WEOF;
}
return ret;
}
wint_t putwc(wchar_t wc, FILE* stream)
{
return fputwc(wc, stream);
}
wint_t fputwc(wchar_t wc, FILE* stream)
{
char buffer[4];
if (!BAN::UTF8::from_codepoints(&wc, 1, buffer))
{
errno = EILSEQ;
return WEOF;
}
FILEScopeLock _(stream);
const auto bytes = BAN::UTF8::byte_length(buffer[0]);
for (uint32_t i = 0; i < bytes; i++)
if (putc_unlocked(buffer[i], stream) == EOF)
return WEOF;
return wc;
}
wint_t ungetwc(wint_t wc, FILE* stream)
{
char buffer[4];
if (!BAN::UTF8::from_codepoints(&wc, 1, buffer))
{
errno = EILSEQ;
return WEOF;
}
FILEScopeLock _(stream);
const auto bytes = BAN::UTF8::byte_length(buffer[0]);
for (uint32_t i = 0; i < bytes; i++)
{
if (ungetc(buffer[i], stream) != EOF)
continue;
for (uint32_t j = 0; j < i; j++)
fgetc(stream);
return WEOF;
}
return wc;
}

View File

@ -1,10 +1,112 @@
#include <BAN/Assert.h>
#include <BAN/UTF8.h>
#include <errno.h>
#include <locale.h>
#include <wchar.h>
size_t mbrtowc(wchar_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict)
wint_t btowc(int c)
{
ASSERT_NOT_REACHED();
if (c == 0 || c > 0x7F)
return WEOF;
return c;
}
int wctob(wint_t c)
{
if (c > 0x7F)
return WEOF;
return c;
}
int wcwidth(wchar_t wc)
{
return wc != '\0';
}
size_t wcrtomb(char* __restrict s, wchar_t ws, mbstate_t* __restrict ps)
{
(void)ps;
// ws == '\0' doesn't seem to apply to UTF8?
if (s == nullptr)
return 1;
if (!BAN::UTF8::from_codepoints(&ws, 1, s))
{
errno = EILSEQ;
return -1;
}
return BAN::UTF8::byte_length(s[0]);
}
size_t mbrtowc(wchar_t* __restrict pwc, const char* __restrict s, size_t n, mbstate_t* __restrict ps)
{
(void)ps;
if (s == nullptr)
return 0;
const auto bytes = BAN::UTF8::byte_length(*s);
if (bytes == BAN::UTF8::invalid)
{
errno = EILSEQ;
return -1;
}
if (n < bytes)
return -1;
const auto codepoint = BAN::UTF8::to_codepoint(s);
if (codepoint == BAN::UTF8::invalid)
{
errno = EILSEQ;
return -1;
}
if (pwc != nullptr)
*pwc = codepoint;
if (codepoint == 0)
return 0;
return bytes;
}
int wcscoll(const wchar_t* ws1, const wchar_t* ws2)
{
return wcscoll_l(ws1, ws2, __getlocale(LC_COLLATE));
}
int wcscoll_l(const wchar_t* ws1, const wchar_t* ws2, locale_t locale)
{
(void)locale;
// TODO: this isn't really correct :D
return wcscmp(ws1, ws2);
}
size_t wcsxfrm(wchar_t* __restrict ws1, const wchar_t* __restrict ws2, size_t n)
{
return wcsxfrm_l(ws1, ws2, n, __getlocale(LC_COLLATE));
}
size_t wcsxfrm_l(wchar_t* __restrict ws1, const wchar_t* __restrict ws2, size_t n, locale_t locale)
{
(void)locale;
// TODO: this isn't really correct :D
wcsncpy(ws1, ws2, n);
return wcslen(ws2);
}
size_t wcsftime(wchar_t* __restrict wcs, size_t maxsize, const wchar_t* __restrict format, const struct tm* __restrict timeptr)
{
(void)wcs;
(void)maxsize;
(void)format;
(void)timeptr;
fprintf(stddbg, "TODO: wcsftime");
return 0;
}
int wcscmp(const wchar_t* ws1, const wchar_t* ws2)
@ -182,3 +284,93 @@ wchar_t* wmemset(wchar_t* ws, wchar_t wc, size_t n)
ws[i] = wc;
return ws;
}
// FIXME: actually support multibyte :D
wint_t towlower(wint_t wc)
{
return tolower(wc);
}
wint_t towupper(wint_t wc)
{
return toupper(wc);
}
#define DEFINE_ISW(class) \
int isw##class(wint_t wc) { \
return is##class(wc); \
}
DEFINE_ISW(alnum);
DEFINE_ISW(alpha);
DEFINE_ISW(blank);
DEFINE_ISW(cntrl);
DEFINE_ISW(digit);
DEFINE_ISW(graph);
DEFINE_ISW(lower);
DEFINE_ISW(print);
DEFINE_ISW(punct);
DEFINE_ISW(space);
DEFINE_ISW(upper);
DEFINE_ISW(xdigit);
#undef DEFINE_ISW
typedef enum {
_alnum = 1,
_alpha,
_blank,
_cntrl,
_digit,
_graph,
_lower,
_print,
_punct,
_space,
_upper,
_xdigit,
} wctype_values;
wctype_t wctype(const char* property)
{
#define CHECK_PROPERTY(class) \
if (strcmp(property, #class) == 0) \
return _##class
CHECK_PROPERTY(alnum);
CHECK_PROPERTY(alpha);
CHECK_PROPERTY(blank);
CHECK_PROPERTY(cntrl);
CHECK_PROPERTY(digit);
CHECK_PROPERTY(graph);
CHECK_PROPERTY(lower);
CHECK_PROPERTY(print);
CHECK_PROPERTY(punct);
CHECK_PROPERTY(space);
CHECK_PROPERTY(upper);
CHECK_PROPERTY(xdigit);
#undef CHECK_TYPE
return 0;
}
int iswctype(wint_t wc, wctype_t charclass)
{
switch (charclass)
{
#define CLASS_CASE(class) \
case _##class: \
return is##class(wc)
CLASS_CASE(alnum);
CLASS_CASE(alpha);
CLASS_CASE(blank);
CLASS_CASE(cntrl);
CLASS_CASE(digit);
CLASS_CASE(graph);
CLASS_CASE(lower);
CLASS_CASE(print);
CLASS_CASE(punct);
CLASS_CASE(space);
CLASS_CASE(upper);
CLASS_CASE(xdigit);
#undef CLASS_CASE
}
return 0;
}

View File

@ -928,7 +928,6 @@ static LoadedElf& load_elf(const char* path, int fd)
case PT_GNU_EH_FRAME:
case PT_GNU_STACK:
case PT_GNU_RELRO:
print(STDDBG_FILENO, "TODO: PT_GNU_*\n");
break;
case PT_TLS:
tls_header = program_header;