Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add selectors core module #48

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 32 additions & 26 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,40 @@ add_library(ini_mod SHARED
ini.c
deps/ini.c)

target_link_libraries(math_mod ${STATIC_LIB_TARGET})
target_link_libraries(os_mod ${STATIC_LIB_TARGET})
target_link_libraries(io_mod ${STATIC_LIB_TARGET})
target_link_libraries(numbers_mod ${STATIC_LIB_TARGET})
target_link_libraries(strings_mod ${STATIC_LIB_TARGET})
target_link_libraries(arrays_mod ${STATIC_LIB_TARGET})
target_link_libraries(utf8_mod ${STATIC_LIB_TARGET})
target_link_libraries(hashing_mod ${STATIC_LIB_TARGET})
target_link_libraries(encoding_mod ${STATIC_LIB_TARGET})
target_link_libraries(socket_mod ${STATIC_LIB_TARGET})
target_link_libraries(json_mod ${STATIC_LIB_TARGET})
target_link_libraries(lists_mod ${STATIC_LIB_TARGET})
target_link_libraries(ini_mod ${STATIC_LIB_TARGET})
add_library(selectors_mod SHARED
selectors.c)

target_link_libraries(math_mod ${STATIC_LIB_TARGET})
target_link_libraries(os_mod ${STATIC_LIB_TARGET})
target_link_libraries(io_mod ${STATIC_LIB_TARGET})
target_link_libraries(numbers_mod ${STATIC_LIB_TARGET})
target_link_libraries(strings_mod ${STATIC_LIB_TARGET})
target_link_libraries(arrays_mod ${STATIC_LIB_TARGET})
target_link_libraries(utf8_mod ${STATIC_LIB_TARGET})
target_link_libraries(hashing_mod ${STATIC_LIB_TARGET})
target_link_libraries(encoding_mod ${STATIC_LIB_TARGET})
target_link_libraries(socket_mod ${STATIC_LIB_TARGET})
target_link_libraries(json_mod ${STATIC_LIB_TARGET})
target_link_libraries(lists_mod ${STATIC_LIB_TARGET})
target_link_libraries(ini_mod ${STATIC_LIB_TARGET})
target_link_libraries(selectors_mod ${STATIC_LIB_TARGET})

if(WIN32)
target_link_libraries(socket_mod ws2_32)
target_link_libraries(selectors_mod ws2_32)
endif()

set_target_properties(math_mod PROPERTIES PREFIX "")
set_target_properties(os_mod PROPERTIES PREFIX "")
set_target_properties(io_mod PROPERTIES PREFIX "")
set_target_properties(numbers_mod PROPERTIES PREFIX "")
set_target_properties(strings_mod PROPERTIES PREFIX "")
set_target_properties(arrays_mod PROPERTIES PREFIX "")
set_target_properties(utf8_mod PROPERTIES PREFIX "")
set_target_properties(hashing_mod PROPERTIES PREFIX "")
set_target_properties(encoding_mod PROPERTIES PREFIX "")
set_target_properties(socket_mod PROPERTIES PREFIX "")
set_target_properties(json_mod PROPERTIES PREFIX "")
set_target_properties(lists_mod PROPERTIES PREFIX "")
set_target_properties(ini_mod PROPERTIES PREFIX "")
set_target_properties(math_mod PROPERTIES PREFIX "")
set_target_properties(os_mod PROPERTIES PREFIX "")
set_target_properties(io_mod PROPERTIES PREFIX "")
set_target_properties(numbers_mod PROPERTIES PREFIX "")
set_target_properties(strings_mod PROPERTIES PREFIX "")
set_target_properties(arrays_mod PROPERTIES PREFIX "")
set_target_properties(utf8_mod PROPERTIES PREFIX "")
set_target_properties(hashing_mod PROPERTIES PREFIX "")
set_target_properties(encoding_mod PROPERTIES PREFIX "")
set_target_properties(socket_mod PROPERTIES PREFIX "")
set_target_properties(json_mod PROPERTIES PREFIX "")
set_target_properties(lists_mod PROPERTIES PREFIX "")
set_target_properties(ini_mod PROPERTIES PREFIX "")
set_target_properties(selectors_mod PROPERTIES PREFIX "")
315 changes: 315 additions & 0 deletions core/selectors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
//
// The Hook Programming Language
// selectors.c
//

