os/kernel/syscall/
io.rs

1//! IO 相关的系统调用实现
2
3use 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
10/// 向文件描述符写入数据
11/// # 参数
12/// - `fd`: 文件描述符
13/// - `buf`: 要写入的数据缓冲区
14/// - `count`: 要写入的字节数
15pub fn write(fd: usize, buf: *const u8, count: usize) -> isize {
16    // 1. 获取文件对象
17    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    // 2. 访问用户态缓冲区并调用 File::write
24    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
36/// 从文件描述符读取数据
37/// # 参数
38/// - `fd`: 文件描述符
39/// - `buf`: 存储读取数据的缓冲区
40/// - `count`: 要读取的字节数
41pub fn read(fd: usize, buf: *mut u8, count: usize) -> isize {
42    // 1. 获取文件对象
43    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    // 2. 访问用户态缓冲区并调用 File::read
50    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
62/// 向量化读取:从文件描述符读取数据到多个缓冲区
63/// # 参数
64/// - `fd`: 文件描述符
65/// - `iov`: iovec 数组指针
66/// - `iovcnt`: iovec 数组元素个数
67pub 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    // 验证 iovec 数组指针
73    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    // 使用 SumGuard 保护整个用户空间访问区域
84    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        // 验证每个 iovec 条目的缓冲区指针
94        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; // 未读满说明已到文件末尾
108                }
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
123/// 向量化写入:将多个缓冲区的数据写入文件描述符
124/// # 参数
125/// - `fd`: 文件描述符
126/// - `iov`: iovec 数组指针
127/// - `iovcnt`: iovec 数组元素个数
128pub 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    // 验证 iovec 数组指针
134    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    // 使用 SumGuard 保护整个用户空间访问区域
145    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        // 验证每个 iovec 条目的缓冲区指针
155        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; // 未写完说明有问题
169                }
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
184/// 位置读取:从指定位置读取数据,不改变文件偏移量
185/// # 参数
186/// - `fd`: 文件描述符
187/// - `buf`: 存储读取数据的缓冲区
188/// - `count`: 要读取的字节数
189/// - `offset`: 文件偏移量
190pub 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
213/// 位置写入:向指定位置写入数据,不改变文件偏移量
214/// # 参数
215/// - `fd`: 文件描述符
216/// - `buf`: 要写入的数据缓冲区
217/// - `count`: 要写入的字节数
218/// - `offset`: 文件偏移量
219pub 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
242/// 向量化位置读取:从指定位置读取数据到多个缓冲区,不改变文件偏移量
243/// # 参数
244/// - `fd`: 文件描述符
245/// - `iov`: iovec 数组指针
246/// - `iovcnt`: iovec 数组元素个数
247/// - `offset`: 文件偏移量
248pub 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    // 验证 iovec 数组指针
254    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    // 使用 SumGuard 保护整个用户空间访问区域
265    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        // 验证每个 iovec 条目的缓冲区指针
276        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
306/// 向量化位置写入:将多个缓冲区的数据写入指定位置,不改变文件偏移量
307/// # 参数
308/// - `fd`: 文件描述符
309/// - `iov`: iovec 数组指针
310/// - `iovcnt`: iovec 数组元素个数
311/// - `offset`: 文件偏移量
312pub 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    // 验证 iovec 数组指针
318    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    // 使用 SumGuard 保护整个用户空间访问区域
329    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        // 验证每个 iovec 条目的缓冲区指针
340        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
370/// 零拷贝文件传输:从一个文件描述符传输数据到另一个
371/// # 参数
372/// - `out_fd`: 输出文件描述符
373/// - `in_fd`: 输入文件描述符
374/// - `offset`: 输入文件偏移量指针(如果非空,从该位置读取并更新)
375/// - `count`: 要传输的字节数
376pub 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    // 如果 offset 非空,使用 pread;否则使用 read
390    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    // 使用 8KB 缓冲区进行传输
405    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        // 读取数据
414        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, // EOF
422            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        // 写入数据
433        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; // 输出端写不完
442                }
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    // 更新 offset 指针
455    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/// pollfd 结构体
464#[repr(C)]
465#[derive(Debug, Clone, Copy)]
466pub struct PollFd {
467    pub fd: i32,
468    pub events: i16,
469    pub revents: i16,
470}
471
472/// poll 事件标志
473pub 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
487/// Wake up all tasks waiting in poll
488pub fn wake_poll_waiters() {
489    POLL_WAIT_QUEUE.lock().wake_up_all();
490}
491
492/// ppoll - poll 的变体,支持信号掩码
493pub 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    // Parse timeout: null pointer means infinite, otherwise it's a timespec
505    let timeout_trigger = if timeout == 0 {
506        None // Infinite timeout
507    } 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 // Negative means infinite
513            } 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        // Register timeout timer if needed
565        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        // Sleep atomically - WaitQueue::sleep() holds lock internally
573        // and marks task as blocked before releasing the lock
574        POLL_WAIT_QUEUE.lock().sleep(task.clone());
575        crate::kernel::schedule();
576
577        // Woken up - remove from timer queue if still there
578        if timeout_trigger.is_some() {
579            use crate::kernel::timer::TIMER_QUEUE;
580            TIMER_QUEUE.lock().remove_task(&task);
581        }
582
583        // Check if woken by timeout
584        if let Some(trigger) = timeout_trigger {
585            use crate::arch::timer::get_time;
586            if get_time() >= trigger {
587                return 0; // Timeout
588            }
589        }
590    }
591}
592
593/// pselect6 - synchronous I/O multiplexing with signal mask
594/// Note: sigmask handling requires signal subsystem refactoring, currently ignored
595pub fn pselect6(
596    nfds: usize,
597    readfds: usize,
598    writefds: usize,
599    exceptfds: usize,
600    timeout: usize,
601    _sigmask: usize,
602) -> isize {
603    // TODO: Implement signal mask handling when signal subsystem is refactored
604    // Requires exposing signal field in Task or adding helper methods
605    select(nfds, readfds, writefds, exceptfds, timeout)
606}
607
608/// select - synchronous I/O multiplexing
609pub 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    // Parse timeout
629    let timeout_trigger = if timeout == 0 {
630        None // Infinite timeout
631    } 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) // Poll mode (no wait)
640            } 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    // Copy input fd_sets once before loop
649    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    // Helper to check fds
671    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            // exceptfds: OOB data, errors (not implemented yet)
706            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        } // EBADF
718
719        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        // Atomic check-and-sleep to prevent lost wakeup
743        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}