wasmer_wasix/syscalls/wasix/
epoll_ctl.rs1use wasmer_wasix_types::wasi::{EpollCtl, EpollEvent, EpollEventCtl, SubscriptionClock, Userdata};
2
3use super::*;
4use crate::{
5 WasiInodes,
6 fs::{InodeValFilePollGuard, InodeValFilePollGuardJoin},
7 os::epoll::register_epoll_handler,
8 state::PollEventSet,
9 syscalls::*,
10};
11
12#[instrument(level = "trace", skip_all, fields(timeout_ms = field::Empty, fd_guards = field::Empty, seen = field::Empty, fd), ret)]
18pub fn epoll_ctl<M: MemorySize + 'static>(
19 mut ctx: FunctionEnvMut<'_, WasiEnv>,
20 epfd: WasiFd,
21 op: EpollCtl,
22 fd: WasiFd,
23 event_ref: WasmPtr<EpollEvent<M>, M>,
24) -> Result<Errno, WasiError> {
25 WasiEnv::do_pending_operations(&mut ctx)?;
26
27 let env = ctx.data();
28
29 let memory = unsafe { env.memory_view(&ctx) };
30 let event = if event_ref.offset() != M::ZERO {
31 Some(wasi_try_mem_ok!(event_ref.read(&memory)))
32 } else {
33 None
34 };
35
36 let event_ctl = event.map(|evt| EpollEventCtl {
37 events: evt.events,
38 ptr: evt.data.ptr.into(),
39 fd: evt.data.fd,
40 data1: evt.data.data1,
41 data2: evt.data.data2,
42 });
43
44 wasi_try_ok!(epoll_ctl_internal(
45 &mut ctx,
46 epfd,
47 op,
48 fd,
49 event_ctl.as_ref()
50 )?);
51 let env = ctx.data();
52
53 #[cfg(feature = "journal")]
54 if env.enable_journal {
55 JournalEffector::save_epoll_ctl(&mut ctx, epfd, op, fd, event_ctl).map_err(|err| {
56 tracing::error!("failed to save epoll_create event - {}", err);
57 WasiError::Exit(ExitCode::from(Errno::Fault))
58 })?;
59 }
60
61 Ok(Errno::Success)
62}
63
64pub(crate) fn epoll_ctl_internal(
65 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
66 epfd: WasiFd,
67 op: EpollCtl,
68 fd: WasiFd,
69 event_ctl: Option<&EpollEventCtl>,
70) -> Result<Result<(), Errno>, WasiError> {
71 let env = ctx.data();
72 let fd_entry = wasi_try_ok_ok!(env.state.fs.get_fd(epfd));
73
74 let mut inode_guard = fd_entry.inode.read();
75 match inode_guard.deref() {
76 Kind::Epoll { state } => {
77 let res = match op {
78 EpollCtl::Add => {
79 let Some(event) = event_ctl else {
80 return Ok(Err(Errno::Inval));
81 };
82 let (epoll_fd, sub_state) = match state.prepare_add(fd, event) {
83 Ok(v) => v,
84 Err(err) => return Ok(Err(err)),
85 };
86
87 match register_epoll_handler(
88 &env.state,
89 &epoll_fd,
90 state.clone(),
91 sub_state.clone(),
92 ) {
93 Ok(fd_guard) => {
94 if let Some(fd_guard) = fd_guard {
95 sub_state.add_join(fd_guard);
96 }
97 Ok(())
98 }
99 Err(err) => {
100 state.rollback_registration(fd, None);
101 Err(err)
102 }
103 }
104 }
105 EpollCtl::Mod => {
106 let Some(event) = event_ctl else {
107 return Ok(Err(Errno::Inval));
108 };
109 let (epoll_fd, sub_state, old_subscription) = match state.prepare_mod(fd, event)
110 {
111 Ok(v) => v,
112 Err(err) => return Ok(Err(err)),
113 };
114 old_subscription.detach_joins();
117
118 match register_epoll_handler(
119 &env.state,
120 &epoll_fd,
121 state.clone(),
122 sub_state.clone(),
123 ) {
124 Ok(fd_guard) => {
125 if let Some(fd_guard) = fd_guard {
126 sub_state.add_join(fd_guard);
127 }
128 Ok(())
129 }
130 Err(err) => {
131 state.rollback_registration(fd, Some(old_subscription.clone()));
132 let old_epoll_fd = old_subscription.fd_meta();
133 match register_epoll_handler(
134 &env.state,
135 &old_epoll_fd,
136 state.clone(),
137 old_subscription.clone(),
138 ) {
139 Ok(fd_guard) => {
140 if let Some(fd_guard) = fd_guard {
141 old_subscription.add_join(fd_guard);
142 }
143 }
144 Err(reinstall_err) => {
145 state.rollback_registration(fd, None);
147 tracing::warn!(
148 fd,
149 ?err,
150 ?reinstall_err,
151 "failed to reinstall previous epoll handler after MOD failure"
152 );
153 return Ok(Err(reinstall_err));
154 }
155 }
156 Err(err)
157 }
158 }
159 }
160 EpollCtl::Del => state.apply_del(fd),
161 EpollCtl::Unknown => Err(Errno::Inval),
162 };
163 Ok(res)
164 }
165 _ => Ok(Err(Errno::Inval)),
166 }
167}