1use crate::cost_model::transferred_byte_cycles;
2use crate::syscalls::{
3 EXEC_LOAD_ELF_V2_CYCLES_BASE, INVALID_FD, MAX_FDS_CREATED, MAX_VMS_SPAWNED, OTHER_END_CLOSED,
4 SPAWN_EXTRA_CYCLES_BASE, SUCCESS, WAIT_FAILURE,
5};
6
7use crate::types::{
8 DataLocation, DataPieceId, FIRST_FD_SLOT, FIRST_VM_ID, Fd, FdArgs, IterationResult, Message,
9 ReadState, RunMode, SgData, SyscallGenerator, TerminatedResult, VmArgs, VmContext, VmId,
10 VmState, WriteState,
11};
12use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider};
13use ckb_types::core::Cycle;
14use ckb_vm::snapshot2::Snapshot2Context;
15use ckb_vm::{
16 Error, FlattenedArgsReader, Register,
17 bytes::Bytes,
18 cost_model::estimate_cycles,
19 elf::parse_elf,
20 machine::{CoreMachine, DefaultMachineBuilder, DefaultMachineRunner, Pause, SupportMachine},
21 memory::Memory,
22 registers::A0,
23 snapshot2::Snapshot2,
24};
25use std::collections::{BTreeMap, HashMap};
26use std::sync::{
27 Arc, Mutex,
28 atomic::{AtomicU64, Ordering},
29};
30
31pub const ROOT_VM_ID: VmId = FIRST_VM_ID;
33pub const MAX_VMS_COUNT: u64 = 16;
35pub const MAX_INSTANTIATED_VMS: usize = 4;
37pub const MAX_FDS: u64 = 64;
39
40pub struct Scheduler<DL, V, M>
47where
48 DL: CellDataProvider,
49 M: DefaultMachineRunner,
50{
51 sg_data: SgData<DL>,
53
54 syscall_generator: SyscallGenerator<DL, V, M::Inner>,
56 syscall_context: V,
58
59 total_cycles: Arc<AtomicU64>,
96 iteration_cycles: Cycle,
98 next_vm_id: VmId,
100 next_fd_slot: u64,
102 states: BTreeMap<VmId, VmState>,
104 fds: BTreeMap<Fd, VmId>,
106 inherited_fd: BTreeMap<VmId, Vec<Fd>>,
108 instantiated: BTreeMap<VmId, (VmContext<DL>, M)>,
110 suspended: BTreeMap<VmId, Snapshot2<DataPieceId>>,
112 terminated_vms: BTreeMap<VmId, i8>,
114 root_vm_args: Vec<Bytes>,
118
119 message_box: Arc<Mutex<Vec<Message>>>,
122}
123
124impl<DL, V, M> Scheduler<DL, V, M>
125where
126 DL: CellDataProvider + HeaderProvider + ExtensionProvider + Clone,
127 V: Clone,
128 M: DefaultMachineRunner,
129{
130 pub fn new(
132 sg_data: SgData<DL>,
133 syscall_generator: SyscallGenerator<DL, V, M::Inner>,
134 syscall_context: V,
135 ) -> Self {
136 Self {
137 sg_data,
138 syscall_generator,
139 syscall_context,
140 total_cycles: Arc::new(AtomicU64::new(0)),
141 iteration_cycles: 0,
142 next_vm_id: FIRST_VM_ID,
143 next_fd_slot: FIRST_FD_SLOT,
144 states: BTreeMap::default(),
145 fds: BTreeMap::default(),
146 inherited_fd: BTreeMap::default(),
147 instantiated: BTreeMap::default(),
148 suspended: BTreeMap::default(),
149 message_box: Arc::new(Mutex::new(Vec::new())),
150 terminated_vms: BTreeMap::default(),
151 root_vm_args: Vec::new(),
152 }
153 }
154
155 pub fn consumed_cycles(&self) -> Cycle {
157 self.total_cycles.load(Ordering::Acquire)
158 }
159
160 pub fn state(&self, vm_id: &VmId) -> Option<VmState> {
162 self.states.get(vm_id).cloned()
163 }
164
165 pub fn sg_data(&self) -> &SgData<DL> {
167 &self.sg_data
168 }
169
170 pub fn peek<F, G, W>(&mut self, vm_id: &VmId, mut f: F, mut g: G) -> Result<W, Error>
179 where
180 F: FnMut(&mut M) -> Result<W, Error>,
181 G: FnMut(&Snapshot2<DataPieceId>, &SgData<DL>) -> Result<W, Error>,
182 {
183 if let Some((_, machine)) = self.instantiated.get_mut(vm_id) {
184 return f(machine);
185 }
186 if let Some(snapshot) = self.suspended.get(vm_id) {
187 return g(snapshot, &self.sg_data);
188 }
189 Err(Error::Unexpected(format!("VM {} does not exist!", vm_id)))
190 }
191
192 fn consume_cycles(&mut self, cycles: Cycle) -> Result<(), Error> {
194 match self
195 .total_cycles
196 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |total_cycles| {
197 total_cycles.checked_add(cycles)
198 }) {
199 Ok(_) => Ok(()),
200 Err(_) => Err(Error::CyclesExceeded),
201 }
202 }
203
204 pub fn run(&mut self, mode: RunMode) -> Result<TerminatedResult, Error> {
218 self.boot_root_vm_if_needed()?;
219
220 let (pause, mut limit_cycles) = match mode {
221 RunMode::LimitCycles(limit_cycles) => (Pause::new(), limit_cycles),
222 RunMode::Pause(pause, limit_cycles) => (pause, limit_cycles),
223 };
224
225 while !self.terminated() {
226 limit_cycles = self.iterate_outer(&pause, limit_cycles)?.1;
227 }
228 assert_eq!(self.iteration_cycles, 0);
229
230 self.terminated_result()
231 }
232
233 pub fn iterate(&mut self) -> Result<IterationResult, Error> {
237 self.boot_root_vm_if_needed()?;
238
239 if self.terminated() {
240 return Ok(IterationResult {
241 executed_vm: ROOT_VM_ID,
242 terminated_status: Some(self.terminated_result()?),
243 });
244 }
245
246 let (id, _) = self.iterate_outer(&Pause::new(), u64::MAX)?;
247 let terminated_status = if self.terminated() {
248 assert_eq!(self.iteration_cycles, 0);
249 Some(self.terminated_result()?)
250 } else {
251 None
252 };
253
254 Ok(IterationResult {
255 executed_vm: id,
256 terminated_status,
257 })
258 }
259
260 fn iterate_prepare_machine(&mut self) -> Result<(u64, &mut M), Error> {
262 let vm_id_to_run = self
264 .states
265 .iter()
266 .rev()
267 .filter(|(_, state)| matches!(state, VmState::Runnable))
268 .map(|(id, _)| *id)
269 .next();
270 let vm_id_to_run = vm_id_to_run.ok_or_else(|| {
271 Error::Unexpected("A deadlock situation has been reached!".to_string())
272 })?;
273 let (_context, machine) = self.ensure_get_instantiated(&vm_id_to_run)?;
274 Ok((vm_id_to_run, machine))
275 }
276
277 fn iterate_process_results(
279 &mut self,
280 vm_id_to_run: u64,
281 result: Result<i8, Error>,
282 ) -> Result<(), Error> {
283 self.process_message_box()?;
285 assert!(self.message_box.lock().expect("lock").is_empty());
286 match result {
289 Ok(code) => {
290 self.terminated_vms.insert(vm_id_to_run, code);
291 if vm_id_to_run == ROOT_VM_ID {
295 self.ensure_vms_instantiated(&[vm_id_to_run])?;
296 self.instantiated.retain(|id, _| *id == vm_id_to_run);
297 self.suspended.clear();
298 self.states.clear();
299 self.states.insert(vm_id_to_run, VmState::Terminated);
300 } else {
301 let joining_vms: Vec<(VmId, u64)> = self
302 .states
303 .iter()
304 .filter_map(|(vm_id, state)| match state {
305 VmState::Wait {
306 target_vm_id,
307 exit_code_addr,
308 } if *target_vm_id == vm_id_to_run => Some((*vm_id, *exit_code_addr)),
309 _ => None,
310 })
311 .collect();
312 for (vm_id, exit_code_addr) in joining_vms {
315 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
316 machine
317 .inner_mut()
318 .memory_mut()
319 .store8(&Self::u64_to_reg(exit_code_addr), &Self::i8_to_reg(code))?;
320 machine
321 .inner_mut()
322 .set_register(A0, Self::u8_to_reg(SUCCESS));
323 self.states.insert(vm_id, VmState::Runnable);
324 }
325 self.fds.retain(|_, vm_id| *vm_id != vm_id_to_run);
327 self.states.remove(&vm_id_to_run);
329 self.instantiated.remove(&vm_id_to_run);
330 self.suspended.remove(&vm_id_to_run);
331 }
332 Ok(())
333 }
334 Err(Error::Yield) => Ok(()),
335 Err(e) => Err(e),
336 }
337 }
338
339 #[inline]
343 fn iterate_outer(
344 &mut self,
345 pause: &Pause,
346 limit_cycles: Cycle,
347 ) -> Result<(VmId, Cycle), Error> {
348 let iterate_return = self.iterate_inner(pause.clone(), limit_cycles);
349 self.consume_cycles(self.iteration_cycles)?;
350 let remaining_cycles = limit_cycles
351 .checked_sub(self.iteration_cycles)
352 .ok_or(Error::CyclesExceeded)?;
353 self.iteration_cycles = 0;
355 self.process_io()?;
380 let id = iterate_return?;
381 Ok((id, remaining_cycles))
382 }
383
384 fn iterate_inner(&mut self, pause: Pause, limit_cycles: Cycle) -> Result<VmId, Error> {
388 let (id, result, cycles) = {
392 let (id, vm) = self.iterate_prepare_machine()?;
393 vm.inner_mut().set_max_cycles(limit_cycles);
394 vm.machine_mut().set_pause(pause);
395 let result = vm.run();
396 let cycles = vm.machine().cycles();
397 vm.inner_mut().set_cycles(0);
398 (id, result, cycles)
399 };
400 self.iteration_cycles = self
401 .iteration_cycles
402 .checked_add(cycles)
403 .ok_or(Error::CyclesExceeded)?;
404 self.iterate_process_results(id, result)?;
405 Ok(id)
406 }
407
408 fn process_message_box(&mut self) -> Result<(), Error> {
409 let messages: Vec<Message> = self.message_box.lock().expect("lock").drain(..).collect();
410 for message in messages {
411 match message {
412 Message::ExecV2(vm_id, args) => {
413 let (old_context, old_machine) = self
414 .instantiated
415 .get_mut(&vm_id)
416 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?;
417 old_machine
418 .inner_mut()
419 .add_cycles_no_checking(EXEC_LOAD_ELF_V2_CYCLES_BASE)?;
420 let old_cycles = old_machine.machine().cycles();
421 let max_cycles = old_machine.machine().max_cycles();
422 let program = {
423 let sc = old_context.snapshot2_context.lock().expect("lock");
424 sc.load_data(
425 &args.location.data_piece_id,
426 args.location.offset,
427 args.location.length,
428 )?
429 .0
430 };
431 let (context, mut new_machine) = self.create_dummy_vm(&vm_id)?;
432 new_machine.inner_mut().set_max_cycles(max_cycles);
433 new_machine.inner_mut().add_cycles_no_checking(old_cycles)?;
434 self.load_vm_program(
435 &context,
436 &mut new_machine,
437 &args.location,
438 program,
439 VmArgs::Reader {
440 vm_id,
441 argc: args.argc,
442 argv: args.argv,
443 },
444 )?;
445 debug_assert!(self.instantiated.contains_key(&vm_id));
447 self.instantiated.insert(vm_id, (context, new_machine));
448 }
449 Message::Spawn(vm_id, args) => {
450 if args.fds.iter().any(|fd| self.fds.get(fd) != Some(&vm_id)) {
452 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
453 machine
454 .inner_mut()
455 .set_register(A0, Self::u8_to_reg(INVALID_FD));
456 continue;
457 }
458 if self.suspended.len() + self.instantiated.len() > MAX_VMS_COUNT as usize {
459 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
460 machine
461 .inner_mut()
462 .set_register(A0, Self::u8_to_reg(MAX_VMS_SPAWNED));
463 continue;
464 }
465 let spawned_vm_id = self.boot_vm(
466 &args.location,
467 VmArgs::Reader {
468 vm_id,
469 argc: args.argc,
470 argv: args.argv,
471 },
472 )?;
473 for fd in &args.fds {
475 self.fds.insert(*fd, spawned_vm_id);
476 }
477 self.inherited_fd.insert(spawned_vm_id, args.fds.clone());
480
481 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
482 machine.inner_mut().memory_mut().store64(
483 &Self::u64_to_reg(args.process_id_addr),
484 &Self::u64_to_reg(spawned_vm_id),
485 )?;
486 machine
487 .inner_mut()
488 .set_register(A0, Self::u8_to_reg(SUCCESS));
489 }
490 Message::Wait(vm_id, args) => {
491 if let Some(exit_code) = self.terminated_vms.get(&args.target_id).copied() {
492 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
493 machine.inner_mut().memory_mut().store8(
494 &Self::u64_to_reg(args.exit_code_addr),
495 &Self::i8_to_reg(exit_code),
496 )?;
497 machine
498 .inner_mut()
499 .set_register(A0, Self::u8_to_reg(SUCCESS));
500 self.states.insert(vm_id, VmState::Runnable);
501 self.terminated_vms.remove(&args.target_id);
502 continue;
503 }
504 if !self.states.contains_key(&args.target_id) {
505 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
506 machine
507 .inner_mut()
508 .set_register(A0, Self::u8_to_reg(WAIT_FAILURE));
509 continue;
510 }
511 self.states.insert(
513 vm_id,
514 VmState::Wait {
515 target_vm_id: args.target_id,
516 exit_code_addr: args.exit_code_addr,
517 },
518 );
519 }
520 Message::Pipe(vm_id, args) => {
521 if self.fds.len() as u64 >= MAX_FDS {
522 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
523 machine
524 .inner_mut()
525 .set_register(A0, Self::u8_to_reg(MAX_FDS_CREATED));
526 continue;
527 }
528 let (p1, p2, slot) = Fd::create(self.next_fd_slot);
529 self.next_fd_slot = slot;
530 self.fds.insert(p1, vm_id);
531 self.fds.insert(p2, vm_id);
532 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
533 machine
534 .inner_mut()
535 .memory_mut()
536 .store64(&Self::u64_to_reg(args.fd1_addr), &Self::u64_to_reg(p1.0))?;
537 machine
538 .inner_mut()
539 .memory_mut()
540 .store64(&Self::u64_to_reg(args.fd2_addr), &Self::u64_to_reg(p2.0))?;
541 machine
542 .inner_mut()
543 .set_register(A0, Self::u8_to_reg(SUCCESS));
544 }
545 Message::FdRead(vm_id, args) => {
546 if !(self.fds.contains_key(&args.fd) && (self.fds[&args.fd] == vm_id)) {
547 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
548 machine
549 .inner_mut()
550 .set_register(A0, Self::u8_to_reg(INVALID_FD));
551 continue;
552 }
553 if !self.fds.contains_key(&args.fd.other_fd()) {
554 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
555 machine
556 .inner_mut()
557 .set_register(A0, Self::u8_to_reg(OTHER_END_CLOSED));
558 continue;
559 }
560 self.states.insert(
562 vm_id,
563 VmState::WaitForRead(ReadState {
564 fd: args.fd,
565 length: args.length,
566 buffer_addr: args.buffer_addr,
567 length_addr: args.length_addr,
568 }),
569 );
570 }
571 Message::FdWrite(vm_id, args) => {
572 if !(self.fds.contains_key(&args.fd) && (self.fds[&args.fd] == vm_id)) {
573 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
574 machine
575 .inner_mut()
576 .set_register(A0, Self::u8_to_reg(INVALID_FD));
577 continue;
578 }
579 if !self.fds.contains_key(&args.fd.other_fd()) {
580 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
581 machine
582 .inner_mut()
583 .set_register(A0, Self::u8_to_reg(OTHER_END_CLOSED));
584 continue;
585 }
586 self.states.insert(
588 vm_id,
589 VmState::WaitForWrite(WriteState {
590 fd: args.fd,
591 consumed: 0,
592 length: args.length,
593 buffer_addr: args.buffer_addr,
594 length_addr: args.length_addr,
595 }),
596 );
597 }
598 Message::InheritedFileDescriptor(vm_id, args) => {
599 let inherited_fd = if vm_id == ROOT_VM_ID {
600 Vec::new()
601 } else {
602 self.inherited_fd[&vm_id].clone()
603 };
604 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
605 let FdArgs {
606 buffer_addr,
607 length_addr,
608 ..
609 } = args;
610 let full_length = machine
611 .inner_mut()
612 .memory_mut()
613 .load64(&Self::u64_to_reg(length_addr))?
614 .to_u64();
615 let real_length = inherited_fd.len() as u64;
616 let copy_length = u64::min(full_length, real_length);
617 for i in 0..copy_length {
618 let fd = inherited_fd[i as usize].0;
619 let offset = i.checked_mul(8).ok_or(Error::MemOutOfBound)?;
620 let addr = buffer_addr
621 .checked_add(offset)
622 .ok_or(Error::MemOutOfBound)?;
623 machine
624 .inner_mut()
625 .memory_mut()
626 .store64(&Self::u64_to_reg(addr), &Self::u64_to_reg(fd))?;
627 }
628 machine.inner_mut().memory_mut().store64(
629 &Self::u64_to_reg(length_addr),
630 &Self::u64_to_reg(real_length),
631 )?;
632 machine
633 .inner_mut()
634 .set_register(A0, Self::u8_to_reg(SUCCESS));
635 }
636 Message::Close(vm_id, fd) => {
637 if self.fds.get(&fd) != Some(&vm_id) {
638 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
639 machine
640 .inner_mut()
641 .set_register(A0, Self::u8_to_reg(INVALID_FD));
642 } else {
643 self.fds.remove(&fd);
644 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
645 machine
646 .inner_mut()
647 .set_register(A0, Self::u8_to_reg(SUCCESS));
648 }
649 }
650 }
651 }
652 Ok(())
653 }
654
655 fn process_io(&mut self) -> Result<(), Error> {
656 let mut reads: HashMap<Fd, (VmId, ReadState)> = HashMap::default();
657 let mut closed_fds: Vec<VmId> = Vec::new();
658
659 self.states.iter().for_each(|(vm_id, state)| {
660 if let VmState::WaitForRead(inner_state) = state {
661 if self.fds.contains_key(&inner_state.fd.other_fd()) {
662 reads.insert(inner_state.fd, (*vm_id, inner_state.clone()));
663 } else {
664 closed_fds.push(*vm_id);
665 }
666 }
667 });
668 let mut pairs: Vec<(VmId, ReadState, VmId, WriteState)> = Vec::new();
669 self.states.iter().for_each(|(vm_id, state)| {
670 if let VmState::WaitForWrite(inner_state) = state {
671 if self.fds.contains_key(&inner_state.fd.other_fd()) {
672 if let Some((read_vm_id, read_state)) = reads.get(&inner_state.fd.other_fd()) {
673 pairs.push((*read_vm_id, read_state.clone(), *vm_id, inner_state.clone()));
674 }
675 } else {
676 closed_fds.push(*vm_id);
677 }
678 }
679 });
680 for vm_id in closed_fds {
682 match self.states[&vm_id].clone() {
683 VmState::WaitForRead(ReadState { length_addr, .. }) => {
684 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
685 machine.inner_mut().memory_mut().store64(
686 &Self::u64_to_reg(length_addr),
687 &<M::Inner as CoreMachine>::REG::zero(),
688 )?;
689 machine
690 .inner_mut()
691 .set_register(A0, Self::u8_to_reg(SUCCESS));
692 self.states.insert(vm_id, VmState::Runnable);
693 }
694 VmState::WaitForWrite(WriteState {
695 consumed,
696 length_addr,
697 ..
698 }) => {
699 let (_, machine) = self.ensure_get_instantiated(&vm_id)?;
700 machine
701 .inner_mut()
702 .memory_mut()
703 .store64(&Self::u64_to_reg(length_addr), &Self::u64_to_reg(consumed))?;
704 machine
705 .inner_mut()
706 .set_register(A0, Self::u8_to_reg(SUCCESS));
707 self.states.insert(vm_id, VmState::Runnable);
708 }
709 _ => (),
710 }
711 }
712 for (read_vm_id, read_state, write_vm_id, write_state) in pairs {
714 let ReadState {
715 length: read_length,
716 buffer_addr: read_buffer_addr,
717 length_addr: read_length_addr,
718 ..
719 } = read_state;
720 let WriteState {
721 fd: write_fd,
722 mut consumed,
723 length: write_length,
724 buffer_addr: write_buffer_addr,
725 length_addr: write_length_addr,
726 } = write_state;
727
728 self.ensure_vms_instantiated(&[read_vm_id, write_vm_id])?;
729 {
730 let fillable = read_length;
731 let consumable = write_length - consumed;
732 let copiable = std::cmp::min(fillable, consumable);
733
734 let (_, write_machine) = self
736 .instantiated
737 .get_mut(&write_vm_id)
738 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?;
739 write_machine
740 .inner_mut()
741 .add_cycles_no_checking(transferred_byte_cycles(copiable))?;
742 let data = write_machine.inner_mut().memory_mut().load_bytes(
743 write_buffer_addr
744 .checked_add(consumed)
745 .ok_or(Error::MemOutOfBound)?,
746 copiable,
747 )?;
748 let (_, read_machine) = self
749 .instantiated
750 .get_mut(&read_vm_id)
751 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?;
752 read_machine
753 .inner_mut()
754 .add_cycles_no_checking(transferred_byte_cycles(copiable))?;
755 read_machine
756 .inner_mut()
757 .memory_mut()
758 .store_bytes(read_buffer_addr, &data)?;
759 read_machine.inner_mut().memory_mut().store64(
761 &Self::u64_to_reg(read_length_addr),
762 &Self::u64_to_reg(copiable),
763 )?;
764 read_machine
765 .inner_mut()
766 .set_register(A0, Self::u8_to_reg(SUCCESS));
767 self.states.insert(read_vm_id, VmState::Runnable);
768
769 consumed += copiable;
772 if consumed == write_length {
773 let (_, write_machine) = self
775 .instantiated
776 .get_mut(&write_vm_id)
777 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?;
778 write_machine.inner_mut().memory_mut().store64(
779 &Self::u64_to_reg(write_length_addr),
780 &Self::u64_to_reg(write_length),
781 )?;
782 write_machine
783 .inner_mut()
784 .set_register(A0, Self::u8_to_reg(SUCCESS));
785 self.states.insert(write_vm_id, VmState::Runnable);
786 } else {
787 self.states.insert(
789 write_vm_id,
790 VmState::WaitForWrite(WriteState {
791 fd: write_fd,
792 consumed,
793 length: write_length,
794 buffer_addr: write_buffer_addr,
795 length_addr: write_length_addr,
796 }),
797 );
798 }
799 }
800 }
801 Ok(())
802 }
803
804 pub fn terminated(&self) -> bool {
806 self.states
807 .get(&ROOT_VM_ID)
808 .map(|state| *state == VmState::Terminated)
809 .unwrap_or(false)
810 }
811
812 fn terminated_result(&mut self) -> Result<TerminatedResult, Error> {
813 assert!(self.terminated());
814
815 let exit_code = {
816 let root_vm = &self.ensure_get_instantiated(&ROOT_VM_ID)?.1;
817 root_vm.machine().exit_code()
818 };
819 Ok(TerminatedResult {
820 exit_code,
821 consumed_cycles: self.consumed_cycles(),
822 })
823 }
824
825 fn ensure_vms_instantiated(&mut self, ids: &[VmId]) -> Result<(), Error> {
827 if ids.len() > MAX_INSTANTIATED_VMS {
828 return Err(Error::Unexpected(format!(
829 "At most {} VMs can be instantiated but {} are requested!",
830 MAX_INSTANTIATED_VMS,
831 ids.len()
832 )));
833 }
834
835 let mut uninstantiated_ids: Vec<VmId> = ids
836 .iter()
837 .filter(|id| !self.instantiated.contains_key(id))
838 .copied()
839 .collect();
840 while (!uninstantiated_ids.is_empty()) && (self.instantiated.len() < MAX_INSTANTIATED_VMS) {
841 let id = uninstantiated_ids
842 .pop()
843 .ok_or_else(|| Error::Unexpected("Map should not be empty".to_string()))?;
844 self.resume_vm(&id)?;
845 }
846
847 if !uninstantiated_ids.is_empty() {
848 let suspendable_ids: Vec<VmId> = self
850 .instantiated
851 .keys()
852 .filter(|id| !ids.contains(id))
853 .copied()
854 .collect();
855
856 assert!(suspendable_ids.len() >= uninstantiated_ids.len());
857 for i in 0..uninstantiated_ids.len() {
858 self.suspend_vm(&suspendable_ids[i])?;
859 self.resume_vm(&uninstantiated_ids[i])?;
860 }
861 }
862
863 Ok(())
864 }
865
866 fn ensure_get_instantiated(&mut self, id: &VmId) -> Result<&mut (VmContext<DL>, M), Error> {
868 self.ensure_vms_instantiated(&[*id])?;
869 self.instantiated
870 .get_mut(id)
871 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))
872 }
873
874 fn resume_vm(&mut self, id: &VmId) -> Result<(), Error> {
876 if !self.suspended.contains_key(id) {
877 return Err(Error::Unexpected(format!("VM {:?} is not suspended!", id)));
878 }
879 let snapshot = &self.suspended[id];
880 self.iteration_cycles = self
881 .iteration_cycles
882 .checked_add(SPAWN_EXTRA_CYCLES_BASE)
883 .ok_or(Error::CyclesExceeded)?;
884 let (context, mut machine) = self.create_dummy_vm(id)?;
885 {
886 let mut sc = context.snapshot2_context.lock().expect("lock");
887 sc.resume(machine.inner_mut(), snapshot)?;
888 }
889 self.instantiated.insert(*id, (context, machine));
890 self.suspended.remove(id);
891 Ok(())
892 }
893
894 fn suspend_vm(&mut self, id: &VmId) -> Result<(), Error> {
896 if !self.instantiated.contains_key(id) {
897 return Err(Error::Unexpected(format!(
898 "VM {:?} is not instantiated!",
899 id
900 )));
901 }
902 self.iteration_cycles = self
903 .iteration_cycles
904 .checked_add(SPAWN_EXTRA_CYCLES_BASE)
905 .ok_or(Error::CyclesExceeded)?;
906 let (context, machine) = self
907 .instantiated
908 .get_mut(id)
909 .ok_or_else(|| Error::Unexpected("Unable to find VM Id".to_string()))?;
910 let snapshot = {
911 let sc = context.snapshot2_context.lock().expect("lock");
912 sc.make_snapshot(machine.inner_mut())?
913 };
914 self.suspended.insert(*id, snapshot);
915 self.instantiated.remove(id);
916 Ok(())
917 }
918
919 fn boot_root_vm_if_needed(&mut self) -> Result<(), Error> {
920 if self.states.is_empty() {
921 let program_id = self.sg_data.sg_info.program_data_piece_id.clone();
923 assert_eq!(
924 self.boot_vm(
925 &DataLocation {
926 data_piece_id: program_id,
927 offset: 0,
928 length: u64::MAX,
929 },
930 VmArgs::Vector(self.root_vm_args.clone()),
931 )?,
932 ROOT_VM_ID
933 );
934 }
935 assert!(self.states.contains_key(&ROOT_VM_ID));
936
937 Ok(())
938 }
939
940 fn boot_vm(&mut self, location: &DataLocation, args: VmArgs) -> Result<VmId, Error> {
942 let id = self.next_vm_id;
943 self.next_vm_id += 1;
944 let (context, mut machine) = self.create_dummy_vm(&id)?;
945 let (program, _) = {
946 let sc = context.snapshot2_context.lock().expect("lock");
947 sc.load_data(&location.data_piece_id, location.offset, location.length)?
948 };
949 self.load_vm_program(&context, &mut machine, location, program, args)?;
950 while self.instantiated.len() >= MAX_INSTANTIATED_VMS {
952 let id = *self
954 .instantiated
955 .first_entry()
956 .ok_or_else(|| Error::Unexpected("Map should not be empty".to_string()))?
957 .key();
958 self.suspend_vm(&id)?;
959 }
960
961 self.instantiated.insert(id, (context, machine));
962 self.states.insert(id, VmState::Runnable);
963
964 Ok(id)
965 }
966
967 fn load_vm_program(
969 &mut self,
970 context: &VmContext<DL>,
971 machine: &mut M,
972 location: &DataLocation,
973 program: Bytes,
974 args: VmArgs,
975 ) -> Result<u64, Error> {
976 let metadata = parse_elf::<u64>(&program, machine.inner_mut().version())?;
977 let bytes = match args {
978 VmArgs::Reader { vm_id, argc, argv } => {
979 let (_, machine_from) = self.ensure_get_instantiated(&vm_id)?;
980 let argc = Self::u64_to_reg(argc);
981 let argv = Self::u64_to_reg(argv);
982 let argv =
983 FlattenedArgsReader::new(machine_from.inner_mut().memory_mut(), argc, argv);
984 machine.load_program_with_metadata(&program, &metadata, argv)?
985 }
986 VmArgs::Vector(data) => {
987 machine.load_program_with_metadata(&program, &metadata, data.into_iter().map(Ok))?
988 }
989 };
990 let mut sc = context.snapshot2_context.lock().expect("lock");
991 sc.mark_program(
992 machine.inner_mut(),
993 &metadata,
994 &location.data_piece_id,
995 location.offset,
996 )?;
997 machine
998 .inner_mut()
999 .add_cycles_no_checking(transferred_byte_cycles(bytes))?;
1000 Ok(bytes)
1001 }
1002
1003 fn create_dummy_vm(&self, id: &VmId) -> Result<(VmContext<DL>, M), Error> {
1005 let version = &self.sg_data.sg_info.script_version;
1006 let core_machine = M::Inner::new(
1007 version.vm_isa(),
1008 version.vm_version(),
1009 u64::MAX,
1011 );
1012 let vm_context = VmContext {
1013 base_cycles: Arc::clone(&self.total_cycles),
1014 message_box: Arc::clone(&self.message_box),
1015 snapshot2_context: Arc::new(Mutex::new(Snapshot2Context::new(self.sg_data.clone()))),
1016 };
1017
1018 let machine_builder = DefaultMachineBuilder::new(core_machine)
1019 .instruction_cycle_func(Box::new(estimate_cycles));
1020 let machine_builder =
1021 (self.syscall_generator)(id, &self.sg_data, &vm_context, &self.syscall_context)
1022 .into_iter()
1023 .fold(machine_builder, |builder, syscall| builder.syscall(syscall));
1024 let default_machine = machine_builder.build();
1025 Ok((vm_context, M::new(default_machine)))
1026 }
1027
1028 pub fn set_root_vm_args(&mut self, args: Vec<Bytes>) {
1031 self.root_vm_args = args;
1032 }
1033
1034 fn i8_to_reg(v: i8) -> <M::Inner as CoreMachine>::REG {
1035 <M::Inner as CoreMachine>::REG::from_i8(v)
1036 }
1037
1038 fn u8_to_reg(v: u8) -> <M::Inner as CoreMachine>::REG {
1039 <M::Inner as CoreMachine>::REG::from_u8(v)
1040 }
1041
1042 fn u64_to_reg(v: u64) -> <M::Inner as CoreMachine>::REG {
1043 <M::Inner as CoreMachine>::REG::from_u64(v)
1044 }
1045}