#include "selectors.h"

#ifdef _WIN32
#include <winsock2.h>
#else
#include <poll.h>
#endif

#ifdef _WIN32
#define Socket SOCKET
#define PollFd WSAPOLLFD
#else
#define Socket int
#define PollFd struct pollfd
#endif

#define MAX_FDS (4096)

typedef struct
{
HK_USERDATA_HEADER
int fld0;
int fld1;
int fld2;
Socket sock;
} SocketUserdata;

typedef struct
{
HK_USERDATA_HEADER
int count;
PollFd fds[MAX_FDS];
SocketUserdata *udatas[MAX_FDS];
} PollSelector;

#ifdef _WIN32
static int initialized = 0;
#endif

#ifdef _WIN32
static inline void startup(void);
static inline void cleanup(void);
#endif

static inline int socket_poll(PollFd *fds, int nfds, int timeout);
static inline PollSelector *poll_selector_new(void);
static inline bool poll_selector_register(PollSelector *selector,
SocketUserdata *udata, int events);
static inline bool poll_selector_unregister(PollSelector *selector,
SocketUserdata *udata);
static inline bool poll_selector_modify(PollSelector *selector,
SocketUserdata *udata, int events);
static inline HkArray *poll_selector_poll(PollSelector *selector, int timeout);
static void poll_selector_deinit(HkUserdata *udata);
static void new_poll_selector_call(HkState *state, HkValue *args);
static void register_call(HkState *state, HkValue *args);
static void unregister_call(HkState *state, HkValue *args);
static void modify_call(HkState *state, HkValue *args);
static void poll_call(HkState *state, HkValue *args);

#ifdef _WIN32
static inline void startup(void)
{
if (!initialized)
{
WSADATA wsa;
(void) WSAStartup(MAKEWORD(2, 2), &wsa);
}
++initialized;
}

static inline void cleanup(void)
{
--initialized;
if (initialized) return;
(void) WSACleanup();
}
#endif

static inline int socket_poll(PollFd *fds, int nfds, int timeout)

Check warning on line 85 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L85

Added line #L85 was not covered by tests
{
#ifdef _WIN32
return WSAPoll(fds, nfds, timeout);
#else
return poll(fds, nfds, timeout);

Check warning on line 90 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L90

Added line #L90 was not covered by tests
#endif
}

static inline PollSelector *poll_selector_new(void)

Check warning on line 94 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L94

Added line #L94 was not covered by tests
{
#ifdef _WIN32
startup();
#endif
PollSelector *selector = (PollSelector *) hk_allocate(sizeof(*selector));
hk_userdata_init((HkUserdata *) selector, poll_selector_deinit);
selector->count = 0;
return selector;

Check warning on line 102 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L99-L102

Added lines #L99 - L102 were not covered by tests
}

static inline bool poll_selector_register(PollSelector *selector,

Check warning on line 105 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L105

Added line #L105 was not covered by tests
SocketUserdata *udata, int events)
{
if (selector->count == MAX_FDS) return false;
PollFd fd = {
.fd = (int) udata->sock,

Check warning on line 110 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L108-L110

Added lines #L108 - L110 were not covered by tests
.events = events,
.revents = 0
};
int index = selector->count;
selector->fds[index] = fd;
selector->udatas[index] = udata;
++selector->count;
return true;

Check warning on line 118 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L114-L118

Added lines #L114 - L118 were not covered by tests
}

