1use crate::arch::trap::SumGuard;
4use crate::kernel::current_cpu;
5use crate::uapi::errno::EFAULT;
6use crate::uapi::errno::EINVAL;
7use crate::uapi::iovec::IoVec;
8use crate::util::user_buffer::{validate_user_ptr, validate_user_ptr_mut};
9
10pub fn write(fd: usize, buf: *const u8, count: usize) -> isize {
16 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
18 let file = match task.lock().fd_table.get(fd) {
19 Ok(f) => f,
20 Err(e) => return e.to_errno(),
21 };
22
23 let result = {
25 let _guard = SumGuard::new();
26 let buffer = unsafe { core::slice::from_raw_parts(buf, count) };
27 match file.write(buffer) {
28 Ok(n) => n as isize,
29 Err(e) => e.to_errno(),
30 }
31 };
32
33 result
34}
35
36pub fn read(fd: usize, buf: *mut u8, count: usize) -> isize {
42 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
44 let file = match task.lock().fd_table.get(fd) {
45 Ok(f) => f,
46 Err(e) => return e.to_errno(),
47 };
48
49 let result = {
51 let _guard = SumGuard::new();
52 let buffer = unsafe { core::slice::from_raw_parts_mut(buf, count) };
53 match file.read(buffer) {
54 Ok(n) => n as isize,
55 Err(e) => e.to_errno(),
56 }
57 };
58
59 result
60}
61
62pub fn readv(fd: usize, iov: *const IoVec, iovcnt: usize) -> isize {
68 if iov.is_null() || iovcnt == 0 || iovcnt > 1024 {
69 return -(EINVAL as isize);
70 }
71
72 if !validate_user_ptr(iov) {
74 return -(EFAULT as isize);
75 }
76
77 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
78 let file = match task.lock().fd_table.get(fd) {
79 Ok(f) => f,
80 Err(e) => return e.to_errno(),
81 };
82
83 let _guard = SumGuard::new();
85 let iovec_array = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
86
87 let mut total_read = 0usize;
88 for vec in iovec_array {
89 if vec.iov_base.is_null() || vec.iov_len == 0 {
90 continue;
91 }
92
93 if !validate_user_ptr_mut(vec.iov_base) {
95 return if total_read > 0 {
96 total_read as isize
97 } else {
98 -(EFAULT as isize)
99 };
100 }
101
102 let buffer = unsafe { core::slice::from_raw_parts_mut(vec.iov_base, vec.iov_len) };
103 match file.read(buffer) {
104 Ok(n) => {
105 total_read += n;
106 if n < vec.iov_len {
107 break; }
109 }
110 Err(e) => {
111 return if total_read > 0 {
112 total_read as isize
113 } else {
114 e.to_errno()
115 };
116 }
117 }
118 }
119
120 total_read as isize
121}
122
123pub fn writev(fd: usize, iov: *const IoVec, iovcnt: usize) -> isize {
129 if iov.is_null() || iovcnt == 0 || iovcnt > 1024 {
130 return -(EINVAL as isize);
131 }
132
133 if !validate_user_ptr(iov) {
135 return -(EFAULT as isize);
136 }
137
138 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
139 let file = match task.lock().fd_table.get(fd) {
140 Ok(f) => f,
141 Err(e) => return e.to_errno(),
142 };
143
144 let _guard = SumGuard::new();
146 let iovec_array = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
147
148 let mut total_written = 0usize;
149 for vec in iovec_array {
150 if vec.iov_base.is_null() || vec.iov_len == 0 {
151 continue;
152 }
153
154 if !validate_user_ptr(vec.iov_base) {
156 return if total_written > 0 {
157 total_written as isize
158 } else {
159 -(EFAULT as isize)
160 };
161 }
162
163 let buffer = unsafe { core::slice::from_raw_parts(vec.iov_base, vec.iov_len) };
164 match file.write(buffer) {
165 Ok(n) => {
166 total_written += n;
167 if n < vec.iov_len {
168 break; }
170 }
171 Err(e) => {
172 return if total_written > 0 {
173 total_written as isize
174 } else {
175 e.to_errno()
176 };
177 }
178 }
179 }
180
181 total_written as isize
182}
183
184pub fn pread64(fd: usize, buf: *mut u8, count: usize, offset: i64) -> isize {
191 if offset < 0 {
192 return -(EINVAL as isize);
193 }
194
195 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
196 let file = match task.lock().fd_table.get(fd) {
197 Ok(f) => f,
198 Err(e) => return e.to_errno(),
199 };
200
201 let result = {
202 let _guard = SumGuard::new();
203 let buffer = unsafe { core::slice::from_raw_parts_mut(buf, count) };
204 match file.read_at(offset as usize, buffer) {
205 Ok(n) => n as isize,
206 Err(e) => e.to_errno(),
207 }
208 };
209
210 result
211}
212
213pub fn pwrite64(fd: usize, buf: *const u8, count: usize, offset: i64) -> isize {
220 if offset < 0 {
221 return -(EINVAL as isize);
222 }
223
224 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
225 let file = match task.lock().fd_table.get(fd) {
226 Ok(f) => f,
227 Err(e) => return e.to_errno(),
228 };
229
230 let result = {
231 let _guard = SumGuard::new();
232 let buffer = unsafe { core::slice::from_raw_parts(buf, count) };
233 match file.write_at(offset as usize, buffer) {
234 Ok(n) => n as isize,
235 Err(e) => e.to_errno(),
236 }
237 };
238
239 result
240}
241
242pub fn preadv(fd: usize, iov: *const IoVec, iovcnt: usize, offset: i64) -> isize {
249 if iov.is_null() || iovcnt == 0 || iovcnt > 1024 || offset < 0 {
250 return -(EINVAL as isize);
251 }
252
253 if !validate_user_ptr(iov) {
255 return -(EFAULT as isize);
256 }
257
258 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
259 let file = match task.lock().fd_table.get(fd) {
260 Ok(f) => f,
261 Err(e) => return e.to_errno(),
262 };
263
264 let _guard = SumGuard::new();
266 let iovec_array = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
267
268 let mut total_read = 0usize;
269 let mut current_offset = offset as usize;
270 for vec in iovec_array {
271 if vec.iov_base.is_null() || vec.iov_len == 0 {
272 continue;
273 }
274
275 if !validate_user_ptr_mut(vec.iov_base) {
277 return if total_read > 0 {
278 total_read as isize
279 } else {
280 -(EFAULT as isize)
281 };
282 }
283
284 let buffer = unsafe { core::slice::from_raw_parts_mut(vec.iov_base, vec.iov_len) };
285 match file.read_at(current_offset, buffer) {
286 Ok(n) => {
287 total_read += n;
288 current_offset += n;
289 if n < vec.iov_len {
290 break;
291 }
292 }
293 Err(e) => {
294 return if total_read > 0 {
295 total_read as isize
296 } else {
297 e.to_errno()
298 };
299 }
300 }
301 }
302
303 total_read as isize
304}
305
306pub fn pwritev(fd: usize, iov: *const IoVec, iovcnt: usize, offset: i64) -> isize {
313 if iov.is_null() || iovcnt == 0 || iovcnt > 1024 || offset < 0 {
314 return -(EINVAL as isize);
315 }
316
317 if !validate_user_ptr(iov) {
319 return -(EFAULT as isize);
320 }
321
322 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
323 let file = match task.lock().fd_table.get(fd) {
324 Ok(f) => f,
325 Err(e) => return e.to_errno(),
326 };
327
328 let _guard = SumGuard::new();
330 let iovec_array = unsafe { core::slice::from_raw_parts(iov, iovcnt) };
331
332 let mut total_written = 0usize;
333 let mut current_offset = offset as usize;
334 for vec in iovec_array {
335 if vec.iov_base.is_null() || vec.iov_len == 0 {
336 continue;
337 }
338
339 if !validate_user_ptr(vec.iov_base) {
341 return if total_written > 0 {
342 total_written as isize
343 } else {
344 -(EFAULT as isize)
345 };
346 }
347
348 let buffer = unsafe { core::slice::from_raw_parts(vec.iov_base, vec.iov_len) };
349 match file.write_at(current_offset, buffer) {
350 Ok(n) => {
351 total_written += n;
352 current_offset += n;
353 if n < vec.iov_len {
354 break;
355 }
356 }
357 Err(e) => {
358 return if total_written > 0 {
359 total_written as isize
360 } else {
361 e.to_errno()
362 };
363 }
364 }
365 }
366
367 total_written as isize
368}
369
370pub fn sendfile(out_fd: usize, in_fd: usize, offset: *mut i64, count: usize) -> isize {
377 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
378
379 let in_file = match task.lock().fd_table.get(in_fd) {
380 Ok(f) => f,
381 Err(e) => return e.to_errno(),
382 };
383
384 let out_file = match task.lock().fd_table.get(out_fd) {
385 Ok(f) => f,
386 Err(e) => return e.to_errno(),
387 };
388
389 let use_offset = !offset.is_null();
391 let mut current_offset = if use_offset {
392 let off = {
393 let _guard = SumGuard::new();
394 unsafe { *offset }
395 };
396 if off < 0 {
397 return -(EINVAL as isize);
398 }
399 off as usize
400 } else {
401 0
402 };
403
404 const BUFFER_SIZE: usize = 8192;
406 let mut buffer = [0u8; BUFFER_SIZE];
407 let mut total_sent = 0usize;
408 let mut remaining = count;
409
410 while remaining > 0 {
411 let to_read = core::cmp::min(remaining, BUFFER_SIZE);
412
413 let read_result = if use_offset {
415 in_file.read_at(current_offset, &mut buffer[..to_read])
416 } else {
417 in_file.read(&mut buffer[..to_read])
418 };
419
420 let n_read = match read_result {
421 Ok(0) => break, Ok(n) => n,
423 Err(e) => {
424 return if total_sent > 0 {
425 total_sent as isize
426 } else {
427 e.to_errno()
428 };
429 }
430 };
431
432 match out_file.write(&buffer[..n_read]) {
434 Ok(n_written) => {
435 total_sent += n_written;
436 if use_offset {
437 current_offset += n_written;
438 }
439 remaining -= n_written;
440 if n_written < n_read {
441 break; }
443 }
444 Err(e) => {
445 return if total_sent > 0 {
446 total_sent as isize
447 } else {
448 e.to_errno()
449 };
450 }
451 }
452 }
453
454 if use_offset {
456 let _guard = SumGuard::new();
457 unsafe { *offset = current_offset as i64 };
458 }
459
460 total_sent as isize
461}
462
463#[repr(C)]
465#[derive(Debug, Clone, Copy)]
466pub struct PollFd {
467 pub fd: i32,
468 pub events: i16,
469 pub revents: i16,
470}
471
472pub const POLLIN: i16 = 0x0001;
474pub const POLLOUT: i16 = 0x0004;
475pub const POLLERR: i16 = 0x0008;
476pub const POLLHUP: i16 = 0x0010;
477pub const POLLNVAL: i16 = 0x0020;
478
479use crate::kernel::scheduler::WaitQueue;
480use crate::sync::SpinLock;
481use lazy_static::lazy_static;
482
483lazy_static! {
484 static ref POLL_WAIT_QUEUE: SpinLock<WaitQueue> = SpinLock::new(WaitQueue::new());
485}
486
487pub fn wake_poll_waiters() {
489 POLL_WAIT_QUEUE.lock().wake_up_all();
490}
491
492pub fn ppoll(fds: usize, nfds: usize, timeout: usize, _sigmask: usize) -> isize {
494 use crate::arch::trap::SumGuard;
495 use crate::kernel::current_cpu;
496 use crate::uapi::errno::EINVAL;
497
498 if nfds > 0 && fds == 0 {
499 return -(EINVAL as isize);
500 }
501
502 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
503
504 let timeout_trigger = if timeout == 0 {
506 None } else {
508 let _guard = SumGuard::new();
509 unsafe {
510 let timespec = timeout as *const crate::uapi::time::TimeSpec;
511 if (*timespec).tv_sec < 0 {
512 None } else {
514 use crate::arch::timer::{clock_freq, get_time};
515 let duration_ns =
516 ((*timespec).tv_sec as u64 * 1_000_000_000) + (*timespec).tv_nsec as u64;
517 let duration_ticks = (duration_ns * clock_freq() as u64 / 1_000_000_000) as usize;
518 Some(get_time() + duration_ticks)
519 }
520 }
521 };
522
523 loop {
524 let mut ready_count = 0;
525
526 {
527 let _guard = SumGuard::new();
528 let pollfds = unsafe { core::slice::from_raw_parts_mut(fds as *mut PollFd, nfds) };
529
530 for pollfd in pollfds.iter_mut() {
531 pollfd.revents = 0;
532
533 if pollfd.fd < 0 {
534 continue;
535 }
536
537 let file = match task.lock().fd_table.get(pollfd.fd as usize) {
538 Ok(f) => f,
539 Err(_) => {
540 pollfd.revents = POLLNVAL;
541 ready_count += 1;
542 continue;
543 }
544 };
545
546 if (pollfd.events & POLLIN) != 0 && file.readable() {
547 pollfd.revents |= POLLIN;
548 }
549
550 if (pollfd.events & POLLOUT) != 0 && file.writable() {
551 pollfd.revents |= POLLOUT;
552 }
553
554 if pollfd.revents != 0 {
555 ready_count += 1;
556 }
557 }
558 }
559
560 if ready_count > 0 {
561 return ready_count;
562 }
563
564 if let Some(trigger) = timeout_trigger {
566 use crate::kernel::timer::TIMER_QUEUE;
567 let mut timer_q = TIMER_QUEUE.lock();
568 timer_q.push(trigger, task.clone());
569 drop(timer_q);
570 }
571
572 POLL_WAIT_QUEUE.lock().sleep(task.clone());
575 crate::kernel::schedule();
576
577 if timeout_trigger.is_some() {
579 use crate::kernel::timer::TIMER_QUEUE;
580 TIMER_QUEUE.lock().remove_task(&task);
581 }
582
583 if let Some(trigger) = timeout_trigger {
585 use crate::arch::timer::get_time;
586 if get_time() >= trigger {
587 return 0; }
589 }
590 }
591}
592
593pub fn pselect6(
596 nfds: usize,
597 readfds: usize,
598 writefds: usize,
599 exceptfds: usize,
600 timeout: usize,
601 _sigmask: usize,
602) -> isize {
603 select(nfds, readfds, writefds, exceptfds, timeout)
606}
607
608pub fn select(
610 nfds: usize,
611 readfds: usize,
612 writefds: usize,
613 exceptfds: usize,
614 timeout: usize,
615) -> isize {
616 use crate::arch::trap::SumGuard;
617 use crate::kernel::current_cpu;
618 use crate::uapi::errno::{EBADF, EINVAL};
619 use crate::uapi::select::FdSet;
620 use crate::uapi::time::timeval;
621
622 if nfds > crate::uapi::select::FD_SETSIZE {
623 return -(EINVAL as isize);
624 }
625
626 let task = current_cpu().lock().current_task.as_ref().unwrap().clone();
627
628 let timeout_trigger = if timeout == 0 {
630 None } else {
632 let _guard = SumGuard::new();
633 unsafe {
634 let tv = &*(timeout as *const timeval);
635 if tv.tv_sec < 0 || tv.tv_usec < 0 {
636 return -(EINVAL as isize);
637 }
638 if tv.is_zero() {
639 Some(0) } else {
641 use crate::arch::timer::{clock_freq, get_time};
642 let duration_ticks = tv.into_freq(clock_freq());
643 Some(get_time() + duration_ticks)
644 }
645 }
646 };
647
648 let (input_read, input_write, input_except) = {
650 let _guard = SumGuard::new();
651 (
652 if readfds != 0 {
653 Some(unsafe { *(readfds as *const FdSet) })
654 } else {
655 None
656 },
657 if writefds != 0 {
658 Some(unsafe { *(writefds as *const FdSet) })
659 } else {
660 None
661 },
662 if exceptfds != 0 {
663 Some(unsafe { *(exceptfds as *const FdSet) })
664 } else {
665 None
666 },
667 )
668 };
669
670 let check_fds = || -> (isize, Option<FdSet>, Option<FdSet>, Option<FdSet>) {
672 let mut ready_count = 0;
673 let mut read_set = input_read.as_ref().map(|_| FdSet::new());
674 let mut write_set = input_write.as_ref().map(|_| FdSet::new());
675 let mut except_set = input_except.as_ref().map(|_| FdSet::new());
676
677 let task_lock = task.lock();
678 for fd in 0..nfds {
679 let check_read = input_read.as_ref().map_or(false, |s| s.is_set(fd));
680 let check_write = input_write.as_ref().map_or(false, |s| s.is_set(fd));
681 let check_except = input_except.as_ref().map_or(false, |s| s.is_set(fd));
682
683 if !check_read && !check_write && !check_except {
684 continue;
685 }
686
687 let file = match task_lock.fd_table.get(fd) {
688 Ok(f) => f,
689 Err(_) => return (-(EBADF as isize), None, None, None),
690 };
691
692 let mut fd_ready = false;
693 if check_read && file.readable() {
694 if let Some(ref mut set) = read_set {
695 set.set(fd);
696 fd_ready = true;
697 }
698 }
699 if check_write && file.writable() {
700 if let Some(ref mut set) = write_set {
701 set.set(fd);
702 fd_ready = true;
703 }
704 }
705 if fd_ready {
707 ready_count += 1;
708 }
709 }
710 (ready_count, read_set, write_set, except_set)
711 };
712
713 loop {
714 let (ready_count, read_set, write_set, except_set) = check_fds();
715 if ready_count < 0 {
716 return ready_count;
717 } if ready_count > 0 {
720 let _guard = SumGuard::new();
721 if let Some(set) = read_set {
722 unsafe { *(readfds as *mut FdSet) = set };
723 }
724 if let Some(set) = write_set {
725 unsafe { *(writefds as *mut FdSet) = set };
726 }
727 if let Some(set) = except_set {
728 unsafe { *(exceptfds as *mut FdSet) = set };
729 }
730 return ready_count;
731 }
732
733 if let Some(0) = timeout_trigger {
734 return 0;
735 }
736
737 if let Some(trigger) = timeout_trigger {
738 use crate::kernel::timer::TIMER_QUEUE;
739 TIMER_QUEUE.lock().push(trigger, task.clone());
740 }
741
742 let slept = {
744 let mut wq = POLL_WAIT_QUEUE.lock();
745 wq.sleep_if(task.clone(), || {
746 let (ready, _, _, _) = check_fds();
747 ready > 0
748 })
749 };
750
751 if slept {
752 crate::kernel::schedule();
753
754 if timeout_trigger.is_some() {
755 use crate::kernel::timer::TIMER_QUEUE;
756 TIMER_QUEUE.lock().remove_task(&task);
757 }
758
759 if let Some(trigger) = timeout_trigger {
760 use crate::arch::timer::get_time;
761 if get_time() >= trigger {
762 return 0;
763 }
764 }
765 }
766 }
767}