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

Noting that process scheduling in ckb-vm is deterministic #445

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
27 changes: 26 additions & 1 deletion rfcs/0050-vm-syscalls-3/0050-vm-syscalls-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ The design of the syscall spawn function draws inspiration from Unix and Linux,

In the context of ckb-vm, a process represents the active execution of a RISC-V binary. This binary can be located within a cell. Additionally, a RISC-V binary can also be found within the witness during a syscall spawn. A pipe is established by associating two file descriptors, each linked to one of its ends. These file descriptors can't be duplicated and are exclusively owned by the process. Furthermore, the file descriptors can only be either read from or written to; they can't be both read from and written to simultaneously.

It is worth noting that process scheduling in ckb-vm is deterministic, specifically:

- For each hardfork version, the process scheduling will be deterministic, any indeterminism will be treated as critical / security bugs that requires immediate intervention
- However, based on real usage on chain, it is expected that future hardfork versions would improve the process scheduling workflow, hence making the behavior different across versions

We added 8 spawn-related syscalls and one block-related syscall, respectively:

- [Spawn]
Expand Down Expand Up @@ -208,7 +213,27 @@ Five new error types added:
- Error code 8: The maximum count of spawned processes has been reached.
- Error code 9: The maximum count of created pipes has been reached.

It's possible for read/write/wait operations to wait for each other, leading to a deadlock state. In such cases, CKB-VM would throw an internal error and terminate immediately.
## Deadlock

Deadlock is a situation where two or more processes are unable to proceed because they are each waiting for resources or conditions that can only be provided by another waiting process. In the context of this scheduler, where processes communicate via pipes and can enter various states, such as `Runnable`, `Running`, `Terminated`, `WaitForExit`, `WaitForRead`, `WaitForWrite`. In our scheduler, deadlock will occur if all unterminated processes are waiting and no process is in a runnable state.

- The process enters the `Runnable` when a process is created, or it's blocking condition is resolved.
- The process enters the `Running` when a process starts running.
- The process enters the `Terminated` when a process is terminated.
- The process enters the `WaitForExit` state by calling the `wait()` on another process still running.
- The process enters the `WaitForRead` state by calling the `read()`. A process might not actually enter `WaitForRead` state by calling `read()`, if data are already available at the other end. It only enters this state when it wants data but data are not ready, in other words, it has a blocking condition.
- The process enters the `WaitForWrite` state by calling the `write()`. A process might not actually enter `WaitForRead` state by calling `write()`, if the other end is in `WaitForRead` state and is able to read all the data.

If multiple processes are in the `WaitForExit`, `WaitForWrite`, or `WaitForRead` states and are waiting on each other in a circular dependency, a deadlock can occur. Here are two examples:

1. A simple deadlock scenario, both processes are waiting for the other process to send data:
- Process A is in `WaitForRead` for data from process B
- Process B is in `WaitForRead` for data from process A. Both processes will wait indefinitely, as each is waiting for the other to proceed.

2. Deadlock caused by unbuffered pipes. Note that the pipe in ckb-vm is unbuffered. If one process blocks on a `WaitForWrite` state because the data is not fully read, and the reader process is also blocked in a `WaitForRead` state (but on a different file descriptor), this can create a deadlock if neither can proceed:
- Process A wants to read 10 bytes from fd0, and then read 10 bytes from fd1, and finally read 10 bytes from fd0.
- Process B writes 20 bytes into fd0, and then write 10 bytes into fd1.


## Cycles

Expand Down
Loading