summaryrefslogtreecommitdiff
path: root/erts/emulator/sys/common/erl_check_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys/common/erl_check_io.c')
-rw-r--r--erts/emulator/sys/common/erl_check_io.c169
1 files changed, 107 insertions, 62 deletions
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 5c1f755c45..39b6517bcf 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2021. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2023. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -93,7 +93,7 @@ typedef enum {
#endif
ERTS_EV_FLAG_WANT_ERROR = 0x10, /* ERL_NIF_SELECT_ERROR turned on */
- /* Combinations */
+ /* Combinations, defined only to be displayed by debugger (gdb) */
ERTS_EV_FLAG_USED_FALLBACK = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_FALLBACK,
ERTS_EV_FLAG_USED_SCHEDULER = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_SCHEDULER,
ERTS_EV_FLAG_USED_IN_SCHEDULER = ERTS_EV_FLAG_USED | ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER,
@@ -101,16 +101,25 @@ typedef enum {
ERTS_EV_FLAG_UNUSED_IN_SCHEDULER = ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER
} EventStateFlags;
-#define flag2str(flags) \
- ((flags) == ERTS_EV_FLAG_CLEAR ? "CLEAR" : \
- ((flags) == ERTS_EV_FLAG_USED ? "USED" : \
- ((flags) == ERTS_EV_FLAG_FALLBACK ? "FLBK" : \
- ((flags) == ERTS_EV_FLAG_USED_FALLBACK ? "USED|FLBK" : \
- ((flags) == ERTS_EV_FLAG_USED_SCHEDULER ? "USED|SCHD" : \
- ((flags) == ERTS_EV_FLAG_UNUSED_SCHEDULER ? "SCHD" : \
- ((flags) == ERTS_EV_FLAG_USED_IN_SCHEDULER ? "USED|IN_SCHD" : \
- ((flags) == ERTS_EV_FLAG_UNUSED_IN_SCHEDULER ? "IN_SCHD" : \
- "ERROR"))))))))
+
+static const char* event_state_flag_to_str(EventStateFlags f)
+{
+ switch ((int)f) {
+ case ERTS_EV_FLAG_CLEAR: return "CLEAR";
+ case ERTS_EV_FLAG_USED: return "USED";
+ case ERTS_EV_FLAG_FALLBACK: return "FLBK";
+ case ERTS_EV_FLAG_FALLBACK | ERTS_EV_FLAG_USED: return "USED|FLBK";
+
+#if ERTS_POLL_USE_SCHEDULER_POLLING
+ case ERTS_EV_FLAG_SCHEDULER: return "SCHD";
+ case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_USED: return "USED|SCHD";
+ case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER: return "IN_SCHD";
+ case ERTS_EV_FLAG_SCHEDULER | ERTS_EV_FLAG_IN_SCHEDULER
+ | ERTS_EV_FLAG_USED: return "USED|IN_SCHD";
+#endif
+ default: return "ERROR";
+ }
+}
/* How many events that can be handled at once by one erts_poll_wait call */
#define ERTS_CHECK_IO_POLL_RES_LEN 512
@@ -137,7 +146,7 @@ static ErtsPollThread *psiv;
static ErtsPollSet *flbk_pollset;
#endif
#if ERTS_POLL_USE_SCHEDULER_POLLING
-static ErtsPollSet *sched_pollset;
+ErtsPollSet *sched_pollset;
#endif
typedef struct {
@@ -409,7 +418,7 @@ static ERTS_INLINE ErtsPollSet *
get_scheduler_pollset(ErtsSysFdType fd)
{
#if ERTS_POLL_USE_SCHEDULER_POLLING
- return sched_pollset;
+ return sched_pollset ? sched_pollset : get_pollset(fd);
#else
return get_pollset(fd);
#endif
@@ -488,16 +497,18 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type,
active_events = state->active_events;
- if (!(state->flags & ERTS_EV_FLAG_IN_SCHEDULER) || type == ERTS_PORT_TASK_OUTPUT) {
+ if (state->type == ERTS_EV_TYPE_DRV_SEL) {
switch (type) {
case ERTS_PORT_TASK_INPUT:
DEBUG_PRINT_FD("executed ready_input", state);
- ASSERT(!(state->active_events & ERTS_POLL_EV_IN));
- if (state->events & ERTS_POLL_EV_IN) {
+ if (!(state->flags & ERTS_EV_FLAG_IN_SCHEDULER)
+ && !(active_events & ERTS_POLL_EV_IN)
+ && (state->events & ERTS_POLL_EV_IN)) {
+
active_events |= ERTS_POLL_EV_IN;
- if (state->count > 10 && ERTS_POLL_USE_SCHEDULER_POLLING) {
+ if (state->count > 10 && erts_sched_poll_enabled()) {
if (!(state->flags & ERTS_EV_FLAG_SCHEDULER))
op = ERTS_POLL_OP_ADD;
state->flags |= ERTS_EV_FLAG_IN_SCHEDULER|ERTS_EV_FLAG_SCHEDULER;
@@ -505,7 +516,7 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type,
DEBUG_PRINT_FD("moving to scheduler ps", state);
} else
new_events = active_events;
- if (!(state->flags & ERTS_EV_FLAG_FALLBACK) && ERTS_POLL_USE_SCHEDULER_POLLING)
+ if (!(state->flags & ERTS_EV_FLAG_FALLBACK) && erts_sched_poll_enabled())
state->count++;
}
break;
@@ -513,8 +524,9 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type,
DEBUG_PRINT_FD("executed ready_output", state);
- ASSERT(!(state->active_events & ERTS_POLL_EV_OUT));
- if (state->events & ERTS_POLL_EV_OUT) {
+ if (!(active_events & ERTS_POLL_EV_OUT)
+ && (state->events & ERTS_POLL_EV_OUT)) {
+
active_events |= ERTS_POLL_EV_OUT;
if (state->flags & ERTS_EV_FLAG_IN_SCHEDULER && active_events & ERTS_POLL_EV_IN)
new_events = ERTS_POLL_EV_OUT;
@@ -527,7 +539,8 @@ erts_io_notify_port_task_executed(ErtsPortTaskType type,
break;
}
- if (state->active_events != active_events && new_events) {
+ if (state->active_events != active_events) {
+ ASSERT(new_events);
state->active_events = active_events;
new_events = erts_io_control(state, op, new_events);
}
@@ -1791,7 +1804,7 @@ erts_check_io(ErtsPollThread *psi, ErtsMonotonicTime timeout_time, int poll_only
select/deselect in rapid succession. */
revents &= state->active_events | ERTS_POLL_EV_NVAL;
- if (psi->ps != get_scheduler_pollset(fd) || !ERTS_POLL_USE_SCHEDULER_POLLING) {
+ if (psi->ps != get_scheduler_pollset(fd) || !erts_sched_poll_enabled()) {
ErtsPollEvents reactive_events;
state->active_events &= ~revents;
@@ -2109,7 +2122,7 @@ get_arg(char* rest, char** argv, int* ip)
}
static void
-parse_args(int *argc, char **argv, int concurrent_waiters)
+parse_args(int *argc, char **argv, int concurrent_waiters, int* use_sched_poll)
{
int i = 0, j;
int no_pollsets = 0, no_poll_threads = 0,
@@ -2151,8 +2164,16 @@ parse_args(int *argc, char **argv, int concurrent_waiters)
erts_fprintf(stderr,"bad I/O pollset percentage number: %s\n", arg);
erts_usage();
}
- } else {
- break;
+ } else if (sys_strcmp(argv[i]+2, "Os") == 0) {
+ const char *arg = get_arg(argv[i]+4, argv, &i);
+ if (sys_strcmp(arg, "true") == 0) {
+ *use_sched_poll = 1;
+ } else if (sys_strcmp(arg, "false") == 0) {
+ *use_sched_poll = 0;
+ } else {
+ erts_fprintf(stderr,"bad +IOs boolean argument: %s\n", arg);
+ erts_usage();
+ }
}
break;
}
@@ -2220,6 +2241,8 @@ void
erts_init_check_io(int *argc, char **argv)
{
int j, concurrent_waiters, no_poll_threads;
+ int use_sched_poll = ERTS_POLL_USE_SCHEDULER_POLLING;
+
ERTS_CT_ASSERT((INT_MIN & (ERL_NIF_SELECT_STOP_CALLED |
ERL_NIF_SELECT_STOP_SCHEDULED |
ERL_NIF_SELECT_INVALID_EVENT |
@@ -2231,7 +2254,7 @@ erts_init_check_io(int *argc, char **argv)
erts_poll_init_flbk(NULL);
#endif
- parse_args(argc, argv, concurrent_waiters);
+ parse_args(argc, argv, concurrent_waiters, &use_sched_poll);
/* Create the actual pollsets */
pollsetv = erts_alloc(ERTS_ALC_T_POLLSET,sizeof(ErtsPollSet *) * erts_no_pollsets);
@@ -2243,10 +2266,16 @@ erts_init_check_io(int *argc, char **argv)
j = -1;
+ if (use_sched_poll) {
#if ERTS_POLL_USE_SCHEDULER_POLLING
- sched_pollset = erts_poll_create_pollset(j--);
- no_poll_threads++;
+ sched_pollset = erts_poll_create_pollset(j--);
+ ASSERT(erts_sched_poll_enabled());
+ no_poll_threads++;
+#else
+ erts_fprintf(stderr,"+IOs true: not supported by this emulator\n");
+ erts_usage();
#endif
+ }
#if ERTS_POLL_USE_FALLBACK
flbk_pollset = erts_poll_create_pollset_flbk(j--);
@@ -2263,13 +2292,13 @@ erts_init_check_io(int *argc, char **argv)
psiv++;
#endif
-#if ERTS_POLL_USE_SCHEDULER_POLLING
- psiv[0].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN;
- psiv[0].pollres = erts_alloc(ERTS_ALC_T_POLLSET,
- sizeof(ErtsPollResFd) * ERTS_CHECK_IO_POLL_RES_LEN);
- psiv[0].ps = get_scheduler_pollset(0);
- psiv++;
-#endif
+ if (erts_sched_poll_enabled()) {
+ psiv[0].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN;
+ psiv[0].pollres = erts_alloc(ERTS_ALC_T_POLLSET,
+ sizeof(ErtsPollResFd) * ERTS_CHECK_IO_POLL_RES_LEN);
+ psiv[0].ps = get_scheduler_pollset(0);
+ psiv++;
+ }
for (j = 0; j < erts_no_poll_threads; j++) {
psiv[j].pollres_len = ERTS_CHECK_IO_POLL_RES_LEN;
@@ -2327,12 +2356,12 @@ erts_check_io_size(void)
erts_poll_info(get_fallback_pollset(), &pi);
res += pi.memory_size;
#endif
-
#if ERTS_POLL_USE_SCHEDULER_POLLING
- erts_poll_info(get_scheduler_pollset(0), &pi);
- res += pi.memory_size;
+ if (erts_sched_poll_enabled()) {
+ erts_poll_info(sched_pollset, &pi);
+ res += pi.memory_size;
+ }
#endif
-
for (i = 0; i < erts_no_pollsets; i++) {
erts_poll_info(pollsetv[i], &pi);
res += pi.memory_size;
@@ -2361,9 +2390,9 @@ erts_check_io_info(void *proc)
Uint sz, *szp, *hp, **hpp;
ErtsPollInfo *piv;
Sint i, j = 0, len;
- int no_pollsets = erts_no_pollsets + ERTS_POLL_USE_FALLBACK + ERTS_POLL_USE_SCHEDULER_POLLING;
+ int no_pollsets = erts_no_pollsets + ERTS_POLL_USE_FALLBACK + erts_sched_poll_enabled();
ERTS_CT_ASSERT(ERTS_POLL_USE_FALLBACK == 0 || ERTS_POLL_USE_FALLBACK == 1);
- ERTS_CT_ASSERT(ERTS_POLL_USE_SCHEDULER_POLLING == 0 || ERTS_POLL_USE_SCHEDULER_POLLING == 1);
+ ERTS_ASSERT(erts_sched_poll_enabled() == 0 || erts_sched_poll_enabled() == 1);
piv = erts_alloc(ERTS_ALC_T_TMP, sizeof(ErtsPollInfo) * no_pollsets);
@@ -2373,14 +2402,14 @@ erts_check_io_info(void *proc)
piv[0].active_fds = 0;
piv++;
#endif
-
#if ERTS_POLL_USE_SCHEDULER_POLLING
- erts_poll_info(get_scheduler_pollset(0), &piv[0]);
- piv[0].poll_threads = 0;
- piv[0].active_fds = 0;
- piv++;
+ if (erts_sched_poll_enabled()) {
+ erts_poll_info(sched_pollset, &piv[0]);
+ piv[0].poll_threads = 0;
+ piv[0].active_fds = 0;
+ piv++;
+ }
#endif
-
for (j = 0; j < erts_no_pollsets; j++) {
erts_poll_info(pollsetv[j], &piv[j]);
piv[j].active_fds = 0;
@@ -2429,7 +2458,7 @@ erts_check_io_info(void *proc)
sz = 0;
piv -= ERTS_POLL_USE_FALLBACK;
- piv -= ERTS_POLL_USE_SCHEDULER_POLLING;
+ piv -= erts_sched_poll_enabled();
bld_it:
@@ -2534,7 +2563,11 @@ print_events(erts_dsprintf_buf_t *dsbufp, ErtsPollEvents ev)
static ERTS_INLINE void
print_flags(erts_dsprintf_buf_t *dsbufp, EventStateFlags f)
{
- erts_dsprintf(dsbufp, "%s", flag2str(f));
+ if (f & ERTS_EV_FLAG_WANT_ERROR) {
+ erts_dsprintf(dsbufp, "WANTERR|");
+ f &= ~ERTS_EV_FLAG_WANT_ERROR;
+ }
+ erts_dsprintf(dsbufp, "%s", event_state_flag_to_str(f));
}
#ifdef DEBUG_PRINT_MODE
@@ -2680,9 +2713,17 @@ static int erts_debug_print_checkio_state(erts_dsprintf_buf_t *dsbufp,
err = 1;
}
else {
- ErtsPollEvents ev = cio_events;
- if (ev != ep_events && ep_events != ERTS_POLL_EV_NONE)
- err = 1;
+ if (ep_events != ERTS_POLL_EV_NONE) {
+ if (!ERTS_POLL_USE_KERNEL_POLL
+ || (!(state->flags & (ERTS_EV_FLAG_SCHEDULER|ERTS_EV_FLAG_FALLBACK))
+ && ((cio_events ^ ep_events) & ep_events) != 0)) {
+ err = 1;
+ }
+ /* else: Kernel poll with oneshot (used by poller threads)
+ * may cause a race where an event just triggered and
+ * thereby was cleared in the pollset (ep_events).
+ */
+ }
erts_dsprintf(dsbufp, "cio_ev=");
print_events(dsbufp, cio_events);
erts_dsprintf(dsbufp, " ep_ev=");
@@ -2898,18 +2939,19 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip)
}
#endif
#if ERTS_POLL_USE_SCHEDULER_POLLING
- erts_dsprintf(dsbufp, "--- fds in scheduler pollset ----------------------------\n");
- erts_poll_get_selected_events(get_scheduler_pollset(0), counters.epep,
- drv_ev_state.max_fds);
- for (fd = 0; fd < len; fd++) {
- if (drv_ev_state.v[fd].flags & ERTS_EV_FLAG_SCHEDULER) {
- if (drv_ev_state.v[fd].events && drv_ev_state.v[fd].events != ERTS_POLL_EV_NONE)
- counters.epep[fd] &= ~ERTS_POLL_EV_OUT;
- doit_erts_check_io_debug(&drv_ev_state.v[fd], &counters, dsbufp);
+ if (erts_sched_poll_enabled()) {
+ erts_dsprintf(dsbufp, "--- fds in scheduler pollset ----------------------------\n");
+ erts_poll_get_selected_events(sched_pollset, counters.epep,
+ drv_ev_state.max_fds);
+ for (fd = 0; fd < len; fd++) {
+ if (drv_ev_state.v[fd].flags & ERTS_EV_FLAG_SCHEDULER) {
+ if (drv_ev_state.v[fd].events && drv_ev_state.v[fd].events != ERTS_POLL_EV_NONE)
+ counters.epep[fd] &= ~ERTS_POLL_EV_OUT;
+ doit_erts_check_io_debug(&drv_ev_state.v[fd], &counters, dsbufp);
+ }
}
}
#endif
-
erts_dsprintf(dsbufp, "--- fds in pollset --------------------------------------\n");
for (i = 0; i < erts_no_pollsets; i++) {
@@ -2921,6 +2963,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip)
&& get_pollset_id(fd) == i) {
if (counters.epep[fd] != ERTS_POLL_EV_NONE &&
drv_ev_state.v[fd].flags & ERTS_EV_FLAG_IN_SCHEDULER) {
+ ERTS_ASSERT(erts_sched_poll_enabled());
/* We add the in flag if it is enabled in the scheduler pollset
and get_selected_events works on the platform */
counters.epep[fd] |= ERTS_POLL_EV_IN;
@@ -2929,6 +2972,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip)
}
}
}
+
for (fd = len ; fd < drv_ev_state.max_fds; fd++) {
null_des.fd = fd;
doit_erts_check_io_debug(&null_des, &counters, dsbufp);
@@ -2955,6 +2999,7 @@ erts_check_io_debug(ErtsCheckIoDebugInfo *ciodip)
erts_dsprintf(dsbufp, "internal fds=%d\n", counters.internal_fds);
#endif
erts_dsprintf(dsbufp, "---------------------------------------------------------\n");
+
erts_send_error_to_logger_nogl(dsbufp);
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
erts_free(ERTS_ALC_T_TMP, (void *) counters.epep);