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

support signal event. #458

Closed
wants to merge 1 commit into from
Closed
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
support signal event.
Huangxiaodui committed Nov 8, 2023
commit 1d0e99630d0b555be40ac0922fdaac906968efb5
17 changes: 17 additions & 0 deletions event/hevent.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef HV_EVENT_H_
#define HV_EVENT_H_

#include <signal.h>
#include "hloop.h"
#include "iowatcher.h"
#include "rudp.h"
@@ -48,6 +49,13 @@ struct hloop_s {
// idles
struct list_head idles;
uint32_t nidles;
// signals
#ifdef OS_LINUX
uint32_t nsignals;
uint32_t enable_signal;
struct list_head signal_events_head[_NSIG];
hio_t* signal_io_watcher;
#endif
// timers
struct heap timers; // monotonic time
struct heap realtimers; // realtime
@@ -73,6 +81,15 @@ struct hidle_s {
struct list_node node;
};

#ifdef OS_LINUX
struct hsig_s {
HEVENT_FIELDS
uint32_t signal;
uint32_t num_calls;
struct list_node self_signal_node;
};
#endif

#define HTIMER_FIELDS \
HEVENT_FIELDS \
uint32_t repeat; \
23 changes: 23 additions & 0 deletions event/hloop.c
Original file line number Diff line number Diff line change
@@ -324,6 +324,13 @@ static void hloop_init(hloop_t* loop) {
// idles
list_init(&loop->idles);

#ifdef OS_LINUX
// signals
for (int i = 0; i < _NSIG; i++) {
list_init(&(loop->signal_events_head[i]));
}
#endif

// timers
heap_init(&loop->timers, timers_compare);
heap_init(&loop->realtimers, timers_compare);
@@ -378,6 +385,22 @@ static void hloop_cleanup(hloop_t* loop) {
}
list_init(&loop->idles);

#ifdef OS_LINUX
loop->signal_io_watcher = NULL;
// signals
printd("cleanup signals...\n");
for (int i = 0; i < _NSIG; i++) {
struct list_node* sig_node = loop->signal_events_head[i].next;
hsig_t* signal;
while (sig_node != &loop->signal_events_head[i]) {
signal = IDLE_ENTRY(sig_node);
sig_node = sig_node->next;
HV_FREE(signal);
}
list_init(&(loop->signal_events_head[i]));
}
#endif

// timers
printd("cleanup timers...\n");
htimer_t* timer;
15 changes: 15 additions & 0 deletions event/hloop.h
Original file line number Diff line number Diff line change
@@ -16,11 +16,17 @@ typedef struct htimer_s htimer_t;
typedef struct htimeout_s htimeout_t;
typedef struct hperiod_s hperiod_t;
typedef struct hio_s hio_t;
#ifdef OS_LINUX
typedef struct hsig_s hsig_t;
#endif

typedef void (*hevent_cb) (hevent_t* ev);
typedef void (*hidle_cb) (hidle_t* idle);
typedef void (*htimer_cb) (htimer_t* timer);
typedef void (*hio_cb) (hio_t* io);
#ifdef OS_LINUX
typedef void (*hsig_cb) (hsig_t* signal);
#endif

typedef void (*haccept_cb) (hio_t* io);
typedef void (*hconnect_cb) (hio_t* io);
@@ -42,6 +48,9 @@ typedef enum {
HEVENT_TYPE_TIMER = HEVENT_TYPE_TIMEOUT|HEVENT_TYPE_PERIOD,
HEVENT_TYPE_IDLE = 0x00000100,
HEVENT_TYPE_CUSTOM = 0x00000400, // 1024
#ifdef OS_LINUX
HEVENT_TYPE_SIGNAL = 0x00001000,
#endif
} hevent_type_e;

#define HEVENT_LOWEST_PRIORITY (-5)
@@ -186,6 +195,12 @@ HV_EXPORT void hloop_post_event(hloop_t* loop, hevent_t* ev);
HV_EXPORT hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE));
HV_EXPORT void hidle_del(hidle_t* idle);

#ifdef OS_LINUX
// signal
HV_EXPORT hsig_t* hsig_add(hloop_t* loop, hsig_cb cb, uint32_t signal DEFAULT(INFINITE));
HV_EXPORT void hsig_del(hsig_t* signal);
#endif

// timer
HV_EXPORT htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout_ms, uint32_t repeat DEFAULT(INFINITE));
/*
162 changes: 162 additions & 0 deletions event/hsignal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#define _POSIX_SOURCE

#include "list.h"
#include "hevent.h"

#define SIGNAL_ENTRY(p) list_entry(p, hsig_t, self_signal_node)

#ifndef SA_RESTART
#define SA_RESTART 0x1000000
#endif

#ifdef OS_LINUX
/*
* The fd here cannot use global content, it must be one for each loop, because it is even when executing sig_event_cb, and each loop will read
* The content written in fd, if all the content is read by the first loop, the remaining loops will not be able to read the information.
* Therefore, there is a limitation in current use. A process can only apply for loop_new once. If there are multiple loop_new scenarios in the future,
* This business logic needs to be optimized.
*/
static int sig_write_fd = -1;
static int pair[2];
static bool sig_init[_NSIG];