static inline bool poll_selector_unregister(PollSelector *selector,

Check warning on line 121 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L121

Added line #L121 was not covered by tests
SocketUserdata *udata)
{
int i = 1;
int n = selector->count;
for (; i < n; ++i)

Check warning on line 126 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L124-L126

Added lines #L124 - L126 were not covered by tests
{
PollFd *fd = &selector->fds[i];
if (fd->fd == (int) udata->sock) break;

Check warning on line 129 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L128-L129

Added lines #L128 - L129 were not covered by tests
}
if (i == n) return false;
for (; i < n - 1; ++i)

Check warning on line 132 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L131-L132

Added lines #L131 - L132 were not covered by tests
{
selector->fds[i] = selector->fds[i + 1];
selector->udatas[i] = selector->udatas[i + 1];

Check warning on line 135 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L134-L135

Added lines #L134 - L135 were not covered by tests
}
--selector->count;
return true;

Check warning on line 138 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L137-L138

Added lines #L137 - L138 were not covered by tests
}

static inline bool poll_selector_modify(PollSelector *selector,

Check warning on line 141 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L141

Added line #L141 was not covered by tests
SocketUserdata *udata, int events)
{
int i = 1;
int n = selector->count;
for (; i < n; ++i)

Check warning on line 146 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L144-L146

Added lines #L144 - L146 were not covered by tests
{
PollFd *fd = &selector->fds[i];
if (fd->fd == (int) udata->sock) break;

Check warning on line 149 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L148-L149

Added lines #L148 - L149 were not covered by tests
}
if (i == n) return false;
selector->fds[i].events = events;
return true;

Check warning on line 153 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L151-L153

Added lines #L151 - L153 were not covered by tests
}

static inline HkArray *poll_selector_poll(PollSelector *selector, int timeout)

Check warning on line 156 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L156

Added line #L156 was not covered by tests
{
HkArray *arr = hk_array_new();
int n = selector->count;
int rc = socket_poll(selector->fds, n, timeout);
if (rc == -1)

Check warning on line 161 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L158-L161

Added lines #L158 - L161 were not covered by tests
{
hk_array_free(arr);
return NULL;

Check warning on line 164 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L163-L164

Added lines #L163 - L164 were not covered by tests
}
if (!rc) goto end;
int j = 0;
for (int i = 0; i < n && j < rc; ++i)

Check warning on line 168 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L166-L168

Added lines #L166 - L168 were not covered by tests
{
PollFd *fd = &selector->fds[i];
int revents = fd->revents;
if (!revents) continue;
HkUserdata *udata = (HkUserdata *) selector->udatas[i];
HkArray *event = hk_array_new_with_capacity(2);
hk_array_inplace_add_element(event, hk_userdata_value(udata));
hk_array_inplace_add_element(event, hk_number_value(revents));
hk_array_inplace_add_element(arr, hk_array_value(event));
++j;

Check warning on line 178 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L170-L178

Added lines #L170 - L178 were not covered by tests
}
end:
return arr;

Check warning on line 181 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L180-L181

Added lines #L180 - L181 were not covered by tests
}

static void poll_selector_deinit(HkUserdata *udata)

Check warning on line 184 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L184

Added line #L184 was not covered by tests
{
(void) udata;
#ifdef _WIN32
cleanup();
#endif
}

static void new_poll_selector_call(HkState *state, HkValue *args)

Check warning on line 192 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L192

Added line #L192 was not covered by tests
{
(void) args;
hk_state_push_userdata(state, (HkUserdata *) poll_selector_new());

Check warning on line 195 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L195

Added line #L195 was not covered by tests
}

static void register_call(HkState *state, HkValue *args)

Check warning on line 198 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L198

