NOP0 / rustmatic

PLC programming in Rust!
Apache License 2.0
35 stars 2 forks source link

Process Execution Model #2

Open Michael-F-Bryan opened 4 years ago

Michael-F-Bryan commented 4 years ago

Looking at the Overview diagram, it sounds like the core of the PLC runtime would be something like this:

while running {
  read_inputs();
  poll_waiting_processes();
  write_outputs();
  do_background_tasks_until_next_tick();
}

Yet it mentions event- and time-driven interrupts.

Would "triggering" an interrupt just be a case of registering that interrupt's readiness so it can be polled as part of the next poll_waiting_processes()? Or were you thinking along the lines of the true preemptive interrupts you see in embedded systems or in unix signals?

NOP0 commented 4 years ago

 read_inputs();
 poll_waiting_processes();
 write_outputs();
 do_background_tasks_until_next_tick();
}
Yes, thats's what I had in mind when I drew the diagram at least.

Regarding the interrupts, I had preemption in mind, since i.e. Siemens and Codesys support this. This might be unrealistic with limited resources...maybe async has some feature for this?

NOP0 commented 4 years ago

Regarding the interrupts, I had preemption in mind, since i.e. Siemens and Codesys support this. This >might be unrealistic with limited resources...maybe async has some feature for this?

That said, I think the interrupt routines share the same global address space, would it be possible to interrupt the bytecode vm?

Michael-F-Bryan commented 4 years ago

That'd depend on what system you're running on. If it's an embedded system (i.e. no OS) then interrupts can interrupt pretty much anything, as long as you aren't in a critical section (e.g. you disabled interrupts to access a mutex).

On the other hand, I'm not sure if a "normal" OS would give you access to the raw interrupt handlers. I know Linux lets you create a per-process timer with timer_create() then register a listener for the SIGALRM signal using sigaction(). Although signal handlers have some pretty tight restrictions (e.g. no locks or blocking), so they're not ideal.


Also, I'm not sure I'd like a program (doesn't necessarily need to be something running on a bytecode VM) to be interrupted midway through. What if my program was reading an input (Device::digital_read()) at the time? My Device object needs to use locks because it's already shared with multiple things, but the system will deadlock if we're running programs in response to a timer/event and that program tries to use that device.

I guess if we take the event-driven approach later, this sort of "interrupt" system for working with timers and events would solve itself. You'd create a priority system or special high-priority queue and handling a timer/event is just a case of adding the handler to the front of the event queue so it's handled straight away. Most JavaScript runtimes have something similar in the form of microtasks.

NOP0 commented 4 years ago

Yeah, I'm guessing for MVP it's probably not necessary to interrupt a program, the interrupt is queued.