void sig_handler(int sig)
{
int save_errno = errno;
char signum = (char)sig;
int n = write(sig_write_fd, &signum, 1);
printf("write %d signals in sig_handler\n", n);

errno = save_errno;
}

void sig_event_cb(hio_t *io)
{
printf("in sig_event_cb\n");
char signals[1024];
int n = 0;
int ncaught[_NSIG];
int fd = io->fd;
hloop_t *loop = hio_context(io);
struct list_head *events_at_sig = NULL;
struct list_head *ev_node = NULL;
memset(signals, 0, sizeof(signals));
memset(ncaught, 0, sizeof(ncaught));

if (loop == NULL) {
return;
}

while (true) {
n = read(fd, signals, sizeof(signals));
if (n <= 0) {
break;
}
for (int i = 0; i < n; ++i) {
char sig = signals[i];
if (sig < _NSIG)
ncaught[sig]++;
}
}

for (int i = 0; i < _NSIG; i++) {
if (ncaught[i] > 0) {
events_at_sig = &(loop->signal_events_head[i]);
if (!list_empty(events_at_sig)) {
ev_node = events_at_sig->next;
while (ev_node != events_at_sig) {
hsig_t *signal = SIGNAL_ENTRY(ev_node);
signal->num_calls = ncaught[i];
// In this part, there should be no need to add events to the awaken_signal_events_head list.
// Instead, they should be directly added to the existing loop's pending.
// According to the logic in hloop.c, various types of events should not invoke their callbacks when processed but should be placed in the pending queue. The callbacks for these events should be invoked collectively after all events are processed (except for timeouts).
// Therefore, the existing logic in hloop should handle the current awaken_signal_events_head.
// However, it's necessary to consider the case where num_calls is greater than one. Multiple pending queues may be needed.
for (int j = 0; j < signal->num_calls; j++) {
EVENT_PENDING(signal);
}
ev_node = ev_node->next;
}
}
}
}

printf("exit sig_event_cb\n");
}

/***
* This function is mainly used to add a semaphore. The signal_events_head in the loop is the maximum value of _NSIG.
* Every time a semaphore is added, it needs to be appended to the signal_events_head[sig] linked list.
* When the semaphore is processed, all registered cbs will be traversed from the corresponding linked list and the callback will be called.
* Use the same pair globally, and all loops are registered to listen to pair[0]. When an event is written, it is judged whether it needs to be processed.
*
* */
hsig_t* hsig_add(hloop_t* loop, hsig_cb cb, uint32_t sig)
{
printf("hsig_add sig=%d\n", sig);

hsig_t* signal;
HV_ALLOC_SIZEOF(signal);
struct list_head *events_at_sig = NULL;
struct sigaction sa;

if (-1 == sig_write_fd) {
socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
fcntl(pair[0], F_SETFL, O_NONBLOCK);
fcntl(pair[1], F_SETFL, O_NONBLOCK);
fcntl(pair[0], F_SETFD, FD_CLOEXEC);
fcntl(pair[1], F_SETFD, FD_CLOEXEC);
sig_write_fd = pair[1];

memset(sig_init, 0, sizeof(sig_init));
}
// 每个信号量只注册一次
if (false == sig_init[sig]) {
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sig_handler;
sa.sa_flags |= SA_RESTART;
sigfillset(&sa.sa_mask);
sigaction(sig, &sa, NULL);
sig_init[sig] = true;
}

if (loop->enable_signal == 0) {
printf("Enable the signal\n");
loop->enable_signal = 1;
for (int i = 0; i < _NSIG; i++) {
list_init(&(loop->signal_events_head[i]));
}
loop->signal_io_watcher = hio_get(loop, pair[0]);
hio_set_context(loop->signal_io_watcher, loop);
hio_add(loop->signal_io_watcher, (hio_cb)sig_event_cb, HV_READ);
}
events_at_sig = &(loop->signal_events_head[sig]);
signal->loop = loop;
signal->event_type = HEVENT_TYPE_SIGNAL;
signal->priority = HEVENT_LOWEST_PRIORITY;
list_add(&signal->self_signal_node, events_at_sig);
EVENT_ADD(loop, signal, cb);
loop->nsignals++;

return signal;
}

static void __hsig_del(hsig_t* signal)
{
if (signal->destroy) {
return;
}
signal->destroy = 1;
list_del(&signal->self_signal_node);
signal->loop->nsignals--;
}

void hsig_del(hsig_t* signal)
{
if (!signal->active) {
return;
}
__hsig_del(signal);
EVENT_DEL(signal);
}
#endif
7 changes: 7 additions & 0 deletions unittest/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -86,6 +86,12 @@ target_include_directories(ftp PRIVATE .. ../base ../protocol)
add_executable(sendmail sendmail_test.c ../protocol/smtp.c ../base/hsocket.c ../util/base64.c)
target_include_directories(sendmail PRIVATE .. ../base ../protocol ../util)

# ------event------
add_executable(event_signal event_signal_test.c ../event/hevent.c)
target_link_libraries(event_signal ${HV_LIBRARIES})
target_compile_definitions(event_signal PRIVATE -DPRINT_DEBUG)
target_include_directories(event_signal PRIVATE ../event ../base ../ssl)

if(UNIX)
add_executable(webbench webbench.c)
endif()
@@ -115,4 +121,5 @@ add_custom_target(unittest DEPENDS
ping
ftp
sendmail
event_signal
)
Loading