A 'lazy' compilation mode to make writting multiplatform code easier without having to clutter the project
ryuukk_
ryuukk.dev at gmail.com
Wed Feb 22 14:54:01 UTC 2023
On Wednesday, 22 February 2023 at 14:51:41 UTC, ryuukk_ wrote:
here my actual module:
```D
module rt.event;
version(Windows)
{
enum OK = true;
import core.sys.windows.winsock2;
import core.stdc.errno;
import core.stdc.string;
alias WSAPOLLFD = pollfd;
alias PWSAPOLLFD = pollfd*;
alias LPWSAPOLLFD = pollfd*;
struct pollfd
{
SOCKET fd;
short events;
short revents;
}
alias poll = WSAPoll;
extern(Windows) nothrow @nogc int WSAPoll(LPWSAPOLLFD
fdArray, ulong fds, int timeout);
enum short POLLRDNORM = 0x0100;
enum short POLLRDBAND = 0x0200;
enum short POLLIN = (POLLRDNORM | POLLRDBAND);
enum short POLLPRI = 0x0400;
enum short POLLWRNORM = 0x0010;
enum short POLLOUT = (POLLWRNORM);
enum short POLLWRBAND = 0x0020;
enum short POLLERR = 0x0001;
enum short POLLHUP = 0x0002;
enum short POLLNVAL = 0x0004;
alias socket_t = size_t;
}
version(Posix)
{
enum OK = true;
import core.stdc.string;
import core.sys.posix.poll;
import core.stdc.errno;
alias socket_t = int;
enum INVALID_SOCKET = -1;
}
version(Linux)
{
import core.sys.linux.epoll;
struct EPollSelector(int MAX)
{
epoll_event[MAX] fds;
size_t _count;
int epollFD_;
int fdsCount_ = 0;
void create()
{
epollFD_ = epoll_create(1);
}
Selector selector()
{
return Selector.create_it!(EPollSelector)(&this);
}
bool insert_fd(socket_t fd, FDEvent ev = FDEvent.READ)
{
auto c = _count;
auto len = fds.length;
if (c >= len)
return false;
epoll_event it;
it.data.fd = fd;
if (ev == FDEvent.READ)
it.events = EPOLLIN;
else if (ev == FDEvent.WRITE)
it.events = EPOLLOUT;
int result = epoll_ctl(epollFD_, EPOLL_CTL_ADD, fd,
&it);
// fds[_count++] = it;
return result;
}
bool update_fd(socket_t fd, FDEvent ev)
{
epoll_event it;
it.data.fd = fd;
if (ev == FDEvent.READ)
it.events = EPOLLIN;
else if (ev == FDEvent.WRITE)
it.events = EPOLLOUT;
int result = epoll_ctl(epollFD_, EPOLL_CTL_MOD, fd,
&it);
return result == 0;
}
bool remove_fd(socket_t fd)
{
int result = epoll_ctl(epollFD_, EPOLL_CTL_DEL, fd,
null);
return result == 0;
}
WaitStatus wait(int timeout)
{
fdsCount_ = epoll_wait(epollFD_, fds.ptr, _count,
timeout);
if (fdsCount_ < 0)
{
switch (errno)
{
case EINTR:
return WaitStatus.NONE;
default:
return WaitStatus.ERROR;
}
}
if (fdsCount_ == 0)
return WaitStatus.NONE;
else
return WaitStatus.OK;
}
FDResult get_status(epoll_event* ev)
{
auto fd = ev.data.fd;
// import rt.dbg;
// LINFO("r: {} {} {}", _count, p.events, p.revents);
if (ev.events & EPOLLERR)
return FDResult(fd, FDStatus.ERROR);
if ((ev.events & EPOLLIN) || (ev.events & EPOLLHUP))
return FDResult(fd, FDStatus.READ);
if (ev.events & EPOLLOUT)
return FDResult(fd, FDStatus.WRITE);
return FDResult(fd, FDStatus.NONE);
}
int opApply(scope int delegate(FDResult) dg)
{
int result;
for (int i = 0; i < _count; i++)
{
auto ptr = &fds[i];
auto res = get_status(ptr);
if ((result = dg(res)) != 0)
break;
}
return result;
}
}
}
static if (OK)
{
struct PollSelector(int MAX)
{
pollfd[MAX] fds;
size_t _count;
void create()
{
_count = 0;
foreach(ref it; fds)
{
it.fd = INVALID_SOCKET;
it.events = 0;
it.revents = 0;
}
}
Selector selector()
{
return Selector.create_it!(PollSelector)(&this);
}
bool insert_fd(socket_t fd, FDEvent ev = FDEvent.READ)
{
auto c = _count;
auto len = fds.length;
if (c >= len)
return false;
pollfd it;
it.fd = fd;
if (ev == FDEvent.READ)
it.events = POLLIN;
else if (ev == FDEvent.WRITE)
it.events = POLLOUT;
it.revents = 0;
fds[_count++] = it;
return true;
}
bool update_fd(socket_t fd, FDEvent ev)
{
foreach(ref it; fds)
{
if (it.fd == fd)
{
if (ev == FDEvent.READ)
it.events = POLLIN;
else if (ev == FDEvent.WRITE)
it.events = POLLOUT;
it.revents = 0;
return true;
}
}
return false;
}
bool remove_fd(socket_t fd)
{
int index = -1;
foreach(i, ref it; fds)
{
if (it.fd == fd)
{
index = cast(int) i;
it.fd = INVALID_SOCKET;
it.events = 0;
it.revents = 0;
break;
}
}
if (index >= 0)
{
memmove(fds.ptr + index, // dest
fds.ptr + index + 1, // src
(_count - index) * pollfd.sizeof); // num
bytes
}
return index >= 0;
}
WaitStatus wait(int timeout)
{
int activity = poll(fds.ptr, _count, timeout);
if (activity < 0)
{
switch (last_error())
{
case EAGAIN:
case EINTR:
return WaitStatus.OK;
default:
return WaitStatus.ERROR;
}
}
if (activity == 0)
return WaitStatus.NONE;
else
return WaitStatus.OK;
}
FDResult get_status(pollfd* p)
{
auto fd = p.fd;
import rt.dbg;
// LINFO("r: {} {} {}", _count, p.events, p.revents);
if (fd >= 0)
{
if (p.revents & POLLERR)
return FDResult(fd, FDStatus.ERROR);
if (p.revents & POLLIN)
return FDResult(fd, FDStatus.READ);
if (p.revents & POLLOUT)
return FDResult(fd, FDStatus.WRITE);
}
return FDResult(fd, FDStatus.NONE);
}
int opApply(scope int delegate(FDResult) dg)
{
int result;
for (int i = 0; i < _count; i++)
{
auto ptr = &fds[i];
auto res = get_status(ptr);
if ((result = dg(res)) != 0)
break;
}
return result;
}
}
struct Selector
{
struct VTable
{
bool function(const void* self, socket_t fd, FDEvent
ev) insert_fd;
bool function(const void* self, socket_t fd, FDEvent
ev) update_fd;
bool function(const void* self, socket_t fd)
remove_fd;
WaitStatus function(const void* self, int timeout)
wait;
FDResult function(const void* self, pollfd* p)
get_status;
}
void* ptr;
VTable* vt;
static Selector create_it(T)(void* pointer)
{
static struct gen(T)
{
__gshared static VTable vtable = {
insert_fd: &insert_fd_impl,
update_fd: &update_fd_impl,
remove_fd: &remove_fd_impl,
wait: &wait_impl,
get_status: &get_status_impl,
};
static bool insert_fd_impl(const void* ptr,
socket_t fd, FDEvent ev)
{
auto self = cast(T*) ptr;
return self.insert_fd(fd, ev);
}
static bool update_fd_impl(const void* ptr,
socket_t fd, FDEvent ev)
{
auto self = cast(T*) ptr;
return self.update_fd(fd, ev);
}
static bool remove_fd_impl(const void* ptr,
socket_t fd)
{
auto self = cast(T*) ptr;
return self.remove_fd(fd);
}
static WaitStatus wait_impl(const void* ptr, int
timeout)
{
auto self = cast(T*) ptr;
return self.wait(timeout);
}
static FDResult get_status_impl(const void* ptr,
pollfd* p)
{
auto self = cast(T*) ptr;
return self.get_status(p);
}
}
assert(pointer);
return Selector(pointer, &gen!(T).vtable);
}
}
enum WaitStatus
{
OK,
NONE,
ERROR
}
enum FDEvent : bool
{
READ,
WRITE
}
enum FDStatus : ubyte
{
NONE,
READ,
WRITE,
ERROR,
STOP
}
struct FDResult
{
socket_t fd = INVALID_SOCKET;
FDStatus status;
}
package:
int last_error()
{
version (Windows)
return WSAGetLastError();
else version (Posix)
return errno;
else
static assert(0);
}
}
```
More information about the Digitalmars-d
mailing list