erl_check_io.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,430 行 · 第 1/3 页
C
1,430 行
#ifdef ERTS_USE_PORT_TASKS erts_port_task_handle_init(&drv_ev_state[fd].driver.event->task);#endif drv_ev_state[fd].driver.event->port = id; drv_ev_state[fd].driver.event->removed_events = (ErtsPollEvents) 0; drv_ev_state[fd].type = ERTS_EV_TYPE_DRV_EV; } drv_ev_state[fd].driver.event->data = event_data; } else { if (drv_ev_state[fd].type == ERTS_EV_TYPE_DRV_EV) {#ifdef ERTS_USE_PORT_TASKS abort_tasks(fd, 0);#endif erts_free(ERTS_ALC_T_DRV_EV_D_STATE, drv_ev_state[fd].driver.event); } drv_ev_state[fd].driver.select = NULL; drv_ev_state[fd].flags = 0; drv_ev_state[fd].type = ERTS_EV_TYPE_NONE; } check_ignore(fd, events, drv_ev_state[fd].events); drv_ev_state[fd].events = events; ASSERT(event_data ? events == event_data->events : events == 0); erts_smp_mtx_unlock(&drv_ev_state_mtx); return 0; error: erts_smp_mtx_unlock(&drv_ev_state_mtx); return -1;#endif}static ERTS_INLINE intchk_stale(Eterm id, int fd, int mode){ if (is_nil(id)) return 0; if (erts_is_port_alive(id)) return 1; /* Steal */ stale_drv_select(id, fd, mode); return 0;}static intneed2steal(int fd, int mode){ int do_steal = 0; switch (drv_ev_state[fd].type) { case ERTS_EV_TYPE_DRV_SEL: if (mode & DO_READ) do_steal |= chk_stale(drv_ev_state[fd].driver.select->inport, fd, DO_READ); if (mode & DO_WRITE) do_steal |= chk_stale(drv_ev_state[fd].driver.select->outport, fd, DO_WRITE); break;#if ERTS_CIO_HAVE_DRV_EVENT case ERTS_EV_TYPE_DRV_EV: do_steal |= chk_stale(drv_ev_state[fd].driver.event->port, fd, 0); break;#endif default: break; } return do_steal;}static voidprint_driver_name(erts_dsprintf_buf_t *dsbufp, Eterm id){ ErtsPortNames *pnp = erts_get_port_names(id); if (!pnp->name && !pnp->driver_name) erts_dsprintf(dsbufp, "%s ", "<unknown>"); else { if (pnp->name) { if (!pnp->driver_name || strcmp(pnp->driver_name, pnp->name) == 0) erts_dsprintf(dsbufp, "%s ", pnp->name); else erts_dsprintf(dsbufp, "%s (%s) ", pnp->driver_name, pnp->name); } else if (pnp->driver_name) { erts_dsprintf(dsbufp, "%s ", pnp->driver_name); } } erts_free_port_names(pnp);}static voidsteal(erts_dsprintf_buf_t *dsbufp, int fd, int mode){ erts_dsprintf(dsbufp, "stealing control of fd=%d from ", fd); switch (drv_ev_state[fd].type) { case ERTS_EV_TYPE_DRV_SEL: { int deselect_mode = 0; Eterm iid = drv_ev_state[fd].driver.select->inport; Eterm oid = drv_ev_state[fd].driver.select->outport; if ((mode & DO_READ) && (is_not_nil(iid))) { erts_dsprintf(dsbufp, "input driver "); print_driver_name(dsbufp, iid); erts_dsprintf(dsbufp, "%T ", iid); deselect_mode |= DO_READ; } if ((mode & DO_READ) && is_not_nil(iid) && (mode & DO_WRITE) && is_not_nil(oid)) erts_dsprintf(dsbufp, "and "); if ((mode & DO_WRITE) && is_not_nil(oid)) { erts_dsprintf(dsbufp, "output driver "); print_driver_name(dsbufp, oid); erts_dsprintf(dsbufp, "%T ", oid); deselect_mode |= DO_WRITE; } if (deselect_mode) deselect(fd, deselect_mode); else { erts_dsprintf(dsbufp, "no one", fd); ASSERT(0); } erts_dsprintf(dsbufp, "\n"); break; }#if ERTS_CIO_HAVE_DRV_EVENT case ERTS_EV_TYPE_DRV_EV: { Eterm eid = drv_ev_state[fd].driver.event->port; if (is_nil(eid)) { erts_dsprintf(dsbufp, "no one", fd); ASSERT(0); } else { erts_dsprintf(dsbufp, "event driver "); print_driver_name(dsbufp, eid); erts_dsprintf(dsbufp, "%T ", eid); } erts_dsprintf(dsbufp, "\n"); deselect(fd, 0); break; }#endif default: erts_dsprintf(dsbufp, "no one\n", fd); ASSERT(0); }}static voidprint_select_op(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix, int fd, int mode, int on){ Port *pp = erts_drvport2port(ix); erts_dsprintf(dsbufp, "driver_select(%p, %d, %s%s%s, %d) " "by ", ix, fd, mode & DO_READ ? "DO_READ" : "", (mode & (DO_READ|DO_WRITE)) == (DO_READ|DO_WRITE) ? "|" : "", mode & DO_WRITE ? "DO_WRITE" : "", on); print_driver_name(dsbufp, pp->id); erts_dsprintf(dsbufp, "driver %T ", pp ? pp->id : NIL);}static voidselect_steal(ErlDrvPort ix, int fd, int mode, int on){ if (need2steal(fd, mode)) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); print_select_op(dsbufp, ix, fd, mode, on); steal(dsbufp, fd, mode); erts_send_error_to_logger_nogl(dsbufp); }}static voidlarge_fd_error_common(erts_dsprintf_buf_t *dsbufp){ erts_dsprintf(dsbufp, "fd=%d is larger than the largest allowed fd=%d\n", max_fds - 1);}static voidselect_large_fd_error(ErlDrvPort ix, int fd, int mode, int on){ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); print_select_op(dsbufp, ix, fd, mode, on); erts_dsprintf(dsbufp, "failed: "); large_fd_error_common(dsbufp); erts_send_error_to_logger_nogl(dsbufp);}#if ERTS_CIO_HAVE_DRV_EVENTstatic voidprint_event_op(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix, int fd, ErlDrvEventData event_data){ Port *pp = erts_drvport2port(ix); erts_dsprintf(dsbufp, "driver_event(%p, %d, ", ix, fd); if (!event_data) erts_dsprintf(dsbufp, "NULL"); else erts_dsprintf(dsbufp, "{0x%x, 0x%x}", (unsigned int) event_data->events, (unsigned int) event_data->revents); erts_dsprintf(dsbufp, ") by "); print_driver_name(dsbufp, pp->id); erts_dsprintf(dsbufp, "driver %T ", pp ? pp->id : NIL);}static voidevent_steal(ErlDrvPort ix, int fd, ErlDrvEventData event_data){ if (need2steal(fd, DO_READ|DO_WRITE)) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); print_event_op(dsbufp, ix, fd, event_data); steal(dsbufp, fd, DO_READ|DO_WRITE); erts_send_error_to_logger_nogl(dsbufp); }}static voidevent_large_fd_error(ErlDrvPort ix, int fd, ErlDrvEventData event_data){ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); print_event_op(dsbufp, ix, fd, event_data); erts_dsprintf(dsbufp, "failed: "); large_fd_error_common(dsbufp); erts_send_error_to_logger_nogl(dsbufp);}#endifstatic ERTS_INLINE voidbump_timers(void){#if defined(ERTS_SMP_USE_IO_THREAD) && !defined(ERTS_TIMER_THREAD) long dt = do_time_read_and_reset(); if (dt) bump_timer(dt);#endif}static ERTS_INLINE voidiready(Eterm id, int fd){#ifdef ERTS_USE_PORT_TASKS if (erts_port_task_schedule(id, &drv_ev_state[fd].driver.select->intask, ERTS_PORT_TASK_INPUT, (ErlDrvEvent) fd, NULL) != 0) { stale_drv_select(id, fd, DO_READ); }#else Port *pp = erts_drvportid2port(id); if (!pp) stale_drv_select(id, fd, DO_READ); else { erts_smp_mtx_unlock(&drv_ev_state_mtx); erts_port_ready_input(pp, (ErlDrvEvent) fd); erts_smp_mtx_lock(&drv_ev_state_mtx); }#endif}static ERTS_INLINE voidoready(Eterm id, int fd){#ifdef ERTS_USE_PORT_TASKS if (erts_port_task_schedule(id, &drv_ev_state[fd].driver.select->outtask, ERTS_PORT_TASK_OUTPUT, (ErlDrvEvent) fd, NULL) != 0) { stale_drv_select(id, fd, DO_WRITE); }#else Port *pp = erts_drvportid2port(id); if (!pp) stale_drv_select(id, fd, DO_WRITE); else { erts_smp_mtx_unlock(&drv_ev_state_mtx); erts_port_ready_output(pp, (ErlDrvEvent) fd); erts_smp_mtx_lock(&drv_ev_state_mtx); }#endif}#if ERTS_CIO_HAVE_DRV_EVENTstatic ERTS_INLINE voideready(Eterm id, int fd, ErlDrvEventData event_data){#ifdef ERTS_USE_PORT_TASKS if (erts_port_task_schedule(id, &drv_ev_state[fd].driver.event->task, ERTS_PORT_TASK_EVENT, (ErlDrvEvent) fd, event_data) != 0) { stale_drv_select(id, fd, 0); }#else Port *pp = erts_drvportid2port(id); if (!pp) stale_drv_select(id, fd, 0); else { erts_smp_mtx_unlock(&drv_ev_state_mtx); erts_port_ready_event(pp, (ErlDrvEvent) fd, event_data); erts_smp_mtx_lock(&drv_ev_state_mtx); }#endif}#endifstatic void bad_fd_in_pollset(int, Eterm, Eterm, ErtsPollEvents);voidERTS_CIO_EXPORT(erts_check_io_interrupt)(int set){ ERTS_CIO_POLL_INTR(pollset, set);}voidERTS_CIO_EXPORT(erts_check_io_interrupt_timed)(int set, long msec){ ERTS_CIO_POLL_INTR_TMD(pollset, set, msec);}voidERTS_CIO_EXPORT(erts_check_io)(int do_wait){ ErtsPollResFd pollres[256]; int pollres_len; SysTimeval wait_time; int poll_ret, i; restart:#ifdef ERTS_SMP_USE_IO_THREAD ERTS_CIO_POLL_INTR(pollset, 0);#endif /* Figure out timeout value */ if (do_wait) { erts_time_remaining(&wait_time); } else { /* poll only */ wait_time.tv_sec = 0; wait_time.tv_usec = 0; }#ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_check_exact(NULL, 0); /* No locks should be locked */#endif#ifndef ERTS_SMP_USE_IO_THREAD erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);#else erts_smp_activity_change(ERTS_ACTIVITY_IO, ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);#endif pollres_len = sizeof(pollres)/sizeof(ErtsPollResFd); erts_smp_atomic_set(&in_poll_wait, 1); poll_ret = ERTS_CIO_POLL_WAIT(pollset, pollres, &pollres_len, &wait_time);#ifdef ERTS_ENABLE_LOCK_CHECK erts_lc_check_exact(NULL, 0); /* No locks should be locked */#endif#ifndef ERTS_SMP_USE_IO_THREAD erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);#else erts_smp_activity_change(ERTS_ACTIVITY_WAIT, ERTS_ACTIVITY_IO, NULL, NULL, NULL);#endif erts_deliver_time(); /* sync the machine's idea of time */ bump_timers(); if (ERTS_BREAK_REQUESTED) erts_do_break_handling(); if (poll_ret != 0) { erts_smp_atomic_set(&in_poll_wait, 0); if (poll_ret == EAGAIN) goto restart; if (poll_ret != ETIMEDOUT && poll_ret != EINTR && poll_ret != ERRNO_BLOCK) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "erts_poll_wait() failed: %s (%d)\n", erl_errno_id(poll_ret), poll_ret); erts_send_error_to_logger_nogl(dsbufp); } return; } erts_smp_mtx_lock(&drv_ev_state_mtx); erts_smp_atomic_set(&in_poll_wait, 0); for (i = 0; i < pollres_len; i++) { int fd = pollres[i].fd; if (drv_ev_state[fd].flags & ERTS_EV_FLG_IGNORE) continue; switch (drv_ev_state[fd].type) { case ERTS_EV_TYPE_DRV_SEL: { /* Requested via driver_select()... */ ErtsPollEvents revents; ErtsPollEvents revent_mask; revent_mask = ~(ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT); revent_mask |= drv_ev_state[fd].events; revents = pollres[i].events & revent_mask; if (revents & ERTS_POLL_EV_ERR) { /* * Let the driver handle the error condition. Only input, * only output, or nothing might have been selected. * We *do not* want to call a callback that corresponds * to an event not selected. revents might give us a clue * on which one to call. */ if ((revents & ERTS_POLL_EV_IN) || (!(revents & ERTS_POLL_EV_OUT) && drv_ev_state[fd].events & ERTS_POLL_EV_IN)) iready(drv_ev_state[fd].driver.select->inport, fd); else if (drv_ev_state[fd].events & ERTS_POLL_EV_OUT) oready(drv_ev_state[fd].driver.select->outport, fd); } else if (revents & (ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT)) { if (revents & ERTS_POLL_EV_OUT) oready(drv_ev_state[fd].driver.select->outport, fd); /* Someone might have deselected input since revents was read (true also on the non-smp emulator since oready() may have been called); therefore, update revents... */ revents &= ~(~drv_ev_state[fd].events & ERTS_POLL_EV_IN); if (revents & ERTS_POLL_EV_IN) iready(drv_ev_state[fd].driver.select->inport, fd); } else if (revents & ERTS_POLL_EV_NVAL) { bad_fd_in_pollset(fd, drv_ev_state[fd].driver.select->inport, drv_ev_state[fd].driver.select->outport, drv_ev_state[fd].events); } break; }#if ERTS_CIO_HAVE_DRV_EVENT case ERTS_EV_TYPE_DRV_EV: { /* Requested via driver_event()... */ ErlDrvEventData event_data; ErtsPollEvents revents; ASSERT(drv_ev_state[fd].driver.event); ASSERT(drv_ev_state[fd].driver.event->data); event_data = drv_ev_state[fd].driver.event->data; revents = pollres[i].events; revents &= ~drv_ev_state[fd].driver.event->removed_events; if (revents) { event_data->events = drv_ev_state[fd].events; event_data->revents = revents; eready(drv_ev_state[fd].driver.event->port, fd, event_data); } break; }#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?