Skip to content
Open
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
93 changes: 92 additions & 1 deletion carrow.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ static struct sigaction old_action;
static unsigned int _openmax;
static struct evbag **_evbags;
static volatile unsigned int _evbagscount;
static unsigned int _asapsmax;
static struct asapbag **_asapbags;
static volatile unsigned int _asapbagscount;
static int _epollfd = -1;


Expand All @@ -44,6 +47,12 @@ struct evbag {
};


struct asapbag {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use struct evbag instead. We need to schedule coroutines to run as soon as possible.

carrow_asapfunc func;
void *params;
};


#define EVBAG_HAS(fd) (_evbags[fd] != NULL)
#define EVBAG_ISNULL(fd) (_evbags[fd] == NULL)

Expand Down Expand Up @@ -169,8 +178,73 @@ evbags_deinit() {
}


static int
asapbags_init() {
_asapbagscount = 0;
_asapbags = calloc(_asapsmax, sizeof(struct asapbag*));
if (_asapbags == NULL) {
errno = ENOMEM;
return -1;
}

memset(_asapbags, 0, sizeof(struct asapbag*) * _asapsmax);
return 0;
}


static void
asapbags_deinit() {
for (int i = 0; i < _asapsmax; i++) {
if (_asapbags[i] != NULL) {
free(_asapbags[i]);
_asapbags[i] = NULL;
}
}

free(_asapbags);
_asapbags = NULL;
}


static void
asap_trigger() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ues carrow_trigger instead.

for(int i = 0; i < _asapbagscount; i++) {
struct asapbag *bag = _asapbags[i];
bag->func(bag->params);
}
_asapbagscount = 0;
}


int
carrow_init(unsigned int openmax) {
carrow_asap_register(carrow_asapfunc func, void *params) {
if (_asapsmax == 0) {
return -1;
}

if (_asapbagscount >= _asapsmax) {
return -1;
}
struct asapbag *bag = _asapbags[_asapbagscount];

if (bag == NULL) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always happening situation. if no needed.

bag = malloc(sizeof(struct asapbag));
if (bag == NULL) {
errno = ENOMEM;
return -1;
}
_asapbags[_asapbagscount] = bag;
}

bag->func = func;
bag->params = params;
_asapbagscount++;
return 0;
}


