1use crate::mm::{
6 MemoryAccessorExt, NumberOfElementsRead, PAGE_SIZE, TaskMemoryAccessor, read_to_vec,
7};
8use crate::security;
9use crate::signals::{SignalInfo, send_standard_signal};
10use crate::task::{CurrentTask, EventHandler, WaitCallback, WaitCanceler, WaitQueue, Waiter};
11use crate::vfs::buffers::{
12 Buffer, InputBuffer, InputBufferCallback, MessageData, MessageQueue, OutputBuffer,
13 OutputBufferCallback, PeekBufferSegmentsCallback, PipeMessageData, UserBuffersOutputBuffer,
14};
15use crate::vfs::fs_registry::FsRegistry;
16use crate::vfs::{
17 CacheMode, FileHandle, FileObject, FileObjectState, FileOps, FileSystem, FileSystemHandle,
18 FileSystemOps, FileSystemOptions, FsNodeInfo, FsStr, SpecialNode, default_fcntl,
19 fileops_impl_nonseekable, fileops_impl_noop_sync,
20};
21use starnix_sync::{Mutex, MutexGuard};
22use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
23use starnix_types::user_buffer::{UserBuffer, UserBuffers};
24use starnix_types::vfs::default_statfs;
25use starnix_uapi::auth::CAP_SYS_RESOURCE;
26use starnix_uapi::errors::{EPIPE, Errno};
27use starnix_uapi::file_mode::mode;
28use starnix_uapi::fs_type::FileSystemTypeFlags;
29use starnix_uapi::open_flags::OpenFlags;
30use starnix_uapi::signals::SIGPIPE;
31use starnix_uapi::user_address::{UserAddress, UserRef};
32use starnix_uapi::vfs::FdEvents;
33use starnix_uapi::{
34 F_GETPIPE_SZ, F_SETPIPE_SZ, FIONREAD, PIPEFS_MAGIC, errno, error, statfs, uapi,
35};
36use std::cmp::Ordering;
37use std::sync::Arc;
38
39const ATOMIC_IO_BYTES: u16 = 4096;
40
41const PIPE_MAX_SIZE: usize = 1 << 31;
43
44fn round_up(value: usize, increment: usize) -> usize {
45 (value + (increment - 1)) & !(increment - 1)
46}
47
48#[derive(Debug)]
49pub struct Pipe {
50 messages: MessageQueue<PipeMessageData>,
51
52 waiters: WaitQueue,
53
54 reader_count: usize,
56
57 had_reader: bool,
59
60 writer_count: usize,
62
63 had_writer: bool,
65}
66
67pub type PipeHandle = Arc<Mutex<Pipe>>;
68
69impl Pipe {
70 pub fn new(default_pipe_capacity: usize) -> PipeHandle {
71 Arc::new(
72 Pipe {
73 messages: MessageQueue::new(default_pipe_capacity),
74 waiters: WaitQueue::default(),
75 reader_count: 0,
76 had_reader: false,
77 writer_count: 0,
78 had_writer: false,
79 }
80 .into(),
81 )
82 }
83
84 pub fn open(
85 current_task: &CurrentTask,
86 pipe: &PipeHandle,
87 flags: OpenFlags,
88 ) -> Result<Box<dyn FileOps>, Errno> {
89 let mut events = FdEvents::empty();
90 let mut pipe_locked = pipe.lock();
91 let mut must_wait_events = FdEvents::empty();
92 if flags.can_read() {
93 if !pipe_locked.had_reader {
94 events |= FdEvents::POLLOUT;
95 }
96 pipe_locked.add_reader();
97 if !flags.contains(OpenFlags::NONBLOCK) && !flags.can_write() && !pipe_locked.had_writer
98 {
99 must_wait_events |= FdEvents::POLLIN;
100 }
101 }
102 if flags.can_write() {
103 if flags.contains(OpenFlags::NONBLOCK) && pipe_locked.reader_count == 0 {
108 assert!(!flags.can_read()); return error!(ENXIO);
110 }
111 if !pipe_locked.had_writer {
112 events |= FdEvents::POLLIN;
113 }
114 pipe_locked.add_writer();
115 if !flags.contains(OpenFlags::NONBLOCK) && !pipe_locked.had_reader {
116 must_wait_events |= FdEvents::POLLOUT;
117 }
118 }
119 if events != FdEvents::empty() {
120 pipe_locked.waiters.notify_fd_events(events);
121 }
122 let ops = PipeFileObject { pipe: Arc::clone(pipe) };
123 if must_wait_events == FdEvents::empty() {
124 return Ok(Box::new(ops));
125 }
126
127 let ops = scopeguard::guard(ops, |ops| {
129 ops.on_close(flags);
130 });
131
132 let waiter = Waiter::new();
134 loop {
135 pipe_locked.waiters.wait_async_fd_events(
136 &waiter,
137 must_wait_events,
138 WaitCallback::none(),
139 );
140 std::mem::drop(pipe_locked);
141 match waiter.wait(current_task) {
142 Err(e) => {
143 return Err(e);
144 }
145 _ => {}
146 }
147 pipe_locked = pipe.lock();
148 if pipe_locked.had_writer && pipe_locked.had_reader {
149 return Ok(Box::new(scopeguard::ScopeGuard::into_inner(ops)));
150 }
151 }
152 }
153
154 pub fn add_reader(&mut self) {
156 self.reader_count += 1;
157 self.had_reader = true;
158 }
159
160 pub fn add_writer(&mut self) {
162 self.writer_count += 1;
163 self.had_writer = true;
164 }
165
166 pub fn on_close(&mut self) {
169 if self.reader_count == 0 && self.writer_count == 0 {
170 self.had_reader = false;
171 self.had_writer = false;
172 self.messages = MessageQueue::new(self.messages.capacity());
173 self.waiters = WaitQueue::default();
174 }
175 }
176
177 fn is_empty(&self) -> bool {
178 self.messages.is_empty()
179 }
180
181 fn capacity(&self) -> usize {
182 self.messages.capacity()
183 }
184
185 fn set_capacity(
186 &mut self,
187 current_task: &CurrentTask,
188 mut requested_capacity: usize,
189 ) -> Result<(), Errno> {
190 if requested_capacity > PIPE_MAX_SIZE {
191 return error!(EINVAL);
192 }
193 if requested_capacity
194 > current_task
195 .kernel()
196 .system_limits
197 .pipe_max_size
198 .load(std::sync::atomic::Ordering::Relaxed)
199 {
200 security::check_task_capable(current_task, CAP_SYS_RESOURCE)?;
201 }
202 let page_size = *PAGE_SIZE as usize;
203 if requested_capacity < page_size {
204 requested_capacity = page_size;
205 }
206 requested_capacity = round_up(requested_capacity, page_size);
207 self.messages.set_capacity(requested_capacity)
208 }
209
210 fn is_readable(&self) -> bool {
211 !self.is_empty() || (self.writer_count == 0 && self.had_writer)
212 }
213
214 fn is_writable(&self, data_size: usize) -> bool {
216 let available_capacity = self.messages.available_capacity();
217 self.had_reader
220 && (self.reader_count == 0
221 || available_capacity >= data_size
222 || (available_capacity > 0 && data_size > uapi::PIPE_BUF as usize))
223 }
224
225 pub fn read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
226 if !self.is_readable() {
230 return error!(EAGAIN);
231 }
232
233 self.messages.read_stream(data).map(|(info, _)| info.bytes_read)
234 }
235
236 pub fn write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
237 if !self.had_reader {
238 return error!(EAGAIN);
239 }
240
241 if self.reader_count == 0 {
242 return error!(EPIPE);
243 }
244
245 if !self.is_writable(data.available()) {
246 return error!(EAGAIN);
247 }
248
249 self.messages.write_stream(data, None, &mut vec![])
250 }
251
252 fn query_events(&self, flags: OpenFlags) -> FdEvents {
253 let mut events = FdEvents::empty();
254
255 if flags.can_read() && self.is_readable() {
256 let writer_closed = self.writer_count == 0 && self.had_writer;
257 let has_data = !self.is_empty();
258 if writer_closed {
259 events |= FdEvents::POLLHUP;
260 }
261 if has_data {
262 events |= FdEvents::POLLIN;
263 }
264 }
265
266 if flags.can_write() && self.is_writable(uapi::PIPE_BUF as usize) {
267 if self.reader_count == 0 && self.had_reader {
268 events |= FdEvents::POLLERR;
269 }
270
271 events |= FdEvents::POLLOUT;
272 }
273
274 events
275 }
276
277 fn fcntl(
278 &mut self,
279 _file: &FileObject,
280 current_task: &CurrentTask,
281 cmd: u32,
282 arg: u64,
283 ) -> Result<SyscallResult, Errno> {
284 match cmd {
285 F_GETPIPE_SZ => Ok(self.capacity().into()),
286 F_SETPIPE_SZ => {
287 self.set_capacity(current_task, arg as usize)?;
288 Ok(self.capacity().into())
289 }
290 _ => default_fcntl(cmd),
291 }
292 }
293
294 fn ioctl(
295 &self,
296 _file: &FileObject,
297 current_task: &CurrentTask,
298 request: u32,
299 arg: SyscallArg,
300 ) -> Result<SyscallResult, Errno> {
301 let user_addr = UserAddress::from(arg);
302 match request {
303 FIONREAD => {
304 let addr = UserRef::<i32>::new(user_addr);
305 let value: i32 = self.messages.len().try_into().map_err(|_| errno!(EINVAL))?;
306 current_task.write_object(addr, &value)?;
307 Ok(SUCCESS)
308 }
309 _ => error!(ENOTTY),
310 }
311 }
312
313 fn notify_fd_events(&self, events: FdEvents) {
314 self.waiters.notify_fd_events(events);
315 }
316
317 pub fn splice(from: &mut Pipe, to: &mut Pipe, len: usize) -> Result<usize, Errno> {
319 if len == 0 {
320 return Ok(0);
321 }
322 let to_was_empty = to.is_empty();
323 let mut bytes_transferred = 0;
324 loop {
325 let limit = std::cmp::min(len - bytes_transferred, to.messages.available_capacity());
326 if limit == 0 {
327 break;
329 }
330 let Some(mut message) = from.messages.read_message() else {
331 break;
333 };
334 if let Some(data) = MessageData::split_off(&mut message.data, limit) {
335 assert!(data.len() > 0);
337 from.messages.write_front(data.into());
338 }
339 bytes_transferred += message.len();
340 to.messages.write_message(message);
341 }
342 if bytes_transferred > 0 {
343 if from.is_empty() {
344 from.notify_fd_events(FdEvents::POLLOUT);
345 }
346 if to_was_empty {
347 to.notify_fd_events(FdEvents::POLLIN);
348 }
349 }
350 return Ok(bytes_transferred);
351 }
352
353 pub fn tee(from: &mut Pipe, to: &mut Pipe, len: usize) -> Result<usize, Errno> {
355 if len == 0 {
356 return Ok(0);
357 }
358 let to_was_empty = to.is_empty();
359 let mut bytes_transferred = 0;
360 for message in from.messages.peek_queue().iter() {
361 let limit = std::cmp::min(len - bytes_transferred, to.messages.available_capacity());
362 if limit == 0 {
363 break;
364 }
365 let message = message.clone_at_most(limit);
366 bytes_transferred += message.len();
367 to.messages.write_message(message);
368 }
369 if bytes_transferred > 0 && to_was_empty {
370 to.notify_fd_events(FdEvents::POLLIN);
371 }
372 return Ok(bytes_transferred);
373 }
374}
375
376pub fn new_pipe(current_task: &CurrentTask) -> Result<(FileHandle, FileHandle), Errno> {
382 let fs = current_task
383 .kernel()
384 .expando
385 .get::<FsRegistry>()
386 .create(current_task, "pipefs".into(), FileSystemOptions::default())
387 .ok_or_else(|| errno!(EINVAL))??;
388 let mut info = FsNodeInfo::new(mode!(IFIFO, 0o600), current_task.current_fscred());
389 info.blksize = ATOMIC_IO_BYTES.into();
390 let node = fs.create_node_and_allocate_node_id(SpecialNode, info);
391 let pipe = node.fifo(current_task);
392 {
393 let mut state = pipe.lock();
394 state.add_reader();
395 state.add_writer();
396 }
397
398 let read_ops = PipeFileObject { pipe: Arc::clone(pipe) };
400 let read_file = FileObject::new_anonymous(
401 current_task,
402 Box::new(read_ops),
403 Arc::clone(&node),
404 OpenFlags::RDONLY,
405 );
406
407 let write_ops = PipeFileObject { pipe: Arc::clone(pipe) };
409 let write_file = FileObject::new(
410 current_task,
411 Box::new(write_ops),
412 read_file.name.to_passive(),
413 OpenFlags::WRONLY,
414 )?;
415
416 Ok((read_file, write_file))
417}
418
419struct PipeFs;
420impl FileSystemOps for PipeFs {
421 fn statfs(&self, _fs: &FileSystem, _current_task: &CurrentTask) -> Result<statfs, Errno> {
422 Ok(default_statfs(PIPEFS_MAGIC))
423 }
424 fn name(&self) -> &'static FsStr {
425 "pipefs".into()
426 }
427}
428
429fn pipe_fs(
430 current_task: &CurrentTask,
431 _options: FileSystemOptions,
432) -> Result<FileSystemHandle, Errno> {
433 struct PipeFsHandle(FileSystemHandle);
434
435 let kernel = current_task.kernel();
436 Ok(kernel
437 .expando
438 .get_or_init(|| {
439 PipeFsHandle(
440 FileSystem::new(kernel, CacheMode::Uncached, PipeFs, FileSystemOptions::default())
441 .expect("pipefs constructed with valid options"),
442 )
443 })
444 .0
445 .clone())
446}
447
448pub fn register_pipe_fs(fs_registry: &FsRegistry) {
449 fs_registry.register("pipefs".into(), FileSystemTypeFlags::empty(), pipe_fs);
450}
451
452pub struct PipeFileObject {
453 pipe: PipeHandle,
454}
455
456impl FileOps for PipeFileObject {
457 fileops_impl_nonseekable!();
458 fileops_impl_noop_sync!();
459
460 fn close(self: Box<Self>, file: &FileObjectState, _current_task: &CurrentTask) {
461 self.on_close(file.flags());
462 }
463
464 fn read(
465 &self,
466 file: &FileObject,
467 current_task: &CurrentTask,
468 offset: usize,
469 data: &mut dyn OutputBuffer,
470 ) -> Result<usize, Errno> {
471 debug_assert!(offset == 0);
472 if data.available() == 0 {
473 return Ok(0);
474 }
475 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
476 let mut pipe = self.pipe.lock();
477 let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
478 let actual = pipe.read(data)?;
479 if !was_writable && pipe.is_writable(uapi::PIPE_BUF as usize) {
480 pipe.notify_fd_events(FdEvents::POLLOUT);
481 }
482 Ok(actual)
483 })
484 }
485
486 fn write(
487 &self,
488 file: &FileObject,
489 current_task: &CurrentTask,
490 offset: usize,
491 data: &mut dyn InputBuffer,
492 ) -> Result<usize, Errno> {
493 debug_assert!(offset == 0);
494 debug_assert!(data.bytes_read() == 0);
495 if data.available() == 0 {
496 return Ok(0);
497 }
498
499 let result = file.blocking_op(current_task, FdEvents::POLLOUT, None, || {
500 let mut pipe = self.pipe.lock();
501 let offset_before = data.bytes_read();
502 let bytes_written = match pipe.write(data) {
503 Err(e) if e == EPIPE => {
504 std::mem::drop(pipe);
505 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
506 return Err(e);
507 }
508 result => result?,
509 };
510 debug_assert!(data.bytes_read() - offset_before == bytes_written);
511 if bytes_written > 0 {
512 pipe.notify_fd_events(FdEvents::POLLIN);
513 }
514 if data.available() > 0 {
515 return error!(EAGAIN);
516 }
517 Ok(())
518 });
519
520 let bytes_written = data.bytes_read();
521 if bytes_written == 0 {
522 result?;
524 }
525 Ok(bytes_written)
526 }
527
528 fn wait_async(
529 &self,
530 file: &FileObject,
531 _current_task: &CurrentTask,
532 waiter: &Waiter,
533 mut events: FdEvents,
534 handler: EventHandler,
535 ) -> Option<WaitCanceler> {
536 let flags = file.flags();
537 if !flags.can_read() {
538 events.remove(FdEvents::POLLIN);
539 }
540 if !flags.can_write() {
541 events.remove(FdEvents::POLLOUT);
542 }
543 Some(self.pipe.lock().waiters.wait_async_fd_events(waiter, events, handler))
544 }
545
546 fn query_events(
547 &self,
548 file: &FileObject,
549 _current_task: &CurrentTask,
550 ) -> Result<FdEvents, Errno> {
551 Ok(self.pipe.lock().query_events(file.flags()))
552 }
553
554 fn fcntl(
555 &self,
556 file: &FileObject,
557 current_task: &CurrentTask,
558 cmd: u32,
559 arg: u64,
560 ) -> Result<SyscallResult, Errno> {
561 self.pipe.lock().fcntl(file, current_task, cmd, arg)
562 }
563
564 fn ioctl(
565 &self,
566 file: &FileObject,
567 current_task: &CurrentTask,
568 request: u32,
569 arg: SyscallArg,
570 ) -> Result<SyscallResult, Errno> {
571 self.pipe.lock().ioctl(file, current_task, request, arg)
572 }
573}
574
575#[derive(Debug)]
577struct SpliceOutputBuffer<'a> {
578 pipe: &'a mut Pipe,
579 len: usize,
580 available: usize,
581}
582
583impl<'a> Buffer for SpliceOutputBuffer<'a> {
584 fn segments_count(&self) -> Result<usize, Errno> {
585 error!(ENOTSUP)
586 }
587
588 fn peek_each_segment(
589 &mut self,
590 _callback: &mut PeekBufferSegmentsCallback<'_>,
591 ) -> Result<(), Errno> {
592 error!(ENOTSUP)
593 }
594}
595
596impl<'a> OutputBuffer for SpliceOutputBuffer<'a> {
597 fn write_each(&mut self, callback: &mut OutputBufferCallback<'_>) -> Result<usize, Errno> {
598 let bytes = unsafe {
600 read_to_vec::<u8, _>(self.available, |buf| callback(buf).map(NumberOfElementsRead))
601 }?;
602 let bytes_len = bytes.len();
603 if bytes_len > 0 {
604 let was_empty = self.pipe.is_empty();
605 self.pipe.messages.write_message(PipeMessageData::from(bytes).into());
606 if was_empty {
607 self.pipe.notify_fd_events(FdEvents::POLLIN);
608 }
609 self.available -= bytes_len;
610 }
611 Ok(bytes_len)
612 }
613
614 fn available(&self) -> usize {
615 self.available
616 }
617
618 fn bytes_written(&self) -> usize {
619 self.len - self.available
620 }
621
622 fn zero(&mut self) -> Result<usize, Errno> {
623 let bytes = vec![0; self.available];
624 let len = bytes.len();
625 if len > 0 {
626 let was_empty = self.pipe.is_empty();
627 self.pipe.messages.write_message(PipeMessageData::from(bytes).into());
628 if was_empty {
629 self.pipe.notify_fd_events(FdEvents::POLLIN);
630 }
631 self.available -= len;
632 }
633 Ok(len)
634 }
635
636 unsafe fn advance(&mut self, _length: usize) -> Result<(), Errno> {
637 error!(ENOTSUP)
638 }
639}
640
641#[derive(Debug)]
643struct SpliceInputBuffer<'a> {
644 pipe: &'a mut Pipe,
645 len: usize,
646 available: usize,
647}
648
649impl<'a> Buffer for SpliceInputBuffer<'a> {
650 fn segments_count(&self) -> Result<usize, Errno> {
651 Ok(self.pipe.messages.len())
652 }
653
654 fn peek_each_segment(
655 &mut self,
656 callback: &mut PeekBufferSegmentsCallback<'_>,
657 ) -> Result<(), Errno> {
658 let mut available = self.available;
659 for message in self.pipe.messages.messages() {
660 let to_read = std::cmp::min(available, message.len());
661 callback(&UserBuffer {
662 address: UserAddress::from(message.data.ptr()? as u64),
663 length: to_read,
664 });
665 available -= to_read;
666 }
667 Ok(())
668 }
669}
670
671impl<'a> InputBuffer for SpliceInputBuffer<'a> {
672 fn peek_each(&mut self, callback: &mut InputBufferCallback<'_>) -> Result<usize, Errno> {
673 let mut read = 0;
674 let mut available = self.available;
675 for message in self.pipe.messages.messages() {
676 let to_read = std::cmp::min(available, message.len());
677 let result = message.data.with_bytes(|bytes| callback(&bytes[0..to_read]))?;
678 if result > to_read {
679 return error!(EINVAL);
680 }
681 read += result;
682 available -= result;
683 if result != to_read {
684 break;
685 }
686 }
687 Ok(read)
688 }
689
690 fn available(&self) -> usize {
691 self.available
692 }
693
694 fn bytes_read(&self) -> usize {
695 self.len - self.available
696 }
697
698 fn drain(&mut self) -> usize {
699 let result = self.available;
700 self.available = 0;
701 result
702 }
703
704 fn advance(&mut self, mut length: usize) -> Result<(), Errno> {
705 if length == 0 {
706 return Ok(());
707 }
708 if length > self.available {
709 return error!(EINVAL);
710 }
711 self.available -= length;
712 while let Some(mut message) = self.pipe.messages.read_message() {
713 if let Some(data) = MessageData::split_off(&mut message.data, length) {
714 self.pipe.messages.write_front(data.into());
716 }
717 length -= message.len();
718 if length == 0 {
719 if self.pipe.is_empty() {
720 self.pipe.notify_fd_events(FdEvents::POLLOUT);
721 }
722 return Ok(());
723 }
724 }
725 panic!();
726 }
727}
728
729impl PipeFileObject {
730 fn on_close(&self, flags: OpenFlags) {
732 let mut events = FdEvents::empty();
733 let mut pipe = self.pipe.lock();
734 if flags.can_read() {
735 assert!(pipe.reader_count > 0);
736 pipe.reader_count -= 1;
737 if pipe.reader_count == 0 {
738 events |= FdEvents::POLLOUT | FdEvents::POLLERR;
739 }
740 }
741 if flags.can_write() {
742 assert!(pipe.writer_count > 0);
743 pipe.writer_count -= 1;
744 if pipe.writer_count == 0 {
745 if pipe.reader_count > 0 {
746 events |= FdEvents::POLLHUP;
747 }
748 if !pipe.is_empty() {
749 events |= FdEvents::POLLIN;
750 }
751 }
752 }
753 if events != FdEvents::empty() {
754 pipe.waiters.notify_fd_events(events);
755 }
756 pipe.on_close();
757 }
758
759 fn wait_for_condition<'a, F, G, V>(
765 &'a self,
766 current_task: &CurrentTask,
767 file: &FileHandle,
768 condition: F,
769 pregen: G,
770 events: FdEvents,
771 ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
772 where
773 F: Fn(&Pipe) -> bool,
774 G: Fn() -> Result<V, Errno>,
775 {
776 file.blocking_op(current_task, events, None, || {
777 let other = pregen()?;
778 let pipe = self.pipe.lock();
779 if condition(&pipe) { Ok((other, pipe)) } else { error!(EAGAIN) }
780 })
781 }
782
783 fn lock_pipe_for_reading_with<'a, G, V>(
785 &'a self,
786 current_task: &CurrentTask,
787 file: &FileHandle,
788 pregen: G,
789 non_blocking: bool,
790 ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
791 where
792 G: Fn() -> Result<V, Errno>,
793 {
794 if non_blocking {
795 let other = pregen()?;
796 let pipe = self.pipe.lock();
797 if !pipe.is_readable() {
798 return error!(EAGAIN);
799 }
800 Ok((other, pipe))
801 } else {
802 self.wait_for_condition(
803 current_task,
804 file,
805 |pipe| pipe.is_readable(),
806 pregen,
807 FdEvents::POLLIN | FdEvents::POLLHUP,
808 )
809 }
810 }
811
812 fn lock_pipe_for_reading<'a>(
813 &'a self,
814 current_task: &CurrentTask,
815 file: &FileHandle,
816 non_blocking: bool,
817 ) -> Result<MutexGuard<'a, Pipe>, Errno> {
818 self.lock_pipe_for_reading_with(current_task, file, || Ok(()), non_blocking).map(|(_, l)| l)
819 }
820
821 fn lock_pipe_for_writing_with<'a, G, V>(
823 &'a self,
824 current_task: &CurrentTask,
825 file: &FileHandle,
826 pregen: G,
827 non_blocking: bool,
828 len: usize,
829 ) -> Result<(V, MutexGuard<'a, Pipe>), Errno>
830 where
831 G: Fn() -> Result<V, Errno>,
832 {
833 let (other, pipe) = if non_blocking {
834 let other = pregen()?;
835 let pipe = self.pipe.lock();
836 if !pipe.is_writable(len) {
837 return error!(EAGAIN);
838 }
839 (other, pipe)
840 } else {
841 self.wait_for_condition(
842 current_task,
843 file,
844 |pipe| pipe.is_writable(len),
845 pregen,
846 FdEvents::POLLOUT,
847 )?
848 };
849 if pipe.reader_count == 0 {
850 std::mem::drop((other, pipe));
851 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
852 return error!(EPIPE);
853 }
854 Ok((other, pipe))
855 }
856
857 fn lock_pipe_for_writing<'a>(
858 &'a self,
859 current_task: &CurrentTask,
860 file: &FileHandle,
861 non_blocking: bool,
862 len: usize,
863 ) -> Result<MutexGuard<'a, Pipe>, Errno> {
864 self.lock_pipe_for_writing_with(current_task, file, || Ok(()), non_blocking, len)
865 .map(|(_, l)| l)
866 }
867
868 pub fn splice_from(
873 &self,
874 current_task: &CurrentTask,
875 self_file: &FileHandle,
876 from: &FileHandle,
877 maybe_offset: Option<usize>,
878 len: usize,
879 non_blocking: bool,
880 ) -> Result<usize, Errno> {
881 assert!(from.downcast_file::<PipeFileObject>().is_none());
883
884 let mut pipe = self.lock_pipe_for_writing(current_task, self_file, non_blocking, len)?;
885 let len = std::cmp::min(len, pipe.messages.available_capacity());
886 let mut buffer = SpliceOutputBuffer { pipe: &mut pipe, len, available: len };
887 let result = if let Some(offset) = maybe_offset {
888 from.read_at(current_task, offset, &mut buffer)
889 } else {
890 from.read(current_task, &mut buffer)
891 };
892 std::mem::drop(pipe);
893 if let Err(err) = &result
894 && *err == EPIPE
895 {
896 send_standard_signal(current_task, SignalInfo::kernel(SIGPIPE));
897 }
898 result
899 }
900
901 pub fn splice_to(
906 &self,
907 current_task: &CurrentTask,
908 self_file: &FileHandle,
909 to: &FileHandle,
910 maybe_offset: Option<usize>,
911 len: usize,
912 non_blocking: bool,
913 ) -> Result<usize, Errno> {
914 assert!(to.downcast_file::<PipeFileObject>().is_none());
916
917 let mut pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
918 let len = std::cmp::min(len, pipe.messages.len());
919 let mut buffer = SpliceInputBuffer { pipe: &mut pipe, len, available: len };
920 if let Some(offset) = maybe_offset {
921 to.write_at(current_task, offset, &mut buffer)
922 } else {
923 to.write(current_task, &mut buffer)
924 }
925 }
926
927 pub fn vmsplice_from(
931 &self,
932 current_task: &CurrentTask,
933 self_file: &FileHandle,
934 mut iovec: UserBuffers,
935 non_blocking: bool,
936 ) -> Result<usize, Errno> {
937 let available = UserBuffer::cap_buffers_to_max_rw_count(
938 current_task.maximum_valid_address().ok_or_else(|| errno!(EINVAL))?,
939 &mut iovec,
940 )?;
941 if available == 0 {
942 return Ok(0);
943 }
944 let mappings = current_task.mm()?.get_mappings_for_vmsplice(&iovec)?;
945
946 let mut pipe =
947 self.lock_pipe_for_writing(current_task, self_file, non_blocking, available)?;
948
949 let mut remaining = std::cmp::min(available, pipe.messages.available_capacity());
950
951 let mut bytes_transferred = 0;
952 for mut mapping in mappings.into_iter() {
953 mapping.truncate(remaining);
954 let actual = mapping.len();
955
956 pipe.messages.write_message(PipeMessageData::Vmspliced(mapping).into());
957 remaining -= actual;
958 bytes_transferred += actual;
959
960 if remaining == 0 {
961 break;
962 }
963 }
964 if bytes_transferred > 0 {
965 pipe.notify_fd_events(FdEvents::POLLIN);
966 }
967 Ok(bytes_transferred)
968 }
969
970 pub fn vmsplice_to(
974 &self,
975 current_task: &CurrentTask,
976 self_file: &FileHandle,
977 iovec: UserBuffers,
978 non_blocking: bool,
979 ) -> Result<usize, Errno> {
980 let mut data = UserBuffersOutputBuffer::unified_new(current_task, iovec)?;
981 if data.available() == 0 {
982 return Ok(0);
983 }
984 let mut pipe = self.lock_pipe_for_reading(current_task, self_file, non_blocking)?;
985 let was_writable = pipe.is_writable(uapi::PIPE_BUF as usize);
986 let actual = pipe.read(&mut data)?;
987 if !was_writable && pipe.is_writable(uapi::PIPE_BUF as usize) {
988 pipe.notify_fd_events(FdEvents::POLLOUT);
989 }
990 Ok(actual)
991 }
992
993 pub fn lock_pipes<'a, 'b>(
999 current_task: &CurrentTask,
1000 file_in: &'a FileHandle,
1001 file_out: &'b FileHandle,
1002 len: usize,
1003 non_blocking: bool,
1004 ) -> Result<PipeOperands<'a, 'b>, Errno> {
1005 let pipe_in = file_in.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1006 let pipe_out = file_out.downcast_file::<PipeFileObject>().ok_or_else(|| errno!(EINVAL))?;
1007
1008 let node_cmp =
1009 Arc::as_ptr(&file_in.name.entry.node).cmp(&Arc::as_ptr(&file_out.name.entry.node));
1010
1011 match node_cmp {
1012 Ordering::Equal => error!(EINVAL),
1013 Ordering::Less => {
1014 let (write, read) = pipe_in.lock_pipe_for_reading_with(
1015 current_task,
1016 file_in,
1017 || pipe_out.lock_pipe_for_writing(current_task, file_out, non_blocking, len),
1018 non_blocking,
1019 )?;
1020 Ok(PipeOperands { read, write })
1021 }
1022 Ordering::Greater => {
1023 let (read, write) = pipe_out.lock_pipe_for_writing_with(
1024 current_task,
1025 file_out,
1026 || pipe_in.lock_pipe_for_reading(current_task, file_in, non_blocking),
1027 non_blocking,
1028 len,
1029 )?;
1030 Ok(PipeOperands { read, write })
1031 }
1032 }
1033 }
1034}
1035
1036pub struct PipeOperands<'a, 'b> {
1037 pub read: MutexGuard<'a, Pipe>,
1038 pub write: MutexGuard<'b, Pipe>,
1039}
1040
1041#[cfg(test)]
1042mod tests {
1043 use super::*;
1044 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
1045 use crate::testing::{anon_test_file, spawn_kernel_and_run};
1046 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
1047
1048 struct StaticSourceFile {
1049 payload: &'static [u8],
1050 }
1051
1052 impl FileOps for StaticSourceFile {
1053 fileops_impl_nonseekable!();
1054 fileops_impl_noop_sync!();
1055
1056 fn read(
1057 &self,
1058 _file: &FileObject,
1059 _current_task: &CurrentTask,
1060 _offset: usize,
1061 data: &mut dyn OutputBuffer,
1062 ) -> Result<usize, Errno> {
1063 data.write(self.payload)
1064 }
1065
1066 fn write(
1067 &self,
1068 _file: &FileObject,
1069 _current_task: &CurrentTask,
1070 _offset: usize,
1071 _data: &mut dyn InputBuffer,
1072 ) -> Result<usize, Errno> {
1073 error!(ENOTSUP)
1074 }
1075 }
1076
1077 #[::fuchsia::test]
1078 async fn test_splice_from_closed_reader_returns_epipe_and_queues_sigpipe() {
1079 spawn_kernel_and_run(async |current_task| {
1080 let kernel = current_task.kernel();
1081 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1082
1083 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1084 std::mem::drop(pipe_out);
1085 current_task.trigger_delayed_releaser();
1086
1087 let source_file = anon_test_file(
1088 ¤t_task,
1089 Box::new(StaticSourceFile { payload: b"DATA" }),
1090 OpenFlags::RDONLY,
1091 );
1092 let err = pipe_in
1093 .downcast_file::<PipeFileObject>()
1094 .unwrap()
1095 .splice_from(¤t_task, &pipe_in, &source_file, None, 4, true)
1096 .unwrap_err();
1097 assert_eq!(err, errno!(EPIPE));
1098 assert!(current_task.write().signals_mut().has_queued(SIGPIPE));
1099 })
1100 .await;
1101 }
1102
1103 #[::fuchsia::test]
1104 async fn test_partial_read_wakes_blocked_writer() {
1105 spawn_kernel_and_run(async |current_task| {
1106 let kernel = current_task.kernel();
1107 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1108
1109 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1110 let capacity =
1111 pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().capacity();
1112 let fill = vec![b'A'; capacity];
1113 assert_eq!(
1114 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&fill)).unwrap(),
1115 capacity
1116 );
1117
1118 let pipe_in_clone = pipe_in.clone();
1119 let (writer_join, req) = SpawnRequestBuilder::new()
1120 .with_sync_closure(move |worker_task: &CurrentTask| {
1121 pipe_in_clone
1122 .write(worker_task, &mut VecInputBuffer::new(b"BBBB"))
1123 .expect("blocked write should succeed after partial read")
1124 })
1125 .build_with_sync_result();
1126 kernel.kthreads.spawner().spawn_from_request(req);
1127
1128 while pipe_in.downcast_file::<PipeFileObject>().unwrap().pipe.lock().waiters.is_empty()
1129 {
1130 std::thread::yield_now();
1131 }
1132
1133 let page_size = *PAGE_SIZE as usize;
1135 let mut partial = VecOutputBuffer::new(page_size);
1136 assert_eq!(pipe_out.read(¤t_task, &mut partial).unwrap(), page_size);
1137 assert_eq!(partial.data(), &fill[..page_size]);
1138
1139 assert_eq!(writer_join().unwrap(), 4);
1140 })
1141 .await;
1142 }
1143
1144 #[::fuchsia::test]
1145 async fn test_zero_length_pipe_io_and_no_empty_message_enqueued() {
1146 spawn_kernel_and_run(async |current_task| {
1147 let kernel = current_task.kernel();
1148 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1149
1150 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1151 let pipe_ops = pipe_out.downcast_file::<PipeFileObject>().unwrap();
1152
1153 assert_eq!(pipe_out.read(¤t_task, &mut VecOutputBuffer::new(0)).unwrap(), 0);
1155 assert_eq!(
1156 pipe_ops
1157 .vmsplice_to(¤t_task, &pipe_out, UserBuffers::default(), true)
1158 .unwrap(),
1159 0
1160 );
1161
1162 assert_eq!(pipe_ops.pipe.lock().write(&mut VecInputBuffer::new(b"")).unwrap(), 0);
1164 assert_eq!(pipe_ops.pipe.lock().messages.peek_queue().len(), 0);
1165
1166 std::mem::drop(pipe_out);
1169 current_task.trigger_delayed_releaser();
1170 assert_eq!(pipe_in.write(¤t_task, &mut VecInputBuffer::new(b"")).unwrap(), 0);
1171 let pipe_in_ops = pipe_in.downcast_file::<PipeFileObject>().unwrap();
1172 assert_eq!(
1173 pipe_in_ops
1174 .vmsplice_from(¤t_task, &pipe_in, UserBuffers::default(), true)
1175 .unwrap(),
1176 0
1177 );
1178 assert!(!current_task.write().signals_mut().has_queued(SIGPIPE));
1179 })
1180 .await;
1181 }
1182}