Compare commits
7 Commits
c352fb600f
...
c26227951f
| Author | SHA1 | Date | |
|---|---|---|---|
| c26227951f | |||
| 05c9f0640c | |||
| fe2c9f7d2d | |||
| d7cdf3818c | |||
| 6a2f041858 | |||
| f0c5fb3a87 | |||
| 28b873b949 |
@@ -7,7 +7,7 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename Lock>
|
template<typename Lock> requires requires(Lock& lock) { lock.lock(); lock.unlock(); }
|
||||||
class LockGuard
|
class LockGuard
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(LockGuard);
|
BAN_NON_COPYABLE(LockGuard);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Kernel
|
|||||||
void rd_lock()
|
void rd_lock()
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
while (m_writers_waiting > 0 || m_writer_active)
|
while (m_writers_waiting > 0 || m_writer != -1)
|
||||||
m_thread_blocker.block_indefinite(&m_mutex);
|
m_thread_blocker.block_indefinite(&m_mutex);
|
||||||
m_readers_active++;
|
m_readers_active++;
|
||||||
}
|
}
|
||||||
@@ -30,19 +30,29 @@ namespace Kernel
|
|||||||
|
|
||||||
void wr_lock()
|
void wr_lock()
|
||||||
{
|
{
|
||||||
|
if (m_writer == Thread::current_tid())
|
||||||
|
{
|
||||||
|
m_writer_depth++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
m_writers_waiting++;
|
m_writers_waiting++;
|
||||||
while (m_readers_active > 0 || m_writer_active)
|
while (m_readers_active > 0 || m_writer != -1)
|
||||||
m_thread_blocker.block_indefinite(&m_mutex);
|
m_thread_blocker.block_indefinite(&m_mutex);
|
||||||
m_writers_waiting--;
|
m_writers_waiting--;
|
||||||
m_writer_active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m_writer = Thread::current_tid();
|
||||||
|
m_writer_depth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void wr_unlock()
|
void wr_unlock()
|
||||||
{
|
{
|
||||||
|
if (--m_writer_depth != 0)
|
||||||
|
return;
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
m_writer_active = false;
|
m_writer = -1;
|
||||||
m_thread_blocker.unblock();
|
m_thread_blocker.unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +61,8 @@ namespace Kernel
|
|||||||
ThreadBlocker m_thread_blocker;
|
ThreadBlocker m_thread_blocker;
|
||||||
uint32_t m_readers_active { 0 };
|
uint32_t m_readers_active { 0 };
|
||||||
uint32_t m_writers_waiting { 0 };
|
uint32_t m_writers_waiting { 0 };
|
||||||
bool m_writer_active { false };
|
pid_t m_writer { -1 };
|
||||||
|
uint32_t m_writer_depth { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class RWLockRDGuard
|
class RWLockRDGuard
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace Kernel
|
|||||||
pid_t pid() const { return m_pid; }
|
pid_t pid() const { return m_pid; }
|
||||||
|
|
||||||
bool is_session_leader() const { return pid() == sid(); }
|
bool is_session_leader() const { return pid() == sid(); }
|
||||||
|
bool is_pgrpg_in_this_session(pid_t) const;
|
||||||
|
|
||||||
const char* name() const { return m_cmdline.empty() ? "<unknown>" : m_cmdline.front().data(); }
|
const char* name() const { return m_cmdline.empty() ? "<unknown>" : m_cmdline.front().data(); }
|
||||||
|
|
||||||
@@ -63,9 +64,6 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> sys_exit(int status);
|
BAN::ErrorOr<long> sys_exit(int status);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_tcgetattr(int fildes, termios*);
|
|
||||||
BAN::ErrorOr<long> sys_tcsetattr(int fildes, int optional_actions, const termios*);
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_fork(uintptr_t rsp, uintptr_t rip);
|
BAN::ErrorOr<long> sys_fork(uintptr_t rsp, uintptr_t rip);
|
||||||
BAN::ErrorOr<long> sys_exec(const char* path, const char* const* argv, const char* const* envp);
|
BAN::ErrorOr<long> sys_exec(const char* path, const char* const* argv, const char* const* envp);
|
||||||
|
|
||||||
@@ -186,7 +184,6 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
|
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_ttyname(int fildes, char* name, size_t namesize);
|
BAN::ErrorOr<long> sys_ttyname(int fildes, char* name, size_t namesize);
|
||||||
BAN::ErrorOr<long> sys_isatty(int fildes);
|
|
||||||
BAN::ErrorOr<long> sys_posix_openpt(int flags);
|
BAN::ErrorOr<long> sys_posix_openpt(int flags);
|
||||||
BAN::ErrorOr<long> sys_ptsname(int fildes, char* buffer, size_t buffer_len);
|
BAN::ErrorOr<long> sys_ptsname(int fildes, char* buffer, size_t buffer_len);
|
||||||
|
|
||||||
@@ -218,9 +215,6 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<long> sys_pthread_self();
|
BAN::ErrorOr<long> sys_pthread_self();
|
||||||
BAN::ErrorOr<long> sys_pthread_kill(pthread_t thread, int signal);
|
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);
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
|
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
|
||||||
|
|
||||||
BAN::ErrorOr<long> sys_load_keymap(const char* path);
|
BAN::ErrorOr<long> sys_load_keymap(const char* path);
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ namespace Kernel
|
|||||||
public:
|
public:
|
||||||
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
virtual BAN::ErrorOr<void> set_font(LibFont::Font&&) { return BAN::Error::from_errno(EINVAL); }
|
||||||
|
|
||||||
void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; }
|
|
||||||
pid_t foreground_pgrp() const { return m_foreground_pgrp; }
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> tty_ctrl(int command, int flags);
|
BAN::ErrorOr<void> tty_ctrl(int command, int flags);
|
||||||
|
|
||||||
// for kprint
|
// for kprint
|
||||||
@@ -52,9 +49,6 @@ namespace Kernel
|
|||||||
void on_key_event(LibInput::KeyEvent);
|
void on_key_event(LibInput::KeyEvent);
|
||||||
void handle_input_byte(uint8_t);
|
void handle_input_byte(uint8_t);
|
||||||
|
|
||||||
void get_termios(termios*);
|
|
||||||
BAN::ErrorOr<void> set_termios(const termios*);
|
|
||||||
|
|
||||||
virtual bool is_tty() const override { return true; }
|
virtual bool is_tty() const override { return true; }
|
||||||
|
|
||||||
virtual dev_t rdev() const final override { return m_rdev; }
|
virtual dev_t rdev() const final override { return m_rdev; }
|
||||||
@@ -87,10 +81,12 @@ namespace Kernel
|
|||||||
bool putchar(uint8_t ch);
|
bool putchar(uint8_t ch);
|
||||||
void do_backspace();
|
void do_backspace();
|
||||||
|
|
||||||
|
termios get_termios();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const dev_t m_rdev;
|
const dev_t m_rdev;
|
||||||
|
|
||||||
pid_t m_foreground_pgrp { 0 };
|
BAN::Atomic<pid_t> m_foreground_pgrp { 0 };
|
||||||
|
|
||||||
struct tty_ctrl_t
|
struct tty_ctrl_t
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -226,6 +226,23 @@ namespace Kernel
|
|||||||
ASSERT(!m_page_table);
|
ASSERT(!m_page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Process::is_pgrpg_in_this_session(pid_t pgrp) const
|
||||||
|
{
|
||||||
|
bool valid_pgrp = false;
|
||||||
|
for_each_process(
|
||||||
|
[&](Process& process)
|
||||||
|
{
|
||||||
|
if (process.sid() == sid() && process.pgrp() == pgrp)
|
||||||
|
{
|
||||||
|
valid_pgrp = true;
|
||||||
|
return BAN::Iteration::Break;
|
||||||
|
}
|
||||||
|
return BAN::Iteration::Continue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return valid_pgrp;
|
||||||
|
}
|
||||||
|
|
||||||
void Process::add_thread(Thread* thread)
|
void Process::add_thread(Thread* thread)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
@@ -624,40 +641,6 @@ namespace Kernel
|
|||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tcgetattr(int fildes, termios* user_termios)
|
|
||||||
{
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
|
|
||||||
if (!inode->is_tty())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
struct termios termios;
|
|
||||||
static_cast<TTY*>(inode.ptr())->get_termios(&termios);
|
|
||||||
|
|
||||||
TRY(write_to_user(user_termios, &termios, sizeof(struct termios)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tcsetattr(int fildes, int optional_actions, const termios* user_termios)
|
|
||||||
{
|
|
||||||
//if (optional_actions != TCSANOW)
|
|
||||||
// return BAN::Error::from_errno(EINVAL);
|
|
||||||
(void)optional_actions;
|
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
|
|
||||||
if (!inode->is_tty())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
termios termios;
|
|
||||||
TRY(read_from_user(user_termios, &termios, sizeof(struct termios)));
|
|
||||||
|
|
||||||
TRY(static_cast<TTY*>(inode.ptr())->set_termios(&termios));
|
|
||||||
|
|
||||||
// FIXME: SIGTTOU
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_fork(uintptr_t sp, uintptr_t ip)
|
BAN::ErrorOr<long> Process::sys_fork(uintptr_t sp, uintptr_t ip)
|
||||||
{
|
{
|
||||||
auto page_table = BAN::UniqPtr<PageTable>::adopt(TRY(PageTable::create_userspace()));
|
auto page_table = BAN::UniqPtr<PageTable>::adopt(TRY(PageTable::create_userspace()));
|
||||||
@@ -2764,15 +2747,6 @@ namespace Kernel
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_isatty(int fildes)
|
|
||||||
{
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
|
|
||||||
if (!inode->is_tty())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_posix_openpt(int flags)
|
BAN::ErrorOr<long> Process::sys_posix_openpt(int flags)
|
||||||
{
|
{
|
||||||
if (flags & ~(O_RDWR | O_NOCTTY))
|
if (flags & ~(O_RDWR | O_NOCTTY))
|
||||||
@@ -3449,64 +3423,6 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ESRCH);
|
return BAN::Error::from_errno(ESRCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tcgetpgrp(int fd)
|
|
||||||
{
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
|
||||||
|
|
||||||
// NOTE: This is a hack but I'm not sure how terminal is supposted to get
|
|
||||||
// slave's foreground pgroup while not having controlling terminal
|
|
||||||
if (TRY(m_open_file_descriptors.path_of(fd)) == "<ptmx>"_sv)
|
|
||||||
return TRY(static_cast<PseudoTerminalMaster*>(inode.ptr())->slave())->foreground_pgrp();
|
|
||||||
|
|
||||||
if (!m_controlling_terminal)
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
if (!inode->is_tty())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
auto* tty = static_cast<TTY*>(inode.ptr());
|
|
||||||
if (tty != m_controlling_terminal.ptr())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
return tty->foreground_pgrp();
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_tcsetpgrp(int fd, pid_t pgrp)
|
|
||||||
{
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
|
|
||||||
if (!m_controlling_terminal)
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
bool valid_pgrp = false;
|
|
||||||
for_each_process(
|
|
||||||
[&](Process& process)
|
|
||||||
{
|
|
||||||
if (process.sid() == sid() && process.pgrp() == pgrp)
|
|
||||||
{
|
|
||||||
valid_pgrp = true;
|
|
||||||
return BAN::Iteration::Break;
|
|
||||||
}
|
|
||||||
return BAN::Iteration::Continue;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if (!valid_pgrp)
|
|
||||||
return BAN::Error::from_errno(EPERM);
|
|
||||||
|
|
||||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
|
||||||
if (!inode->is_tty())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
auto* tty = static_cast<TTY*>(inode.ptr());
|
|
||||||
if (tty != m_controlling_terminal.ptr())
|
|
||||||
return BAN::Error::from_errno(ENOTTY);
|
|
||||||
|
|
||||||
tty->set_foreground_pgrp(pgrp);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_setuid(uid_t uid)
|
BAN::ErrorOr<long> Process::sys_setuid(uid_t uid)
|
||||||
{
|
{
|
||||||
if (uid < 0 || uid >= 1'000'000'000)
|
if (uid < 0 || uid >= 1'000'000'000)
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENODEV);
|
return BAN::Error::from_errno(ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return CharacterDevice::ioctl(request, argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
|
PseudoTerminalSlave::PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
|||||||
@@ -210,8 +210,47 @@ namespace Kernel
|
|||||||
(void)Process::kill(-m_foreground_pgrp, SIGWINCH);
|
(void)Process::kill(-m_foreground_pgrp, SIGWINCH);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case TCGETS:
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_termios_lock);
|
||||||
|
auto* termios = static_cast<struct termios*>(argument);
|
||||||
|
*termios = m_termios;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case TCSETSW:
|
||||||
|
case TCSETSF:
|
||||||
|
dwarnln("TODO: proper TCSETSW/TCSETSWF");
|
||||||
|
[[fallthrough]];
|
||||||
|
case TCSETS:
|
||||||
|
{
|
||||||
|
// FIXME: do some validation
|
||||||
|
SpinLockGuard _(m_termios_lock);
|
||||||
|
const auto* termios = static_cast<const struct termios*>(argument);
|
||||||
|
m_termios = *termios;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case TIOCGPGRP:
|
||||||
|
{
|
||||||
|
pid_t* pgrp = static_cast<pid_t*>(argument);
|
||||||
|
*pgrp = m_foreground_pgrp.load();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case TIOCSPGRP:
|
||||||
|
{
|
||||||
|
const pid_t pgrp = *static_cast<const pid_t*>(argument);
|
||||||
|
|
||||||
|
if (!Process::current().is_pgrpg_in_this_session(pgrp))
|
||||||
|
return BAN::Error::from_errno(EPERM);
|
||||||
|
|
||||||
|
if (this != Process::current().controlling_terminal().ptr())
|
||||||
|
return BAN::Error::from_errno(ENOTTY);
|
||||||
|
|
||||||
|
m_foreground_pgrp = pgrp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
|
return CharacterDevice::ioctl(request, argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::on_key_event(LibInput::RawKeyEvent event)
|
void TTY::on_key_event(LibInput::RawKeyEvent event)
|
||||||
@@ -234,19 +273,10 @@ namespace Kernel
|
|||||||
after_write();
|
after_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::get_termios(termios* termios)
|
termios TTY::get_termios()
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_termios_lock);
|
SpinLockGuard _(m_termios_lock);
|
||||||
*termios = m_termios;
|
return m_termios;
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> TTY::set_termios(const termios* termios)
|
|
||||||
{
|
|
||||||
// FIXME: do some validation
|
|
||||||
|
|
||||||
SpinLockGuard _(m_termios_lock);
|
|
||||||
m_termios = *termios;
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::handle_input_byte(uint8_t ch)
|
void TTY::handle_input_byte(uint8_t ch)
|
||||||
@@ -256,9 +286,7 @@ namespace Kernel
|
|||||||
|
|
||||||
LockGuard _0(m_mutex);
|
LockGuard _0(m_mutex);
|
||||||
|
|
||||||
termios termios;
|
const auto termios = get_termios();
|
||||||
get_termios(&termios);
|
|
||||||
|
|
||||||
|
|
||||||
if ((termios.c_iflag & ISTRIP))
|
if ((termios.c_iflag & ISTRIP))
|
||||||
ch &= 0x7F;
|
ch &= 0x7F;
|
||||||
@@ -394,8 +422,7 @@ namespace Kernel
|
|||||||
if (!m_tty_ctrl.draw_graphics)
|
if (!m_tty_ctrl.draw_graphics)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
termios termios;
|
const auto termios = get_termios();
|
||||||
get_termios(&termios);
|
|
||||||
|
|
||||||
SpinLockGuard _1(m_write_lock);
|
SpinLockGuard _1(m_write_lock);
|
||||||
if (termios.c_oflag & OPOST)
|
if (termios.c_oflag & OPOST)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ int aio_read(struct aiocb* aiocbp);
|
|||||||
ssize_t aio_return(struct aiocb* aiocbp);
|
ssize_t aio_return(struct aiocb* aiocbp);
|
||||||
int aio_suspend(const struct aiocb* const list[], int nent, const struct timespec* timeout);
|
int aio_suspend(const struct aiocb* const list[], int nent, const struct timespec* timeout);
|
||||||
int aio_write(struct aiocb* aiocbp);
|
int aio_write(struct aiocb* aiocbp);
|
||||||
int lio_listio(int mode, struct aiocb* __restrict const list[__restrict], int nent, struct sigevent* __restrict sig);
|
int lio_listio(int mode, struct aiocb* __restrict const* __restrict list, int nent, struct sigevent* __restrict sig);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,14 @@ struct winsize
|
|||||||
unsigned short ws_xpixel; /* unused by kernel */
|
unsigned short ws_xpixel; /* unused by kernel */
|
||||||
unsigned short ws_ypixel; /* unused by kernel */
|
unsigned short ws_ypixel; /* unused by kernel */
|
||||||
};
|
};
|
||||||
#define TIOCGWINSZ 50
|
#define TIOCGWINSZ 50
|
||||||
#define TIOCSWINSZ 51
|
#define TIOCSWINSZ 51
|
||||||
|
#define TCGETS 52
|
||||||
|
#define TCSETS 53
|
||||||
|
#define TCSETSW 54
|
||||||
|
#define TCSETSF 55
|
||||||
|
#define TIOCGPGRP 56
|
||||||
|
#define TIOCSPGRP 57
|
||||||
|
|
||||||
struct snd_volume_info
|
struct snd_volume_info
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ __BEGIN_DECLS
|
|||||||
O(SYS_SEEK, seek) \
|
O(SYS_SEEK, seek) \
|
||||||
O(SYS_TELL, tell) \
|
O(SYS_TELL, tell) \
|
||||||
O(SYS_RENAMEAT, renameat) \
|
O(SYS_RENAMEAT, renameat) \
|
||||||
O(SYS_TCGETATTR, tcgetattr) \
|
|
||||||
O(SYS_TCSETATTR, tcsetattr) \
|
|
||||||
O(SYS_FORK, fork) \
|
O(SYS_FORK, fork) \
|
||||||
O(SYS_EXEC, exec) \
|
O(SYS_EXEC, exec) \
|
||||||
O(SYS_SLEEP, sleep) \
|
O(SYS_SLEEP, sleep) \
|
||||||
@@ -39,8 +37,6 @@ __BEGIN_DECLS
|
|||||||
O(SYS_PIPE, pipe) \
|
O(SYS_PIPE, pipe) \
|
||||||
O(SYS_DUP2, dup2) \
|
O(SYS_DUP2, dup2) \
|
||||||
O(SYS_KILL, kill) \
|
O(SYS_KILL, kill) \
|
||||||
O(SYS_TCGETPGRP, tcgetpgrp) \
|
|
||||||
O(SYS_TCSETPGRP, tcsetpgrp) \
|
|
||||||
O(SYS_GET_PPID, getppid) \
|
O(SYS_GET_PPID, getppid) \
|
||||||
O(SYS_GET_PID, getpid) \
|
O(SYS_GET_PID, getpid) \
|
||||||
O(SYS_GET_PGID, getpgid) \
|
O(SYS_GET_PGID, getpgid) \
|
||||||
@@ -79,7 +75,6 @@ __BEGIN_DECLS
|
|||||||
O(SYS_SMO_CREATE, smo_create) \
|
O(SYS_SMO_CREATE, smo_create) \
|
||||||
O(SYS_SMO_DELETE, smo_delete) \
|
O(SYS_SMO_DELETE, smo_delete) \
|
||||||
O(SYS_SMO_MAP, smo_map) \
|
O(SYS_SMO_MAP, smo_map) \
|
||||||
O(SYS_ISATTY, isatty) \
|
|
||||||
O(SYS_GETSOCKNAME, getsockname) \
|
O(SYS_GETSOCKNAME, getsockname) \
|
||||||
O(SYS_GETPEERNAME, getpeername) \
|
O(SYS_GETPEERNAME, getpeername) \
|
||||||
O(SYS_GETSOCKOPT, getsockopt) \
|
O(SYS_GETSOCKOPT, getsockopt) \
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef _TERMIOS_H
|
#ifndef _TERMIOS_H
|
||||||
#define _TERMIOS_H 1
|
#define _TERMIOS_H 1
|
||||||
|
|
||||||
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html
|
// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/termios.h.html
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
@@ -39,6 +39,14 @@ struct termios
|
|||||||
speed_t c_ispeed;
|
speed_t c_ispeed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct winsize
|
||||||
|
{
|
||||||
|
unsigned short ws_row;
|
||||||
|
unsigned short ws_col;
|
||||||
|
unsigned short ws_xpixel; /* unused by kernel */
|
||||||
|
unsigned short ws_ypixel; /* unused by kernel */
|
||||||
|
};
|
||||||
|
|
||||||
#define BRKINT 0x001
|
#define BRKINT 0x001
|
||||||
#define ICRNL 0x002
|
#define ICRNL 0x002
|
||||||
#define IGNBRK 0x004
|
#define IGNBRK 0x004
|
||||||
@@ -143,8 +151,10 @@ int tcflow(int fildes, int action);
|
|||||||
int tcflush(int fildes, int queue_selector);
|
int tcflush(int fildes, int queue_selector);
|
||||||
int tcgetattr(int fildes, struct termios* termios_p);
|
int tcgetattr(int fildes, struct termios* termios_p);
|
||||||
pid_t tcgetsid(int fildes);
|
pid_t tcgetsid(int fildes);
|
||||||
|
int tcgetwinsize(int fildes, struct winsize* winsize_p);
|
||||||
int tcsendbreak(int fildes, int duration);
|
int tcsendbreak(int fildes, int duration);
|
||||||
int tcsetattr(int fildes, int optional_actions, const struct termios* termios_p);
|
int tcsetattr(int fildes, int optional_actions, const struct termios* termios_p);
|
||||||
|
int tcsetwinsize(int fildes, const struct winsize* winsize_p);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|||||||
@@ -1,328 +1,349 @@
|
|||||||
#include <BAN/Debug.h>
|
|
||||||
#include <BAN/Math.h>
|
#include <BAN/Math.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define DEBUG_MALLOC 0
|
static constexpr size_t s_allocator_chunk_size { 64 };
|
||||||
|
static constexpr size_t s_allocator_size { 1024 * 1024 };
|
||||||
|
static constexpr size_t s_mmap_threshold { 64 * 1024 };
|
||||||
|
|
||||||
static consteval size_t log_size_t(size_t value, size_t base)
|
struct alignas(max_align_t) MmapAllocationHeader
|
||||||
{
|
{
|
||||||
size_t result = 0;
|
size_t mmap_size;
|
||||||
while (value /= base)
|
size_t offset;
|
||||||
result++;
|
};
|
||||||
|
|
||||||
|
struct BitmapAllocator
|
||||||
|
{
|
||||||
|
struct alignas(max_align_t) Header
|
||||||
|
{
|
||||||
|
size_t chunks { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t bitmap_chunks { 0 };
|
||||||
|
uint32_t total_chunks { 0 };
|
||||||
|
uint32_t free_chunks { 0 };
|
||||||
|
uint32_t allocations { 0 };
|
||||||
|
uint8_t* base { nullptr };
|
||||||
|
|
||||||
|
static size_t needed_chunks(size_t size)
|
||||||
|
{
|
||||||
|
return BAN::Math::div_round_up(sizeof(BitmapAllocator::Header) + size, s_allocator_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initialize()
|
||||||
|
{
|
||||||
|
void* base = mmap(nullptr, s_allocator_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (base == MAP_FAILED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
constexpr size_t bitmap_bytes = BAN::Math::div_round_up(s_allocator_size, s_allocator_chunk_size * 8);
|
||||||
|
constexpr size_t bitmap_chunks = BAN::Math::div_round_up(bitmap_bytes, s_allocator_chunk_size);
|
||||||
|
constexpr size_t usable_chunks = s_allocator_size / s_allocator_chunk_size - bitmap_chunks;
|
||||||
|
|
||||||
|
this->bitmap_chunks = bitmap_chunks;
|
||||||
|
this->total_chunks = usable_chunks;
|
||||||
|
this->free_chunks = usable_chunks;
|
||||||
|
this->base = static_cast<uint8_t*>(base);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* data_start() { return base + bitmap_chunks * s_allocator_chunk_size; }
|
||||||
|
const uint8_t* data_start() const { return base + bitmap_chunks * s_allocator_chunk_size; }
|
||||||
|
|
||||||
|
size_t get_first_chunk(void* ptr) const
|
||||||
|
{
|
||||||
|
return (static_cast<uint8_t*>(ptr) - sizeof(Header) - data_start()) / s_allocator_chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(void* ptr) const
|
||||||
|
{
|
||||||
|
if (ptr < data_start() + sizeof(Header))
|
||||||
|
return false;
|
||||||
|
return get_first_chunk(ptr) < total_chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_bit(size_t index) const
|
||||||
|
{
|
||||||
|
assert(index < total_chunks);
|
||||||
|
const size_t byte = index / 8;
|
||||||
|
const size_t bit = index % 8;
|
||||||
|
return (base[byte] >> bit) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bit(size_t index, bool value)
|
||||||
|
{
|
||||||
|
assert(index < total_chunks);
|
||||||
|
const size_t byte = index / 8;
|
||||||
|
const size_t bit = index % 8;
|
||||||
|
if (value)
|
||||||
|
base[byte] |= 1 << bit;
|
||||||
|
else
|
||||||
|
base[byte] &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t find_unset_bit(size_t index) const
|
||||||
|
{
|
||||||
|
// NOTE: We could optimize other bitmap functions than this
|
||||||
|
// but this one is the bottle neck so it doesn't matter
|
||||||
|
|
||||||
|
static_assert(sizeof(unsigned long long) == sizeof(uint64_t));
|
||||||
|
|
||||||
|
if (index >= total_chunks)
|
||||||
|
return index;
|
||||||
|
|
||||||
|
if (const auto rem = index % 64)
|
||||||
|
{
|
||||||
|
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + (index - rem) / 8) >> rem;
|
||||||
|
if (qword != UINT64_MAX >> rem)
|
||||||
|
return index + __builtin_ctzll(~qword);
|
||||||
|
index += 64 - rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index < total_chunks)
|
||||||
|
{
|
||||||
|
const uint64_t qword = *reinterpret_cast<const uint64_t*>(base + index / 8);
|
||||||
|
if (qword != UINT64_MAX)
|
||||||
|
return index + __builtin_ctzll(~qword);
|
||||||
|
index += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count_unset_bits(size_t index, size_t wanted) const
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for (; index + count < total_chunks && count < wanted; count++)
|
||||||
|
if (get_bit(index + count))
|
||||||
|
break;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Header& header_from_chunk(size_t index)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<Header*>(data_start() + index * s_allocator_chunk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* allocate(size_t size)
|
||||||
|
{
|
||||||
|
const size_t needed_chunks = this->needed_chunks(size);
|
||||||
|
if (needed_chunks > free_chunks)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (size_t i = find_unset_bit(0); i <= total_chunks - needed_chunks; i = find_unset_bit(i))
|
||||||
|
{
|
||||||
|
if (const size_t count = count_unset_bits(i, needed_chunks); count < needed_chunks)
|
||||||
|
{
|
||||||
|
i += count + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < needed_chunks; j++)
|
||||||
|
set_bit(i + j, true);
|
||||||
|
|
||||||
|
auto& header = header_from_chunk(i);
|
||||||
|
header = {
|
||||||
|
.chunks = needed_chunks,
|
||||||
|
};
|
||||||
|
|
||||||
|
free_chunks -= header.chunks;
|
||||||
|
allocations++;
|
||||||
|
|
||||||
|
return &header + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resize(void* ptr, size_t size)
|
||||||
|
{
|
||||||
|
assert(contains(ptr));
|
||||||
|
|
||||||
|
const size_t first_chunk = get_first_chunk(ptr);
|
||||||
|
auto& header = header_from_chunk(first_chunk);
|
||||||
|
|
||||||
|
const size_t needed_chunks = this->needed_chunks(size);
|
||||||
|
if (needed_chunks <= header.chunks)
|
||||||
|
{
|
||||||
|
for (size_t i = needed_chunks; i < header.chunks; i++)
|
||||||
|
set_bit(first_chunk + i, false);
|
||||||
|
free_chunks += header.chunks - needed_chunks;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const size_t extra_chunks = header.chunks - needed_chunks;
|
||||||
|
if (count_unset_bits(first_chunk + header.chunks, extra_chunks) < extra_chunks)
|
||||||
|
return false;
|
||||||
|
for (size_t i = header.chunks; i < needed_chunks; i++)
|
||||||
|
set_bit(first_chunk + i, true);
|
||||||
|
free_chunks -= needed_chunks - header.chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = {
|
||||||
|
.chunks = needed_chunks,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
|
{
|
||||||
|
assert(contains(ptr));
|
||||||
|
|
||||||
|
const size_t first_chunk = get_first_chunk(ptr);
|
||||||
|
|
||||||
|
auto& header = header_from_chunk(first_chunk);
|
||||||
|
for (size_t i = 0; i < header.chunks; i++)
|
||||||
|
set_bit(first_chunk + i, false);
|
||||||
|
|
||||||
|
free_chunks += header.chunks;
|
||||||
|
allocations--;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t allocation_size(void* ptr)
|
||||||
|
{
|
||||||
|
assert(contains(ptr));
|
||||||
|
return header_from_chunk(get_first_chunk(ptr)).chunks * s_allocator_chunk_size - sizeof(Header);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t s_allocator_count { 0 };
|
||||||
|
static size_t s_allocator_capacity { 0 };
|
||||||
|
|
||||||
|
static BitmapAllocator* s_allocators { nullptr };
|
||||||
|
static pthread_mutex_t s_allocator_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void* malloc(size_t total_size)
|
||||||
|
{
|
||||||
|
if (total_size >= s_mmap_threshold)
|
||||||
|
{
|
||||||
|
const size_t mmap_size = sizeof(MmapAllocationHeader) + total_size;
|
||||||
|
|
||||||
|
void* address = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (address == MAP_FAILED)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto& header = static_cast<MmapAllocationHeader*>(address)[0];
|
||||||
|
header = {
|
||||||
|
.mmap_size = mmap_size,
|
||||||
|
.offset = sizeof(MmapAllocationHeader),
|
||||||
|
};
|
||||||
|
return &header + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t allocators_per_page = PAGE_SIZE / sizeof(BitmapAllocator);
|
||||||
|
|
||||||
|
void* result = nullptr;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&s_allocator_lock);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < s_allocator_count; i++)
|
||||||
|
if ((result = s_allocators[i].allocate(total_size)))
|
||||||
|
goto malloc_return;
|
||||||
|
|
||||||
|
if (s_allocator_capacity % allocators_per_page == 0)
|
||||||
|
{
|
||||||
|
void* new_allocators = mmap(nullptr, (s_allocator_capacity + allocators_per_page) * sizeof(BitmapAllocator), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (new_allocators == MAP_FAILED)
|
||||||
|
goto malloc_return;
|
||||||
|
|
||||||
|
static_assert(BAN::is_trivially_copyable_v<BitmapAllocator>);
|
||||||
|
memcpy(new_allocators, s_allocators, s_allocator_count * sizeof(BitmapAllocator));
|
||||||
|
|
||||||
|
munmap(s_allocators, s_allocator_capacity * sizeof(BitmapAllocator));
|
||||||
|
|
||||||
|
s_allocators = static_cast<BitmapAllocator*>(new_allocators);
|
||||||
|
s_allocator_capacity = s_allocator_capacity + allocators_per_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_allocators[s_allocator_count].initialize())
|
||||||
|
goto malloc_return;
|
||||||
|
result = s_allocators[s_allocator_count++].allocate(total_size);
|
||||||
|
|
||||||
|
malloc_return:
|
||||||
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
|
|
||||||
|
if (result == nullptr)
|
||||||
|
errno = ENOMEM;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t s_malloc_pool_size_initial = 4096;
|
void free(void* ptr)
|
||||||
static constexpr size_t s_malloc_pool_size_multiplier = 2;
|
|
||||||
static constexpr size_t s_malloc_pool_count = sizeof(size_t) * 8 - log_size_t(s_malloc_pool_size_initial, s_malloc_pool_size_multiplier);
|
|
||||||
static constexpr size_t s_malloc_default_align = alignof(max_align_t);
|
|
||||||
// This is indirectly smallest allowed allocation
|
|
||||||
static constexpr size_t s_malloc_shrink_threshold = 64;
|
|
||||||
|
|
||||||
struct malloc_node_t
|
|
||||||
{
|
{
|
||||||
// TODO: these two pointers could be put into data region
|
if (ptr == nullptr)
|
||||||
malloc_node_t* prev_free;
|
|
||||||
malloc_node_t* next_free;
|
|
||||||
size_t size;
|
|
||||||
bool allocated;
|
|
||||||
bool last;
|
|
||||||
alignas(s_malloc_default_align) uint8_t data[0];
|
|
||||||
|
|
||||||
size_t data_size() const { return size - sizeof(malloc_node_t); }
|
|
||||||
malloc_node_t* next() { return (malloc_node_t*)(data + data_size()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct malloc_pool_t
|
|
||||||
{
|
|
||||||
uint8_t* start;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
malloc_node_t* free_list;
|
|
||||||
|
|
||||||
uint8_t* end() const { return start + size; }
|
|
||||||
bool contains(malloc_node_t* node) const { return start <= (uint8_t*)node && (uint8_t*)node->next() <= end(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct malloc_info_t
|
|
||||||
{
|
|
||||||
consteval malloc_info_t()
|
|
||||||
{
|
|
||||||
size_t pool_size = s_malloc_pool_size_initial;
|
|
||||||
for (auto& pool : pools)
|
|
||||||
{
|
|
||||||
pool = {
|
|
||||||
.start = nullptr,
|
|
||||||
.size = pool_size,
|
|
||||||
.free_list = nullptr,
|
|
||||||
};
|
|
||||||
pool_size *= s_malloc_pool_size_multiplier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
malloc_pool_t pools[s_malloc_pool_count];
|
|
||||||
};
|
|
||||||
|
|
||||||
static malloc_info_t s_malloc_info;
|
|
||||||
static auto& s_malloc_pools = s_malloc_info.pools;
|
|
||||||
|
|
||||||
static pthread_mutex_t s_malloc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
static bool allocate_pool(size_t pool_index)
|
|
||||||
{
|
|
||||||
auto& pool = s_malloc_pools[pool_index];
|
|
||||||
assert(pool.start == nullptr);
|
|
||||||
|
|
||||||
// allocate memory for pool
|
|
||||||
void* new_pool = mmap(nullptr, pool.size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
||||||
if (new_pool == MAP_FAILED)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pool.start = (uint8_t*)new_pool;
|
|
||||||
|
|
||||||
// initialize pool to single unallocated node
|
|
||||||
auto* node = (malloc_node_t*)pool.start;
|
|
||||||
node->allocated = false;
|
|
||||||
node->size = pool.size;
|
|
||||||
node->last = true;
|
|
||||||
node->prev_free = nullptr;
|
|
||||||
node->next_free = nullptr;
|
|
||||||
|
|
||||||
pool.free_list = node;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_node_from_pool_free_list(malloc_pool_t& pool, malloc_node_t* node)
|
|
||||||
{
|
|
||||||
if (node == pool.free_list)
|
|
||||||
{
|
|
||||||
pool.free_list = pool.free_list->next_free;
|
|
||||||
if (pool.free_list)
|
|
||||||
pool.free_list->prev_free = nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (node->next_free)
|
|
||||||
node->next_free->prev_free = node->prev_free;
|
|
||||||
if (node->prev_free)
|
|
||||||
node->prev_free->next_free = node->next_free;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void merge_following_free_nodes(malloc_pool_t& pool, malloc_node_t* node)
|
|
||||||
{
|
|
||||||
while (!node->last && !node->next()->allocated)
|
|
||||||
{
|
|
||||||
auto* next = node->next();
|
|
||||||
remove_node_from_pool_free_list(pool, next);
|
|
||||||
node->last = next->last;
|
|
||||||
node->size += next->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shrink_node_if_needed(malloc_pool_t& pool, malloc_node_t* node, size_t size)
|
|
||||||
{
|
|
||||||
assert(size <= node->data_size());
|
|
||||||
if (node->data_size() - size < sizeof(malloc_node_t) + s_malloc_shrink_threshold)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint8_t* node_end = (uint8_t*)node->next();
|
pthread_mutex_lock(&s_allocator_lock);
|
||||||
|
for (size_t i = 0; i < s_allocator_count; i++)
|
||||||
node->size = sizeof(malloc_node_t) + size;
|
|
||||||
if (auto rem = (node->size + sizeof(malloc_node_t)) % s_malloc_default_align)
|
|
||||||
node->size += s_malloc_default_align - rem;
|
|
||||||
|
|
||||||
auto* next = node->next();
|
|
||||||
next->allocated = false;
|
|
||||||
next->size = node_end - (uint8_t*)next;
|
|
||||||
next->last = node->last;
|
|
||||||
|
|
||||||
node->last = false;
|
|
||||||
|
|
||||||
// insert excess node to free list
|
|
||||||
if (pool.free_list)
|
|
||||||
pool.free_list->prev_free = next;
|
|
||||||
next->next_free = pool.free_list;
|
|
||||||
next->prev_free = nullptr;
|
|
||||||
pool.free_list = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* allocate_from_pool(size_t pool_index, size_t size)
|
|
||||||
{
|
|
||||||
assert(size % s_malloc_default_align == 0);
|
|
||||||
|
|
||||||
auto& pool = s_malloc_pools[pool_index];
|
|
||||||
assert(pool.start != nullptr);
|
|
||||||
|
|
||||||
if (!pool.free_list)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
for (auto* node = pool.free_list; node; node = node->next_free)
|
|
||||||
{
|
{
|
||||||
assert(!node->allocated);
|
if (!s_allocators[i].contains(ptr))
|
||||||
|
|
||||||
merge_following_free_nodes(pool, node);
|
|
||||||
if (node->data_size() < size)
|
|
||||||
continue;
|
continue;
|
||||||
|
s_allocators[i].free(ptr);
|
||||||
node->allocated = true;
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
remove_node_from_pool_free_list(pool, node);
|
return;
|
||||||
|
|
||||||
shrink_node_if_needed(pool, node, size);
|
|
||||||
|
|
||||||
assert(((uintptr_t)node->data & (s_malloc_default_align - 1)) == 0);
|
|
||||||
return node->data;
|
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
|
|
||||||
return nullptr;
|
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
|
||||||
|
munmap(static_cast<uint8_t*>(ptr) - header.offset, header.mmap_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static malloc_node_t* node_from_data_pointer(void* data_pointer)
|
static size_t allocation_size(void* ptr)
|
||||||
{
|
{
|
||||||
return (malloc_node_t*)((uint8_t*)data_pointer - sizeof(malloc_node_t));
|
pthread_mutex_lock(&s_allocator_lock);
|
||||||
}
|
for (size_t i = 0; i < s_allocator_count; i++)
|
||||||
|
|
||||||
static malloc_pool_t& pool_from_node(malloc_node_t* node)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < s_malloc_pool_count; i++)
|
|
||||||
if (s_malloc_pools[i].start && s_malloc_pools[i].contains(node))
|
|
||||||
return s_malloc_pools[i];
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* malloc(size_t size)
|
|
||||||
{
|
|
||||||
dprintln_if(DEBUG_MALLOC, "malloc({})", size);
|
|
||||||
|
|
||||||
// align size to s_malloc_default_align boundary
|
|
||||||
if (size_t ret = size % s_malloc_default_align)
|
|
||||||
size += s_malloc_default_align - ret;
|
|
||||||
|
|
||||||
// find the first pool with size atleast size
|
|
||||||
size_t first_usable_pool = 0;
|
|
||||||
while (s_malloc_pools[first_usable_pool].size - sizeof(malloc_node_t) < size)
|
|
||||||
first_usable_pool++;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&s_malloc_mutex);
|
|
||||||
|
|
||||||
// try to find any already existing pools that we can allocate in
|
|
||||||
for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++)
|
|
||||||
{
|
{
|
||||||
if (s_malloc_pools[i].start == nullptr)
|
if (!s_allocators[i].contains(ptr))
|
||||||
continue;
|
continue;
|
||||||
void* ret = allocate_from_pool(i, size);
|
const size_t size = s_allocators[i].allocation_size(ptr);
|
||||||
if (ret == nullptr)
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
continue;
|
return size;
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
|
|
||||||
// allocate new pool
|
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
|
||||||
for (size_t i = first_usable_pool; i < s_malloc_pool_count; i++)
|
return header.mmap_size - sizeof(MmapAllocationHeader);
|
||||||
{
|
|
||||||
if (s_malloc_pools[i].start != nullptr)
|
|
||||||
continue;
|
|
||||||
void* ret = allocate_pool(i)
|
|
||||||
? allocate_from_pool(i, size)
|
|
||||||
: nullptr;
|
|
||||||
if (ret == nullptr)
|
|
||||||
break;
|
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
|
|
||||||
errno = ENOMEM;
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* realloc(void* ptr, size_t size)
|
void* realloc(void* ptr, size_t size)
|
||||||
{
|
{
|
||||||
dprintln_if(DEBUG_MALLOC, "realloc({}, {})", ptr, size);
|
|
||||||
|
|
||||||
if (ptr == nullptr)
|
if (ptr == nullptr)
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
|
|
||||||
// align size to s_malloc_default_align boundary
|
pthread_mutex_lock(&s_allocator_lock);
|
||||||
if (size_t ret = size % s_malloc_default_align)
|
for (size_t i = 0; i < s_allocator_count; i++)
|
||||||
size += s_malloc_default_align - ret;
|
{
|
||||||
|
if (!s_allocators[i].contains(ptr))
|
||||||
pthread_mutex_lock(&s_malloc_mutex);
|
continue;
|
||||||
|
if (!s_allocators[i].resize(ptr, size))
|
||||||
auto* node = node_from_data_pointer(ptr);
|
break;
|
||||||
auto& pool = pool_from_node(node);
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
|
|
||||||
assert(node->allocated);
|
|
||||||
|
|
||||||
const size_t oldsize = node->data_size();
|
|
||||||
|
|
||||||
// try to grow the node if needed
|
|
||||||
if (size > oldsize)
|
|
||||||
merge_following_free_nodes(pool, node);
|
|
||||||
|
|
||||||
const bool needs_allocation = node->data_size() < size;
|
|
||||||
|
|
||||||
shrink_node_if_needed(pool, node, needs_allocation ? oldsize : size);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
|
|
||||||
if (!needs_allocation)
|
|
||||||
return ptr;
|
return ptr;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&s_allocator_lock);
|
||||||
|
|
||||||
|
// TODO: maybe an in-place realloc for mmap-backed allocations?
|
||||||
|
|
||||||
// allocate new pointer
|
|
||||||
void* new_ptr = malloc(size);
|
void* new_ptr = malloc(size);
|
||||||
if (new_ptr == nullptr)
|
if (new_ptr == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// move data to the new pointer
|
memcpy(new_ptr, ptr, BAN::Math::min(allocation_size(ptr), size));
|
||||||
const size_t bytes_to_copy = (oldsize < size) ? oldsize : size;
|
|
||||||
memcpy(new_ptr, ptr, bytes_to_copy);
|
|
||||||
free(ptr);
|
free(ptr);
|
||||||
|
|
||||||
return new_ptr;
|
return new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void* ptr)
|
|
||||||
{
|
|
||||||
dprintln_if(DEBUG_MALLOC, "free({})", ptr);
|
|
||||||
|
|
||||||
if (ptr == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&s_malloc_mutex);
|
|
||||||
|
|
||||||
auto* node = node_from_data_pointer(ptr);
|
|
||||||
auto& pool = pool_from_node(node);
|
|
||||||
|
|
||||||
assert(node->allocated);
|
|
||||||
node->allocated = false;
|
|
||||||
|
|
||||||
merge_following_free_nodes(pool, node);
|
|
||||||
|
|
||||||
// add node to free list
|
|
||||||
if (pool.free_list)
|
|
||||||
pool.free_list->prev_free = node;
|
|
||||||
node->prev_free = nullptr;
|
|
||||||
node->next_free = pool.free_list;
|
|
||||||
pool.free_list = node;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* calloc(size_t nmemb, size_t size)
|
void* calloc(size_t nmemb, size_t size)
|
||||||
{
|
{
|
||||||
dprintln_if(DEBUG_MALLOC, "calloc({}, {})", nmemb, size);
|
|
||||||
|
|
||||||
const size_t total = nmemb * size;
|
const size_t total = nmemb * size;
|
||||||
if (size != 0 && total / size != nmemb)
|
if (size != 0 && total / size != nmemb)
|
||||||
{
|
{
|
||||||
@@ -340,66 +361,44 @@ void* calloc(size_t nmemb, size_t size)
|
|||||||
|
|
||||||
void* aligned_alloc(size_t alignment, size_t size)
|
void* aligned_alloc(size_t alignment, size_t size)
|
||||||
{
|
{
|
||||||
dprintln_if(DEBUG_MALLOC, "aligned_alloc({}, {})", alignment, size);
|
if (!BAN::Math::is_power_of_two(alignment))
|
||||||
|
|
||||||
if (alignment < sizeof(void*) || alignment % sizeof(void*) || !BAN::Math::is_power_of_two(alignment / sizeof(void*)))
|
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alignment < s_malloc_default_align)
|
if (alignment <= alignof(max_align_t))
|
||||||
alignment = s_malloc_default_align;
|
return malloc(size);
|
||||||
|
|
||||||
void* unaligned = malloc(size + alignment + sizeof(malloc_node_t));
|
static_assert(sizeof(MmapAllocationHeader) <= alignof(max_align_t));
|
||||||
if (unaligned == nullptr)
|
|
||||||
|
const size_t mmap_size = alignment + size;
|
||||||
|
|
||||||
|
void* address = mmap(nullptr, mmap_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
if (address == MAP_FAILED)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
pthread_mutex_lock(&s_malloc_mutex);
|
uintptr_t data = reinterpret_cast<uintptr_t>(address) + sizeof(MmapAllocationHeader);
|
||||||
|
if (auto rem = data % alignment)
|
||||||
|
data += alignment - rem;
|
||||||
|
|
||||||
auto* node = node_from_data_pointer(unaligned);
|
// TODO: unmap possible unused pages in alignment, they are only allocated when accessed so doesn't really matter :^)
|
||||||
auto& pool = pool_from_node(node);
|
|
||||||
|
|
||||||
// NOTE: gcc does not like accessing the node from pointer returned by malloc
|
auto& header = reinterpret_cast<MmapAllocationHeader*>(data)[-1];
|
||||||
#pragma GCC diagnostic push
|
header = {
|
||||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
.mmap_size = mmap_size,
|
||||||
if (reinterpret_cast<uintptr_t>(unaligned) % alignment)
|
.offset = data - reinterpret_cast<uintptr_t>(address),
|
||||||
{
|
};
|
||||||
uintptr_t curr_data_address = reinterpret_cast<uintptr_t>(unaligned);
|
return &header + 1;
|
||||||
|
|
||||||
uintptr_t next_data_address = curr_data_address + sizeof(malloc_node_t);
|
|
||||||
if (auto rem = next_data_address % alignment)
|
|
||||||
next_data_address += alignment - rem;
|
|
||||||
|
|
||||||
auto* next = node_from_data_pointer(reinterpret_cast<void*>(next_data_address));
|
|
||||||
next->size = reinterpret_cast<uintptr_t>(node->next()) - reinterpret_cast<uintptr_t>(next);
|
|
||||||
next->allocated = true;
|
|
||||||
assert(next->data_size() >= size);
|
|
||||||
|
|
||||||
node->size = reinterpret_cast<uintptr_t>(next) - reinterpret_cast<uintptr_t>(node);
|
|
||||||
node->allocated = false;
|
|
||||||
|
|
||||||
// add node to free list
|
|
||||||
if (pool.free_list)
|
|
||||||
pool.free_list->prev_free = node;
|
|
||||||
node->prev_free = nullptr;
|
|
||||||
node->next_free = pool.free_list;
|
|
||||||
pool.free_list = node;
|
|
||||||
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
shrink_node_if_needed(pool, node, size);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&s_malloc_mutex);
|
|
||||||
|
|
||||||
assert(((uintptr_t)node->data & (alignment - 1)) == 0);
|
|
||||||
return node->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int posix_memalign(void** memptr, size_t alignment, size_t size)
|
int posix_memalign(void** memptr, size_t alignment, size_t size)
|
||||||
{
|
{
|
||||||
dprintln_if(DEBUG_MALLOC, "posix_memalign({}, {})", alignment, size);
|
if (alignment < sizeof(void*) || !BAN::Math::is_power_of_two(alignment))
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1;
|
return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,11 +277,11 @@ int fgetpos(FILE* file, fpos_t* pos)
|
|||||||
|
|
||||||
char* fgets(char* str, int size, FILE* file)
|
char* fgets(char* str, int size, FILE* file)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
if (size <= 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
ScopeLock _(file);
|
ScopeLock _(file);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < size - 1; i++)
|
while (i < size - 1)
|
||||||
{
|
{
|
||||||
int c = getc_unlocked(file);
|
int c = getc_unlocked(file);
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
@@ -290,12 +290,9 @@ char* fgets(char* str, int size, FILE* file)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str[i] = c;
|
str[i++] = c;
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
|
||||||
i++;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
str[i] = '\0';
|
str[i] = '\0';
|
||||||
return str;
|
return str;
|
||||||
|
|||||||
@@ -3,20 +3,11 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
speed_t cfgetispeed(const struct termios* termios)
|
|
||||||
{
|
|
||||||
return termios->c_ispeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
speed_t cfgetospeed(const struct termios* termios)
|
|
||||||
{
|
|
||||||
return termios->c_ospeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_valid_speed(speed_t speed)
|
static bool is_valid_speed(speed_t speed)
|
||||||
{
|
{
|
||||||
switch (speed)
|
switch (speed)
|
||||||
@@ -43,6 +34,16 @@ static bool is_valid_speed(speed_t speed)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
speed_t cfgetispeed(const struct termios* termios)
|
||||||
|
{
|
||||||
|
return termios->c_ispeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
speed_t cfgetospeed(const struct termios* termios)
|
||||||
|
{
|
||||||
|
return termios->c_ospeed;
|
||||||
|
}
|
||||||
|
|
||||||
int cfsetispeed(struct termios* termios, speed_t speed)
|
int cfsetispeed(struct termios* termios, speed_t speed)
|
||||||
{
|
{
|
||||||
if (!is_valid_speed(speed))
|
if (!is_valid_speed(speed))
|
||||||
@@ -87,10 +88,29 @@ int tcflush(int fd, int queue_selector)
|
|||||||
|
|
||||||
int tcgetattr(int fildes, struct termios* termios)
|
int tcgetattr(int fildes, struct termios* termios)
|
||||||
{
|
{
|
||||||
return syscall(SYS_TCGETATTR, fildes, termios);
|
return ioctl(fildes, TCGETS, termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t tcgetsid(int);
|
int tcsetattr(int fildes, int optional_actions, const struct termios* termios)
|
||||||
|
{
|
||||||
|
int ioctl_num;
|
||||||
|
switch (optional_actions)
|
||||||
|
{
|
||||||
|
case TCSANOW:
|
||||||
|
ioctl_num = TCSETS;
|
||||||
|
break;
|
||||||
|
case TCSADRAIN:
|
||||||
|
ioctl_num = TCSETSW;
|
||||||
|
break;
|
||||||
|
case TCSAFLUSH:
|
||||||
|
ioctl_num = TCSETSF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ioctl(fildes, ioctl_num, termios);
|
||||||
|
}
|
||||||
|
|
||||||
int tcsendbreak(int fd, int duration)
|
int tcsendbreak(int fd, int duration)
|
||||||
{
|
{
|
||||||
@@ -98,7 +118,12 @@ int tcsendbreak(int fd, int duration)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tcsetattr(int fildes, int optional_actions, const struct termios* termios)
|
int tcgetwinsize(int fildes, struct winsize* winsize_p)
|
||||||
{
|
{
|
||||||
return syscall(SYS_TCSETATTR, fildes, optional_actions, termios);
|
return ioctl(fildes, TIOCGWINSZ, winsize_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcsetwinsize(int fildes, const struct winsize* winsize_p)
|
||||||
|
{
|
||||||
|
return ioctl(fildes, TIOCSWINSZ, winsize_p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <BAN/Debug.h>
|
#include <BAN/Debug.h>
|
||||||
#include <BAN/ScopeGuard.h>
|
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
|
|
||||||
#include <LibELF/AuxiliaryVector.h>
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
@@ -21,6 +20,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/banan-os.h>
|
#include <sys/banan-os.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -350,7 +350,8 @@ int dup2(int fildes, int fildes2)
|
|||||||
|
|
||||||
int isatty(int fildes)
|
int isatty(int fildes)
|
||||||
{
|
{
|
||||||
return syscall(SYS_ISATTY, fildes) >= 0;
|
struct termios termios;
|
||||||
|
return tcgetattr(fildes, &termios) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gethostname(char* name, size_t namelen)
|
int gethostname(char* name, size_t namelen)
|
||||||
@@ -444,13 +445,15 @@ static int exec_impl_shebang(FILE* fp, const char* pathname, char* const* argv,
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
BAN::ScopeGuard _1([buffer] { free(buffer); });
|
|
||||||
|
|
||||||
buffer = fgets(buffer, buffer_len, fp);
|
if (fgets(buffer, buffer_len, fp) == nullptr)
|
||||||
fclose(fp);
|
{
|
||||||
|
free(buffer);
|
||||||
if (buffer == nullptr)
|
fclose(fp);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
const auto sv_trim_whitespace =
|
const auto sv_trim_whitespace =
|
||||||
[](BAN::StringView sv) -> BAN::StringView
|
[](BAN::StringView sv) -> BAN::StringView
|
||||||
@@ -465,6 +468,7 @@ static int exec_impl_shebang(FILE* fp, const char* pathname, char* const* argv,
|
|||||||
BAN::StringView buffer_sv = buffer;
|
BAN::StringView buffer_sv = buffer;
|
||||||
if (buffer_sv.back() != '\n')
|
if (buffer_sv.back() != '\n')
|
||||||
{
|
{
|
||||||
|
free(buffer);
|
||||||
errno = ENOEXEC;
|
errno = ENOEXEC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -481,6 +485,7 @@ static int exec_impl_shebang(FILE* fp, const char* pathname, char* const* argv,
|
|||||||
|
|
||||||
if (interpreter.empty())
|
if (interpreter.empty())
|
||||||
{
|
{
|
||||||
|
free(buffer);
|
||||||
errno = ENOEXEC;
|
errno = ENOEXEC;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -495,10 +500,12 @@ static int exec_impl_shebang(FILE* fp, const char* pathname, char* const* argv,
|
|||||||
old_argc++;
|
old_argc++;
|
||||||
|
|
||||||
const size_t extra_args = 1 + !argument.empty();
|
const size_t extra_args = 1 + !argument.empty();
|
||||||
char** new_argv = static_cast<char**>(malloc((extra_args + old_argc + 1) * sizeof(char*)));;
|
char** new_argv = static_cast<char**>(malloc((extra_args + old_argc + 1) * sizeof(char*)));
|
||||||
if (new_argv == nullptr)
|
if (new_argv == nullptr)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
return -1;
|
return -1;
|
||||||
BAN::ScopeGuard _2([new_argv] { free(new_argv); });
|
}
|
||||||
|
|
||||||
new_argv[0] = const_cast<char*>(pathname);
|
new_argv[0] = const_cast<char*>(pathname);
|
||||||
if (!argument.empty())
|
if (!argument.empty())
|
||||||
@@ -509,7 +516,10 @@ static int exec_impl_shebang(FILE* fp, const char* pathname, char* const* argv,
|
|||||||
new_argv[extra_args + i] = argv[i];
|
new_argv[extra_args + i] = argv[i];
|
||||||
new_argv[extra_args + old_argc] = nullptr;
|
new_argv[extra_args + old_argc] = nullptr;
|
||||||
|
|
||||||
return exec_impl(interpreter.data(), new_argv, envp, true, shebang_depth + 1);
|
int result = exec_impl(interpreter.data(), new_argv, envp, true, shebang_depth + 1);
|
||||||
|
free(new_argv);
|
||||||
|
free(buffer);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int execl_impl(const char* pathname, const char* arg0, va_list ap, bool has_env, bool do_path_resolution)
|
static int execl_impl(const char* pathname, const char* arg0, va_list ap, bool has_env, bool do_path_resolution)
|
||||||
@@ -830,7 +840,10 @@ pid_t getsid(pid_t pid)
|
|||||||
|
|
||||||
int tcgetpgrp(int fildes)
|
int tcgetpgrp(int fildes)
|
||||||
{
|
{
|
||||||
return syscall(SYS_TCGETPGRP, fildes);
|
pid_t pgrp;
|
||||||
|
if (ioctl(fildes, TIOCGPGRP, &pgrp) == -1)
|
||||||
|
return -1;
|
||||||
|
return pgrp;
|
||||||
}
|
}
|
||||||
|
|
||||||
int seteuid(uid_t uid)
|
int seteuid(uid_t uid)
|
||||||
@@ -881,7 +894,7 @@ int setpgid(pid_t pid, pid_t pgid)
|
|||||||
|
|
||||||
int tcsetpgrp(int fildes, pid_t pgid_id)
|
int tcsetpgrp(int fildes, pid_t pgid_id)
|
||||||
{
|
{
|
||||||
return syscall(SYS_TCSETPGRP, fildes, pgid_id);
|
return ioctl(fildes, TIOCSPGRP, &pgid_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getlogin(void)
|
char* getlogin(void)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -141,14 +141,14 @@ void Terminal::run()
|
|||||||
m_cells_cols = cols();
|
m_cells_cols = cols();
|
||||||
|
|
||||||
{
|
{
|
||||||
winsize winsize {
|
const winsize winsize {
|
||||||
.ws_row = static_cast<unsigned short>(rows()),
|
.ws_row = static_cast<unsigned short>(rows()),
|
||||||
.ws_col = static_cast<unsigned short>(cols()),
|
.ws_col = static_cast<unsigned short>(cols()),
|
||||||
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
||||||
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
||||||
};
|
};
|
||||||
if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
|
if (tcsetwinsize(m_shell_info.pts_master, &winsize) == -1)
|
||||||
perror("ioctl");
|
perror("tcsetwinsize");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -212,11 +212,8 @@ void Terminal::run()
|
|||||||
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
||||||
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
||||||
};
|
};
|
||||||
if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
|
if (tcsetwinsize(m_shell_info.pts_master, &winsize) == -1)
|
||||||
{
|
perror("tcsetwinsize");
|
||||||
perror("ioctl");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent::event_t event) {
|
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent::event_t event) {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
struct config_t
|
struct config_t
|
||||||
{
|
{
|
||||||
@@ -406,7 +406,7 @@ int main(int argc, const char* argv[])
|
|||||||
else for (; i < argc; i++)
|
else for (; i < argc; i++)
|
||||||
MUST(files.emplace_back(BAN::StringView(argv[i])));
|
MUST(files.emplace_back(BAN::StringView(argv[i])));
|
||||||
|
|
||||||
g_stdout_terminal = isatty(STDOUT_FILENO) && ioctl(STDOUT_FILENO, TIOCGWINSZ, &g_terminal_size) == 0;
|
g_stdout_terminal = isatty(STDOUT_FILENO) && tcgetwinsize(STDOUT_FILENO, &g_terminal_size) == 0;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
for (size_t i = 0; i < files.size(); i++)
|
for (size_t i = 0; i < files.size(); i++)
|
||||||
|
|||||||
Reference in New Issue
Block a user