Compare commits
5 Commits
97d7a7cc6b
...
d49fbb8016
Author | SHA1 | Date | |
---|---|---|---|
d49fbb8016 | |||
8b91b7acc0 | |||
ec5b83ff01 | |||
be5903c0c8 | |||
d4fc002d8a |
@ -43,3 +43,4 @@ luna_app(kill.cpp kill)
|
|||||||
luna_app(gol.cpp gol)
|
luna_app(gol.cpp gol)
|
||||||
luna_app(buffer-test.cpp buffer-test)
|
luna_app(buffer-test.cpp buffer-test)
|
||||||
luna_app(socket-test.cpp socket-test)
|
luna_app(socket-test.cpp socket-test)
|
||||||
|
luna_app(socket-client.cpp socket-client)
|
||||||
|
40
apps/socket-client.cpp
Normal file
40
apps/socket-client.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
perror("socket");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un un;
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
strncpy(un.sun_path, "/tmp/local.sock", sizeof(un.sun_path));
|
||||||
|
|
||||||
|
if (connect(sockfd, (struct sockaddr*)&un, sizeof(un)) < 0)
|
||||||
|
{
|
||||||
|
perror("connect");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t nread = read(sockfd, buf, sizeof(buf) - 1);
|
||||||
|
if (nread > 0)
|
||||||
|
{
|
||||||
|
buf[nread] = 0;
|
||||||
|
printf("Message from server: %s\n", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* message = "EXIT";
|
||||||
|
write(sockfd, message, strlen(message));
|
||||||
|
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,10 +1,18 @@
|
|||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
setgid(1000);
|
||||||
|
setuid(1000);
|
||||||
|
|
||||||
|
remove("/tmp/local.sock");
|
||||||
|
|
||||||
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
{
|
{
|
||||||
@ -21,4 +29,47 @@ int main()
|
|||||||
perror("bind");
|
perror("bind");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (listen(sockfd, 10) < 0)
|
||||||
|
{
|
||||||
|
perror("listen");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int fd = accept(sockfd, NULL, NULL);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
perror("accept");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("New connection from client, sending hello");
|
||||||
|
|
||||||
|
const char* message = "Hello, client!";
|
||||||
|
write(fd, message, strlen(message));
|
||||||
|
|
||||||
|
puts("Now waiting for client to message back");
|
||||||
|
|
||||||
|
char buf[4096];
|
||||||
|
ssize_t nread = read(fd, buf, sizeof(buf) - 1);
|
||||||
|
if (nread >= 0)
|
||||||
|
{
|
||||||
|
buf[nread] = 0;
|
||||||
|
printf("Message from client: %s\n", buf);
|
||||||
|
if (!strcasecmp(buf, "exit"))
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
close(sockfd);
|
||||||
|
remove("/tmp/local.sock");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { printf("Error reading from client: %s\n", strerror(errno)); }
|
||||||
|
|
||||||
|
puts("Transmission ended, closing connection");
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
6
base/etc/init/98-listen
Normal file
6
base/etc/init/98-listen
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Name=listen
|
||||||
|
Description=Start a Unix domain socket test server.
|
||||||
|
Command=/usr/bin/socket-test
|
||||||
|
StandardOutput=/dev/uart0
|
||||||
|
StandardError=/dev/uart0
|
||||||
|
Restart=true
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "arch/CPU.h"
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
|
#include "thread/Thread.h"
|
||||||
#include <bits/socket.h>
|
#include <bits/socket.h>
|
||||||
|
|
||||||
class Socket : public VFS::FileInode
|
class Socket : public VFS::FileInode
|
||||||
@ -47,7 +49,11 @@ class Socket : public VFS::FileInode
|
|||||||
virtual Result<usize> recv(u8*, usize, int) const = 0;
|
virtual Result<usize> recv(u8*, usize, int) const = 0;
|
||||||
|
|
||||||
virtual Result<void> bind(SharedPtr<Socket>, struct sockaddr*, socklen_t) = 0;
|
virtual Result<void> bind(SharedPtr<Socket>, struct sockaddr*, socklen_t) = 0;
|
||||||
virtual Result<void> connect(struct sockaddr*, socklen_t) = 0;
|
virtual Result<void> connect(Registers*, int, struct sockaddr*, socklen_t) = 0;
|
||||||
|
|
||||||
|
virtual Result<SharedPtr<OpenFileDescription>> accept(Registers*, int, struct sockaddr**, socklen_t*) = 0;
|
||||||
|
|
||||||
|
virtual Result<void> listen(int backlog) = 0;
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
Result<void> truncate(usize) override
|
||||||
{
|
{
|
||||||
@ -105,7 +111,7 @@ class Socket : public VFS::FileInode
|
|||||||
virtual ~Socket() = default;
|
virtual ~Socket() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VFS::FileSystem* m_fs;
|
VFS::FileSystem* m_fs { nullptr };
|
||||||
usize m_inode_number { 0 };
|
usize m_inode_number { 0 };
|
||||||
mode_t m_mode;
|
mode_t m_mode;
|
||||||
u32 m_uid { 0 };
|
u32 m_uid { 0 };
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "net/UnixSocket.h"
|
#include "net/UnixSocket.h"
|
||||||
|
#include <bits/open-flags.h>
|
||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
#include <thread/Scheduler.h>
|
#include <thread/Scheduler.h>
|
||||||
|
|
||||||
@ -45,8 +46,8 @@ Result<usize> UnixSocket::send(const u8* buf, usize length, int)
|
|||||||
|
|
||||||
Result<usize> UnixSocket::recv(u8* buf, usize length, int) const
|
Result<usize> UnixSocket::recv(u8* buf, usize length, int) const
|
||||||
{
|
{
|
||||||
if (m_state == State::Reset) return err(ECONNRESET);
|
if (m_state == State::Reset && !m_data.size()) return err(ECONNRESET);
|
||||||
if (m_state != State::Connected) return err(ENOTCONN);
|
if (m_state != State::Connected && m_state != State::Reset) return err(ENOTCONN);
|
||||||
|
|
||||||
return m_data.dequeue_data(buf, length);
|
return m_data.dequeue_data(buf, length);
|
||||||
}
|
}
|
||||||
@ -104,7 +105,100 @@ Result<void> UnixSocket::bind(SharedPtr<Socket> socket, struct sockaddr* addr, s
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> UnixSocket::connect(struct sockaddr*, socklen_t)
|
Result<void> UnixSocket::connect(Registers* regs, int flags, struct sockaddr* addr, socklen_t addrlen)
|
||||||
{
|
{
|
||||||
return err(ENOSYS);
|
if (!addr) return err(EINVAL);
|
||||||
|
if (addr->sa_family != AF_UNIX) return err(EAFNOSUPPORT);
|
||||||
|
if ((usize)addrlen > sizeof(sockaddr_un)) return err(EINVAL);
|
||||||
|
|
||||||
|
if (m_state == State::Connected) return err(EISCONN);
|
||||||
|
if (m_state == State::Connecting) return err(EALREADY);
|
||||||
|
if (m_state != State::Inactive) return err(EINVAL);
|
||||||
|
|
||||||
|
struct sockaddr_un* un_address = (struct sockaddr_un*)addr;
|
||||||
|
|
||||||
|
String path = TRY(String::from_string_view(
|
||||||
|
StringView::from_fixed_size_cstring(un_address->sun_path, addrlen - sizeof(sa_family_t))));
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||||
|
if (inode->type() != VFS::InodeType::Socket)
|
||||||
|
return err(ENOTSOCK); // FIXME: POSIX doesn't say what error to return here?
|
||||||
|
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||||
|
|
||||||
|
auto socket = (SharedPtr<UnixSocket>)inode;
|
||||||
|
if (socket->m_state != State::Listening) return err(ECONNREFUSED);
|
||||||
|
if (!socket->m_listen_queue.try_push(this)) return err(ECONNREFUSED);
|
||||||
|
if (socket->m_blocked_thread) socket->m_blocked_thread->wake_up();
|
||||||
|
|
||||||
|
m_state = Connecting;
|
||||||
|
if (flags & O_NONBLOCK) return err(EINPROGRESS);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
m_blocked_thread = current;
|
||||||
|
kernel_wait_for_event();
|
||||||
|
m_blocked_thread = nullptr;
|
||||||
|
if (current->interrupted)
|
||||||
|
{
|
||||||
|
if (current->will_invoke_signal_handler()) return err(EINTR);
|
||||||
|
current->process_pending_signals(regs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
check(m_state == Connected);
|
||||||
|
check(m_peer);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> UnixSocket::listen(int backlog)
|
||||||
|
{
|
||||||
|
if (backlog < 0) backlog = 0;
|
||||||
|
if (m_state == State::Listening || m_state == State::Connected) return err(EINVAL);
|
||||||
|
if (m_state != State::Bound) return err(EDESTADDRREQ);
|
||||||
|
TRY(m_listen_queue.set_size(backlog));
|
||||||
|
m_state = State::Listening;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<OpenFileDescription>> UnixSocket::accept(Registers* regs, int flags, struct sockaddr** addr,
|
||||||
|
socklen_t* addrlen)
|
||||||
|
{
|
||||||
|
if (m_state != State::Listening) return err(EINVAL);
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
UnixSocket* peer = nullptr;
|
||||||
|
while (!m_listen_queue.try_pop(peer))
|
||||||
|
{
|
||||||
|
if (flags & O_NONBLOCK) return err(EAGAIN);
|
||||||
|
m_blocked_thread = current;
|
||||||
|
kernel_wait_for_event();
|
||||||
|
m_blocked_thread = nullptr;
|
||||||
|
if (current->interrupted)
|
||||||
|
{
|
||||||
|
if (current->will_invoke_signal_handler()) return err(EINTR);
|
||||||
|
current->process_pending_signals(regs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check(peer);
|
||||||
|
|
||||||
|
auto socket = TRY(make_shared<UnixSocket>(peer));
|
||||||
|
auto description = TRY(make_shared<OpenFileDescription>(socket, O_RDWR));
|
||||||
|
|
||||||
|
peer->m_peer = socket.ptr();
|
||||||
|
peer->m_state = State::Connected;
|
||||||
|
|
||||||
|
if (peer->m_blocked_thread) peer->m_blocked_thread->wake_up();
|
||||||
|
|
||||||
|
*addr = (struct sockaddr*)&peer->m_addr;
|
||||||
|
*addrlen = peer->m_addrlen;
|
||||||
|
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "net/Socket.h"
|
#include "net/Socket.h"
|
||||||
|
#include "thread/Thread.h"
|
||||||
#include <luna/Buffer.h>
|
#include <luna/Buffer.h>
|
||||||
|
#include <luna/CircularQueue.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
@ -12,14 +14,17 @@ class UnixSocket : public Socket
|
|||||||
|
|
||||||
bool blocking() const override
|
bool blocking() const override
|
||||||
{
|
{
|
||||||
return !m_data.size();
|
return (m_state == Connected || m_state == Reset) && !m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<usize> send(const u8*, usize, int) override;
|
Result<usize> send(const u8*, usize, int) override;
|
||||||
Result<usize> recv(u8*, usize, int) const override;
|
Result<usize> recv(u8*, usize, int) const override;
|
||||||
|
|
||||||
Result<void> bind(SharedPtr<Socket>, struct sockaddr*, socklen_t) override;
|
Result<void> bind(SharedPtr<Socket>, struct sockaddr*, socklen_t) override;
|
||||||
Result<void> connect(struct sockaddr*, socklen_t) override;
|
Result<void> connect(Registers*, int, struct sockaddr*, socklen_t) override;
|
||||||
|
Result<SharedPtr<OpenFileDescription>> accept(Registers*, int, struct sockaddr**, socklen_t*) override;
|
||||||
|
|
||||||
|
Result<void> listen(int backlog) override;
|
||||||
|
|
||||||
void did_close() override;
|
void did_close() override;
|
||||||
|
|
||||||
@ -39,10 +44,14 @@ class UnixSocket : public Socket
|
|||||||
};
|
};
|
||||||
|
|
||||||
State m_state = State::Inactive;
|
State m_state = State::Inactive;
|
||||||
UnixSocket* m_peer;
|
UnixSocket* m_peer = nullptr;
|
||||||
|
|
||||||
mutable Buffer m_data;
|
mutable Buffer m_data;
|
||||||
|
|
||||||
|
Thread* m_blocked_thread { nullptr };
|
||||||
|
|
||||||
|
DynamicCircularQueue<UnixSocket*> m_listen_queue;
|
||||||
|
|
||||||
struct sockaddr_un m_addr = { .sun_family = AF_UNIX, .sun_path = {} };
|
struct sockaddr_un m_addr = { .sun_family = AF_UNIX, .sun_path = {} };
|
||||||
socklen_t m_addrlen = sizeof(sa_family_t);
|
socklen_t m_addrlen = sizeof(sa_family_t);
|
||||||
};
|
};
|
||||||
|
@ -47,3 +47,83 @@ Result<u64> sys_bind(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<u64> sys_connect(Registers* regs, SyscallArgs args)
|
||||||
|
{
|
||||||
|
int sockfd = (int)args[0];
|
||||||
|
struct sockaddr* addr = (struct sockaddr*)args[1];
|
||||||
|
socklen_t addrlen = (socklen_t)args[2];
|
||||||
|
|
||||||
|
struct sockaddr_storage storage;
|
||||||
|
if ((usize)addrlen > sizeof(storage)) return err(EINVAL);
|
||||||
|
if (!MemoryManager::copy_from_user(addr, &storage, addrlen)) return err(EFAULT);
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
auto description = TRY(current->resolve_fd(sockfd))->description;
|
||||||
|
|
||||||
|
if (description->inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK);
|
||||||
|
|
||||||
|
auto socket = (SharedPtr<Socket>)description->inode;
|
||||||
|
|
||||||
|
TRY(socket->connect(regs, description->flags, (struct sockaddr*)&storage, addrlen));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<u64> sys_listen(Registers*, SyscallArgs args)
|
||||||
|
{
|
||||||
|
int sockfd = (int)args[0];
|
||||||
|
int backlog = (int)args[1];
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
auto inode = TRY(current->resolve_fd(sockfd))->inode();
|
||||||
|
|
||||||
|
if (inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK);
|
||||||
|
|
||||||
|
auto socket = (SharedPtr<Socket>)inode;
|
||||||
|
|
||||||
|
TRY(socket->listen(backlog));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<u64> sys_accept(Registers* regs, SyscallArgs args)
|
||||||
|
{
|
||||||
|
int sockfd = (int)args[0];
|
||||||
|
struct sockaddr* addr = (struct sockaddr*)args[1];
|
||||||
|
socklen_t* addrlen = (socklen_t*)args[2];
|
||||||
|
|
||||||
|
if (addr && !addrlen) return err(EINVAL);
|
||||||
|
|
||||||
|
socklen_t len;
|
||||||
|
if (addr)
|
||||||
|
{
|
||||||
|
if (!MemoryManager::copy_from_user_typed(addrlen, &len)) return err(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* current = Scheduler::current();
|
||||||
|
|
||||||
|
auto description = TRY(current->resolve_fd(sockfd))->description;
|
||||||
|
|
||||||
|
if (description->inode->type() != VFS::InodeType::Socket) return err(ENOTSOCK);
|
||||||
|
|
||||||
|
auto socket = (SharedPtr<Socket>)description->inode;
|
||||||
|
|
||||||
|
struct sockaddr* client;
|
||||||
|
socklen_t client_len;
|
||||||
|
auto new_description = TRY(socket->accept(regs, description->flags, &client, &client_len));
|
||||||
|
|
||||||
|
int fd = TRY(current->allocate_fd(0));
|
||||||
|
current->fd_table[fd] = FileDescriptor { new_description, 0 };
|
||||||
|
|
||||||
|
if (client_len < len) len = client_len;
|
||||||
|
if (addr)
|
||||||
|
{
|
||||||
|
MemoryManager::copy_to_user(addr, client, len);
|
||||||
|
MemoryManager::copy_to_user_typed(addrlen, &client_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
@ -16,6 +16,15 @@ extern "C"
|
|||||||
/* Bind a socket to an address. */
|
/* Bind a socket to an address. */
|
||||||
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen);
|
int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
|
||||||
|
/* Connect a socket to a remote address. */
|
||||||
|
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
|
||||||
|
/* Start listening on a socket. */
|
||||||
|
int listen(int sockfd, int backlog);
|
||||||
|
|
||||||
|
/* Wait for an incoming connection on a socket. */
|
||||||
|
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,4 +16,22 @@ extern "C"
|
|||||||
long rc = syscall(SYS_bind, sockfd, addr, addrlen);
|
long rc = syscall(SYS_bind, sockfd, addr, addrlen);
|
||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
long rc = syscall(SYS_connect, sockfd, addr, addrlen);
|
||||||
|
__errno_return(rc, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
int listen(int sockfd, int backlog)
|
||||||
|
{
|
||||||
|
long rc = syscall(SYS_listen, sockfd, backlog);
|
||||||
|
__errno_return(rc, int);
|
||||||
|
}
|
||||||
|
|
||||||
|
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||||
|
{
|
||||||
|
long rc = syscall(SYS_accept, sockfd, addr, addrlen);
|
||||||
|
__errno_return(rc, int);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Atomic.h>
|
#include <luna/Atomic.h>
|
||||||
|
#include <luna/Heap.h>
|
||||||
|
#include <luna/Result.h>
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
|
|
||||||
template <typename T, usize Size> class CircularQueue
|
template <typename T, usize Size> class CircularQueue
|
||||||
@ -55,3 +57,68 @@ template <typename T, usize Size> class CircularQueue
|
|||||||
Atomic<usize> m_head = 0;
|
Atomic<usize> m_head = 0;
|
||||||
Atomic<usize> m_tail = 0;
|
Atomic<usize> m_tail = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> class DynamicCircularQueue
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
DynamicCircularQueue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~DynamicCircularQueue()
|
||||||
|
{
|
||||||
|
if (m_data) free_impl(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> set_size(usize size)
|
||||||
|
{
|
||||||
|
m_data = (T*)TRY(calloc_impl(size + 1, sizeof(T), false));
|
||||||
|
m_capacity = size + 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_push(const T& value)
|
||||||
|
{
|
||||||
|
check(m_capacity);
|
||||||
|
usize current_tail = m_tail.load(MemoryOrder::Relaxed);
|
||||||
|
const usize new_tail = (current_tail + 1) % m_capacity;
|
||||||
|
if (new_tail == m_head.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is full
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_data[current_tail] = value;
|
||||||
|
if (!m_tail.compare_exchange_strong(current_tail, new_tail, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the tail
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_pop(T& value)
|
||||||
|
{
|
||||||
|
check(m_capacity);
|
||||||
|
usize current_head = m_head.load(MemoryOrder::Relaxed);
|
||||||
|
if (current_head == m_tail.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is empty
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = m_data[current_head];
|
||||||
|
const usize new_head = (current_head + 1) % m_capacity;
|
||||||
|
if (!m_head.compare_exchange_strong(current_head, new_head, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the head
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* m_data = nullptr;
|
||||||
|
usize m_capacity = 0;
|
||||||
|
Atomic<usize> m_head = 0;
|
||||||
|
Atomic<usize> m_tail = 0;
|
||||||
|
};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
_e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \
|
_e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \
|
||||||
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
|
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
|
||||||
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
||||||
_e(getpgid) _e(socket) _e(bind)
|
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept)
|
||||||
|
|
||||||
enum Syscalls
|
enum Syscalls
|
||||||
{
|
{
|
||||||
|
@ -1,59 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define EPERM 1 // Operation not permitted
|
#define EPERM 1 // Operation not permitted
|
||||||
#define ENOENT 2 // No such file or directory
|
#define ENOENT 2 // No such file or directory
|
||||||
#define ESRCH 3 // No such process
|
#define ESRCH 3 // No such process
|
||||||
#define EINTR 4 // Interrupted system call
|
#define EINTR 4 // Interrupted system call
|
||||||
#define EIO 5 // Input/output error
|
#define EIO 5 // Input/output error
|
||||||
#define ENXIO 6 // No such device or address
|
#define ENXIO 6 // No such device or address
|
||||||
#define E2BIG 7 // Argument list too long
|
#define E2BIG 7 // Argument list too long
|
||||||
#define ENOEXEC 8 // Exec format error
|
#define ENOEXEC 8 // Exec format error
|
||||||
#define EBADF 9 // Bad file descriptor
|
#define EBADF 9 // Bad file descriptor
|
||||||
#define ECHILD 10 // No child processes
|
#define ECHILD 10 // No child processes
|
||||||
#define EAGAIN 11 // Resource temporarily unavailable
|
#define EAGAIN 11 // Resource temporarily unavailable
|
||||||
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
||||||
#define ENOMEM 12 // Cannot allocate memory
|
#define ENOMEM 12 // Cannot allocate memory
|
||||||
#define EACCES 13 // Permission denied
|
#define EACCES 13 // Permission denied
|
||||||
#define EFAULT 14 // Bad address
|
#define EFAULT 14 // Bad address
|
||||||
#define ENOTBLK 15 // Block device required
|
#define ENOTBLK 15 // Block device required
|
||||||
#define EBUSY 16 // Device or resource busy
|
#define EBUSY 16 // Device or resource busy
|
||||||
#define EEXIST 17 // File exists
|
#define EEXIST 17 // File exists
|
||||||
#define EXDEV 18 // Invalid cross-device link
|
#define EXDEV 18 // Invalid cross-device link
|
||||||
#define ENODEV 19 // No such device
|
#define ENODEV 19 // No such device
|
||||||
#define ENOTDIR 20 // Not a directory
|
#define ENOTDIR 20 // Not a directory
|
||||||
#define EISDIR 21 // Is a directory
|
#define EISDIR 21 // Is a directory
|
||||||
#define EINVAL 22 // Invalid argument
|
#define EINVAL 22 // Invalid argument
|
||||||
#define ENFILE 23 // Too many open files in system
|
#define ENFILE 23 // Too many open files in system
|
||||||
#define EMFILE 24 // Too many open files
|
#define EMFILE 24 // Too many open files
|
||||||
#define ENOTTY 25 // Inappropriate ioctl for device
|
#define ENOTTY 25 // Inappropriate ioctl for device
|
||||||
#define ETXTBSY 26 // Text file busy
|
#define ETXTBSY 26 // Text file busy
|
||||||
#define EFBIG 27 // File too large
|
#define EFBIG 27 // File too large
|
||||||
#define ENOSPC 28 // No space left on device
|
#define ENOSPC 28 // No space left on device
|
||||||
#define ESPIPE 29 // Illegal seek
|
#define ESPIPE 29 // Illegal seek
|
||||||
#define EROFS 30 // Read-only file system
|
#define EROFS 30 // Read-only file system
|
||||||
#define EMLINK 31 // Too many links
|
#define EMLINK 31 // Too many links
|
||||||
#define EPIPE 32 // Broken pipe
|
#define EPIPE 32 // Broken pipe
|
||||||
#define EDOM 33 // Numerical argument out of domain
|
#define EDOM 33 // Numerical argument out of domain
|
||||||
#define ERANGE 34 // Numerical result out of range
|
#define ERANGE 34 // Numerical result out of range
|
||||||
#define EDEADLK 35 // Resource deadlock avoided
|
#define EDEADLK 35 // Resource deadlock avoided
|
||||||
#define ENAMETOOLONG 36 // File name too long
|
#define ENAMETOOLONG 36 // File name too long
|
||||||
#define ENOLCK 37 // No locks available
|
#define ENOLCK 37 // No locks available
|
||||||
#define ENOSYS 38 // Function not implemented
|
#define ENOSYS 38 // Function not implemented
|
||||||
#define ENOTEMPTY 39 // Directory not empty
|
#define ENOTEMPTY 39 // Directory not empty
|
||||||
#define ELOOP 40 // Too many levels of symbolic links
|
#define ELOOP 40 // Too many levels of symbolic links
|
||||||
#define ENOMSG 42 // No message of desired type
|
#define ENOMSG 42 // No message of desired type
|
||||||
#define EOVERFLOW 75 // Value too large for defined data type
|
#define EOVERFLOW 75 // Value too large for defined data type
|
||||||
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character
|
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character
|
||||||
#define ENOTSOCK 88 // Socket operation on non-socket
|
#define ENOTSOCK 88 // Socket operation on non-socket
|
||||||
#define EDESTADDRREQ 89 // Destination address required
|
#define EDESTADDRREQ 89 // Destination address required
|
||||||
#define EPROTOTYPE 91 // Protocol wrong type for socket
|
#define EPROTOTYPE 91 // Protocol wrong type for socket
|
||||||
#define ENOTSUP 95 // Operation not supported
|
#define ENOTSUP 95 // Operation not supported
|
||||||
#define EOPNOTSUPP 95 // Operation not supported
|
#define EOPNOTSUPP 95 // Operation not supported
|
||||||
#define EAFNOSUPPORT 97 // Address family not supported by protocol
|
#define EAFNOSUPPORT 97 // Address family not supported by protocol
|
||||||
#define EADDRINUSE 98 // Address already in use
|
#define EADDRINUSE 98 // Address already in use
|
||||||
#define ENETRESET 102 // Network dropped connection on reset
|
#define EADDRNOTAVAIL 99 // Cannot assign requested address
|
||||||
#define ECONNRESET 104 // Connection reset by peer
|
#define ENETRESET 102 // Network dropped connection on reset
|
||||||
#define EISCONN 106 // Transport endpoint is already connected
|
#define ECONNRESET 104 // Connection reset by peer
|
||||||
#define ENOTCONN 107 // Transport endpoint is not connected
|
#define EISCONN 106 // Transport endpoint is already connected
|
||||||
#define ETIMEDOUT 110 // Connection timed out
|
#define ENOTCONN 107 // Transport endpoint is not connected
|
||||||
#define EALREADY 114 // Operation already in progress
|
#define ETIMEDOUT 110 // Connection timed out
|
||||||
|
#define ECONNREFUSED 111 // Connection refused
|
||||||
|
#define EALREADY 114 // Operation already in progress
|
||||||
|
#define EINPROGRESS 115 // Operation now in progress
|
||||||
|
@ -60,6 +60,9 @@ const char* error_string(int error)
|
|||||||
case EPROTOTYPE: return "Protocol wrong type for socket";
|
case EPROTOTYPE: return "Protocol wrong type for socket";
|
||||||
case EAFNOSUPPORT: return "Address family not supported by protocol";
|
case EAFNOSUPPORT: return "Address family not supported by protocol";
|
||||||
case ENOTCONN: return "Transport endpoint is not connected";
|
case ENOTCONN: return "Transport endpoint is not connected";
|
||||||
|
case EADDRNOTAVAIL: return "Cannot assign requested address";
|
||||||
|
case ECONNREFUSED: return "Connection refused";
|
||||||
|
case EINPROGRESS: return "Operation now in progress";
|
||||||
default: return "Unknown error";
|
default: return "Unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,6 +125,13 @@ const char* error_name(int error)
|
|||||||
ERROR(EISCONN);
|
ERROR(EISCONN);
|
||||||
ERROR(ETIMEDOUT);
|
ERROR(ETIMEDOUT);
|
||||||
ERROR(EALREADY);
|
ERROR(EALREADY);
|
||||||
|
ERROR(EDESTADDRREQ);
|
||||||
|
ERROR(EPROTOTYPE);
|
||||||
|
ERROR(EAFNOSUPPORT);
|
||||||
|
ERROR(ENOTCONN);
|
||||||
|
ERROR(EADDRNOTAVAIL);
|
||||||
|
ERROR(ECONNREFUSED);
|
||||||
|
ERROR(EINPROGRESS);
|
||||||
default: return nullptr;
|
default: return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user