Skip to content

Commit

Permalink
added selectors core module
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiosvm committed Apr 1, 2024
1 parent c0fd9a0 commit c8e0890
Show file tree
Hide file tree
Showing 6 changed files with 549 additions and 27 deletions.
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 "")
319 changes: 319 additions & 0 deletions core/selectors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
//
// 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;
int rc = WSAStartup(MAKEWORD(2, 2), &wsa);
assert(!rc);
(void) rc;
}
++initialized;
}

static inline void cleanup(void)
{
--initialized;
if (initialized) return;
int rc = WSACleanup();
assert(!rc);
(void) rc;
}
#endif

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

Check warning on line 89 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L89

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

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
#endif
}

static inline PollSelector *poll_selector_new(void)

Check warning on line 98 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L98

Added line #L98 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 106 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L103-L106

Added lines #L103 - L106 were not covered by tests
}

static inline bool poll_selector_register(PollSelector *selector,

Check warning on line 109 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L109

Added line #L109 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 114 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L112-L114

Added lines #L112 - L114 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 122 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L118-L122

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

static inline bool poll_selector_unregister(PollSelector *selector,

Check warning on line 125 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L125

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

Check warning on line 130 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L128-L130

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

Check warning on line 133 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L132-L133

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

Check warning on line 136 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L135-L136

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

Check warning on line 139 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L138-L139

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

Check warning on line 142 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L141-L142

Added lines #L141 - L142 were not covered by tests
}

static inline bool poll_selector_modify(PollSelector *selector,

Check warning on line 145 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L145

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

Check warning on line 150 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L148-L150

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

Check warning on line 153 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L152-L153

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

Check warning on line 157 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L155-L157

Added lines #L155 - L157 were not covered by tests
}

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

Check warning on line 160 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L160

Added line #L160 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 165 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L162-L165

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

Check warning on line 168 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L167-L168

Added lines #L167 - L168 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 172 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L170-L172

Added lines #L170 - L172 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 182 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L174-L182

Added lines #L174 - L182 were not covered by tests
}
end:
return arr;

Check warning on line 185 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L184-L185

Added lines #L184 - L185 were not covered by tests
}

static void poll_selector_deinit(HkUserdata *udata)

Check warning on line 188 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L188

Added line #L188 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 196 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L196

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

Check warning on line 199 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L199

Added line #L199 was not covered by tests
}

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

Check warning on line 202 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L202

Added line #L202 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 213 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L204-L213

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

Check warning on line 216 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L215-L216

Added lines #L215 - L216 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 218 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L218

Added line #L218 was not covered by tests
}

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

Check warning on line 221 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L221

Added line #L221 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 229 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L223-L229

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

Check warning on line 232 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L231-L232

Added lines #L231 - L232 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 234 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L234

Added line #L234 was not covered by tests
}

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

Check warning on line 237 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L237

Added line #L237 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 248 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L239-L248

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

Check warning on line 251 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L250-L251

Added lines #L250 - L251 were not covered by tests
}
hk_state_push_nil(state);

Check warning on line 253 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L253

Added line #L253 was not covered by tests
}

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

Check warning on line 256 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L256

Added line #L256 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 267 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L258-L267

Added lines #L258 - L267 were not covered by tests
}

HK_LOAD_MODULE_HANDLER(selectors)

Check warning on line 270 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L270

Added line #L270 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 318 in core/selectors.c

View check run for this annotation

Codecov / codecov/patch

core/selectors.c#L272-L318

Added lines #L272 - L318 were not covered by tests
}
Loading

0 comments on commit c8e0890

Please sign in to comment.