*/ REBINT Wait_Ports(REBSER *ports, REBCNT timeout, REBINT only) /* ** Inputs: ** Ports: a block of ports or zero (on stack to avoid GC). ** Timeout: milliseconds to wait ** ** Returns: ** TRUE when port action happened, or FALSE for timeout. ** ***********************************************************************/ { REBI64 base = OS_DELTA_TIME(0, 0); REBCNT time; REBINT result; REBCNT wt = 1; REBCNT res = (timeout >= 1000) ? 0 : 16; // OS dependent? while (wt) { if (GET_SIGNAL(SIG_ESCAPE)) { CLR_SIGNAL(SIG_ESCAPE); raise Error_Is(TASK_HALT_ERROR); } // Process any waiting events: if ((result = Awake_System(ports, only)) > 0) return TRUE; // If activity, use low wait time, otherwise increase it: if (result == 0) wt = 1; else { wt *= 2; if (wt > MAX_WAIT_MS) wt = MAX_WAIT_MS; } if (timeout != ALL_BITS) { // Figure out how long that (and OS_WAIT) took: time = (REBCNT)(OS_DELTA_TIME(base, 0)/1000); if (time >= timeout) break; // done (was dt = 0 before) else if (wt > timeout - time) // use smaller residual time wt = timeout - time; } //printf("%d %d %d\n", dt, time, timeout); // Wait for events or time to expire: //Debug_Num("OSW", wt); OS_WAIT(wt, res); } //time = (REBCNT)OS_DELTA_TIME(base, 0); //Print("dt: %d", time); return FALSE; // timeout }
*/ static REB_R Event_Actor(struct Reb_Call *call_, REBSER *port, REBCNT action) /* ** Internal port handler for events. ** ***********************************************************************/ { REBVAL *spec; REBVAL *state; REB_R result; REBVAL *arg; REBVAL save_port; Validate_Port(port, action); arg = D_ARG(2); *D_OUT = *D_ARG(1); // Validate and fetch relevant PORT fields: state = BLK_SKIP(port, STD_PORT_STATE); spec = BLK_SKIP(port, STD_PORT_SPEC); if (!IS_OBJECT(spec)) Trap1_DEAD_END(RE_INVALID_SPEC, spec); // Get or setup internal state data: if (!IS_BLOCK(state)) Set_Block(state, Make_Block(EVENTS_CHUNK - 1)); switch (action) { case A_UPDATE: return R_NONE; // Normal block actions done on events: case A_POKE: if (!IS_EVENT(D_ARG(3))) Trap_Arg_DEAD_END(D_ARG(3)); goto act_blk; case A_INSERT: case A_APPEND: //case A_PATH: // not allowed: port/foo is port object field access //case A_PATH_SET: // not allowed: above if (!IS_EVENT(arg)) Trap_Arg_DEAD_END(arg); case A_PICK: act_blk: save_port = *D_ARG(1); // save for return *D_ARG(1) = *state; result = T_Block(call_, action); SET_SIGNAL(SIG_EVENT_PORT); if (action == A_INSERT || action == A_APPEND || action == A_REMOVE) { *D_OUT = save_port; break; } return result; // return condition case A_CLEAR: VAL_TAIL(state) = 0; VAL_BLK_TERM(state); CLR_SIGNAL(SIG_EVENT_PORT); break; case A_LENGTHQ: SET_INTEGER(D_OUT, VAL_TAIL(state)); break; case A_OPEN: if (!req) { //!!! req = OS_MAKE_DEVREQ(RDI_EVENT); if (req) { SET_OPEN(req); OS_DO_DEVICE(req, RDC_CONNECT); // stays queued } } break; case A_CLOSE: OS_ABORT_DEVICE(req); OS_DO_DEVICE(req, RDC_CLOSE); // free req!!! SET_CLOSED(req); req = 0; break; case A_FIND: // add it default: Trap_Action_DEAD_END(REB_PORT, action); } return R_OUT; }