int
carrow_init(unsigned int openmax, unsigned int asapsmax) {
if (_epollfd != -1) {
return -1;
}
Expand All @@ -191,6 +265,14 @@ carrow_init(unsigned int openmax) {
return -1;
}

_asapsmax = asapsmax;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get or set it by two accessors:

int
carrow_asapmax_get();

void
carrow_asapmax_set(int count);

if (_asapsmax > 0) {
if (asapbags_init()) {
evbags_deinit();
return -1;
}
}

_epollfd = epoll_create1(0);
if (_epollfd < 0) {
return -1;
Expand Down Expand Up @@ -314,6 +396,10 @@ carrow_evloop(volatile int *status) {

evloop:
while (_evbagscount && ((status == NULL) || (*status > EXIT_FAILURE))) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check _asapbags.

if (_asapbagscount > 0) {
asap_trigger();
}

errno = 0;
nfds = epoll_wait(_epollfd, events, _openmax, -1);
if (nfds < 0) {
Expand Down Expand Up @@ -351,5 +437,10 @@ carrow_deinit() {
close(_epollfd);
_epollfd = -1;
evbags_deinit();

if (_asapsmax > 0) {
asapbags_deinit();
}

errno = 0;
}
10 changes: 9 additions & 1 deletion carrow.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ struct carrow_generic_coro {
typedef void (*carrow_generic_corofunc) (void *coro, void *state);


/* A function pointer type representing a carrow asap function */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not define it.

typedef void (*carrow_asapfunc) (void *params);


/* A function that initializes the event loop with the given maximum number
of file descriptors. */
int
carrow_init(unsigned int openmax);
carrow_init(unsigned int openmax, unsigned int asapsmax);


/* A function that frees the memory allocated for the _evbags array. */
Expand Down Expand Up @@ -165,6 +169,10 @@ int
carrow_evloop_unregister(int fd);


int
carrow_asap_register(carrow_asapfunc func, void *params);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature must be similar to carrow_evloop_register.



/* A function that runs the event loop until the _evbagscount is zero or
the status is set to a value less than or equal to EXIT_FAILURE.
It waits for events on the epoll instance and triggers thecorresponding
Expand Down
4 changes: 2 additions & 2 deletions carrow_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ CARROW_NAME(evloop_unregister) (int fd) {

int
CARROW_NAME(forever) (CARROW_NAME(corofunc) f, CARROW_ENTITY *state,
volatile int *status) {
volatile int *status, unsigned int asapsmax) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asapmax is garbage here.

int ret = EXIT_SUCCESS;

carrow_init(0);
carrow_init(0, asapsmax);
CARROW_NAME(coro_create_and_run) (f, state);
if (carrow_evloop(status)) {
ret = EXIT_FAILURE;
Expand Down
2 changes: 1 addition & 1 deletion carrow_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ CARROW_NAME(evloop_unregister) (int fd);

int
CARROW_NAME(forever) (CARROW_NAME(corofunc) resolve, CARROW_ENTITY *state,
volatile int *status);
volatile int *status, unsigned int asapsmax);


#endif
14 changes: 14 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ add_custom_target(profile_timer
)


add_executable(timerasap
$<TARGET_OBJECTS:carrow>
timerasap.c
)
target_include_directories(timerasap PUBLIC "${CMAKE_SOURCE_DIR}")
target_link_libraries(timerasap PUBLIC clog mrb)
add_custom_target(run_timerasap $<TARGET_FILE:timerasap>)
add_custom_target(profile_timerasap
COMMAND "valgrind"
${VALGRIND_FLAGS}
$<TARGET_FILE:timerasap>
)


add_executable(sleep
$<TARGET_OBJECTS:carrow>
sleep.c
Expand Down
2 changes: 1 addition & 1 deletion examples/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ main() {
.counter = 0
};

return foo_forever(fooA, &state, NULL);
return foo_forever(fooA, &state, NULL, 0);
}
2 changes: 1 addition & 1 deletion examples/tcpclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ main() {
return EXIT_FAILURE;
}

ret = tcpconn_forever(connectA, &conn, NULL);
ret = tcpconn_forever(connectA, &conn, NULL, 0);
if (mrb_destroy(conn.inbuff) || mrb_destroy(conn.outbuff)) {
ERROR("Cannot dispose buffers.");
ret = EXIT_FAILURE;
Expand Down
2 changes: 1 addition & 1 deletion examples/tcpserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,5 +205,5 @@ main() {
.backlog = 2,
};

return tcpserver_forever(listenA, &state, NULL);
return tcpserver_forever(listenA, &state, NULL, 0);
}
2 changes: 1 addition & 1 deletion examples/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ main() {
.value = 0,
};

carrow_init(0);
carrow_init(0, 0);
timer_coro_create_and_run(timerA, &state1);
timer_coro_create_and_run(timerA, &state2);
carrow_evloop(NULL);
Expand Down
126 changes: 126 additions & 0 deletions examples/timerasap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Copyright 2023 Vahid Mardani
/*
* This file is part of Carrow.
* Carrow is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Carrow is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Carrow. If not, see <https://www.gnu.org/licenses/>.
*
* Author: Vahid Mardani <[email protected]>
*/
#include <sys/timerfd.h>
#include <stdlib.h>
#include <unistd.h>

#include <clog.h>

#include "carrow.h"


typedef struct timer {
unsigned int interval;
unsigned long value;
const char *title;
} timer;


#undef CARROW_ENTITY
#define CARROW_ENTITY timer
#include "carrow_generic.h"
#include "carrow_generic.c"


static int
maketimer(unsigned int interval) {
int fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);
if (fd == -1) {
return -1;
}

struct timespec sec1 = {interval, 0};
struct itimerspec spec = {sec1, sec1};
if (timerfd_settime(fd, 0, &spec, NULL) == -1) {
return -1;
}
return fd;
}


static void
timer_asapfunc(int value) {
INFO("called from asapfunction value: %d", value);
}


static void
timerA(struct timer_coro *self, struct timer *state) {
CORO_START;
unsigned long tmp;
ssize_t bytes;

self->fd = maketimer(state->interval);
if (self->fd == -1) {
CORO_REJECT("maketimer");
}

while (true) {
CORO_WAIT(self->fd, CIN);
bytes = read(self->fd, &tmp, sizeof(tmp));
state->value += tmp;
INFO("%s, fd: %d, value: %lu", state->title, self->fd, state->value);

if (state->value % 5 == 0) {
INFO("registering to asap");
carrow_asap_register((carrow_asapfunc)timer_asapfunc,
(void *) state->value);
}
}

CORO_FINALLY;
if (self->fd != -1) {
timer_evloop_unregister(self->fd);
close(self->fd);
}
CORO_END;
}


int
main() {
clog_verbosity = CLOG_DEBUG;

if (carrow_handleinterrupts()) {
return EXIT_FAILURE;
}

struct timer state1 = {
.title = "Foo",
.interval = 1,
.value = 0,
};
struct timer state2 = {
.title = "Bar",
.interval = 3,
.value = 0,
};
if (carrow_init(0, 10)) {
ERROR("unable to init carrow");
return EXIT_FAILURE;
}

INFO("CARROW INIT");
timer_coro_create_and_run(timerA, &state1);
//timer_coro_create_and_run(timerA, &state2);
carrow_evloop(NULL);
carrow_deinit();

return EXIT_SUCCESS;
}