Added line #L198 was not covered by tests
{
hk_state_check_argument_userdata(state, args, 1);
hk_return_if_not_ok(state);
hk_state_check_argument_userdata(state, args, 2);
hk_return_if_not_ok(state);
hk_state_check_argument_int(state, args, 3);
hk_return_if_not_ok(state);
PollSelector *selector = (PollSelector *) hk_as_userdata(args[1]);
SocketUserdata *udata = (SocketUserdata *) hk_as_userdata(args[2]);
int events = (int) hk_as_number(args[3]);
if (!poll_selector_register(selector, udata, events))

Check warning on line 209 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L200-L209

Added lines #L200 - L209 were not covered by tests
{
hk_state_runtime_error(state, "too many file descriptors");
return;

Check warning on line 212 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L211-L212

Added lines #L211 - L212 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 214 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L214

Added line #L214 was not covered by tests
}

static void unregister_call(HkState *state, HkValue *args)

Check warning on line 217 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L217

Added line #L217 was not covered by tests
{
hk_state_check_argument_userdata(state, args, 1);
hk_return_if_not_ok(state);
hk_state_check_argument_userdata(state, args, 2);
hk_return_if_not_ok(state);
PollSelector *selector = (PollSelector *) hk_as_userdata(args[1]);
SocketUserdata *udata = (SocketUserdata *) hk_as_userdata(args[2]);
if (!poll_selector_unregister(selector, udata))

Check warning on line 225 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L219-L225

Added lines #L219 - L225 were not covered by tests
{
hk_state_runtime_error(state, "file descriptor not found");
return;

Check warning on line 228 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L227-L228

Added lines #L227 - L228 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 230 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L230

Added line #L230 was not covered by tests
}

static void modify_call(HkState *state, HkValue *args)

Check warning on line 233 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L233

Added line #L233 was not covered by tests
{
hk_state_check_argument_userdata(state, args, 1);
hk_return_if_not_ok(state);
hk_state_check_argument_userdata(state, args, 2);
hk_return_if_not_ok(state);
hk_state_check_argument_int(state, args, 3);
hk_return_if_not_ok(state);
PollSelector *selector = (PollSelector *) hk_as_userdata(args[1]);
SocketUserdata *udata = (SocketUserdata *) hk_as_userdata(args[2]);
int events = (int) hk_as_number(args[3]);
if (!poll_selector_modify(selector, udata, events))

Check warning on line 244 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L235-L244

Added lines #L235 - L244 were not covered by tests
{
hk_state_runtime_error(state, "file descriptor not found");
return;

Check warning on line 247 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L246-L247

Added lines #L246 - L247 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 249 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L249

Added line #L249 was not covered by tests
}

static void poll_call(HkState *state, HkValue *args)

Check warning on line 252 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L252

Added line #L252 was not covered by tests
{
hk_state_check_argument_userdata(state, args, 1);
hk_return_if_not_ok(state);
hk_state_check_argument_number(state, args, 2);
hk_return_if_not_ok(state);
PollSelector *selector = (PollSelector *) hk_as_userdata(args[1]);
int timeout = (int) hk_as_number(args[2]);
HkArray *arr = poll_selector_poll(selector, timeout);
hk_state_push_array(state, arr);
if (!hk_state_is_ok(state))
hk_array_free(arr);

Check warning on line 263 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L254-L263

Added lines #L254 - L263 were not covered by tests
}

HK_LOAD_MODULE_HANDLER(selectors)

Check warning on line 266 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L266

Added line #L266 was not covered by tests
{
hk_state_push_string_from_chars(state, -1, "selectors");
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLIN");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLIN);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLOUT");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLOUT);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLERR");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLERR);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLHUP");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLHUP);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLNVAL");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLNVAL);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "POLLPRI");
hk_return_if_not_ok(state);
hk_state_push_number(state, POLLPRI);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "new_poll_selector");
hk_return_if_not_ok(state);
hk_state_push_new_native(state, "new_poll_selector", 0, new_poll_selector_call);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "register");
hk_return_if_not_ok(state);
hk_state_push_new_native(state, "register", 3, register_call);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "unregister");
hk_return_if_not_ok(state);
hk_state_push_new_native(state, "unregister", 2, unregister_call);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "modify");
hk_return_if_not_ok(state);
hk_state_push_new_native(state, "modify", 3, modify_call);
hk_return_if_not_ok(state);
hk_state_push_string_from_chars(state, -1, "poll");
hk_return_if_not_ok(state);
hk_state_push_new_native(state, "poll", 2, poll_call);
hk_return_if_not_ok(state);
hk_state_construct(state, 11);

Check warning on line 314 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L268-L314

Added lines #L268 - L314 were not covered by tests
}
13 changes: 13 additions & 0 deletions core/selectors.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// The Hook Programming Language
// selectors.h
//

#ifndef SELECTORS_H
#define SELECTORS_H

#include <hook.h>

HK_LOAD_MODULE_HANDLER(selectors);

#endif // SELECTORS_H
Loading
Loading